From 0f3a8c3f34f728e7c96651bb7271e1c388c9aac2 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 25 Apr 2016 16:15:51 +0300 Subject: iio: Add support for creating IIO devices via configfs This is similar with support for creating triggers via configfs. Devices will be hosted under: * /config/iio/devices We allow users to register "device types" under: * /config/iio/devices// Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- include/linux/iio/sw_device.h | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 include/linux/iio/sw_device.h (limited to 'include/linux') diff --git a/include/linux/iio/sw_device.h b/include/linux/iio/sw_device.h new file mode 100644 index 000000000000..23ca41515527 --- /dev/null +++ b/include/linux/iio/sw_device.h @@ -0,0 +1,70 @@ +/* + * Industrial I/O software device interface + * + * Copyright (c) 2016 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef __IIO_SW_DEVICE +#define __IIO_SW_DEVICE + +#include +#include +#include +#include + +#define module_iio_sw_device_driver(__iio_sw_device_type) \ + module_driver(__iio_sw_device_type, iio_register_sw_device_type, \ + iio_unregister_sw_device_type) + +struct iio_sw_device_ops; + +struct iio_sw_device_type { + const char *name; + struct module *owner; + const struct iio_sw_device_ops *ops; + struct list_head list; + struct config_group *group; +}; + +struct iio_sw_device { + struct iio_dev *device; + struct iio_sw_device_type *device_type; + struct config_group group; +}; + +struct iio_sw_device_ops { + struct iio_sw_device* (*probe)(const char *); + int (*remove)(struct iio_sw_device *); +}; + +static inline +struct iio_sw_device *to_iio_sw_device(struct config_item *item) +{ + return container_of(to_config_group(item), struct iio_sw_device, + group); +} + +int iio_register_sw_device_type(struct iio_sw_device_type *dt); +void iio_unregister_sw_device_type(struct iio_sw_device_type *dt); + +struct iio_sw_device *iio_sw_device_create(const char *, const char *); +void iio_sw_device_destroy(struct iio_sw_device *); + +int iio_sw_device_type_configfs_register(struct iio_sw_device_type *dt); +void iio_sw_device_type_configfs_unregister(struct iio_sw_device_type *dt); + +static inline +void iio_swd_group_init_type_name(struct iio_sw_device *d, + const char *name, + struct config_item_type *type) +{ +#ifdef CONFIG_CONFIGFS_FS + config_group_init_type_name(&d->group, name, type); +#endif +} + +#endif /* __IIO_SW_DEVICE */ -- cgit v1.2.3 From dfe3ab1af0765eb800da5ce4cb4c685783096d9c Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Tue, 19 Apr 2016 11:18:38 +0200 Subject: iio:st_sensors: unexport st_sensors_get_buffer_element Remove st_sensors_get_buffer_element symbol export since not explicitly used outside of st_sensors driver. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_buffer.c | 3 +-- include/linux/iio/common/st_sensors.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index c55898543a47..4ccc438afb5f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -22,7 +22,7 @@ #include -int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) +static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) { int i, len; int total = 0; @@ -49,7 +49,6 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) return total; } -EXPORT_SYMBOL(st_sensors_get_buffer_element); irqreturn_t st_sensors_trigger_handler(int irq, void *p) { diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index d029ffac0d69..78a193494370 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -251,8 +251,6 @@ struct st_sensor_data { #ifdef CONFIG_IIO_BUFFER irqreturn_t st_sensors_trigger_handler(int irq, void *p); - -int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf); #endif #ifdef CONFIG_IIO_TRIGGER -- cgit v1.2.3 From 14f295c846063c4f1812b09427195cee522aa006 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Tue, 19 Apr 2016 11:18:40 +0200 Subject: iio:st_sensors: fix power regulator usage Ensure failure to enable power regulators is properly handled. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 12 ++++++---- drivers/iio/common/st_sensors/st_sensors_core.c | 29 ++++++++++++++++++++----- drivers/iio/gyro/st_gyro_core.c | 12 ++++++---- drivers/iio/magnetometer/st_magn_core.c | 12 ++++++---- drivers/iio/pressure/st_pressure_core.c | 12 ++++++---- include/linux/iio/common/st_sensors.h | 2 +- 6 files changed, 57 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index dc73f2d85e6d..b8d3c3c91b4d 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -757,13 +757,15 @@ int st_accel_common_probe(struct iio_dev *indio_dev) indio_dev->info = &accel_info; mutex_init(&adata->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_accel_sensors_settings), st_accel_sensors_settings); if (err < 0) - return err; + goto st_accel_power_off; adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS; adata->multiread_bit = adata->sensor_settings->multi_read_bit; @@ -780,11 +782,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data); if (err < 0) - return err; + goto st_accel_power_off; err = st_accel_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_accel_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -807,6 +809,8 @@ st_accel_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_accel_probe_trigger_error: st_accel_deallocate_ring(indio_dev); +st_accel_power_off: + st_sensors_power_disable(indio_dev); return err; } diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index dffe00692169..00078b5fe33c 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -228,7 +228,7 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) } EXPORT_SYMBOL(st_sensors_set_axis_enable); -void st_sensors_power_enable(struct iio_dev *indio_dev) +int st_sensors_power_enable(struct iio_dev *indio_dev) { struct st_sensor_data *pdata = iio_priv(indio_dev); int err; @@ -237,18 +237,37 @@ void st_sensors_power_enable(struct iio_dev *indio_dev) pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd"); if (!IS_ERR(pdata->vdd)) { err = regulator_enable(pdata->vdd); - if (err != 0) + if (err != 0) { dev_warn(&indio_dev->dev, "Failed to enable specified Vdd supply\n"); + return err; + } + } else { + err = PTR_ERR(pdata->vdd); + if (err != -ENODEV) + return err; } pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio"); if (!IS_ERR(pdata->vdd_io)) { err = regulator_enable(pdata->vdd_io); - if (err != 0) + if (err != 0) { dev_warn(&indio_dev->dev, "Failed to enable specified Vdd_IO supply\n"); + goto st_sensors_disable_vdd; + } + } else { + err = PTR_ERR(pdata->vdd_io); + if (err != -ENODEV) + goto st_sensors_disable_vdd; } + + return 0; + +st_sensors_disable_vdd: + if (!IS_ERR_OR_NULL(pdata->vdd)) + regulator_disable(pdata->vdd); + return err; } EXPORT_SYMBOL(st_sensors_power_enable); @@ -256,10 +275,10 @@ void st_sensors_power_disable(struct iio_dev *indio_dev) { struct st_sensor_data *pdata = iio_priv(indio_dev); - if (!IS_ERR(pdata->vdd)) + if (!IS_ERR_OR_NULL(pdata->vdd)) regulator_disable(pdata->vdd); - if (!IS_ERR(pdata->vdd_io)) + if (!IS_ERR_OR_NULL(pdata->vdd_io)) regulator_disable(pdata->vdd_io); } EXPORT_SYMBOL(st_sensors_power_disable); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 52a3c87c375c..ae1377da9a0b 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -425,13 +425,15 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) indio_dev->info = &gyro_info; mutex_init(&gdata->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_gyro_sensors_settings), st_gyro_sensors_settings); if (err < 0) - return err; + goto st_gyro_power_off; gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS; gdata->multiread_bit = gdata->sensor_settings->multi_read_bit; @@ -445,11 +447,11 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, (struct st_sensors_platform_data *)&gyro_pdata); if (err < 0) - return err; + goto st_gyro_power_off; err = st_gyro_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_gyro_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -472,6 +474,8 @@ st_gyro_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_gyro_probe_trigger_error: st_gyro_deallocate_ring(indio_dev); +st_gyro_power_off: + st_sensors_power_disable(indio_dev); return err; } diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 62036d2a9956..7c94adc3ff1d 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -588,13 +588,15 @@ int st_magn_common_probe(struct iio_dev *indio_dev) indio_dev->info = &magn_info; mutex_init(&mdata->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_magn_sensors_settings), st_magn_sensors_settings); if (err < 0) - return err; + goto st_magn_power_off; mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS; mdata->multiread_bit = mdata->sensor_settings->multi_read_bit; @@ -607,11 +609,11 @@ int st_magn_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, NULL); if (err < 0) - return err; + goto st_magn_power_off; err = st_magn_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_magn_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -634,6 +636,8 @@ st_magn_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_magn_probe_trigger_error: st_magn_deallocate_ring(indio_dev); +st_magn_power_off: + st_sensors_power_disable(indio_dev); return err; } diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index c0ff3bf071d8..4d317af55405 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -527,13 +527,15 @@ int st_press_common_probe(struct iio_dev *indio_dev) indio_dev->info = &press_info; mutex_init(&press_data->tb.buf_lock); - st_sensors_power_enable(indio_dev); + err = st_sensors_power_enable(indio_dev); + if (err) + return err; err = st_sensors_check_device_support(indio_dev, ARRAY_SIZE(st_press_sensors_settings), st_press_sensors_settings); if (err < 0) - return err; + goto st_press_power_off; press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS; press_data->multiread_bit = press_data->sensor_settings->multi_read_bit; @@ -554,11 +556,11 @@ int st_press_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data); if (err < 0) - return err; + goto st_press_power_off; err = st_press_allocate_ring(indio_dev); if (err < 0) - return err; + goto st_press_power_off; if (irq > 0) { err = st_sensors_allocate_trigger(indio_dev, @@ -581,6 +583,8 @@ st_press_device_register_error: st_sensors_deallocate_trigger(indio_dev); st_press_probe_trigger_error: st_press_deallocate_ring(indio_dev); +st_press_power_off: + st_sensors_power_disable(indio_dev); return err; } diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 78a193494370..91d5f684a53a 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -278,7 +278,7 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable); int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable); -void st_sensors_power_enable(struct iio_dev *indio_dev); +int st_sensors_power_enable(struct iio_dev *indio_dev); void st_sensors_power_disable(struct iio_dev *indio_dev); -- cgit v1.2.3 From 2853908a59603118f854b813da055c26257dfa4f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 May 2016 13:49:56 -0400 Subject: undo "fs: allow d_instantiate to be called with negative parent dentry" Background: spufs used to mangle the order in which it had been building dentry trees. It was broken in a lot of ways, but most of them required the right timing to trigger until an fsnotify change had added one more - the one that was always triggered. Unfortunately, insteading of fixing their long-standing bug the spufs folks had chosen to paper over the fsnotify trigger. Eventually said bug had been spotted and killed off, but the pointless check in fsnotify has remained, complete with the implication that one *could* do that kind of crap. Again, a parent of any dentry should always be positive. Any code can rely upon that and anything violating that assert is a bug, *not* something to be accomodated. Signed-off-by: Al Viro --- include/linux/fsnotify_backend.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 29f917517299..d188a107c562 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -281,7 +281,7 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry) * us with the new state. */ parent = dentry->d_parent; - if (parent->d_inode && fsnotify_inode_watches_children(parent->d_inode)) + if (fsnotify_inode_watches_children(parent->d_inode)) dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; else dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; -- cgit v1.2.3 From affda48410a5bbfd516def60bbc97f2683cd9f7b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 29 May 2016 18:35:12 -0400 Subject: trim fsnotify hooks a bit fsnotify_d_move()/__fsnotify_d_instantiate()/__fsnotify_update_dcache_flags() are identical to each other, regardless of the config. Signed-off-by: Al Viro --- fs/dcache.c | 8 ++++---- include/linux/fsnotify.h | 12 ------------ include/linux/fsnotify_backend.h | 20 +++----------------- 3 files changed, 7 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/fs/dcache.c b/fs/dcache.c index ad4a542e9bab..f9c63c108881 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1769,7 +1769,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) raw_write_seqcount_begin(&dentry->d_seq); __d_set_inode_and_type(dentry, inode, add_flags); raw_write_seqcount_end(&dentry->d_seq); - __fsnotify_d_instantiate(dentry); + fsnotify_update_flags(dentry); spin_unlock(&dentry->d_lock); } @@ -2563,7 +2563,7 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode) raw_write_seqcount_begin(&dentry->d_seq); __d_set_inode_and_type(dentry, inode, add_flags); raw_write_seqcount_end(&dentry->d_seq); - __fsnotify_d_instantiate(dentry); + fsnotify_update_flags(dentry); } _d_rehash(dentry); if (dir) @@ -2853,8 +2853,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target, list_move(&target->d_child, &target->d_parent->d_subdirs); list_move(&dentry->d_child, &dentry->d_parent->d_subdirs); if (exchange) - fsnotify_d_move(target); - fsnotify_d_move(dentry); + fsnotify_update_flags(target); + fsnotify_update_flags(dentry); } write_seqcount_end(&target->d_seq); diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 0141f257d67b..eed9e853a06f 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -51,18 +51,6 @@ static inline int fsnotify_perm(struct file *file, int mask) return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); } -/* - * fsnotify_d_move - dentry has been moved - */ -static inline void fsnotify_d_move(struct dentry *dentry) -{ - /* - * On move we need to update dentry->d_flags to indicate if the new parent - * cares about events from this dentry. - */ - __fsnotify_update_dcache_flags(dentry); -} - /* * fsnotify_link_count - inode's link count changed */ diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index d188a107c562..58205f33af02 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -267,10 +267,8 @@ static inline int fsnotify_inode_watches_children(struct inode *inode) * Update the dentry with a flag indicating the interest of its parent to receive * filesystem events when those events happens to this dentry->d_inode. */ -static inline void __fsnotify_update_dcache_flags(struct dentry *dentry) +static inline void fsnotify_update_flags(struct dentry *dentry) { - struct dentry *parent; - assert_spin_locked(&dentry->d_lock); /* @@ -280,21 +278,12 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry) * find our entry, so it will spin until we complete here, and update * us with the new state. */ - parent = dentry->d_parent; - if (fsnotify_inode_watches_children(parent->d_inode)) + if (fsnotify_inode_watches_children(dentry->d_parent->d_inode)) dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; else dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; } -/* - * fsnotify_d_instantiate - instantiate a dentry for inode - */ -static inline void __fsnotify_d_instantiate(struct dentry *dentry) -{ - __fsnotify_update_dcache_flags(dentry); -} - /* called from fsnotify listeners, such as fanotify or dnotify */ /* create a new group */ @@ -386,10 +375,7 @@ static inline void __fsnotify_inode_delete(struct inode *inode) static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) {} -static inline void __fsnotify_update_dcache_flags(struct dentry *dentry) -{} - -static inline void __fsnotify_d_instantiate(struct dentry *dentry) +static inline void fsnotify_update_flags(struct dentry *dentry) {} static inline u32 fsnotify_get_cookie(void) -- cgit v1.2.3 From 8d5b5d5ce58ee1b90110f4e358eefe3c3a6b08a2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 1 May 2016 19:36:57 +0900 Subject: reset: add devm_reset_controller_register API Add a device managed API for reset_controller_register(). This helps in reducing code in .remove callbacks and sometimes dropping .remove callbacks entirely. Signed-off-by: Masahiro Yamada Acked-by: Laxman Dewangan Signed-off-by: Philipp Zabel --- Documentation/driver-model/devres.txt | 4 ++++ drivers/reset/core.c | 37 +++++++++++++++++++++++++++++++++++ include/linux/reset-controller.h | 4 ++++ 3 files changed, 45 insertions(+) (limited to 'include/linux') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index c63eea0c1c8c..f5e522342ee5 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -352,6 +352,10 @@ REGULATOR devm_regulator_put() devm_regulator_register() +RESET + devm_reset_control_get() + devm_reset_controller_register() + SLAVE DMA ENGINE devm_acpi_dma_controller_register() diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 72b32bd15549..395dc9ce492e 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -93,6 +93,43 @@ void reset_controller_unregister(struct reset_controller_dev *rcdev) } EXPORT_SYMBOL_GPL(reset_controller_unregister); +static void devm_reset_controller_release(struct device *dev, void *res) +{ + reset_controller_unregister(*(struct reset_controller_dev **)res); +} + +/** + * devm_reset_controller_register - resource managed reset_controller_register() + * @dev: device that is registering this reset controller + * @rcdev: a pointer to the initialized reset controller device + * + * Managed reset_controller_register(). For reset controllers registered by + * this function, reset_controller_unregister() is automatically called on + * driver detach. See reset_controller_register() for more information. + */ +int devm_reset_controller_register(struct device *dev, + struct reset_controller_dev *rcdev) +{ + struct reset_controller_dev **rcdevp; + int ret; + + rcdevp = devres_alloc(devm_reset_controller_release, sizeof(*rcdevp), + GFP_KERNEL); + if (!rcdevp) + return -ENOMEM; + + ret = reset_controller_register(rcdev); + if (!ret) { + *rcdevp = rcdev; + devres_add(dev, rcdevp); + } else { + devres_free(rcdevp); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_reset_controller_register); + /** * reset_control_reset - reset the controlled device * @rstc: reset controller diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h index b91ba932bbd4..db1fe6772ad5 100644 --- a/include/linux/reset-controller.h +++ b/include/linux/reset-controller.h @@ -53,4 +53,8 @@ struct reset_controller_dev { int reset_controller_register(struct reset_controller_dev *rcdev); void reset_controller_unregister(struct reset_controller_dev *rcdev); +struct device; +int devm_reset_controller_register(struct device *dev, + struct reset_controller_dev *rcdev); + #endif -- cgit v1.2.3 From 312521d0543513f37f0badb4efc7bfed2d99672e Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 24 May 2016 15:35:34 -0700 Subject: ACPI / NUMA: Move acpi_numa_arch_fixup() to ia64 only Since acpi_numa_arch_fixup() is only used in arch ia64, move it there to make a generic interface easier. This avoids empty function stubs or some complex kconfig options for x86 and arm64. Signed-off-by: Robert Richter Reviewed-by: Hanjun Guo Signed-off-by: David Daney Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/acpi.h | 3 +++ arch/ia64/kernel/acpi.c | 2 +- arch/ia64/kernel/setup.c | 1 + arch/x86/mm/srat.c | 2 -- drivers/acpi/numa.c | 2 -- include/linux/acpi.h | 1 - 6 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index aa0fdf125aba..a3d0211970e9 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h @@ -140,6 +140,9 @@ static inline void per_cpu_scan_finalize(int min_cpus, int reserve_cpus) } } } + +extern void acpi_numa_fixup(void); + #endif /* CONFIG_ACPI_NUMA */ #endif /*__KERNEL__*/ diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index b1698bc042c8..92b7bc956795 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -524,7 +524,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) return 0; } -void __init acpi_numa_arch_fixup(void) +void __init acpi_numa_fixup(void) { int i, j, node_from, node_to; diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 2029a38a72ae..afddb3e80a29 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -552,6 +552,7 @@ setup_arch (char **cmdline_p) early_acpi_boot_init(); # ifdef CONFIG_ACPI_NUMA acpi_numa_init(); + acpi_numa_fixup(); # ifdef CONFIG_ACPI_HOTPLUG_CPU prefill_possible_map(); # endif diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index b5f821881465..90b6ed9a00dc 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c @@ -212,8 +212,6 @@ out_err: return -1; } -void __init acpi_numa_arch_fixup(void) {} - int __init x86_acpi_numa_init(void) { int ret; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 6f1cad8d22a3..fb2c0d61f252 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -324,8 +324,6 @@ int __init acpi_numa_init(void) /* SLIT: System Locality Information Table */ acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); - acpi_numa_arch_fixup(); - if (cnt < 0) return cnt; else if (!parsed_numa_memblks) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 288fac5294f5..8010b266e856 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -237,7 +237,6 @@ void acpi_numa_slit_init (struct acpi_table_slit *slit); void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa); int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); -void acpi_numa_arch_fixup(void); #ifndef PHYS_CPUID_INVALID typedef u32 phys_cpuid_t; -- cgit v1.2.3 From 2230c49f09b552454eac51b81e9e4e41060b5e70 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 13 May 2016 16:45:18 +0100 Subject: ASoC: arizona: Add a notifier chain for CODEC events Add a notifier chain that can be used from the machine driver to catch events generated by the CODEC. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/linux/mfd/arizona/core.h | 10 ++++++++++ sound/soc/codecs/arizona.c | 35 +++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 10 ++++++++++ sound/soc/codecs/cs47l24.c | 1 + sound/soc/codecs/wm5110.c | 1 + 5 files changed, 57 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index d55a42297d49..58ab4c0fe761 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h @@ -14,6 +14,7 @@ #define _WM_ARIZONA_CORE_H #include +#include #include #include #include @@ -148,8 +149,17 @@ struct arizona { uint16_t dac_comp_coeff; uint8_t dac_comp_enabled; struct mutex dac_comp_lock; + + struct blocking_notifier_head notifier; }; +static inline int arizona_call_notifiers(struct arizona *arizona, + unsigned long event, + void *data) +{ + return blocking_notifier_call_chain(&arizona->notifier, event, data); +} + int arizona_clk32k_enable(struct arizona *arizona); int arizona_clk32k_disable(struct arizona *arizona); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 664a8c044ffb..7f9ab92ffa91 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -324,6 +324,17 @@ int arizona_init_gpio(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(arizona_init_gpio); +int arizona_init_notifiers(struct snd_soc_codec *codec) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + + BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier); + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_notifiers); + const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", "Tone Generator 1", @@ -2573,6 +2584,30 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); +int arizona_register_notifier(struct snd_soc_codec *codec, + struct notifier_block *nb, + int (*notify)(struct notifier_block *nb, + unsigned long action, void *data)) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + + nb->notifier_call = notify; + + return blocking_notifier_chain_register(&arizona->notifier, nb); +} +EXPORT_SYMBOL_GPL(arizona_register_notifier); + +int arizona_unregister_notifier(struct snd_soc_codec *codec, + struct notifier_block *nb) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + + return blocking_notifier_chain_unregister(&arizona->notifier, nb); +} +EXPORT_SYMBOL_GPL(arizona_unregister_notifier); + MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index ce0531b8c632..245d13c157a5 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -306,6 +306,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source, extern int arizona_init_spk(struct snd_soc_codec *codec); extern int arizona_init_gpio(struct snd_soc_codec *codec); extern int arizona_init_mono(struct snd_soc_codec *codec); +extern int arizona_init_notifiers(struct snd_soc_codec *codec); extern int arizona_free_spk(struct snd_soc_codec *codec); @@ -317,4 +318,13 @@ int arizona_set_output_mode(struct snd_soc_codec *codec, int output, extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); + +extern int arizona_register_notifier(struct snd_soc_codec *codec, + struct notifier_block *nb, + int (*notify)(struct notifier_block *nb, + unsigned long action, + void *data)); +extern int arizona_unregister_notifier(struct snd_soc_codec *codec, + struct notifier_block *nb); + #endif diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 5ec5a682d186..fa9a6a5a6120 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1096,6 +1096,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) arizona_init_spk(codec); arizona_init_gpio(codec); arizona_init_mono(codec); + arizona_init_notifiers(codec); ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index b5820e4d5471..338a3b52705b 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2251,6 +2251,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) arizona_init_spk(codec); arizona_init_gpio(codec); arizona_init_mono(codec); + arizona_init_notifiers(codec); ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, "ADSP2 Compressed IRQ", wm5110_adsp2_irq, -- cgit v1.2.3 From 97c79a38cd454602645f0470ffb444b3b75ce574 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 28 Apr 2016 13:16:33 -0300 Subject: perf core: Per event callchain limit Additionally to being able to control the system wide maximum depth via /proc/sys/kernel/perf_event_max_stack, now we are able to ask for different depths per event, using perf_event_attr.sample_max_stack for that. This uses an u16 hole at the end of perf_event_attr, that, when perf_event_attr.sample_type has the PERF_SAMPLE_CALLCHAIN, if sample_max_stack is zero, means use perf_event_max_stack, otherwise it'll be bounds checked under callchain_mutex. Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: David Ahern Cc: Frederic Weisbecker Cc: He Kuang Cc: Jiri Olsa Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: Wang Nan Cc: Zefan Li Link: http://lkml.kernel.org/n/tip-kolmn1yo40p7jhswxwrc7rrd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- include/linux/perf_event.h | 2 +- include/uapi/linux/perf_event.h | 6 +++++- kernel/bpf/stackmap.c | 2 +- kernel/events/callchain.c | 14 ++++++++++++-- kernel/events/core.c | 5 ++++- 5 files changed, 23 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 6b87be908790..0e43355c7aad 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1076,7 +1076,7 @@ extern void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct extern struct perf_callchain_entry * get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, u32 max_stack, bool crosstask, bool add_mark); -extern int get_callchain_buffers(void); +extern int get_callchain_buffers(int max_stack); extern void put_callchain_buffers(void); extern int sysctl_perf_event_max_stack; diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 36ce552cf6a9..c66a485a24ac 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -276,6 +276,9 @@ enum perf_event_read_format { /* * Hardware event_id to monitor via a performance monitoring event: + * + * @sample_max_stack: Max number of frame pointers in a callchain, + * should be < /proc/sys/kernel/perf_event_max_stack */ struct perf_event_attr { @@ -385,7 +388,8 @@ struct perf_event_attr { * Wakeup watermark for AUX area */ __u32 aux_watermark; - __u32 __reserved_2; /* align to __u64 */ + __u16 sample_max_stack; + __u16 __reserved_2; /* align to __u64 */ }; #define perf_flags(attr) (*(&(attr)->read_format + 1)) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index a82d7605db3f..f1de5c1a2af6 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -99,7 +99,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) if (err) goto free_smap; - err = get_callchain_buffers(); + err = get_callchain_buffers(sysctl_perf_event_max_stack); if (err) goto free_smap; diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 179ef4640964..e9fdb5203de5 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -104,7 +104,7 @@ fail: return -ENOMEM; } -int get_callchain_buffers(void) +int get_callchain_buffers(int event_max_stack) { int err = 0; int count; @@ -121,6 +121,15 @@ int get_callchain_buffers(void) /* If the allocation failed, give up */ if (!callchain_cpus_entries) err = -ENOMEM; + /* + * If requesting per event more than the global cap, + * return a different error to help userspace figure + * this out. + * + * And also do it here so that we have &callchain_mutex held. + */ + if (event_max_stack > sysctl_perf_event_max_stack) + err = -EOVERFLOW; goto exit; } @@ -174,11 +183,12 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs) bool user = !event->attr.exclude_callchain_user; /* Disallow cross-task user callchains. */ bool crosstask = event->ctx->task && event->ctx->task != current; + const u32 max_stack = event->attr.sample_max_stack; if (!kernel && !user) return NULL; - return get_perf_callchain(regs, 0, kernel, user, sysctl_perf_event_max_stack, crosstask, true); + return get_perf_callchain(regs, 0, kernel, user, max_stack, crosstask, true); } struct perf_callchain_entry * diff --git a/kernel/events/core.c b/kernel/events/core.c index 050a290c72c7..79363f298445 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -8843,7 +8843,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, if (!event->parent) { if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { - err = get_callchain_buffers(); + err = get_callchain_buffers(attr->sample_max_stack); if (err) goto err_addr_filters; } @@ -9165,6 +9165,9 @@ SYSCALL_DEFINE5(perf_event_open, return -EINVAL; } + if (!attr.sample_max_stack) + attr.sample_max_stack = sysctl_perf_event_max_stack; + /* * In cgroup mode, the pid argument is used to pass the fd * opened to the cgroup directory in cgroupfs. The cpu argument -- cgit v1.2.3 From 4bdf1cfca5d46294142cdf49cd997b8b83491adf Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Thu, 26 May 2016 12:57:50 +0200 Subject: lib/mpi: purge mpi_set_buffer() mpi_set_buffer() has no in-tree users and similar functionality is provided by mpi_read_raw_data(). Remove mpi_set_buffer(). Signed-off-by: Nicolai Stange Signed-off-by: Herbert Xu --- include/linux/mpi.h | 1 - lib/mpi/mpicoder.c | 76 ----------------------------------------------------- 2 files changed, 77 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mpi.h b/include/linux/mpi.h index 3a5abe95affd..f219559e5e80 100644 --- a/include/linux/mpi.h +++ b/include/linux/mpi.h @@ -80,7 +80,6 @@ void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign); int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, int *sign); void *mpi_get_secure_buffer(MPI a, unsigned *nbytes, int *sign); -int mpi_set_buffer(MPI a, const void *buffer, unsigned nbytes, int sign); int mpi_write_to_sgl(MPI a, struct scatterlist *sg, unsigned *nbytes, int *sign); diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 747606f9e4a3..c7420335a5bb 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -250,82 +250,6 @@ void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) } EXPORT_SYMBOL_GPL(mpi_get_buffer); -/**************** - * Use BUFFER to update MPI. - */ -int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign) -{ - const uint8_t *buffer = xbuffer, *p; - mpi_limb_t alimb; - int nlimbs; - int i; - - nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB); - if (RESIZE_IF_NEEDED(a, nlimbs) < 0) - return -ENOMEM; - a->sign = sign; - - for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) { -#if BYTES_PER_MPI_LIMB == 4 - alimb = (mpi_limb_t) *p--; - alimb |= (mpi_limb_t) *p-- << 8; - alimb |= (mpi_limb_t) *p-- << 16; - alimb |= (mpi_limb_t) *p-- << 24; -#elif BYTES_PER_MPI_LIMB == 8 - alimb = (mpi_limb_t) *p--; - alimb |= (mpi_limb_t) *p-- << 8; - alimb |= (mpi_limb_t) *p-- << 16; - alimb |= (mpi_limb_t) *p-- << 24; - alimb |= (mpi_limb_t) *p-- << 32; - alimb |= (mpi_limb_t) *p-- << 40; - alimb |= (mpi_limb_t) *p-- << 48; - alimb |= (mpi_limb_t) *p-- << 56; -#else -#error please implement for this limb size. -#endif - a->d[i++] = alimb; - } - if (p >= buffer) { -#if BYTES_PER_MPI_LIMB == 4 - alimb = *p--; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 8; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 16; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 24; -#elif BYTES_PER_MPI_LIMB == 8 - alimb = (mpi_limb_t) *p--; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 8; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 16; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 24; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 32; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 40; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 48; - if (p >= buffer) - alimb |= (mpi_limb_t) *p-- << 56; -#else -#error please implement for this limb size. -#endif - a->d[i++] = alimb; - } - a->nlimbs = i; - - if (i != nlimbs) { - pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i, - nlimbs); - BUG(); - } - return 0; -} -EXPORT_SYMBOL_GPL(mpi_set_buffer); - /** * mpi_write_to_sgl() - Funnction exports MPI to an sgl (msb first) * -- cgit v1.2.3 From 168d7c4e8bb25c076ed8be67fcca84f5dcd0b2c6 Mon Sep 17 00:00:00 2001 From: John Youn Date: Tue, 31 May 2016 16:55:01 -0700 Subject: reset: Return -ENOTSUPP when not configured Prior to commit 6c96f05c8bb8 ("reset: Make [of_]reset_control_get[_foo] functions wrappers"), the "optional" functions returned -ENOTSUPP when CONFIG_RESET_CONTROLLER was not set. Revert back to the old behavior by changing the new __devm_reset_control_get() and __of_reset_control_get() functions to return ERR_PTR(-ENOTSUPP) when compiled without CONFIG_RESET_CONTROLLER. Otherwise they will return -EINVAL causing users to think that an error occurred when CONFIG_RESET_CONTROLLER is not set. Fixes: 6c96f05c8bb8 ("reset: Make [of_]reset_control_get[_foo] functions wrappers") Signed-off-by: John Youn Signed-off-by: Philipp Zabel --- include/linux/reset.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/reset.h b/include/linux/reset.h index ec0306ce7b92..067db57c81dc 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -71,14 +71,14 @@ static inline struct reset_control *__of_reset_control_get( struct device_node *node, const char *id, int index, int shared) { - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOTSUPP); } static inline struct reset_control *__devm_reset_control_get( struct device *dev, const char *id, int index, int shared) { - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOTSUPP); } #endif /* CONFIG_RESET_CONTROLLER */ -- cgit v1.2.3 From 59451e1233bd315c5379a631838a03d80e689581 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Thu, 5 May 2016 17:31:47 -0700 Subject: mtd: spi-nor: change return value of read/write Change the return value of spi-nor device read and write methods to allow returning amount of data transferred and errors as read(2)/write(2) does. Also, start handling positive returns in spi_nor_read(), since we want to convert drivers to start returning the read-length both via *retlen and the return code. (We don't need to do the same transition process for spi_nor_write(), since ->write() didn't used to have a return code at all.) Signed-off-by: Michal Suchanek Signed-off-by: Brian Norris Tested-by Cyrille Pitchen Acked-by: Michal Suchanek Tested-by: Michal Suchanek --- drivers/mtd/devices/m25p80.c | 5 +++-- drivers/mtd/spi-nor/fsl-quadspi.c | 5 +++-- drivers/mtd/spi-nor/mtk-quadspi.c | 26 ++++++++++++++++++-------- drivers/mtd/spi-nor/nxp-spifi.c | 12 ++++++------ drivers/mtd/spi-nor/spi-nor.c | 5 ++++- include/linux/mtd/spi-nor.h | 4 ++-- 6 files changed, 36 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 9d6854467651..3bd75e87ed89 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -73,7 +73,7 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) return spi_write(spi, flash->command, len + 1); } -static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len, +static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct m25p *flash = nor->priv; @@ -101,6 +101,7 @@ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len, spi_sync(spi, &m); *retlen += m.actual_length - cmd_sz; + return 0; } static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor) @@ -119,7 +120,7 @@ static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor) * Read an address range from the nor chip. The address range * may be any size provided it is within the physical boundaries. */ -static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, +static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct m25p *flash = nor->priv; diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 9ab2b51d54b8..74dc155e1b3b 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -868,7 +868,7 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) return ret; } -static void fsl_qspi_write(struct spi_nor *nor, loff_t to, +static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct fsl_qspi *q = nor->priv; @@ -878,9 +878,10 @@ static void fsl_qspi_write(struct spi_nor *nor, loff_t to, /* invalid the data in the AHB buffer. */ fsl_qspi_invalid(q); + return 0; } -static int fsl_qspi_read(struct spi_nor *nor, loff_t from, +static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct fsl_qspi *q = nor->priv; diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c index 8bed1a4cb79c..ab92ac0f6b2b 100644 --- a/drivers/mtd/spi-nor/mtk-quadspi.c +++ b/drivers/mtd/spi-nor/mtk-quadspi.c @@ -243,8 +243,8 @@ static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr) writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR3_REG); } -static int mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length, - size_t *retlen, u_char *buffer) +static ssize_t mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length, + size_t *retlen, u_char *buffer) { int i, ret; int addr = (int)from; @@ -297,36 +297,46 @@ static int mt8173_nor_write_buffer(struct mt8173_nor *mt8173_nor, int addr, return mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_WR_CMD); } -static void mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static ssize_t mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { int ret; struct mt8173_nor *mt8173_nor = nor->priv; ret = mt8173_nor_write_buffer_enable(mt8173_nor); - if (ret < 0) + if (ret < 0) { dev_warn(mt8173_nor->dev, "write buffer enable failed!\n"); + return ret; + } while (len >= SFLASH_WRBUF_SIZE) { ret = mt8173_nor_write_buffer(mt8173_nor, to, buf); - if (ret < 0) + if (ret < 0) { dev_err(mt8173_nor->dev, "write buffer failed!\n"); + return ret; + } len -= SFLASH_WRBUF_SIZE; to += SFLASH_WRBUF_SIZE; buf += SFLASH_WRBUF_SIZE; (*retlen) += SFLASH_WRBUF_SIZE; } ret = mt8173_nor_write_buffer_disable(mt8173_nor); - if (ret < 0) + if (ret < 0) { dev_warn(mt8173_nor->dev, "write buffer disable failed!\n"); + return ret; + } if (len) { ret = mt8173_nor_write_single_byte(mt8173_nor, to, (int)len, (u8 *)buf); - if (ret < 0) + if (ret < 0) { dev_err(mt8173_nor->dev, "write single byte failed!\n"); + return ret; + } (*retlen) += len; } + + return 0; } static int mt8173_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c index ae428cb0e04b..187adba5e69f 100644 --- a/drivers/mtd/spi-nor/nxp-spifi.c +++ b/drivers/mtd/spi-nor/nxp-spifi.c @@ -172,8 +172,8 @@ static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) return nxp_spifi_wait_for_cmd(spifi); } -static int nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static ssize_t nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len, + size_t *retlen, u_char *buf) { struct nxp_spifi *spifi = nor->priv; int ret; @@ -188,8 +188,8 @@ static int nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len, return 0; } -static void nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static ssize_t nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { struct nxp_spifi *spifi = nor->priv; u32 cmd; @@ -197,7 +197,7 @@ static void nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len, ret = nxp_spifi_set_memory_mode_off(spifi); if (ret) - return; + return ret; writel(to, spifi->io_base + SPIFI_ADDR); *retlen += len; @@ -212,7 +212,7 @@ static void nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len, while (len--) writeb(*buf++, spifi->io_base + SPIFI_DATA); - nxp_spifi_wait_for_cmd(spifi); + return nxp_spifi_wait_for_cmd(spifi); } static int nxp_spifi_erase(struct spi_nor *nor, loff_t offs) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index c52e45594bfd..6c92b9524c8b 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1034,7 +1034,10 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, ret = nor->read(nor, from, len, retlen, buf); spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); - return ret; + if (ret < 0) + return ret; + + return 0; } static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 7f041bd88b82..34680a493156 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -173,9 +173,9 @@ struct spi_nor { int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); - int (*read)(struct spi_nor *nor, loff_t from, + ssize_t (*read)(struct spi_nor *nor, loff_t from, size_t len, size_t *retlen, u_char *read_buf); - void (*write)(struct spi_nor *nor, loff_t to, + ssize_t (*write)(struct spi_nor *nor, loff_t to, size_t len, size_t *retlen, const u_char *write_buf); int (*erase)(struct spi_nor *nor, loff_t offs); -- cgit v1.2.3 From 2dd087b16946cf168f401526adf26afa771bb740 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Thu, 5 May 2016 17:31:53 -0700 Subject: mtd: spi-nor: stop passing around retlen Do not pass retlen to hardware driver read/write functions. Update it in spi-nor generic driver instead. Signed-off-by: Michal Suchanek Signed-off-by: Brian Norris Tested-by Cyrille Pitchen Acked-by: Michal Suchanek Tested-by: Michal Suchanek --- drivers/mtd/devices/m25p80.c | 7 ++----- drivers/mtd/spi-nor/fsl-quadspi.c | 17 ++++++----------- drivers/mtd/spi-nor/mtk-quadspi.c | 8 +++----- drivers/mtd/spi-nor/nxp-spifi.c | 6 ++---- drivers/mtd/spi-nor/spi-nor.c | 21 +++++++++++++-------- include/linux/mtd/spi-nor.h | 4 ++-- 6 files changed, 28 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 2ef5a6015276..eab46d211ae6 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -74,7 +74,7 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) } static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, - size_t *retlen, const u_char *buf) + const u_char *buf) { struct m25p *flash = nor->priv; struct spi_device *spi = flash->spi; @@ -106,7 +106,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, ret = m.actual_length - cmd_sz; if (ret < 0) return -EIO; - *retlen += ret; return ret; } @@ -127,7 +126,7 @@ static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor) * may be any size provided it is within the physical boundaries. */ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, - size_t *retlen, u_char *buf) + u_char *buf) { struct m25p *flash = nor->priv; struct spi_device *spi = flash->spi; @@ -156,7 +155,6 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, msg.data_nbits = m25p80_rx_nbits(nor); ret = spi_flash_read(spi, &msg); - *retlen = msg.retlen; if (ret < 0) return ret; return msg.retlen; @@ -184,7 +182,6 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, ret = m.actual_length - m25p_cmdsz(nor) - dummy; if (ret < 0) return -EIO; - *retlen += ret; return ret; } diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index ea296769f015..5c82e4ef1904 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -620,7 +620,7 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q) static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, u8 opcode, unsigned int to, u32 *txbuf, - unsigned count, size_t *retlen) + unsigned count) { int ret, i, j; u32 tmp; @@ -647,11 +647,8 @@ static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, /* Trigger it */ ret = fsl_qspi_runcmd(q, opcode, to, count); - if (ret == 0) { - if (retlen) - *retlen += count; + if (ret == 0) return count; - } return ret; } @@ -862,7 +859,7 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) } else if (len > 0) { ret = fsl_qspi_nor_write(q, nor, opcode, 0, - (u32 *)buf, len, NULL); + (u32 *)buf, len); if (ret > 0) return 0; } else { @@ -874,12 +871,11 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) } static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to, - size_t len, size_t *retlen, const u_char *buf) + size_t len, const u_char *buf) { struct fsl_qspi *q = nor->priv; - ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to, - (u32 *)buf, len, retlen); + (u32 *)buf, len); /* invalid the data in the AHB buffer. */ fsl_qspi_invalid(q); @@ -887,7 +883,7 @@ static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to, } static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from, - size_t len, size_t *retlen, u_char *buf) + size_t len, u_char *buf) { struct fsl_qspi *q = nor->priv; u8 cmd = nor->read_opcode; @@ -929,7 +925,6 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from, memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, len); - *retlen += len; return len; } diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c index e85687126c25..21c31b373cd3 100644 --- a/drivers/mtd/spi-nor/mtk-quadspi.c +++ b/drivers/mtd/spi-nor/mtk-quadspi.c @@ -244,7 +244,7 @@ static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr) } static ssize_t mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length, - size_t *retlen, u_char *buffer) + u_char *buffer) { int i, ret; int addr = (int)from; @@ -255,7 +255,7 @@ static ssize_t mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length, mt8173_nor_set_read_mode(mt8173_nor); mt8173_nor_set_addr(mt8173_nor, addr); - for (i = 0; i < length; i++, (*retlen)++) { + for (i = 0; i < length; i++) { ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PIO_READ_CMD); if (ret < 0) return ret; @@ -298,7 +298,7 @@ static int mt8173_nor_write_buffer(struct mt8173_nor *mt8173_nor, int addr, } static ssize_t mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len, - size_t *retlen, const u_char *buf) + const u_char *buf) { int ret; struct mt8173_nor *mt8173_nor = nor->priv; @@ -318,7 +318,6 @@ static ssize_t mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len, } to += SFLASH_WRBUF_SIZE; buf += SFLASH_WRBUF_SIZE; - (*retlen) += SFLASH_WRBUF_SIZE; } ret = mt8173_nor_write_buffer_disable(mt8173_nor); if (ret < 0) { @@ -333,7 +332,6 @@ static ssize_t mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len, dev_err(mt8173_nor->dev, "write single byte failed!\n"); return ret; } - (*retlen) += len; } return len; diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c index b0fb86996b8f..73a14f40928b 100644 --- a/drivers/mtd/spi-nor/nxp-spifi.c +++ b/drivers/mtd/spi-nor/nxp-spifi.c @@ -173,7 +173,7 @@ static int nxp_spifi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) } static ssize_t nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len, - size_t *retlen, u_char *buf) + u_char *buf) { struct nxp_spifi *spifi = nor->priv; int ret; @@ -183,13 +183,12 @@ static ssize_t nxp_spifi_read(struct spi_nor *nor, loff_t from, size_t len, return ret; memcpy_fromio(buf, spifi->flash_base + from, len); - *retlen += len; return len; } static ssize_t nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len, - size_t *retlen, const u_char *buf) + const u_char *buf) { struct nxp_spifi *spifi = nor->priv; u32 cmd; @@ -201,7 +200,6 @@ static ssize_t nxp_spifi_write(struct spi_nor *nor, loff_t to, size_t len, return ret; writel(to, spifi->io_base + SPIFI_ADDR); - *retlen += len; cmd = SPIFI_CMD_DOUT | SPIFI_CMD_DATALEN(len) | diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index f204d29d1139..34dd95373e77 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1031,12 +1031,13 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, if (ret) return ret; - ret = nor->read(nor, from, len, retlen, buf); + ret = nor->read(nor, from, len, buf); spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); if (ret < 0) return ret; + *retlen += ret; return 0; } @@ -1063,7 +1064,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, nor->program_opcode = SPINOR_OP_BP; /* write one byte. */ - ret = nor->write(nor, to, 1, retlen, buf); + ret = nor->write(nor, to, 1, buf); if (ret < 0) goto sst_write_err; WARN(ret != 1, "While writing 1 byte written %i bytes\n", @@ -1079,7 +1080,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, nor->program_opcode = SPINOR_OP_AAI_WP; /* write two bytes. */ - ret = nor->write(nor, to, 2, retlen, buf + actual); + ret = nor->write(nor, to, 2, buf + actual); if (ret < 0) goto sst_write_err; WARN(ret != 2, "While writing 2 bytes written %i bytes\n", @@ -1102,7 +1103,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, write_enable(nor); nor->program_opcode = SPINOR_OP_BP; - ret = nor->write(nor, to, 1, retlen, buf + actual); + ret = nor->write(nor, to, 1, buf + actual); if (ret < 0) goto sst_write_err; WARN(ret != 1, "While writing 1 byte written %i bytes\n", @@ -1111,8 +1112,10 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, if (ret) goto sst_write_err; write_disable(nor); + actual += 1; } sst_write_err: + *retlen += actual; spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); return ret; } @@ -1141,15 +1144,17 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, /* do all the bytes fit onto one page? */ if (page_offset + len <= nor->page_size) { - ret = nor->write(nor, to, len, retlen, buf); + ret = nor->write(nor, to, len, buf); if (ret < 0) goto write_err; + *retlen += ret; } else { /* the size of data remaining on the first page */ page_size = nor->page_size - page_offset; - ret = nor->write(nor, to, page_size, retlen, buf); + ret = nor->write(nor, to, page_size, buf); if (ret < 0) goto write_err; + *retlen += ret; /* write everything in nor->page_size chunks */ for (i = ret; i < len; ) { @@ -1163,10 +1168,10 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, write_enable(nor); - ret = nor->write(nor, to + i, page_size, retlen, - buf + i); + ret = nor->write(nor, to + i, page_size, buf + i); if (ret < 0) goto write_err; + *retlen += ret; i += ret; } } diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 34680a493156..c425c7b4c2a0 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -174,9 +174,9 @@ struct spi_nor { int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); ssize_t (*read)(struct spi_nor *nor, loff_t from, - size_t len, size_t *retlen, u_char *read_buf); + size_t len, u_char *read_buf); ssize_t (*write)(struct spi_nor *nor, loff_t to, - size_t len, size_t *retlen, const u_char *write_buf); + size_t len, const u_char *write_buf); int (*erase)(struct spi_nor *nor, loff_t offs); int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len); -- cgit v1.2.3 From 8cfc8ddc99df9509a46043b14af81f5c6a223eab Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 18 Feb 2016 22:04:22 +0800 Subject: pstore: add lzo/lz4 compression support Like zlib compression in pstore, this patch added lzo and lz4 compression support so that users can have more options and better compression ratio. The original code treats the compressed data together with the uncompressed ECC correction notice by using zlib decompress. The ECC correction notice is missing in the decompression process. The treatment also makes lzo and lz4 not working. So I treat them separately by using pstore_decompress() to treat the compressed data, and memcpy() to treat the uncompressed ECC correction notice. Signed-off-by: Geliang Tang Signed-off-by: Kees Cook --- arch/powerpc/kernel/nvram_64.c | 4 +- drivers/acpi/apei/erst.c | 7 +- drivers/firmware/efi/efi-pstore.c | 6 ++ fs/pstore/Kconfig | 31 +++++- fs/pstore/platform.c | 218 ++++++++++++++++++++++++++++++++++++-- fs/pstore/ram.c | 10 +- include/linux/pstore.h | 3 +- 7 files changed, 261 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 856f9a7944cd..64174bf95611 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -444,7 +444,8 @@ static int nvram_pstore_write(enum pstore_type_id type, */ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, - bool *compressed, struct pstore_info *psi) + bool *compressed, ssize_t *ecc_notice_size, + struct pstore_info *psi) { struct oops_log_info *oops_hdr; unsigned int err_type, id_no, size = 0; @@ -545,6 +546,7 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, return -ENOMEM; kfree(buff); + *ecc_notice_size = 0; if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) *compressed = true; else diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 006c3894c6ea..f096ab3cb54d 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -927,7 +927,8 @@ static int erst_open_pstore(struct pstore_info *psi); static int erst_close_pstore(struct pstore_info *psi); static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, - bool *compressed, struct pstore_info *psi); + bool *compressed, ssize_t *ecc_notice_size, + struct pstore_info *psi); static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, u64 *id, unsigned int part, int count, bool compressed, size_t size, struct pstore_info *psi); @@ -987,7 +988,8 @@ static int erst_close_pstore(struct pstore_info *psi) static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, - bool *compressed, struct pstore_info *psi) + bool *compressed, ssize_t *ecc_notice_size, + struct pstore_info *psi) { int rc; ssize_t len = 0; @@ -1033,6 +1035,7 @@ skip: memcpy(*buf, rcd->data, len - sizeof(*rcd)); *id = record_id; *compressed = false; + *ecc_notice_size = 0; if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_DMESG_Z) == 0) { *type = PSTORE_TYPE_DMESG; diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index eac76a79a880..d5903ea77238 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -34,6 +34,7 @@ struct pstore_read_data { int *count; struct timespec *timespec; bool *compressed; + ssize_t *ecc_notice_size; char **buf; }; @@ -69,6 +70,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) *cb_data->compressed = true; else *cb_data->compressed = false; + *cb_data->ecc_notice_size = 0; } else if (sscanf(name, "dump-type%u-%u-%d-%lu", cb_data->type, &part, &cnt, &time) == 4) { *cb_data->id = generic_id(time, part, cnt); @@ -76,6 +78,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) cb_data->timespec->tv_sec = time; cb_data->timespec->tv_nsec = 0; *cb_data->compressed = false; + *cb_data->ecc_notice_size = 0; } else if (sscanf(name, "dump-type%u-%u-%lu", cb_data->type, &part, &time) == 3) { /* @@ -88,6 +91,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data) cb_data->timespec->tv_sec = time; cb_data->timespec->tv_nsec = 0; *cb_data->compressed = false; + *cb_data->ecc_notice_size = 0; } else return 0; @@ -210,6 +214,7 @@ static int efi_pstore_sysfs_entry_iter(void *data, struct efivar_entry **pos) static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, int *count, struct timespec *timespec, char **buf, bool *compressed, + ssize_t *ecc_notice_size, struct pstore_info *psi) { struct pstore_read_data data; @@ -220,6 +225,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, data.count = count; data.timespec = timespec; data.compressed = compressed; + data.ecc_notice_size = ecc_notice_size; data.buf = buf; *data.buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL); diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index 360ae43f590c..be40813eff52 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -1,8 +1,6 @@ config PSTORE tristate "Persistent store support" default n - select ZLIB_DEFLATE - select ZLIB_INFLATE help This option enables generic access to platform level persistent storage via "pstore" filesystem that can @@ -14,6 +12,35 @@ config PSTORE If you don't have a platform persistent store driver, say N. +choice + prompt "Choose compression algorithm" + depends on PSTORE + default PSTORE_ZLIB_COMPRESS + help + This option chooses compression algorithm. + +config PSTORE_ZLIB_COMPRESS + bool "ZLIB" + select ZLIB_DEFLATE + select ZLIB_INFLATE + help + This option enables ZLIB compression algorithm support. + +config PSTORE_LZO_COMPRESS + bool "LZO" + select LZO_COMPRESS + select LZO_DECOMPRESS + help + This option enables LZO compression algorithm support. + +config PSTORE_LZ4_COMPRESS + bool "LZ4" + select LZ4_COMPRESS + select LZ4_DECOMPRESS + help + This option enables LZ4 compression algorithm support. +endchoice + config PSTORE_CONSOLE bool "Log kernel console messages" depends on PSTORE diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index fe41d8ec663a..16ecca5b72d8 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -28,7 +28,15 @@ #include #include #include +#ifdef CONFIG_PSTORE_ZLIB_COMPRESS #include +#endif +#ifdef CONFIG_PSTORE_LZO_COMPRESS +#include +#endif +#ifdef CONFIG_PSTORE_LZ4_COMPRESS +#include +#endif #include #include #include @@ -69,10 +77,23 @@ struct pstore_info *psinfo; static char *backend; /* Compression parameters */ +#ifdef CONFIG_PSTORE_ZLIB_COMPRESS #define COMPR_LEVEL 6 #define WINDOW_BITS 12 #define MEM_LEVEL 4 static struct z_stream_s stream; +#else +static unsigned char *workspace; +#endif + +struct pstore_zbackend { + int (*compress)(const void *in, void *out, size_t inlen, size_t outlen); + int (*decompress)(void *in, void *out, size_t inlen, size_t outlen); + void (*allocate)(void); + void (*free)(void); + + const char *name; +}; static char *big_oops_buf; static size_t big_oops_buf_sz; @@ -129,9 +150,9 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason) } EXPORT_SYMBOL_GPL(pstore_cannot_block_path); +#ifdef CONFIG_PSTORE_ZLIB_COMPRESS /* Derived from logfs_compress() */ -static int pstore_compress(const void *in, void *out, size_t inlen, - size_t outlen) +static int compress_zlib(const void *in, void *out, size_t inlen, size_t outlen) { int err, ret; @@ -165,7 +186,7 @@ error: } /* Derived from logfs_uncompress */ -static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen) +static int decompress_zlib(void *in, void *out, size_t inlen, size_t outlen) { int err, ret; @@ -194,7 +215,7 @@ error: return ret; } -static void allocate_buf_for_compression(void) +static void allocate_zlib(void) { size_t size; size_t cmpr; @@ -237,12 +258,190 @@ static void allocate_buf_for_compression(void) } -static void free_buf_for_compression(void) +static void free_zlib(void) { kfree(stream.workspace); stream.workspace = NULL; kfree(big_oops_buf); big_oops_buf = NULL; + big_oops_buf_sz = 0; +} + +static struct pstore_zbackend backend_zlib = { + .compress = compress_zlib, + .decompress = decompress_zlib, + .allocate = allocate_zlib, + .free = free_zlib, + .name = "zlib", +}; +#endif + +#ifdef CONFIG_PSTORE_LZO_COMPRESS +static int compress_lzo(const void *in, void *out, size_t inlen, size_t outlen) +{ + int ret; + + ret = lzo1x_1_compress(in, inlen, out, &outlen, workspace); + if (ret != LZO_E_OK) { + pr_err("lzo_compress error, ret = %d!\n", ret); + return -EIO; + } + + return outlen; +} + +static int decompress_lzo(void *in, void *out, size_t inlen, size_t outlen) +{ + int ret; + + ret = lzo1x_decompress_safe(in, inlen, out, &outlen); + if (ret != LZO_E_OK) { + pr_err("lzo_decompress error, ret = %d!\n", ret); + return -EIO; + } + + return outlen; +} + +static void allocate_lzo(void) +{ + big_oops_buf_sz = lzo1x_worst_compress(psinfo->bufsize); + big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); + if (big_oops_buf) { + workspace = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); + if (!workspace) { + pr_err("No memory for compression workspace; skipping compression\n"); + kfree(big_oops_buf); + big_oops_buf = NULL; + } + } else { + pr_err("No memory for uncompressed data; skipping compression\n"); + workspace = NULL; + } +} + +static void free_lzo(void) +{ + kfree(workspace); + kfree(big_oops_buf); + big_oops_buf = NULL; + big_oops_buf_sz = 0; +} + +static struct pstore_zbackend backend_lzo = { + .compress = compress_lzo, + .decompress = decompress_lzo, + .allocate = allocate_lzo, + .free = free_lzo, + .name = "lzo", +}; +#endif + +#ifdef CONFIG_PSTORE_LZ4_COMPRESS +static int compress_lz4(const void *in, void *out, size_t inlen, size_t outlen) +{ + int ret; + + ret = lz4_compress(in, inlen, out, &outlen, workspace); + if (ret) { + pr_err("lz4_compress error, ret = %d!\n", ret); + return -EIO; + } + + return outlen; +} + +static int decompress_lz4(void *in, void *out, size_t inlen, size_t outlen) +{ + int ret; + + ret = lz4_decompress_unknownoutputsize(in, inlen, out, &outlen); + if (ret) { + pr_err("lz4_decompress error, ret = %d!\n", ret); + return -EIO; + } + + return outlen; +} + +static void allocate_lz4(void) +{ + big_oops_buf_sz = lz4_compressbound(psinfo->bufsize); + big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); + if (big_oops_buf) { + workspace = kmalloc(LZ4_MEM_COMPRESS, GFP_KERNEL); + if (!workspace) { + pr_err("No memory for compression workspace; skipping compression\n"); + kfree(big_oops_buf); + big_oops_buf = NULL; + } + } else { + pr_err("No memory for uncompressed data; skipping compression\n"); + workspace = NULL; + } +} + +static void free_lz4(void) +{ + kfree(workspace); + kfree(big_oops_buf); + big_oops_buf = NULL; + big_oops_buf_sz = 0; +} + +static struct pstore_zbackend backend_lz4 = { + .compress = compress_lz4, + .decompress = decompress_lz4, + .allocate = allocate_lz4, + .free = free_lz4, + .name = "lz4", +}; +#endif + +static struct pstore_zbackend *zbackend = +#if defined(CONFIG_PSTORE_ZLIB_COMPRESS) + &backend_zlib; +#elif defined(CONFIG_PSTORE_LZO_COMPRESS) + &backend_lzo; +#elif defined(CONFIG_PSTORE_LZ4_COMPRESS) + &backend_lz4; +#else + NULL; +#endif + +static int pstore_compress(const void *in, void *out, + size_t inlen, size_t outlen) +{ + if (zbackend) + return zbackend->compress(in, out, inlen, outlen); + else + return -EIO; +} + +static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen) +{ + if (zbackend) + return zbackend->decompress(in, out, inlen, outlen); + else + return -EIO; +} + +static void allocate_buf_for_compression(void) +{ + if (zbackend) { + pr_info("using %s compression\n", zbackend->name); + zbackend->allocate(); + } else { + pr_err("allocate compression buffer error!\n"); + } +} + +static void free_buf_for_compression(void) +{ + if (zbackend) + zbackend->free(); + else + pr_err("free compression buffer error!\n"); } /* @@ -522,6 +721,7 @@ void pstore_get_records(int quiet) int failed = 0, rc; bool compressed; int unzipped_len = -1; + ssize_t ecc_notice_size = 0; if (!psi) return; @@ -531,7 +731,7 @@ void pstore_get_records(int quiet) goto out; while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed, - psi)) > 0) { + &ecc_notice_size, psi)) > 0) { if (compressed && (type == PSTORE_TYPE_DMESG)) { if (big_oops_buf) unzipped_len = pstore_decompress(buf, @@ -539,6 +739,9 @@ void pstore_get_records(int quiet) big_oops_buf_sz); if (unzipped_len > 0) { + if (ecc_notice_size) + memcpy(big_oops_buf + unzipped_len, + buf + size, ecc_notice_size); kfree(buf); buf = big_oops_buf; size = unzipped_len; @@ -550,7 +753,8 @@ void pstore_get_records(int quiet) } } rc = pstore_mkfile(type, psi->name, id, count, buf, - compressed, (size_t)size, time, psi); + compressed, size + ecc_notice_size, + time, psi); if (unzipped_len < 0) { /* Free buffer other than big oops */ kfree(buf); diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index bd9812e83461..d9668c2b43cb 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -181,10 +181,10 @@ static bool prz_ok(struct persistent_ram_zone *prz) static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, bool *compressed, + ssize_t *ecc_notice_size, struct pstore_info *psi) { ssize_t size; - ssize_t ecc_notice_size; struct ramoops_context *cxt = psi->data; struct persistent_ram_zone *prz = NULL; int header_length = 0; @@ -229,16 +229,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, size = persistent_ram_old_size(prz) - header_length; /* ECC correction notice */ - ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0); + *ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0); - *buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL); + *buf = kmalloc(size + *ecc_notice_size + 1, GFP_KERNEL); if (*buf == NULL) return -ENOMEM; memcpy(*buf, (char *)persistent_ram_old(prz) + header_length, size); - persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1); + persistent_ram_ecc_string(prz, *buf + size, *ecc_notice_size + 1); - return size + ecc_notice_size; + return size; } static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz, diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 831479f8df8f..899e95e84400 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -58,7 +58,8 @@ struct pstore_info { int (*close)(struct pstore_info *psi); ssize_t (*read)(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, - bool *compressed, struct pstore_info *psi); + bool *compressed, ssize_t *ecc_notice_size, + struct pstore_info *psi); int (*write)(enum pstore_type_id type, enum kmsg_dump_reason reason, u64 *id, unsigned int part, int count, bool compressed, -- cgit v1.2.3 From e788892ba3cc71d385b75895f7a375fbc659ce86 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 2 Jun 2016 23:24:15 +0200 Subject: cpufreq: governor: Get rid of governor events The design of the cpufreq governor API is not very straightforward, as struct cpufreq_governor provides only one callback to be invoked from different code paths for different purposes. The purpose it is invoked for is determined by its second "event" argument, causing it to act as a "callback multiplexer" of sorts. Unfortunately, that leads to extra complexity in governors, some of which implement the ->governor() callback as a switch statement that simply checks the event argument and invokes a separate function to handle that specific event. That extra complexity can be eliminated by replacing the all-purpose ->governor() callback with a family of callbacks to carry out specific governor operations: initialization and exit, start and stop and policy limits updates. That also turns out to reduce the code size too, so do it. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- arch/powerpc/platforms/cell/cpufreq_spudemand.c | 72 ++++++++-------- drivers/cpufreq/cpufreq.c | 31 ++++--- drivers/cpufreq/cpufreq_conservative.c | 7 +- drivers/cpufreq/cpufreq_governor.c | 39 +++------ drivers/cpufreq/cpufreq_governor.h | 20 ++++- drivers/cpufreq/cpufreq_ondemand.c | 7 +- drivers/cpufreq/cpufreq_performance.c | 17 +--- drivers/cpufreq/cpufreq_powersave.c | 17 +--- drivers/cpufreq/cpufreq_userspace.c | 104 ++++++++++++------------ include/linux/cpufreq.h | 14 ++-- kernel/sched/cpufreq_schedutil.c | 34 ++------ 11 files changed, 158 insertions(+), 204 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/platforms/cell/cpufreq_spudemand.c b/arch/powerpc/platforms/cell/cpufreq_spudemand.c index 82607d621aca..88301e53f085 100644 --- a/arch/powerpc/platforms/cell/cpufreq_spudemand.c +++ b/arch/powerpc/platforms/cell/cpufreq_spudemand.c @@ -85,61 +85,57 @@ static void spu_gov_cancel_work(struct spu_gov_info_struct *info) cancel_delayed_work_sync(&info->work); } -static int spu_gov_govern(struct cpufreq_policy *policy, unsigned int event) +static int spu_gov_start(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; - struct spu_gov_info_struct *info, *affected_info; + struct spu_gov_info_struct *info = &per_cpu(spu_gov_info, cpu); + struct spu_gov_info_struct *affected_info; int i; - int ret = 0; - info = &per_cpu(spu_gov_info, cpu); - - switch (event) { - case CPUFREQ_GOV_START: - if (!cpu_online(cpu)) { - printk(KERN_ERR "cpu %d is not online\n", cpu); - ret = -EINVAL; - break; - } + if (!cpu_online(cpu)) { + printk(KERN_ERR "cpu %d is not online\n", cpu); + return -EINVAL; + } - if (!policy->cur) { - printk(KERN_ERR "no cpu specified in policy\n"); - ret = -EINVAL; - break; - } + if (!policy->cur) { + printk(KERN_ERR "no cpu specified in policy\n"); + return -EINVAL; + } - /* initialize spu_gov_info for all affected cpus */ - for_each_cpu(i, policy->cpus) { - affected_info = &per_cpu(spu_gov_info, i); - affected_info->policy = policy; - } + /* initialize spu_gov_info for all affected cpus */ + for_each_cpu(i, policy->cpus) { + affected_info = &per_cpu(spu_gov_info, i); + affected_info->policy = policy; + } - info->poll_int = POLL_TIME; + info->poll_int = POLL_TIME; - /* setup timer */ - spu_gov_init_work(info); + /* setup timer */ + spu_gov_init_work(info); - break; + return 0; +} - case CPUFREQ_GOV_STOP: - /* cancel timer */ - spu_gov_cancel_work(info); +static void spu_gov_stop(struct cpufreq_policy *policy) +{ + unsigned int cpu = policy->cpu; + struct spu_gov_info_struct *info = &per_cpu(spu_gov_info, cpu); + int i; - /* clean spu_gov_info for all affected cpus */ - for_each_cpu (i, policy->cpus) { - info = &per_cpu(spu_gov_info, i); - info->policy = NULL; - } + /* cancel timer */ + spu_gov_cancel_work(info); - break; + /* clean spu_gov_info for all affected cpus */ + for_each_cpu (i, policy->cpus) { + info = &per_cpu(spu_gov_info, i); + info->policy = NULL; } - - return ret; } static struct cpufreq_governor spu_governor = { .name = "spudemand", - .governor = spu_gov_govern, + .start = spu_gov_start, + .stop = spu_gov_stop, .owner = THIS_MODULE, }; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 268566e40684..d98ff688b2f1 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2023,10 +2023,12 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy) pr_debug("%s: for CPU %u\n", __func__, policy->cpu); - ret = policy->governor->governor(policy, CPUFREQ_GOV_POLICY_INIT); - if (ret) { - module_put(policy->governor->owner); - return ret; + if (policy->governor->init) { + ret = policy->governor->init(policy); + if (ret) { + module_put(policy->governor->owner); + return ret; + } } policy->governor->initialized++; @@ -2040,7 +2042,8 @@ static void cpufreq_exit_governor(struct cpufreq_policy *policy) pr_debug("%s: for CPU %u\n", __func__, policy->cpu); - policy->governor->governor(policy, CPUFREQ_GOV_POLICY_EXIT); + if (policy->governor->exit) + policy->governor->exit(policy); policy->governor->initialized--; module_put(policy->governor->owner); @@ -2061,11 +2064,15 @@ static int cpufreq_start_governor(struct cpufreq_policy *policy) if (cpufreq_driver->get && !cpufreq_driver->setpolicy) cpufreq_update_current_freq(policy); - ret = policy->governor->governor(policy, CPUFREQ_GOV_START); - if (ret) - return ret; + if (policy->governor->start) { + ret = policy->governor->start(policy); + if (ret) + return ret; + } + + if (policy->governor->limits) + policy->governor->limits(policy); - policy->governor->governor(policy, CPUFREQ_GOV_LIMITS); return 0; } @@ -2076,7 +2083,8 @@ static void cpufreq_stop_governor(struct cpufreq_policy *policy) pr_debug("%s: for CPU %u\n", __func__, policy->cpu); - policy->governor->governor(policy, CPUFREQ_GOV_STOP); + if (policy->governor->stop) + policy->governor->stop(policy); } static void cpufreq_governor_limits(struct cpufreq_policy *policy) @@ -2086,7 +2094,8 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy) pr_debug("%s: for CPU %u\n", __func__, policy->cpu); - policy->governor->governor(policy, CPUFREQ_GOV_LIMITS); + if (policy->governor->limits) + policy->governor->limits(policy); } int cpufreq_register_governor(struct cpufreq_governor *governor) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 316df247e00d..2568508fca38 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -313,12 +313,7 @@ static void cs_start(struct cpufreq_policy *policy) } static struct dbs_governor cs_dbs_gov = { - .gov = { - .name = "conservative", - .governor = cpufreq_governor_dbs, - .max_transition_latency = TRANSITION_LATENCY_LIMIT, - .owner = THIS_MODULE, - }, + .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"), .kobj_type = { .default_attrs = cs_attributes }, .gov_dbs_timer = cs_dbs_timer, .alloc = cs_alloc, diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index be498d56dd69..ca9927c15a71 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -389,7 +389,7 @@ static void free_policy_dbs_info(struct policy_dbs_info *policy_dbs, gov->free(policy_dbs); } -static int cpufreq_governor_init(struct cpufreq_policy *policy) +int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) { struct dbs_governor *gov = dbs_governor_of(policy); struct dbs_data *dbs_data; @@ -474,8 +474,9 @@ out: mutex_unlock(&gov_dbs_data_mutex); return ret; } +EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_init); -static int cpufreq_governor_exit(struct cpufreq_policy *policy) +void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy) { struct dbs_governor *gov = dbs_governor_of(policy); struct policy_dbs_info *policy_dbs = policy->governor_data; @@ -500,10 +501,10 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy) free_policy_dbs_info(policy_dbs, gov); mutex_unlock(&gov_dbs_data_mutex); - return 0; } +EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_exit); -static int cpufreq_governor_start(struct cpufreq_policy *policy) +int cpufreq_dbs_governor_start(struct cpufreq_policy *policy) { struct dbs_governor *gov = dbs_governor_of(policy); struct policy_dbs_info *policy_dbs = policy->governor_data; @@ -539,14 +540,15 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy) gov_set_update_util(policy_dbs, sampling_rate); return 0; } +EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_start); -static int cpufreq_governor_stop(struct cpufreq_policy *policy) +void cpufreq_dbs_governor_stop(struct cpufreq_policy *policy) { gov_cancel_work(policy); - return 0; } +EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop); -static int cpufreq_governor_limits(struct cpufreq_policy *policy) +void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy) { struct policy_dbs_info *policy_dbs = policy->governor_data; @@ -560,26 +562,5 @@ static int cpufreq_governor_limits(struct cpufreq_policy *policy) gov_update_sample_delay(policy_dbs, 0); mutex_unlock(&policy_dbs->timer_mutex); - - return 0; -} - -int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event) -{ - if (event == CPUFREQ_GOV_POLICY_INIT) { - return cpufreq_governor_init(policy); - } else if (policy->governor_data) { - switch (event) { - case CPUFREQ_GOV_POLICY_EXIT: - return cpufreq_governor_exit(policy); - case CPUFREQ_GOV_START: - return cpufreq_governor_start(policy); - case CPUFREQ_GOV_STOP: - return cpufreq_governor_stop(policy); - case CPUFREQ_GOV_LIMITS: - return cpufreq_governor_limits(policy); - } - } - return -EINVAL; } -EXPORT_SYMBOL_GPL(cpufreq_governor_dbs); +EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_limits); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 34eb214b6d57..36f0d19dd869 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -148,6 +148,25 @@ static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy return container_of(policy->governor, struct dbs_governor, gov); } +/* Governor callback routines */ +int cpufreq_dbs_governor_init(struct cpufreq_policy *policy); +void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy); +int cpufreq_dbs_governor_start(struct cpufreq_policy *policy); +void cpufreq_dbs_governor_stop(struct cpufreq_policy *policy); +void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy); + +#define CPUFREQ_DBS_GOVERNOR_INITIALIZER(_name_) \ + { \ + .name = _name_, \ + .max_transition_latency = TRANSITION_LATENCY_LIMIT, \ + .owner = THIS_MODULE, \ + .init = cpufreq_dbs_governor_init, \ + .exit = cpufreq_dbs_governor_exit, \ + .start = cpufreq_dbs_governor_start, \ + .stop = cpufreq_dbs_governor_stop, \ + .limits = cpufreq_dbs_governor_limits, \ + } + /* Governor specific operations */ struct od_ops { unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy, @@ -155,7 +174,6 @@ struct od_ops { }; unsigned int dbs_update(struct cpufreq_policy *policy); -int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event); void od_register_powersave_bias_handler(unsigned int (*f) (struct cpufreq_policy *, unsigned int, unsigned int), unsigned int powersave_bias); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 300163430516..09d6c0c405e4 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -420,12 +420,7 @@ static struct od_ops od_ops = { }; static struct dbs_governor od_dbs_gov = { - .gov = { - .name = "ondemand", - .governor = cpufreq_governor_dbs, - .max_transition_latency = TRANSITION_LATENCY_LIMIT, - .owner = THIS_MODULE, - }, + .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("ondemand"), .kobj_type = { .default_attrs = od_attributes }, .gov_dbs_timer = od_dbs_timer, .alloc = od_alloc, diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index dd4dca3ab844..dafb679adc58 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -16,25 +16,16 @@ #include #include -static int cpufreq_governor_performance(struct cpufreq_policy *policy, - unsigned int event) +static void cpufreq_gov_performance_limits(struct cpufreq_policy *policy) { - switch (event) { - case CPUFREQ_GOV_LIMITS: - pr_debug("setting to %u kHz\n", policy->max); - __cpufreq_driver_target(policy, policy->max, - CPUFREQ_RELATION_H); - break; - default: - break; - } - return 0; + pr_debug("setting to %u kHz\n", policy->max); + __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); } static struct cpufreq_governor cpufreq_gov_performance = { .name = "performance", - .governor = cpufreq_governor_performance, .owner = THIS_MODULE, + .limits = cpufreq_gov_performance_limits, }; static int __init cpufreq_gov_performance_init(void) diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 691e573e46ee..78a651038faf 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -16,24 +16,15 @@ #include #include -static int cpufreq_governor_powersave(struct cpufreq_policy *policy, - unsigned int event) +static void cpufreq_gov_powersave_limits(struct cpufreq_policy *policy) { - switch (event) { - case CPUFREQ_GOV_LIMITS: - pr_debug("setting to %u kHz\n", policy->min); - __cpufreq_driver_target(policy, policy->min, - CPUFREQ_RELATION_L); - break; - default: - break; - } - return 0; + pr_debug("setting to %u kHz\n", policy->min); + __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); } static struct cpufreq_governor cpufreq_gov_powersave = { .name = "powersave", - .governor = cpufreq_governor_powersave, + .limits = cpufreq_gov_powersave_limits, .owner = THIS_MODULE, }; diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 9f3dec9a3f36..bd897e3e134d 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -65,66 +65,66 @@ static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) return 0; } -static int cpufreq_governor_userspace(struct cpufreq_policy *policy, - unsigned int event) +static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) +{ + mutex_lock(&userspace_mutex); + kfree(policy->governor_data); + policy->governor_data = NULL; + mutex_unlock(&userspace_mutex); +} + +static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) { unsigned int *setspeed = policy->governor_data; - unsigned int cpu = policy->cpu; - int rc = 0; - if (event == CPUFREQ_GOV_POLICY_INIT) - return cpufreq_userspace_policy_init(policy); + BUG_ON(!policy->cur); + pr_debug("started managing cpu %u\n", policy->cpu); - if (!setspeed) - return -EINVAL; - - switch (event) { - case CPUFREQ_GOV_POLICY_EXIT: - mutex_lock(&userspace_mutex); - policy->governor_data = NULL; - kfree(setspeed); - mutex_unlock(&userspace_mutex); - break; - case CPUFREQ_GOV_START: - BUG_ON(!policy->cur); - pr_debug("started managing cpu %u\n", cpu); - - mutex_lock(&userspace_mutex); - per_cpu(cpu_is_managed, cpu) = 1; - *setspeed = policy->cur; - mutex_unlock(&userspace_mutex); - break; - case CPUFREQ_GOV_STOP: - pr_debug("managing cpu %u stopped\n", cpu); - - mutex_lock(&userspace_mutex); - per_cpu(cpu_is_managed, cpu) = 0; - *setspeed = 0; - mutex_unlock(&userspace_mutex); - break; - case CPUFREQ_GOV_LIMITS: - mutex_lock(&userspace_mutex); - pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", - cpu, policy->min, policy->max, policy->cur, *setspeed); - - if (policy->max < *setspeed) - __cpufreq_driver_target(policy, policy->max, - CPUFREQ_RELATION_H); - else if (policy->min > *setspeed) - __cpufreq_driver_target(policy, policy->min, - CPUFREQ_RELATION_L); - else - __cpufreq_driver_target(policy, *setspeed, - CPUFREQ_RELATION_L); - mutex_unlock(&userspace_mutex); - break; - } - return rc; + mutex_lock(&userspace_mutex); + per_cpu(cpu_is_managed, policy->cpu) = 1; + *setspeed = policy->cur; + mutex_unlock(&userspace_mutex); + return 0; +} + +static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) +{ + unsigned int *setspeed = policy->governor_data; + + pr_debug("managing cpu %u stopped\n", policy->cpu); + + mutex_lock(&userspace_mutex); + per_cpu(cpu_is_managed, policy->cpu) = 0; + *setspeed = 0; + mutex_unlock(&userspace_mutex); +} + +static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) +{ + unsigned int *setspeed = policy->governor_data; + + mutex_lock(&userspace_mutex); + + pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", + policy->cpu, policy->min, policy->max, policy->cur, *setspeed); + + if (policy->max < *setspeed) + __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); + else if (policy->min > *setspeed) + __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); + else + __cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L); + + mutex_unlock(&userspace_mutex); } static struct cpufreq_governor cpufreq_gov_userspace = { .name = "userspace", - .governor = cpufreq_governor_userspace, + .init = cpufreq_userspace_policy_init, + .exit = cpufreq_userspace_policy_exit, + .start = cpufreq_userspace_policy_start, + .stop = cpufreq_userspace_policy_stop, + .limits = cpufreq_userspace_policy_limits, .store_setspeed = cpufreq_set, .show_setspeed = show_speed, .owner = THIS_MODULE, diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 4e81e08db752..5bcda3e6aa9e 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -455,18 +455,14 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, #define MIN_LATENCY_MULTIPLIER (20) #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) -/* Governor Events */ -#define CPUFREQ_GOV_START 1 -#define CPUFREQ_GOV_STOP 2 -#define CPUFREQ_GOV_LIMITS 3 -#define CPUFREQ_GOV_POLICY_INIT 4 -#define CPUFREQ_GOV_POLICY_EXIT 5 - struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; int initialized; - int (*governor) (struct cpufreq_policy *policy, - unsigned int event); + int (*init)(struct cpufreq_policy *policy); + void (*exit)(struct cpufreq_policy *policy); + int (*start)(struct cpufreq_policy *policy); + void (*stop)(struct cpufreq_policy *policy); + void (*limits)(struct cpufreq_policy *policy); ssize_t (*show_setspeed) (struct cpufreq_policy *policy, char *buf); int (*store_setspeed) (struct cpufreq_policy *policy, diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 14c4aa25cc45..fdcee3cf38fc 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -394,7 +394,7 @@ static int sugov_init(struct cpufreq_policy *policy) return ret; } -static int sugov_exit(struct cpufreq_policy *policy) +static void sugov_exit(struct cpufreq_policy *policy) { struct sugov_policy *sg_policy = policy->governor_data; struct sugov_tunables *tunables = sg_policy->tunables; @@ -412,7 +412,6 @@ static int sugov_exit(struct cpufreq_policy *policy) mutex_unlock(&global_tunables_lock); sugov_policy_free(sg_policy); - return 0; } static int sugov_start(struct cpufreq_policy *policy) @@ -444,7 +443,7 @@ static int sugov_start(struct cpufreq_policy *policy) return 0; } -static int sugov_stop(struct cpufreq_policy *policy) +static void sugov_stop(struct cpufreq_policy *policy) { struct sugov_policy *sg_policy = policy->governor_data; unsigned int cpu; @@ -456,10 +455,9 @@ static int sugov_stop(struct cpufreq_policy *policy) irq_work_sync(&sg_policy->irq_work); cancel_work_sync(&sg_policy->work); - return 0; } -static int sugov_limits(struct cpufreq_policy *policy) +static void sugov_limits(struct cpufreq_policy *policy) { struct sugov_policy *sg_policy = policy->governor_data; @@ -477,32 +475,16 @@ static int sugov_limits(struct cpufreq_policy *policy) } sg_policy->need_freq_update = true; - return 0; -} - -int sugov_governor(struct cpufreq_policy *policy, unsigned int event) -{ - if (event == CPUFREQ_GOV_POLICY_INIT) { - return sugov_init(policy); - } else if (policy->governor_data) { - switch (event) { - case CPUFREQ_GOV_POLICY_EXIT: - return sugov_exit(policy); - case CPUFREQ_GOV_START: - return sugov_start(policy); - case CPUFREQ_GOV_STOP: - return sugov_stop(policy); - case CPUFREQ_GOV_LIMITS: - return sugov_limits(policy); - } - } - return -EINVAL; } static struct cpufreq_governor schedutil_gov = { .name = "schedutil", - .governor = sugov_governor, .owner = THIS_MODULE, + .init = sugov_init, + .exit = sugov_exit, + .start = sugov_start, + .stop = sugov_stop, + .limits = sugov_limits, }; static int __init sugov_module_init(void) -- cgit v1.2.3 From bf2be2de8493dd5f86d6e0f0d4eecb5810ad035b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 18 May 2016 17:55:31 +0530 Subject: cpufreq: governor: Create cpufreq_policy_apply_limits() Create a new helper to avoid code duplication across governors. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 7 +------ include/linux/cpufreq.h | 8 ++++++++ kernel/sched/cpufreq_schedutil.c | 9 +-------- 3 files changed, 10 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 18eab7f4ba4c..4b88b5bec4ef 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -553,12 +553,7 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy) struct policy_dbs_info *policy_dbs = policy->governor_data; mutex_lock(&policy_dbs->timer_mutex); - - if (policy->max < policy->cur) - __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > policy->cur) - __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); - + cpufreq_policy_apply_limits(policy); gov_update_sample_delay(policy_dbs, 0); mutex_unlock(&policy_dbs->timer_mutex); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 5bcda3e6aa9e..3be54a0b4373 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -489,6 +489,14 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor); struct cpufreq_governor *cpufreq_default_governor(void); struct cpufreq_governor *cpufreq_fallback_governor(void); +static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy) +{ + if (policy->max < policy->cur) + __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); + else if (policy->min > policy->cur) + __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); +} + /* Governor attribute set */ struct gov_attr_set { struct kobject kobj; diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index fdcee3cf38fc..758efd7f3abe 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -463,14 +463,7 @@ static void sugov_limits(struct cpufreq_policy *policy) if (!policy->fast_switch_enabled) { mutex_lock(&sg_policy->work_lock); - - if (policy->max < policy->cur) - __cpufreq_driver_target(policy, policy->max, - CPUFREQ_RELATION_H); - else if (policy->min > policy->cur) - __cpufreq_driver_target(policy, policy->min, - CPUFREQ_RELATION_L); - + cpufreq_policy_apply_limits(policy); mutex_unlock(&sg_policy->work_lock); } -- cgit v1.2.3 From 9a15fb2c797a15524e63eacb10bd6cd68a99e830 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 18 May 2016 22:59:49 +0200 Subject: cpufreq: Drop the 'initialized' field from struct cpufreq_governor The 'initialized' field in struct cpufreq_governor is only used by the conservative governor (as a usage counter) and the way that happens is far from straightforward and arguably incorrect. Namely, the value of 'initialized' is checked by cpufreq_dbs_governor_init() and cpufreq_dbs_governor_exit() and the results of those checks are passed (as the second argument) to the ->init() and ->exit() callbacks in struct dbs_governor. Those callbacks are only implemented by the ondemand and conservative governors and ondemand doesn't use their second argument at all. In turn, the conservative governor uses it to decide whether or not to either register or unregister a transition notifier. That whole mechanism is not only unnecessarily convoluted, but also racy, because the 'initialized' field of struct cpufreq_governor is updated in cpufreq_init_governor() and cpufreq_exit_governor() under policy->rwsem which doesn't help if one of these functions is run twice in parallel for different policies (which isn't impossible in principle), for example. Instead of it, add a proper usage counter to the conservative governor and update it from cs_init() and cs_exit() which is guaranteed to be non-racy, as those functions are only called under gov_dbs_data_mutex which is global. With that in place, drop the 'initialized' field from struct cpufreq_governor as it is not used any more. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 3 --- drivers/cpufreq/cpufreq_conservative.c | 44 ++++++++++++++++++++++------------ drivers/cpufreq/cpufreq_governor.c | 6 ++--- drivers/cpufreq/cpufreq_governor.h | 4 ++-- drivers/cpufreq/cpufreq_ondemand.c | 4 ++-- include/linux/cpufreq.h | 1 - 6 files changed, 36 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d98ff688b2f1..bdf1f280ae39 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2031,7 +2031,6 @@ static int cpufreq_init_governor(struct cpufreq_policy *policy) } } - policy->governor->initialized++; return 0; } @@ -2045,7 +2044,6 @@ static void cpufreq_exit_governor(struct cpufreq_policy *policy) if (policy->governor->exit) policy->governor->exit(policy); - policy->governor->initialized--; module_put(policy->governor->owner); } @@ -2110,7 +2108,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor) mutex_lock(&cpufreq_governor_mutex); - governor->initialized = 0; err = -EBUSY; if (!find_governor(governor->name)) { err = 0; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 78faa9fbc384..f967ec6c5720 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -127,7 +127,6 @@ static struct notifier_block cs_cpufreq_notifier_block = { }; /************************** sysfs interface ************************/ -static struct dbs_governor cs_dbs_gov; static ssize_t store_sampling_down_factor(struct gov_attr_set *attr_set, const char *buf, size_t count) @@ -255,6 +254,13 @@ static struct attribute *cs_attributes[] = { /************************** sysfs end ************************/ +struct cs_governor { + struct dbs_governor dbs_gov; + unsigned int usage_count; +}; + +static struct cs_governor cs_gov; + static struct policy_dbs_info *cs_alloc(void) { struct cs_policy_dbs_info *dbs_info; @@ -268,7 +274,7 @@ static void cs_free(struct policy_dbs_info *policy_dbs) kfree(to_dbs_info(policy_dbs)); } -static int cs_init(struct dbs_data *dbs_data, bool notify) +static int cs_init(struct dbs_data *dbs_data) { struct cs_dbs_tuners *tuners; @@ -286,16 +292,22 @@ static int cs_init(struct dbs_data *dbs_data, bool notify) dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); - if (notify) + /* + * This function and cs_exit() are only called under gov_dbs_data_mutex + * which is global, so the cs_gov.usage_count accesses are guaranteed + * to be serialized. + */ + if (!cs_gov.usage_count++) cpufreq_register_notifier(&cs_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); return 0; } -static void cs_exit(struct dbs_data *dbs_data, bool notify) +static void cs_exit(struct dbs_data *dbs_data) { - if (notify) + /* Protected by gov_dbs_data_mutex - see the comment in cs_init(). */ + if (!--cs_gov.usage_count) cpufreq_unregister_notifier(&cs_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); @@ -310,18 +322,20 @@ static void cs_start(struct cpufreq_policy *policy) dbs_info->requested_freq = policy->cur; } -static struct dbs_governor cs_dbs_gov = { - .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"), - .kobj_type = { .default_attrs = cs_attributes }, - .gov_dbs_timer = cs_dbs_timer, - .alloc = cs_alloc, - .free = cs_free, - .init = cs_init, - .exit = cs_exit, - .start = cs_start, +static struct cs_governor cs_gov = { + .dbs_gov = { + .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"), + .kobj_type = { .default_attrs = cs_attributes }, + .gov_dbs_timer = cs_dbs_timer, + .alloc = cs_alloc, + .free = cs_free, + .init = cs_init, + .exit = cs_exit, + .start = cs_start, + }, }; -#define CPU_FREQ_GOV_CONSERVATIVE (&cs_dbs_gov.gov) +#define CPU_FREQ_GOV_CONSERVATIVE (&cs_gov.dbs_gov.gov) static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 4b88b5bec4ef..31369e247192 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -429,7 +429,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) gov_attr_set_init(&dbs_data->attr_set, &policy_dbs->list); - ret = gov->init(dbs_data, !policy->governor->initialized); + ret = gov->init(dbs_data); if (ret) goto free_policy_dbs_info; @@ -464,7 +464,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) if (!have_governor_per_policy()) gov->gdbs_data = NULL; - gov->exit(dbs_data, !policy->governor->initialized); + gov->exit(dbs_data); kfree(dbs_data); free_policy_dbs_info: @@ -494,7 +494,7 @@ void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy) if (!have_governor_per_policy()) gov->gdbs_data = NULL; - gov->exit(dbs_data, policy->governor->initialized == 1); + gov->exit(dbs_data); kfree(dbs_data); } diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 36f0d19dd869..ef1037e9c92b 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -138,8 +138,8 @@ struct dbs_governor { unsigned int (*gov_dbs_timer)(struct cpufreq_policy *policy); struct policy_dbs_info *(*alloc)(void); void (*free)(struct policy_dbs_info *policy_dbs); - int (*init)(struct dbs_data *dbs_data, bool notify); - void (*exit)(struct dbs_data *dbs_data, bool notify); + int (*init)(struct dbs_data *dbs_data); + void (*exit)(struct dbs_data *dbs_data); void (*start)(struct cpufreq_policy *policy); }; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 4441a11139f1..c84fc2240d49 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -361,7 +361,7 @@ static void od_free(struct policy_dbs_info *policy_dbs) kfree(to_dbs_info(policy_dbs)); } -static int od_init(struct dbs_data *dbs_data, bool notify) +static int od_init(struct dbs_data *dbs_data) { struct od_dbs_tuners *tuners; u64 idle_time; @@ -400,7 +400,7 @@ static int od_init(struct dbs_data *dbs_data, bool notify) return 0; } -static void od_exit(struct dbs_data *dbs_data, bool notify) +static void od_exit(struct dbs_data *dbs_data) { kfree(dbs_data->tuners); } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 3be54a0b4373..fbd696edf5bd 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -457,7 +457,6 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; - int initialized; int (*init)(struct cpufreq_policy *policy); void (*exit)(struct cpufreq_policy *policy); int (*start)(struct cpufreq_policy *policy); -- cgit v1.2.3 From 1aefc75b2449eb68a6fc3ca932e2a4ee353b748d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 31 May 2016 22:14:44 +0200 Subject: cpufreq: stats: Make the stats code non-modular The modularity of cpufreq_stats is quite problematic. First off, the usage of policy notifiers for the initialization and cleanup in the cpufreq_stats module is inherently racy with respect to CPU offline/online and the initialization and cleanup of the cpufreq driver. Second, fast frequency switching (used by the schedutil governor) cannot be enabled if any transition notifiers are registered, so if the cpufreq_stats module (that registers a transition notifier for updating transition statistics) is loaded, the schedutil governor cannot use fast frequency switching. On the other hand, allowing cpufreq_stats to be built as a module doesn't really add much value. Arguably, there's not much reason for that code to be modular at all. For the above reasons, make the cpufreq stats code non-modular, modify the core to invoke functions provided by that code directly and drop the notifiers from it. Make the stats sysfs attributes appear empty if fast frequency switching is enabled as the statistics will not be updated in that case anyway (and returning -EBUSY from those attributes breaks powertop). While at it, clean up Kconfig help for the CPU_FREQ_STAT and CPU_FREQ_STAT_DETAILS options. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/Kconfig | 13 ++-- drivers/cpufreq/cpufreq.c | 4 ++ drivers/cpufreq/cpufreq_stats.c | 154 ++++++---------------------------------- include/linux/cpufreq.h | 12 ++++ 4 files changed, 41 insertions(+), 142 deletions(-) (limited to 'include/linux') diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index b7445b6ae5a4..c822d72629d5 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -31,23 +31,18 @@ config CPU_FREQ_BOOST_SW depends on THERMAL config CPU_FREQ_STAT - tristate "CPU frequency translation statistics" + bool "CPU frequency transition statistics" default y help - This driver exports CPU frequency statistics information through sysfs - file system. - - To compile this driver as a module, choose M here: the - module will be called cpufreq_stats. + Export CPU frequency statistics information through sysfs. If in doubt, say N. config CPU_FREQ_STAT_DETAILS - bool "CPU frequency translation statistics details" + bool "CPU frequency transition statistics details" depends on CPU_FREQ_STAT help - This will show detail CPU frequency translation table in sysfs file - system. + Show detailed CPU frequency transition table in sysfs. If in doubt, say N. diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 198416bc22de..c6a14ba239a2 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -347,6 +347,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, pr_debug("FREQ: %lu - CPU: %lu\n", (unsigned long)freqs->new, (unsigned long)freqs->cpu); trace_cpu_frequency(freqs->new, freqs->cpu); + cpufreq_stats_record_transition(policy, freqs->new); srcu_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); if (likely(policy) && likely(policy->cpu == freqs->cpu)) @@ -1108,6 +1109,7 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify) CPUFREQ_REMOVE_POLICY, policy); down_write(&policy->rwsem); + cpufreq_stats_free_table(policy); cpufreq_remove_dev_symlink(policy); kobj = &policy->kobj; cmp = &policy->kobj_unregister; @@ -1262,6 +1264,8 @@ static int cpufreq_online(unsigned int cpu) ret = cpufreq_add_dev_interface(policy); if (ret) goto out_exit_policy; + + cpufreq_stats_create_table(policy); blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_CREATE_POLICY, policy); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 5e370a30a964..c6e7f81a0397 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -15,7 +15,7 @@ #include #include -static spinlock_t cpufreq_stats_lock; +static DEFINE_SPINLOCK(cpufreq_stats_lock); struct cpufreq_stats { unsigned int total_trans; @@ -52,6 +52,9 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) ssize_t len = 0; int i; + if (policy->fast_switch_enabled) + return 0; + cpufreq_stats_update(stats); for (i = 0; i < stats->state_num; i++) { len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i], @@ -68,6 +71,9 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) ssize_t len = 0; int i, j; + if (policy->fast_switch_enabled) + return 0; + len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stats->state_num; i++) { @@ -130,7 +136,7 @@ static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq) return -1; } -static void __cpufreq_stats_free_table(struct cpufreq_policy *policy) +void cpufreq_stats_free_table(struct cpufreq_policy *policy) { struct cpufreq_stats *stats = policy->stats; @@ -146,20 +152,7 @@ static void __cpufreq_stats_free_table(struct cpufreq_policy *policy) policy->stats = NULL; } -static void cpufreq_stats_free_table(unsigned int cpu) -{ - struct cpufreq_policy *policy; - - policy = cpufreq_cpu_get(cpu); - if (!policy) - return; - - __cpufreq_stats_free_table(policy); - - cpufreq_cpu_put(policy); -} - -static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) +void cpufreq_stats_create_table(struct cpufreq_policy *policy) { unsigned int i = 0, count = 0, ret = -ENOMEM; struct cpufreq_stats *stats; @@ -170,15 +163,15 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) /* We need cpufreq table for creating stats table */ table = cpufreq_frequency_get_table(cpu); if (unlikely(!table)) - return 0; + return; /* stats already initialized */ if (policy->stats) - return -EEXIST; + return; stats = kzalloc(sizeof(*stats), GFP_KERNEL); if (!stats) - return -ENOMEM; + return; /* Find total allocation size */ cpufreq_for_each_valid_entry(pos, table) @@ -215,80 +208,32 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) policy->stats = stats; ret = sysfs_create_group(&policy->kobj, &stats_attr_group); if (!ret) - return 0; + return; /* We failed, release resources */ policy->stats = NULL; kfree(stats->time_in_state); free_stat: kfree(stats); - - return ret; -} - -static void cpufreq_stats_create_table(unsigned int cpu) -{ - struct cpufreq_policy *policy; - - /* - * "likely(!policy)" because normally cpufreq_stats will be registered - * before cpufreq driver - */ - policy = cpufreq_cpu_get(cpu); - if (likely(!policy)) - return; - - __cpufreq_stats_create_table(policy); - - cpufreq_cpu_put(policy); } -static int cpufreq_stat_notifier_policy(struct notifier_block *nb, - unsigned long val, void *data) +void cpufreq_stats_record_transition(struct cpufreq_policy *policy, + unsigned int new_freq) { - int ret = 0; - struct cpufreq_policy *policy = data; - - if (val == CPUFREQ_CREATE_POLICY) - ret = __cpufreq_stats_create_table(policy); - else if (val == CPUFREQ_REMOVE_POLICY) - __cpufreq_stats_free_table(policy); - - return ret; -} - -static int cpufreq_stat_notifier_trans(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct cpufreq_freqs *freq = data; - struct cpufreq_policy *policy = cpufreq_cpu_get(freq->cpu); - struct cpufreq_stats *stats; + struct cpufreq_stats *stats = policy->stats; int old_index, new_index; - if (!policy) { - pr_err("%s: No policy found\n", __func__); - return 0; - } - - if (val != CPUFREQ_POSTCHANGE) - goto put_policy; - - if (!policy->stats) { + if (!stats) { pr_debug("%s: No stats found\n", __func__); - goto put_policy; + return; } - stats = policy->stats; - old_index = stats->last_index; - new_index = freq_table_get_index(stats, freq->new); + new_index = freq_table_get_index(stats, new_freq); /* We can't do stats->time_in_state[-1]= .. */ - if (old_index == -1 || new_index == -1) - goto put_policy; - - if (old_index == new_index) - goto put_policy; + if (old_index == -1 || new_index == -1 || old_index == new_index) + return; cpufreq_stats_update(stats); @@ -297,61 +242,4 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, stats->trans_table[old_index * stats->max_state + new_index]++; #endif stats->total_trans++; - -put_policy: - cpufreq_cpu_put(policy); - return 0; } - -static struct notifier_block notifier_policy_block = { - .notifier_call = cpufreq_stat_notifier_policy -}; - -static struct notifier_block notifier_trans_block = { - .notifier_call = cpufreq_stat_notifier_trans -}; - -static int __init cpufreq_stats_init(void) -{ - int ret; - unsigned int cpu; - - spin_lock_init(&cpufreq_stats_lock); - ret = cpufreq_register_notifier(¬ifier_policy_block, - CPUFREQ_POLICY_NOTIFIER); - if (ret) - return ret; - - for_each_online_cpu(cpu) - cpufreq_stats_create_table(cpu); - - ret = cpufreq_register_notifier(¬ifier_trans_block, - CPUFREQ_TRANSITION_NOTIFIER); - if (ret) { - cpufreq_unregister_notifier(¬ifier_policy_block, - CPUFREQ_POLICY_NOTIFIER); - for_each_online_cpu(cpu) - cpufreq_stats_free_table(cpu); - return ret; - } - - return 0; -} -static void __exit cpufreq_stats_exit(void) -{ - unsigned int cpu; - - cpufreq_unregister_notifier(¬ifier_policy_block, - CPUFREQ_POLICY_NOTIFIER); - cpufreq_unregister_notifier(¬ifier_trans_block, - CPUFREQ_TRANSITION_NOTIFIER); - for_each_online_cpu(cpu) - cpufreq_stats_free_table(cpu); -} - -MODULE_AUTHOR("Zou Nan hai "); -MODULE_DESCRIPTION("Export cpufreq stats via sysfs"); -MODULE_LICENSE("GPL"); - -module_init(cpufreq_stats_init); -module_exit(cpufreq_stats_exit); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index fbd696edf5bd..7ed93c310c08 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -185,6 +185,18 @@ static inline unsigned int cpufreq_quick_get_max(unsigned int cpu) static inline void disable_cpufreq(void) { } #endif +#ifdef CONFIG_CPU_FREQ_STAT +void cpufreq_stats_create_table(struct cpufreq_policy *policy); +void cpufreq_stats_free_table(struct cpufreq_policy *policy); +void cpufreq_stats_record_transition(struct cpufreq_policy *policy, + unsigned int new_freq); +#else +static inline void cpufreq_stats_create_table(struct cpufreq_policy *policy) { } +static inline void cpufreq_stats_free_table(struct cpufreq_policy *policy) { } +static inline void cpufreq_stats_record_transition(struct cpufreq_policy *policy, + unsigned int new_freq) { } +#endif /* CONFIG_CPU_FREQ_STAT */ + /********************************************************************* * CPUFREQ DRIVER INTERFACE * *********************************************************************/ -- cgit v1.2.3 From ccc12561926c0bef9a40865db93b926a0927e93f Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 20 May 2016 20:40:26 +0530 Subject: regmap: irq: Add support to call client specific pre/post interrupt service Regmap irq implements the generic interrupt service routine which is common for most of devices. Some devices, like MAX77620, MAX20024 needs the special handling before and after servicing the interrupt as generic. For the example, MAX77620 programming guidelines for interrupt servicing says: 1. When interrupt occurs from PMIC, mask the PMIC interrupt by setting GLBLM. 2. Read IRQTOP and service the interrupt accordingly. 3. Once all interrupts has been checked and serviced, the interrupt service routine un-masks the hardware interrupt line by clearing GLBLM. The step (2) is implemented in regmap irq as generic routine. For step (1) and (3), add callbacks from regmap irq to client driver to handle chip specific configurations. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-irq.c | 15 +++++++++++---- include/linux/regmap.h | 10 ++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 26f799e71c82..ec262476d043 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -268,13 +268,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) bool handled = false; u32 reg; + if (chip->handle_pre_irq) + chip->handle_pre_irq(chip->irq_drv_data); + if (chip->runtime_pm) { ret = pm_runtime_get_sync(map->dev); if (ret < 0) { dev_err(map->dev, "IRQ thread failed to resume: %d\n", ret); pm_runtime_put(map->dev); - return IRQ_NONE; + goto exit; } } @@ -296,7 +299,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (ret != 0) { dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); - return IRQ_NONE; + goto exit; } for (i = 0; i < data->chip->num_regs; i++) { @@ -312,7 +315,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) break; default: BUG(); - return IRQ_NONE; + goto exit; } } @@ -329,7 +332,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) ret); if (chip->runtime_pm) pm_runtime_put(map->dev); - return IRQ_NONE; + goto exit; } } } @@ -365,6 +368,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (chip->runtime_pm) pm_runtime_put(map->dev); +exit: + if (chip->handle_post_irq) + chip->handle_post_irq(chip->irq_drv_data); + if (handled) return IRQ_HANDLED; else diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 3dc08ce15426..a0bfe481f9ab 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -851,6 +851,12 @@ struct regmap_irq { * @num_type_reg: Number of type registers. * @type_reg_stride: Stride to use for chips where type registers are not * contiguous. + * @handle_pre_irq: Driver specific callback to handle interrupt from device + * before regmap_irq_handler process the interrupts. + * @handle_post_irq: Driver specific callback to handle interrupt from device + * 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. */ struct regmap_irq_chip { const char *name; @@ -877,6 +883,10 @@ struct regmap_irq_chip { int num_type_reg; unsigned int type_reg_stride; + + int (*handle_pre_irq)(void *irq_drv_data); + int (*handle_post_irq)(void *irq_drv_data); + void *irq_drv_data; }; struct regmap_irq_chip_data; -- cgit v1.2.3 From 351a4dedb34cbeb9f747f0e2309e891b6fb906cb Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 2 Jun 2016 10:23:29 +0300 Subject: qed: Utilize FW 8.10.3.0 The New QED firmware contains several fixes, including: - Wrong classification of packets in 4-port devices. - Anti-spoof interoperability with encapsulated packets. - Tx-switching of encapsulated packets. It also slightly improves Tx performance of the device. In addition, this firmware contains the necessary logic for supporting iscsi & rdma, for which we plan on pushing protocol drivers in the imminent future. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 68 +- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 7962 +++++++++----------- drivers/net/ethernet/qlogic/qed/qed_hw.c | 6 +- .../net/ethernet/qlogic/qed/qed_init_fw_funcs.c | 184 +- drivers/net/ethernet/qlogic/qed/qed_init_ops.c | 9 +- drivers/net/ethernet/qlogic/qed/qed_l2.c | 108 +- drivers/net/ethernet/qlogic/qed/qed_main.c | 22 +- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 44 +- drivers/net/ethernet/qlogic/qed/qed_mcp.h | 3 + drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 8 +- drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 4 +- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 20 +- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 2 + drivers/net/ethernet/qlogic/qede/qede_main.c | 16 +- include/linux/qed/common_hsi.h | 205 +- include/linux/qed/eth_common.h | 124 +- include/linux/qed/qed_eth_if.h | 1 + 17 files changed, 4129 insertions(+), 4657 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 2d89e8c16b32..e9ce6a7bc63b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -244,6 +244,7 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable) qm_info->qm_pq_params[curr_queue].tc_id = p_hwfn->hw_info.non_offload_tc; qm_info->qm_pq_params[curr_queue].wrr_group = 1; + qm_info->qm_pq_params[curr_queue].rl_valid = 1; curr_queue++; } @@ -256,7 +257,10 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable) for (i = 0; i < num_ports; i++) { p_qm_port = &qm_info->qm_port_params[i]; p_qm_port->active = 1; - p_qm_port->num_active_phys_tcs = 4; + if (num_ports == 4) + p_qm_port->active_phys_tcs = 0x7; + else + p_qm_port->active_phys_tcs = 0x9f; p_qm_port->num_pbf_cmd_lines = PBF_MAX_CMD_LINES / num_ports; p_qm_port->num_btb_blocks = BTB_MAX_BLOCKS / num_ports; } @@ -703,8 +707,31 @@ static int qed_hw_init_port(struct qed_hwfn *p_hwfn, { int rc = 0; - rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, - hw_mode); + rc = qed_init_run(p_hwfn, p_ptt, PHASE_PORT, p_hwfn->port_id, hw_mode); + if (rc != 0) + return rc; + + if (hw_mode & (1 << MODE_MF_SI)) { + u8 pf_id = 0; + + if (!qed_hw_init_first_eth(p_hwfn, p_ptt, &pf_id)) { + DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, + "PF[%08x] is first eth on engine\n", pf_id); + + /* We should have configured BIT for ppfid, i.e., the + * relative function number in the port. But there's a + * bug in LLH in BB where the ppfid is actually engine + * based, so we need to take this into account. + */ + qed_wr(p_hwfn, p_ptt, + NIG_REG_LLH_TAGMAC_DEF_PF_VECTOR, 1 << pf_id); + } + + /* Take the protocol-based hit vector if there is a hit, + * otherwise take the other vector. + */ + qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_CLS_TYPE_DUALMODE, 0x2); + } return rc; } @@ -773,6 +800,21 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, /* Pure runtime initializations - directly to the HW */ qed_int_igu_init_pure_rt(p_hwfn, p_ptt, true, true); + if (hw_mode & (1 << MODE_MF_SI)) { + u8 pf_id = 0; + u32 val; + + if (!qed_hw_init_first_eth(p_hwfn, p_ptt, &pf_id)) { + if (p_hwfn->rel_pf_id == pf_id) { + DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, + "PF[%d] is first ETH on engine\n", + pf_id); + val = 1; + } + qed_wr(p_hwfn, p_ptt, PRS_REG_MSG_INFO, val); + } + } + if (b_hw_start) { /* enable interrupts */ qed_int_igu_enable(p_hwfn, p_ptt, int_mode); @@ -1304,31 +1346,31 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, switch ((core_cfg & NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK) >> NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET) { - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X40G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_2X40G: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X40G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X50G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X50G: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X50G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X100G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_1X100G: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X100G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X10G_F: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X10G_F: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X10G_F; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X10G_E: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X10G_E: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X10G_E; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X20G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X20G: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_4X20G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X40G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X40G: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X40G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X25G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X25G: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_2X25G; break; - case NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X25G: + case NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X25G: p_hwfn->hw_info.port_mode = QED_PORT_MODE_DE_1X25G; break; default: @@ -1373,7 +1415,7 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, case NVM_CFG1_PORT_DRV_LINK_SPEED_50G: link->speed.forced_speed = 50000; break; - case NVM_CFG1_PORT_DRV_LINK_SPEED_100G: + case NVM_CFG1_PORT_DRV_LINK_SPEED_BB_100G: link->speed.forced_speed = 100000; break; default: diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 9afc15fdbb02..d104ca790977 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -21,9 +21,6 @@ struct qed_hwfn; struct qed_ptt; -/********************************/ -/* Add include to common target */ -/********************************/ /* opcodes for the event ring */ enum common_event_opcode { @@ -32,9 +29,10 @@ enum common_event_opcode { COMMON_EVENT_VF_START, COMMON_EVENT_VF_STOP, COMMON_EVENT_VF_PF_CHANNEL, - COMMON_EVENT_RESERVED4, - COMMON_EVENT_RESERVED5, - COMMON_EVENT_RESERVED6, + COMMON_EVENT_VF_FLR, + COMMON_EVENT_PF_UPDATE, + COMMON_EVENT_MALICIOUS_VF, + COMMON_EVENT_RL_UPDATE, COMMON_EVENT_EMPTY, MAX_COMMON_EVENT_OPCODE }; @@ -42,11 +40,12 @@ enum common_event_opcode { /* Common Ramrod Command IDs */ enum common_ramrod_cmd_id { COMMON_RAMROD_UNUSED, - COMMON_RAMROD_PF_START /* PF Function Start Ramrod */, - COMMON_RAMROD_PF_STOP /* PF Function Stop Ramrod */, + COMMON_RAMROD_PF_START, + COMMON_RAMROD_PF_STOP, COMMON_RAMROD_VF_START, COMMON_RAMROD_VF_STOP, COMMON_RAMROD_PF_UPDATE, + COMMON_RAMROD_RL_UPDATE, COMMON_RAMROD_EMPTY, MAX_COMMON_RAMROD_CMD_ID }; @@ -63,448 +62,448 @@ struct pstorm_core_conn_st_ctx { /* Core Slowpath Connection storm context of Xstorm */ struct xstorm_core_conn_st_ctx { - __le32 spq_base_lo /* SPQ Ring Base Address low dword */; - __le32 spq_base_hi /* SPQ Ring Base Address high dword */; - struct regpair consolid_base_addr; - __le16 spq_cons /* SPQ Ring Consumer */; - __le16 consolid_cons /* Consolidation Ring Consumer */; - __le32 reserved0[55] /* Pad to 15 cycles */; + __le32 spq_base_lo; + __le32 spq_base_hi; + struct regpair consolid_base_addr; + __le16 spq_cons; + __le16 consolid_cons; + __le32 reserved0[55]; }; struct xstorm_core_conn_ag_ctx { - u8 reserved0 /* cdu_validation */; - u8 core_state /* state */; - u8 flags0; -#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 -#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED1_MASK 0x1 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED1_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED2_MASK 0x1 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED2_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 -#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED3_MASK 0x1 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED3_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED4_MASK 0x1 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED4_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED5_MASK 0x1 /* bit6 */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED5_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED6_MASK 0x1 /* bit7 */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED6_SHIFT 7 + u8 reserved0; + u8 core_state; + u8 flags0; +#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED1_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED1_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED2_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED3_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED4_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED4_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED5_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED5_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED6_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED6_SHIFT 7 u8 flags1; -#define XSTORM_CORE_CONN_AG_CTX_RESERVED7_MASK 0x1 /* bit8 */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED7_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED8_MASK 0x1 /* bit9 */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED8_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED9_MASK 0x1 /* bit10 */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED9_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_BIT11_MASK 0x1 /* bit11 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT11_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_BIT12_MASK 0x1 /* bit12 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT12_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_BIT13_MASK 0x1 /* bit13 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT13_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_TX_RULE_ACTIVE_MASK 0x1 /* bit14 */ -#define XSTORM_CORE_CONN_AG_CTX_TX_RULE_ACTIVE_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE_MASK 0x1 /* bit15 */ -#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT 7 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED7_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED7_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED8_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED8_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED9_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED9_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_TX_RULE_ACTIVE_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_TX_RULE_ACTIVE_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT 7 u8 flags2; -#define XSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ -#define XSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ -#define XSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ -#define XSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 -#define XSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 6 u8 flags3; -#define XSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ -#define XSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ -#define XSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ -#define XSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ -#define XSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 6 u8 flags4; -#define XSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ -#define XSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ -#define XSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ -#define XSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_CF11_MASK 0x3 /* cf11 */ -#define XSTORM_CORE_CONN_AG_CTX_CF11_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF11_SHIFT 6 u8 flags5; -#define XSTORM_CORE_CONN_AG_CTX_CF12_MASK 0x3 /* cf12 */ -#define XSTORM_CORE_CONN_AG_CTX_CF12_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_CF13_MASK 0x3 /* cf13 */ -#define XSTORM_CORE_CONN_AG_CTX_CF13_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_CF14_MASK 0x3 /* cf14 */ -#define XSTORM_CORE_CONN_AG_CTX_CF14_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_CF15_MASK 0x3 /* cf15 */ -#define XSTORM_CORE_CONN_AG_CTX_CF15_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF14_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF14_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF15_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF15_SHIFT 6 u8 flags6; -#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_MASK 0x3 /* cf16 */ -#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_CF17_MASK 0x3 -#define XSTORM_CORE_CONN_AG_CTX_CF17_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_MASK 0x3 /* cf18 */ -#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_MASK 0x3 /* cf19 */ -#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF17_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF17_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_SHIFT 6 u8 flags7; -#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 /* cf20 */ -#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED10_MASK 0x3 /* cf21 */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED10_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_MASK 0x3 /* cf22 */ -#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ -#define XSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ -#define XSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 7 +#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED10_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED10_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 7 u8 flags8; -#define XSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ -#define XSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ -#define XSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ -#define XSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ -#define XSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ -#define XSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ -#define XSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ -#define XSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ -#define XSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 7 +#define XSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 7 u8 flags9; -#define XSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ -#define XSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_CF11EN_MASK 0x1 /* cf11en */ -#define XSTORM_CORE_CONN_AG_CTX_CF11EN_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_CF12EN_MASK 0x1 /* cf12en */ -#define XSTORM_CORE_CONN_AG_CTX_CF12EN_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_CF13EN_MASK 0x1 /* cf13en */ -#define XSTORM_CORE_CONN_AG_CTX_CF13EN_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_CF14EN_MASK 0x1 /* cf14en */ -#define XSTORM_CORE_CONN_AG_CTX_CF14EN_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_CF15EN_MASK 0x1 /* cf15en */ -#define XSTORM_CORE_CONN_AG_CTX_CF15EN_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN_MASK 0x1 /* cf16en */ -#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_CF17EN_MASK 0x1 -#define XSTORM_CORE_CONN_AG_CTX_CF17EN_SHIFT 7 +#define XSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_CF14EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF14EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF15EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_CF17EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF17EN_SHIFT 7 u8 flags10; -#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN_MASK 0x1 /* cf18en */ -#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_EN_MASK 0x1 /* cf19en */ -#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_EN_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 /* cf20en */ -#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED11_MASK 0x1 /* cf21en */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED11_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 /* cf22en */ -#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_CF23EN_MASK 0x1 /* cf23en */ -#define XSTORM_CORE_CONN_AG_CTX_CF23EN_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED12_MASK 0x1 /* rule0en */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED12_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED13_MASK 0x1 /* rule1en */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED13_SHIFT 7 +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_TERMINATE_CF_EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED11_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED11_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_CF23EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_CF23EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED12_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED12_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED13_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED13_SHIFT 7 u8 flags11; -#define XSTORM_CORE_CONN_AG_CTX_RESERVED14_MASK 0x1 /* rule2en */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED14_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_RESERVED15_MASK 0x1 /* rule3en */ -#define XSTORM_CORE_CONN_AG_CTX_RESERVED15_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_TX_DEC_RULE_EN_MASK 0x1 /* rule4en */ -#define XSTORM_CORE_CONN_AG_CTX_TX_DEC_RULE_EN_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 /* rule8en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_RULE9EN_MASK 0x1 /* rule9en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE9EN_SHIFT 7 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED14_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED14_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED15_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RESERVED15_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_TX_DEC_RULE_EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_TX_DEC_RULE_EN_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE9EN_SHIFT 7 u8 flags12; -#define XSTORM_CORE_CONN_AG_CTX_RULE10EN_MASK 0x1 /* rule10en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE10EN_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_RULE11EN_MASK 0x1 /* rule11en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE11EN_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 /* rule12en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 /* rule13en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_RULE14EN_MASK 0x1 /* rule14en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE14EN_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_RULE15EN_MASK 0x1 /* rule15en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE15EN_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_RULE16EN_MASK 0x1 /* rule16en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE16EN_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_RULE17EN_MASK 0x1 /* rule17en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE17EN_SHIFT 7 +#define XSTORM_CORE_CONN_AG_CTX_RULE10EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE10EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RULE11EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_RULE14EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE14EN_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_RULE16EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_RULE17EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE17EN_SHIFT 7 u8 flags13; -#define XSTORM_CORE_CONN_AG_CTX_RULE18EN_MASK 0x1 /* rule18en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE18EN_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_RULE19EN_MASK 0x1 /* rule19en */ -#define XSTORM_CORE_CONN_AG_CTX_RULE19EN_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 /* rule20en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 /* rule21en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 /* rule22en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 /* rule23en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 /* rule24en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 /* rule25en */ -#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 +#define XSTORM_CORE_CONN_AG_CTX_RULE18EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE18EN_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_RULE19EN_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_RULE19EN_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 u8 flags14; -#define XSTORM_CORE_CONN_AG_CTX_BIT16_MASK 0x1 /* bit16 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT16_SHIFT 0 -#define XSTORM_CORE_CONN_AG_CTX_BIT17_MASK 0x1 /* bit17 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT17_SHIFT 1 -#define XSTORM_CORE_CONN_AG_CTX_BIT18_MASK 0x1 /* bit18 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT18_SHIFT 2 -#define XSTORM_CORE_CONN_AG_CTX_BIT19_MASK 0x1 /* bit19 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT19_SHIFT 3 -#define XSTORM_CORE_CONN_AG_CTX_BIT20_MASK 0x1 /* bit20 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT20_SHIFT 4 -#define XSTORM_CORE_CONN_AG_CTX_BIT21_MASK 0x1 /* bit21 */ -#define XSTORM_CORE_CONN_AG_CTX_BIT21_SHIFT 5 -#define XSTORM_CORE_CONN_AG_CTX_CF23_MASK 0x3 /* cf23 */ -#define XSTORM_CORE_CONN_AG_CTX_CF23_SHIFT 6 - u8 byte2 /* byte2 */; - __le16 physical_q0 /* physical_q0 */; - __le16 consolid_prod /* physical_q1 */; - __le16 reserved16 /* physical_q2 */; - __le16 tx_bd_cons /* word3 */; - __le16 tx_bd_or_spq_prod /* word4 */; - __le16 word5 /* word5 */; - __le16 conn_dpi /* conn_dpi */; - u8 byte3 /* byte3 */; - u8 byte4 /* byte4 */; - u8 byte5 /* byte5 */; - u8 byte6 /* byte6 */; - __le32 reg0 /* reg0 */; - __le32 reg1 /* reg1 */; - __le32 reg2 /* reg2 */; - __le32 reg3 /* reg3 */; - __le32 reg4 /* reg4 */; - __le32 reg5 /* cf_array0 */; - __le32 reg6 /* cf_array1 */; - __le16 word7 /* word7 */; - __le16 word8 /* word8 */; - __le16 word9 /* word9 */; - __le16 word10 /* word10 */; - __le32 reg7 /* reg7 */; - __le32 reg8 /* reg8 */; - __le32 reg9 /* reg9 */; - u8 byte7 /* byte7 */; - u8 byte8 /* byte8 */; - u8 byte9 /* byte9 */; - u8 byte10 /* byte10 */; - u8 byte11 /* byte11 */; - u8 byte12 /* byte12 */; - u8 byte13 /* byte13 */; - u8 byte14 /* byte14 */; - u8 byte15 /* byte15 */; - u8 byte16 /* byte16 */; - __le16 word11 /* word11 */; - __le32 reg10 /* reg10 */; - __le32 reg11 /* reg11 */; - __le32 reg12 /* reg12 */; - __le32 reg13 /* reg13 */; - __le32 reg14 /* reg14 */; - __le32 reg15 /* reg15 */; - __le32 reg16 /* reg16 */; - __le32 reg17 /* reg17 */; - __le32 reg18 /* reg18 */; - __le32 reg19 /* reg19 */; - __le16 word12 /* word12 */; - __le16 word13 /* word13 */; - __le16 word14 /* word14 */; - __le16 word15 /* word15 */; +#define XSTORM_CORE_CONN_AG_CTX_BIT16_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT16_SHIFT 0 +#define XSTORM_CORE_CONN_AG_CTX_BIT17_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT17_SHIFT 1 +#define XSTORM_CORE_CONN_AG_CTX_BIT18_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT18_SHIFT 2 +#define XSTORM_CORE_CONN_AG_CTX_BIT19_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT19_SHIFT 3 +#define XSTORM_CORE_CONN_AG_CTX_BIT20_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT20_SHIFT 4 +#define XSTORM_CORE_CONN_AG_CTX_BIT21_MASK 0x1 +#define XSTORM_CORE_CONN_AG_CTX_BIT21_SHIFT 5 +#define XSTORM_CORE_CONN_AG_CTX_CF23_MASK 0x3 +#define XSTORM_CORE_CONN_AG_CTX_CF23_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 consolid_prod; + __le16 reserved16; + __le16 tx_bd_cons; + __le16 tx_bd_or_spq_prod; + __le16 word5; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le16 word7; + __le16 word8; + __le16 word9; + __le16 word10; + __le32 reg7; + __le32 reg8; + __le32 reg9; + u8 byte7; + u8 byte8; + u8 byte9; + u8 byte10; + u8 byte11; + u8 byte12; + u8 byte13; + u8 byte14; + u8 byte15; + u8 byte16; + __le16 word11; + __le32 reg10; + __le32 reg11; + __le32 reg12; + __le32 reg13; + __le32 reg14; + __le32 reg15; + __le32 reg16; + __le32 reg17; + __le32 reg18; + __le32 reg19; + __le16 word12; + __le16 word13; + __le16 word14; + __le16 word15; }; struct tstorm_core_conn_ag_ctx { - u8 byte0 /* cdu_validation */; - u8 byte1 /* state */; - u8 flags0; -#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ -#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ -#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK 0x1 /* bit2 */ -#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK 0x1 /* bit3 */ -#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK 0x1 /* bit4 */ -#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK 0x1 /* bit5 */ -#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ -#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 6 + u8 byte0; + u8 byte1; + u8 flags0; +#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 6 u8 flags1; -#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ -#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ -#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ -#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ -#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT 6 u8 flags2; -#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ -#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ -#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ -#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ -#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT 6 u8 flags3; -#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ -#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ -#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ -#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ -#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ -#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ -#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 7 +#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK 0x3 +#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 7 u8 flags4; -#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ -#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ -#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ -#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ -#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ -#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ -#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ -#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 +#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 u8 flags5; -#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 -#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 -#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 -#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 -#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 -#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 -#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 -#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ -#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 - __le32 reg0 /* reg0 */; - __le32 reg1 /* reg1 */; - __le32 reg2 /* reg2 */; - __le32 reg3 /* reg3 */; - __le32 reg4 /* reg4 */; - __le32 reg5 /* reg5 */; - __le32 reg6 /* reg6 */; - __le32 reg7 /* reg7 */; - __le32 reg8 /* reg8 */; - u8 byte2 /* byte2 */; - u8 byte3 /* byte3 */; - __le16 word0 /* word0 */; - u8 byte4 /* byte4 */; - u8 byte5 /* byte5 */; - __le16 word1 /* word1 */; - __le16 word2 /* conn_dpi */; - __le16 word3 /* word3 */; - __le32 reg9 /* reg9 */; - __le32 reg10 /* reg10 */; +#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 byte2; + u8 byte3; + __le16 word0; + u8 byte4; + u8 byte5; + __le16 word1; + __le16 word2; + __le16 word3; + __le32 reg9; + __le32 reg10; }; struct ustorm_core_conn_ag_ctx { - u8 reserved /* cdu_validation */; - u8 byte1 /* state */; - u8 flags0; -#define USTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ -#define USTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 -#define USTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ -#define USTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 -#define USTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ -#define USTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 -#define USTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ -#define USTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 -#define USTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ -#define USTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 reserved; + u8 byte1; + u8 flags0; +#define USTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define USTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define USTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define USTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define USTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 u8 flags1; -#define USTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ -#define USTORM_CORE_CONN_AG_CTX_CF3_SHIFT 0 -#define USTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ -#define USTORM_CORE_CONN_AG_CTX_CF4_SHIFT 2 -#define USTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ -#define USTORM_CORE_CONN_AG_CTX_CF5_SHIFT 4 -#define USTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ -#define USTORM_CORE_CONN_AG_CTX_CF6_SHIFT 6 +#define USTORM_CORE_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_CORE_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_CORE_CONN_AG_CTX_CF4_MASK 0x3 +#define USTORM_CORE_CONN_AG_CTX_CF4_SHIFT 2 +#define USTORM_CORE_CONN_AG_CTX_CF5_MASK 0x3 +#define USTORM_CORE_CONN_AG_CTX_CF5_SHIFT 4 +#define USTORM_CORE_CONN_AG_CTX_CF6_MASK 0x3 +#define USTORM_CORE_CONN_AG_CTX_CF6_SHIFT 6 u8 flags2; -#define USTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ -#define USTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 -#define USTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ -#define USTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 -#define USTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ -#define USTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 -#define USTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ -#define USTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 3 -#define USTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ -#define USTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 4 -#define USTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ -#define USTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 5 -#define USTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ -#define USTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 6 -#define USTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ -#define USTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 +#define USTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define USTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_CORE_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_CORE_CONN_AG_CTX_CF4EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT 4 +#define USTORM_CORE_CONN_AG_CTX_CF5EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT 5 +#define USTORM_CORE_CONN_AG_CTX_CF6EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7 u8 flags3; -#define USTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ -#define USTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 -#define USTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ -#define USTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 -#define USTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ -#define USTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 -#define USTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ -#define USTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 -#define USTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ -#define USTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 -#define USTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ -#define USTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 -#define USTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ -#define USTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 -#define USTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ -#define USTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 - u8 byte2 /* byte2 */; - u8 byte3 /* byte3 */; - __le16 word0 /* conn_dpi */; - __le16 word1 /* word1 */; - __le32 rx_producers /* reg0 */; - __le32 reg1 /* reg1 */; - __le32 reg2 /* reg2 */; - __le32 reg3 /* reg3 */; - __le16 word2 /* word2 */; - __le16 word3 /* word3 */; +#define USTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define USTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_CORE_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_CORE_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_CORE_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_CORE_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le16 word1; + __le32 rx_producers; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le16 word2; + __le16 word3; }; /* The core storm context for the Mstorm */ @@ -519,122 +518,186 @@ struct ustorm_core_conn_st_ctx { /* core connection context */ struct core_conn_context { - struct ystorm_core_conn_st_ctx ystorm_st_context; - struct regpair ystorm_st_padding[2] /* padding */; - struct pstorm_core_conn_st_ctx pstorm_st_context; - struct regpair pstorm_st_padding[2]; - struct xstorm_core_conn_st_ctx xstorm_st_context; - struct xstorm_core_conn_ag_ctx xstorm_ag_context; - struct tstorm_core_conn_ag_ctx tstorm_ag_context; - struct ustorm_core_conn_ag_ctx ustorm_ag_context; - struct mstorm_core_conn_st_ctx mstorm_st_context; - struct ustorm_core_conn_st_ctx ustorm_st_context; - struct regpair ustorm_st_padding[2] /* padding */; + struct ystorm_core_conn_st_ctx ystorm_st_context; + struct regpair ystorm_st_padding[2]; + struct pstorm_core_conn_st_ctx pstorm_st_context; + struct regpair pstorm_st_padding[2]; + struct xstorm_core_conn_st_ctx xstorm_st_context; + struct xstorm_core_conn_ag_ctx xstorm_ag_context; + struct tstorm_core_conn_ag_ctx tstorm_ag_context; + struct ustorm_core_conn_ag_ctx ustorm_ag_context; + struct mstorm_core_conn_st_ctx mstorm_st_context; + struct ustorm_core_conn_st_ctx ustorm_st_context; + struct regpair ustorm_st_padding[2]; +}; + +struct eth_mstorm_per_pf_stat { + struct regpair gre_discard_pkts; + struct regpair vxlan_discard_pkts; + struct regpair geneve_discard_pkts; + struct regpair lb_discard_pkts; }; struct eth_mstorm_per_queue_stat { - struct regpair ttl0_discard; - struct regpair packet_too_big_discard; - struct regpair no_buff_discard; - struct regpair not_active_discard; - struct regpair tpa_coalesced_pkts; - struct regpair tpa_coalesced_events; - struct regpair tpa_aborts_num; - struct regpair tpa_coalesced_bytes; + struct regpair ttl0_discard; + struct regpair packet_too_big_discard; + struct regpair no_buff_discard; + struct regpair not_active_discard; + struct regpair tpa_coalesced_pkts; + struct regpair tpa_coalesced_events; + struct regpair tpa_aborts_num; + struct regpair tpa_coalesced_bytes; +}; + +/* Ethernet TX Per PF */ +struct eth_pstorm_per_pf_stat { + struct regpair sent_lb_ucast_bytes; + struct regpair sent_lb_mcast_bytes; + struct regpair sent_lb_bcast_bytes; + struct regpair sent_lb_ucast_pkts; + struct regpair sent_lb_mcast_pkts; + struct regpair sent_lb_bcast_pkts; + struct regpair sent_gre_bytes; + struct regpair sent_vxlan_bytes; + struct regpair sent_geneve_bytes; + struct regpair sent_gre_pkts; + struct regpair sent_vxlan_pkts; + struct regpair sent_geneve_pkts; + struct regpair gre_drop_pkts; + struct regpair vxlan_drop_pkts; + struct regpair geneve_drop_pkts; +}; + +/* Ethernet TX Per Queue Stats */ +struct eth_pstorm_per_queue_stat { + struct regpair sent_ucast_bytes; + struct regpair sent_mcast_bytes; + struct regpair sent_bcast_bytes; + struct regpair sent_ucast_pkts; + struct regpair sent_mcast_pkts; + struct regpair sent_bcast_pkts; + struct regpair error_drop_pkts; +}; + +/* ETH Rx producers data */ +struct eth_rx_rate_limit { + __le16 mult; + __le16 cnst; + u8 add_sub_cnst; + u8 reserved0; + __le16 reserved1; }; -struct eth_pstorm_per_queue_stat { - struct regpair sent_ucast_bytes; - struct regpair sent_mcast_bytes; - struct regpair sent_bcast_bytes; - struct regpair sent_ucast_pkts; - struct regpair sent_mcast_pkts; - struct regpair sent_bcast_pkts; - struct regpair error_drop_pkts; +struct eth_ustorm_per_pf_stat { + struct regpair rcv_lb_ucast_bytes; + struct regpair rcv_lb_mcast_bytes; + struct regpair rcv_lb_bcast_bytes; + struct regpair rcv_lb_ucast_pkts; + struct regpair rcv_lb_mcast_pkts; + struct regpair rcv_lb_bcast_pkts; + struct regpair rcv_gre_bytes; + struct regpair rcv_vxlan_bytes; + struct regpair rcv_geneve_bytes; + struct regpair rcv_gre_pkts; + struct regpair rcv_vxlan_pkts; + struct regpair rcv_geneve_pkts; }; struct eth_ustorm_per_queue_stat { - struct regpair rcv_ucast_bytes; - struct regpair rcv_mcast_bytes; - struct regpair rcv_bcast_bytes; - struct regpair rcv_ucast_pkts; - struct regpair rcv_mcast_pkts; - struct regpair rcv_bcast_pkts; + struct regpair rcv_ucast_bytes; + struct regpair rcv_mcast_bytes; + struct regpair rcv_bcast_bytes; + struct regpair rcv_ucast_pkts; + struct regpair rcv_mcast_pkts; + struct regpair rcv_bcast_pkts; }; /* Event Ring Next Page Address */ struct event_ring_next_addr { - struct regpair addr /* Next Page Address */; - __le32 reserved[2] /* Reserved */; + struct regpair addr; + __le32 reserved[2]; }; +/* Event Ring Element */ union event_ring_element { - struct event_ring_entry entry /* Event Ring Entry */; - struct event_ring_next_addr next_addr; + struct event_ring_entry entry; + struct event_ring_next_addr next_addr; +}; + +/* Major and Minor hsi Versions */ +struct hsi_fp_ver_struct { + u8 minor_ver_arr[2]; + u8 major_ver_arr[2]; }; +/* Mstorm non-triggering VF zone */ struct mstorm_non_trigger_vf_zone { struct eth_mstorm_per_queue_stat eth_queue_stat; + struct eth_rx_prod_data eth_rx_queue_producers[ETH_MAX_NUM_RX_QUEUES_PER_VF]; }; +/* Mstorm VF zone */ struct mstorm_vf_zone { struct mstorm_non_trigger_vf_zone non_trigger; + }; +/* personality per PF */ enum personality_type { BAD_PERSONALITY_TYP, PERSONALITY_RESERVED, PERSONALITY_RESERVED2, - PERSONALITY_RDMA_AND_ETH /* Roce or Iwarp */, + PERSONALITY_RDMA_AND_ETH, PERSONALITY_RESERVED3, PERSONALITY_CORE, - PERSONALITY_ETH /* Ethernet */, + PERSONALITY_ETH, PERSONALITY_RESERVED4, MAX_PERSONALITY_TYPE }; +/* tunnel configuration */ struct pf_start_tunnel_config { - u8 set_vxlan_udp_port_flg; - u8 set_geneve_udp_port_flg; - u8 tx_enable_vxlan /* If set, enable VXLAN tunnel in TX path. */; - u8 tx_enable_l2geneve; - u8 tx_enable_ipgeneve; - u8 tx_enable_l2gre /* If set, enable l2 GRE tunnel in TX path. */; - u8 tx_enable_ipgre /* If set, enable IP GRE tunnel in TX path. */; - u8 tunnel_clss_vxlan /* Classification scheme for VXLAN tunnel. */; - u8 tunnel_clss_l2geneve; - u8 tunnel_clss_ipgeneve; - u8 tunnel_clss_l2gre; - u8 tunnel_clss_ipgre; - __le16 vxlan_udp_port /* VXLAN tunnel UDP destination port. */; - __le16 geneve_udp_port /* GENEVE tunnel UDP destination port. */; + u8 set_vxlan_udp_port_flg; + u8 set_geneve_udp_port_flg; + u8 tx_enable_vxlan; + u8 tx_enable_l2geneve; + u8 tx_enable_ipgeneve; + u8 tx_enable_l2gre; + u8 tx_enable_ipgre; + u8 tunnel_clss_vxlan; + u8 tunnel_clss_l2geneve; + u8 tunnel_clss_ipgeneve; + u8 tunnel_clss_l2gre; + u8 tunnel_clss_ipgre; + __le16 vxlan_udp_port; + __le16 geneve_udp_port; }; /* Ramrod data for PF start ramrod */ struct pf_start_ramrod_data { - struct regpair event_ring_pbl_addr; - struct regpair consolid_q_pbl_addr; - struct pf_start_tunnel_config tunnel_config; - __le16 event_ring_sb_id; - u8 base_vf_id; - u8 num_vfs; - u8 event_ring_num_pages; - u8 event_ring_sb_index; - u8 path_id; - u8 warning_as_error; - u8 dont_log_ramrods; - u8 personality; - __le16 log_type_mask; - u8 mf_mode /* Multi function mode */; - u8 integ_phase /* Integration phase */; - u8 allow_npar_tx_switching; - u8 inner_to_outer_pri_map[8]; - u8 pri_map_valid; - u32 outer_tag; - u8 reserved0[4]; -}; - -/* Data for port update ramrod */ + struct regpair event_ring_pbl_addr; + struct regpair consolid_q_pbl_addr; + struct pf_start_tunnel_config tunnel_config; + __le16 event_ring_sb_id; + u8 base_vf_id; + u8 num_vfs; + u8 event_ring_num_pages; + u8 event_ring_sb_index; + u8 path_id; + u8 warning_as_error; + u8 dont_log_ramrods; + u8 personality; + __le16 log_type_mask; + u8 mf_mode; + u8 integ_phase; + u8 allow_npar_tx_switching; + u8 inner_to_outer_pri_map[8]; + u8 pri_map_valid; + __le32 outer_tag; + struct hsi_fp_ver_struct hsi_fp_ver; + +}; + struct protocol_dcb_data { u8 dcb_enable_flag; u8 dcb_priority; @@ -642,25 +705,24 @@ struct protocol_dcb_data { u8 reserved; }; -/* tunnel configuration */ struct pf_update_tunnel_config { - u8 update_rx_pf_clss; - u8 update_tx_pf_clss; - u8 set_vxlan_udp_port_flg; - u8 set_geneve_udp_port_flg; - u8 tx_enable_vxlan; - u8 tx_enable_l2geneve; - u8 tx_enable_ipgeneve; - u8 tx_enable_l2gre; - u8 tx_enable_ipgre; - u8 tunnel_clss_vxlan; - u8 tunnel_clss_l2geneve; - u8 tunnel_clss_ipgeneve; - u8 tunnel_clss_l2gre; - u8 tunnel_clss_ipgre; - __le16 vxlan_udp_port; - __le16 geneve_udp_port; - __le16 reserved[3]; + u8 update_rx_pf_clss; + u8 update_tx_pf_clss; + u8 set_vxlan_udp_port_flg; + u8 set_geneve_udp_port_flg; + u8 tx_enable_vxlan; + u8 tx_enable_l2geneve; + u8 tx_enable_ipgeneve; + u8 tx_enable_l2gre; + u8 tx_enable_ipgre; + u8 tunnel_clss_vxlan; + u8 tunnel_clss_l2geneve; + u8 tunnel_clss_ipgeneve; + u8 tunnel_clss_l2gre; + u8 tunnel_clss_ipgre; + __le16 vxlan_udp_port; + __le16 geneve_udp_port; + __le16 reserved[3]; }; struct pf_update_ramrod_data { @@ -669,38 +731,43 @@ struct pf_update_ramrod_data { u8 update_fcoe_dcb_data_flag; u8 update_iscsi_dcb_data_flag; u8 update_roce_dcb_data_flag; + u8 update_iwarp_dcb_data_flag; u8 update_mf_vlan_flag; - __le16 mf_vlan; + u8 reserved; struct protocol_dcb_data eth_dcb_data; struct protocol_dcb_data fcoe_dcb_data; struct protocol_dcb_data iscsi_dcb_data; struct protocol_dcb_data roce_dcb_data; - struct pf_update_tunnel_config tunnel_config; -}; - -/* Tunnel classification scheme */ -enum tunnel_clss { - TUNNEL_CLSS_MAC_VLAN = 0, - TUNNEL_CLSS_MAC_VNI, - TUNNEL_CLSS_INNER_MAC_VLAN, - TUNNEL_CLSS_INNER_MAC_VNI, - MAX_TUNNEL_CLSS + struct protocol_dcb_data iwarp_dcb_data; + __le16 mf_vlan; + __le16 reserved2; + struct pf_update_tunnel_config tunnel_config; }; +/* Ports mode */ enum ports_mode { - ENGX2_PORTX1 /* 2 engines x 1 port */, - ENGX2_PORTX2 /* 2 engines x 2 ports */, - ENGX1_PORTX1 /* 1 engine x 1 port */, - ENGX1_PORTX2 /* 1 engine x 2 ports */, - ENGX1_PORTX4 /* 1 engine x 4 ports */, + ENGX2_PORTX1, + ENGX2_PORTX2, + ENGX1_PORTX1, + ENGX1_PORTX2, + ENGX1_PORTX4, MAX_PORTS_MODE }; +/* use to index in hsi_fp_[major|minor]_ver_arr per protocol */ +enum protocol_version_array_key { + ETH_VER_KEY = 0, + ROCE_VER_KEY, + MAX_PROTOCOL_VERSION_ARRAY_KEY +}; + +/* Pstorm non-triggering VF zone */ struct pstorm_non_trigger_vf_zone { struct eth_pstorm_per_queue_stat eth_queue_stat; struct regpair reserved[2]; }; +/* Pstorm VF zone */ struct pstorm_vf_zone { struct pstorm_non_trigger_vf_zone non_trigger; struct regpair reserved[7]; @@ -708,56 +775,89 @@ struct pstorm_vf_zone { /* Ramrod Header of SPQE */ struct ramrod_header { - __le32 cid /* Slowpath Connection CID */; - u8 cmd_id /* Ramrod Cmd (Per Protocol Type) */; - u8 protocol_id /* Ramrod Protocol ID */; - __le16 echo /* Ramrod echo */; + __le32 cid; + u8 cmd_id; + u8 protocol_id; + __le16 echo; }; /* Slowpath Element (SPQE) */ struct slow_path_element { - struct ramrod_header hdr /* Ramrod Header */; - struct regpair data_ptr; + struct ramrod_header hdr; + struct regpair data_ptr; +}; + +/* Tstorm non-triggering VF zone */ +struct tstorm_non_trigger_vf_zone { + struct regpair reserved[2]; }; struct tstorm_per_port_stat { - struct regpair trunc_error_discard; - struct regpair mac_error_discard; - struct regpair mftag_filter_discard; - struct regpair eth_mac_filter_discard; - struct regpair ll2_mac_filter_discard; - struct regpair ll2_conn_disabled_discard; - struct regpair iscsi_irregular_pkt; - struct regpair fcoe_irregular_pkt; - struct regpair roce_irregular_pkt; - struct regpair eth_irregular_pkt; - struct regpair toe_irregular_pkt; - struct regpair preroce_irregular_pkt; + struct regpair trunc_error_discard; + struct regpair mac_error_discard; + struct regpair mftag_filter_discard; + struct regpair eth_mac_filter_discard; + struct regpair reserved[5]; + struct regpair eth_irregular_pkt; + struct regpair reserved1[2]; + struct regpair eth_gre_tunn_filter_discard; + struct regpair eth_vxlan_tunn_filter_discard; + struct regpair eth_geneve_tunn_filter_discard; }; +/* Tstorm VF zone */ +struct tstorm_vf_zone { + struct tstorm_non_trigger_vf_zone non_trigger; +}; + +/* Tunnel classification scheme */ +enum tunnel_clss { + TUNNEL_CLSS_MAC_VLAN = 0, + TUNNEL_CLSS_MAC_VNI, + TUNNEL_CLSS_INNER_MAC_VLAN, + TUNNEL_CLSS_INNER_MAC_VNI, + TUNNEL_CLSS_MAC_VLAN_DUAL_STAGE, + MAX_TUNNEL_CLSS +}; + +/* Ustorm non-triggering VF zone */ struct ustorm_non_trigger_vf_zone { struct eth_ustorm_per_queue_stat eth_queue_stat; struct regpair vf_pf_msg_addr; }; +/* Ustorm triggering VF zone */ struct ustorm_trigger_vf_zone { u8 vf_pf_msg_valid; u8 reserved[7]; }; +/* Ustorm VF zone */ struct ustorm_vf_zone { struct ustorm_non_trigger_vf_zone non_trigger; struct ustorm_trigger_vf_zone trigger; }; +/* VF-PF channel data */ +struct vf_pf_channel_data { + __le32 ready; + u8 valid; + u8 reserved0; + __le16 reserved1; +}; + +/* Ramrod data for VF start ramrod */ struct vf_start_ramrod_data { u8 vf_id; u8 enable_flr_ack; __le16 opaque_fid; u8 personality; - u8 reserved[3]; + u8 reserved[7]; + struct hsi_fp_ver_struct hsi_fp_ver; + }; +/* Ramrod data for VF start ramrod */ struct vf_stop_ramrod_data { u8 vf_id; u8 reserved0; @@ -765,94 +865,474 @@ struct vf_stop_ramrod_data { __le32 reserved2; }; +/* Attentions status block */ struct atten_status_block { - __le32 atten_bits; - __le32 atten_ack; - __le16 reserved0; - __le16 sb_index /* status block running index */; - __le32 reserved1; + __le32 atten_bits; + __le32 atten_ack; + __le16 reserved0; + __le16 sb_index; + __le32 reserved1; +}; + +enum command_type_bit { + IGU_COMMAND_TYPE_NOP = 0, + IGU_COMMAND_TYPE_SET = 1, + MAX_COMMAND_TYPE_BIT +}; + +/* DMAE command */ +struct dmae_cmd { + __le32 opcode; +#define DMAE_CMD_SRC_MASK 0x1 +#define DMAE_CMD_SRC_SHIFT 0 +#define DMAE_CMD_DST_MASK 0x3 +#define DMAE_CMD_DST_SHIFT 1 +#define DMAE_CMD_C_DST_MASK 0x1 +#define DMAE_CMD_C_DST_SHIFT 3 +#define DMAE_CMD_CRC_RESET_MASK 0x1 +#define DMAE_CMD_CRC_RESET_SHIFT 4 +#define DMAE_CMD_SRC_ADDR_RESET_MASK 0x1 +#define DMAE_CMD_SRC_ADDR_RESET_SHIFT 5 +#define DMAE_CMD_DST_ADDR_RESET_MASK 0x1 +#define DMAE_CMD_DST_ADDR_RESET_SHIFT 6 +#define DMAE_CMD_COMP_FUNC_MASK 0x1 +#define DMAE_CMD_COMP_FUNC_SHIFT 7 +#define DMAE_CMD_COMP_WORD_EN_MASK 0x1 +#define DMAE_CMD_COMP_WORD_EN_SHIFT 8 +#define DMAE_CMD_COMP_CRC_EN_MASK 0x1 +#define DMAE_CMD_COMP_CRC_EN_SHIFT 9 +#define DMAE_CMD_COMP_CRC_OFFSET_MASK 0x7 +#define DMAE_CMD_COMP_CRC_OFFSET_SHIFT 10 +#define DMAE_CMD_RESERVED1_MASK 0x1 +#define DMAE_CMD_RESERVED1_SHIFT 13 +#define DMAE_CMD_ENDIANITY_MODE_MASK 0x3 +#define DMAE_CMD_ENDIANITY_MODE_SHIFT 14 +#define DMAE_CMD_ERR_HANDLING_MASK 0x3 +#define DMAE_CMD_ERR_HANDLING_SHIFT 16 +#define DMAE_CMD_PORT_ID_MASK 0x3 +#define DMAE_CMD_PORT_ID_SHIFT 18 +#define DMAE_CMD_SRC_PF_ID_MASK 0xF +#define DMAE_CMD_SRC_PF_ID_SHIFT 20 +#define DMAE_CMD_DST_PF_ID_MASK 0xF +#define DMAE_CMD_DST_PF_ID_SHIFT 24 +#define DMAE_CMD_SRC_VF_ID_VALID_MASK 0x1 +#define DMAE_CMD_SRC_VF_ID_VALID_SHIFT 28 +#define DMAE_CMD_DST_VF_ID_VALID_MASK 0x1 +#define DMAE_CMD_DST_VF_ID_VALID_SHIFT 29 +#define DMAE_CMD_RESERVED2_MASK 0x3 +#define DMAE_CMD_RESERVED2_SHIFT 30 + __le32 src_addr_lo; + __le32 src_addr_hi; + __le32 dst_addr_lo; + __le32 dst_addr_hi; + __le16 length_dw; + __le16 opcode_b; +#define DMAE_CMD_SRC_VF_ID_MASK 0xFF +#define DMAE_CMD_SRC_VF_ID_SHIFT 0 +#define DMAE_CMD_DST_VF_ID_MASK 0xFF +#define DMAE_CMD_DST_VF_ID_SHIFT 8 + __le32 comp_addr_lo; + __le32 comp_addr_hi; + __le32 comp_val; + __le32 crc32; + __le32 crc_32_c; + __le16 crc16; + __le16 crc16_c; + __le16 crc10; + __le16 reserved; + __le16 xsum16; + __le16 xsum8; +}; + +enum dmae_cmd_comp_crc_en_enum { + dmae_cmd_comp_crc_disabled, + dmae_cmd_comp_crc_enabled, + MAX_DMAE_CMD_COMP_CRC_EN_ENUM +}; + +enum dmae_cmd_comp_func_enum { + dmae_cmd_comp_func_to_src, + dmae_cmd_comp_func_to_dst, + MAX_DMAE_CMD_COMP_FUNC_ENUM +}; + +enum dmae_cmd_comp_word_en_enum { + dmae_cmd_comp_word_disabled, + dmae_cmd_comp_word_enabled, + MAX_DMAE_CMD_COMP_WORD_EN_ENUM +}; + +enum dmae_cmd_c_dst_enum { + dmae_cmd_c_dst_pcie, + dmae_cmd_c_dst_grc, + MAX_DMAE_CMD_C_DST_ENUM +}; + +enum dmae_cmd_dst_enum { + dmae_cmd_dst_none_0, + dmae_cmd_dst_pcie, + dmae_cmd_dst_grc, + dmae_cmd_dst_none_3, + MAX_DMAE_CMD_DST_ENUM +}; + +enum dmae_cmd_error_handling_enum { + dmae_cmd_error_handling_send_regular_comp, + dmae_cmd_error_handling_send_comp_with_err, + dmae_cmd_error_handling_dont_send_comp, + MAX_DMAE_CMD_ERROR_HANDLING_ENUM +}; + +enum dmae_cmd_src_enum { + dmae_cmd_src_pcie, + dmae_cmd_src_grc, + MAX_DMAE_CMD_SRC_ENUM +}; + +/* IGU cleanup command */ +struct igu_cleanup { + __le32 sb_id_and_flags; +#define IGU_CLEANUP_RESERVED0_MASK 0x7FFFFFF +#define IGU_CLEANUP_RESERVED0_SHIFT 0 +#define IGU_CLEANUP_CLEANUP_SET_MASK 0x1 +#define IGU_CLEANUP_CLEANUP_SET_SHIFT 27 +#define IGU_CLEANUP_CLEANUP_TYPE_MASK 0x7 +#define IGU_CLEANUP_CLEANUP_TYPE_SHIFT 28 +#define IGU_CLEANUP_COMMAND_TYPE_MASK 0x1 +#define IGU_CLEANUP_COMMAND_TYPE_SHIFT 31 + __le32 reserved1; +}; + +/* IGU firmware driver command */ +union igu_command { + struct igu_prod_cons_update prod_cons_update; + struct igu_cleanup cleanup; +}; + +/* IGU firmware driver command */ +struct igu_command_reg_ctrl { + __le16 opaque_fid; + __le16 igu_command_reg_ctrl_fields; +#define IGU_COMMAND_REG_CTRL_PXP_BAR_ADDR_MASK 0xFFF +#define IGU_COMMAND_REG_CTRL_PXP_BAR_ADDR_SHIFT 0 +#define IGU_COMMAND_REG_CTRL_RESERVED_MASK 0x7 +#define IGU_COMMAND_REG_CTRL_RESERVED_SHIFT 12 +#define IGU_COMMAND_REG_CTRL_COMMAND_TYPE_MASK 0x1 +#define IGU_COMMAND_REG_CTRL_COMMAND_TYPE_SHIFT 15 +}; + +/* IGU mapping line structure */ +struct igu_mapping_line { + __le32 igu_mapping_line_fields; +#define IGU_MAPPING_LINE_VALID_MASK 0x1 +#define IGU_MAPPING_LINE_VALID_SHIFT 0 +#define IGU_MAPPING_LINE_VECTOR_NUMBER_MASK 0xFF +#define IGU_MAPPING_LINE_VECTOR_NUMBER_SHIFT 1 +#define IGU_MAPPING_LINE_FUNCTION_NUMBER_MASK 0xFF +#define IGU_MAPPING_LINE_FUNCTION_NUMBER_SHIFT 9 +#define IGU_MAPPING_LINE_PF_VALID_MASK 0x1 +#define IGU_MAPPING_LINE_PF_VALID_SHIFT 17 +#define IGU_MAPPING_LINE_IPS_GROUP_MASK 0x3F +#define IGU_MAPPING_LINE_IPS_GROUP_SHIFT 18 +#define IGU_MAPPING_LINE_RESERVED_MASK 0xFF +#define IGU_MAPPING_LINE_RESERVED_SHIFT 24 +}; + +/* IGU MSIX line structure */ +struct igu_msix_vector { + struct regpair address; + __le32 data; + __le32 msix_vector_fields; +#define IGU_MSIX_VECTOR_MASK_BIT_MASK 0x1 +#define IGU_MSIX_VECTOR_MASK_BIT_SHIFT 0 +#define IGU_MSIX_VECTOR_RESERVED0_MASK 0x7FFF +#define IGU_MSIX_VECTOR_RESERVED0_SHIFT 1 +#define IGU_MSIX_VECTOR_STEERING_TAG_MASK 0xFF +#define IGU_MSIX_VECTOR_STEERING_TAG_SHIFT 16 +#define IGU_MSIX_VECTOR_RESERVED1_MASK 0xFF +#define IGU_MSIX_VECTOR_RESERVED1_SHIFT 24 +}; + +struct mstorm_core_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; }; +/* per encapsulation type enabling flags */ +struct prs_reg_encapsulation_type_en { + u8 flags; +#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GRE_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GRE_ENABLE_SHIFT 0 +#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GRE_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GRE_ENABLE_SHIFT 1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_VXLAN_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_VXLAN_ENABLE_SHIFT 2 +#define PRS_REG_ENCAPSULATION_TYPE_EN_T_TAG_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_T_TAG_ENABLE_SHIFT 3 +#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GENEVE_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GENEVE_ENABLE_SHIFT 4 +#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GENEVE_ENABLE_MASK 0x1 +#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GENEVE_ENABLE_SHIFT 5 +#define PRS_REG_ENCAPSULATION_TYPE_EN_RESERVED_MASK 0x3 +#define PRS_REG_ENCAPSULATION_TYPE_EN_RESERVED_SHIFT 6 +}; + +enum pxp_tph_st_hint { + TPH_ST_HINT_BIDIR, + TPH_ST_HINT_REQUESTER, + TPH_ST_HINT_TARGET, + TPH_ST_HINT_TARGET_PRIO, + MAX_PXP_TPH_ST_HINT +}; + +/* QM hardware structure of enable bypass credit mask */ +struct qm_rf_bypass_mask { + u8 flags; +#define QM_RF_BYPASS_MASK_LINEVOQ_MASK 0x1 +#define QM_RF_BYPASS_MASK_LINEVOQ_SHIFT 0 +#define QM_RF_BYPASS_MASK_RESERVED0_MASK 0x1 +#define QM_RF_BYPASS_MASK_RESERVED0_SHIFT 1 +#define QM_RF_BYPASS_MASK_PFWFQ_MASK 0x1 +#define QM_RF_BYPASS_MASK_PFWFQ_SHIFT 2 +#define QM_RF_BYPASS_MASK_VPWFQ_MASK 0x1 +#define QM_RF_BYPASS_MASK_VPWFQ_SHIFT 3 +#define QM_RF_BYPASS_MASK_PFRL_MASK 0x1 +#define QM_RF_BYPASS_MASK_PFRL_SHIFT 4 +#define QM_RF_BYPASS_MASK_VPQCNRL_MASK 0x1 +#define QM_RF_BYPASS_MASK_VPQCNRL_SHIFT 5 +#define QM_RF_BYPASS_MASK_FWPAUSE_MASK 0x1 +#define QM_RF_BYPASS_MASK_FWPAUSE_SHIFT 6 +#define QM_RF_BYPASS_MASK_RESERVED1_MASK 0x1 +#define QM_RF_BYPASS_MASK_RESERVED1_SHIFT 7 +}; + +/* QM hardware structure of opportunistic credit mask */ +struct qm_rf_opportunistic_mask { + __le16 flags; +#define QM_RF_OPPORTUNISTIC_MASK_LINEVOQ_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_LINEVOQ_SHIFT 0 +#define QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ_SHIFT 1 +#define QM_RF_OPPORTUNISTIC_MASK_PFWFQ_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_PFWFQ_SHIFT 2 +#define QM_RF_OPPORTUNISTIC_MASK_VPWFQ_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_VPWFQ_SHIFT 3 +#define QM_RF_OPPORTUNISTIC_MASK_PFRL_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_PFRL_SHIFT 4 +#define QM_RF_OPPORTUNISTIC_MASK_VPQCNRL_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_VPQCNRL_SHIFT 5 +#define QM_RF_OPPORTUNISTIC_MASK_FWPAUSE_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_FWPAUSE_SHIFT 6 +#define QM_RF_OPPORTUNISTIC_MASK_RESERVED0_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_RESERVED0_SHIFT 7 +#define QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY_MASK 0x1 +#define QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY_SHIFT 8 +#define QM_RF_OPPORTUNISTIC_MASK_RESERVED1_MASK 0x7F +#define QM_RF_OPPORTUNISTIC_MASK_RESERVED1_SHIFT 9 +}; + +/* QM hardware structure of QM map memory */ +struct qm_rf_pq_map { + __le32 reg; +#define QM_RF_PQ_MAP_PQ_VALID_MASK 0x1 +#define QM_RF_PQ_MAP_PQ_VALID_SHIFT 0 +#define QM_RF_PQ_MAP_RL_ID_MASK 0xFF +#define QM_RF_PQ_MAP_RL_ID_SHIFT 1 +#define QM_RF_PQ_MAP_VP_PQ_ID_MASK 0x1FF +#define QM_RF_PQ_MAP_VP_PQ_ID_SHIFT 9 +#define QM_RF_PQ_MAP_VOQ_MASK 0x1F +#define QM_RF_PQ_MAP_VOQ_SHIFT 18 +#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_MASK 0x3 +#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_SHIFT 23 +#define QM_RF_PQ_MAP_RL_VALID_MASK 0x1 +#define QM_RF_PQ_MAP_RL_VALID_SHIFT 25 +#define QM_RF_PQ_MAP_RESERVED_MASK 0x3F +#define QM_RF_PQ_MAP_RESERVED_SHIFT 26 +}; + +/* Completion params for aggregated interrupt completion */ +struct sdm_agg_int_comp_params { + __le16 params; +#define SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_MASK 0x3F +#define SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_SHIFT 0 +#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_MASK 0x1 +#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_SHIFT 6 +#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_MASK 0x1FF +#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_SHIFT 7 +}; + +/* SDM operation gen command (generate aggregative interrupt) */ +struct sdm_op_gen { + __le32 command; +#define SDM_OP_GEN_COMP_PARAM_MASK 0xFFFF +#define SDM_OP_GEN_COMP_PARAM_SHIFT 0 +#define SDM_OP_GEN_COMP_TYPE_MASK 0xF +#define SDM_OP_GEN_COMP_TYPE_SHIFT 16 +#define SDM_OP_GEN_RESERVED_MASK 0xFFF +#define SDM_OP_GEN_RESERVED_SHIFT 20 +}; + +struct ystorm_core_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_CORE_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_CORE_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_CORE_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_CORE_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_CORE_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_CORE_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_CORE_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_CORE_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_CORE_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; + +/****************************************/ +/* Debug Tools HSI constants and macros */ +/****************************************/ + enum block_addr { - GRCBASE_GRC = 0x50000, - GRCBASE_MISCS = 0x9000, - GRCBASE_MISC = 0x8000, - GRCBASE_DBU = 0xa000, - GRCBASE_PGLUE_B = 0x2a8000, - GRCBASE_CNIG = 0x218000, - GRCBASE_CPMU = 0x30000, - GRCBASE_NCSI = 0x40000, - GRCBASE_OPTE = 0x53000, - GRCBASE_BMB = 0x540000, - GRCBASE_PCIE = 0x54000, - GRCBASE_MCP = 0xe00000, - GRCBASE_MCP2 = 0x52000, - GRCBASE_PSWHST = 0x2a0000, - GRCBASE_PSWHST2 = 0x29e000, - GRCBASE_PSWRD = 0x29c000, - GRCBASE_PSWRD2 = 0x29d000, - GRCBASE_PSWWR = 0x29a000, - GRCBASE_PSWWR2 = 0x29b000, - GRCBASE_PSWRQ = 0x280000, - GRCBASE_PSWRQ2 = 0x240000, - GRCBASE_PGLCS = 0x0, - GRCBASE_PTU = 0x560000, - GRCBASE_DMAE = 0xc000, - GRCBASE_TCM = 0x1180000, - GRCBASE_MCM = 0x1200000, - GRCBASE_UCM = 0x1280000, - GRCBASE_XCM = 0x1000000, - GRCBASE_YCM = 0x1080000, - GRCBASE_PCM = 0x1100000, - GRCBASE_QM = 0x2f0000, - GRCBASE_TM = 0x2c0000, - GRCBASE_DORQ = 0x100000, - GRCBASE_BRB = 0x340000, - GRCBASE_SRC = 0x238000, - GRCBASE_PRS = 0x1f0000, - GRCBASE_TSDM = 0xfb0000, - GRCBASE_MSDM = 0xfc0000, - GRCBASE_USDM = 0xfd0000, - GRCBASE_XSDM = 0xf80000, - GRCBASE_YSDM = 0xf90000, - GRCBASE_PSDM = 0xfa0000, - GRCBASE_TSEM = 0x1700000, - GRCBASE_MSEM = 0x1800000, - GRCBASE_USEM = 0x1900000, - GRCBASE_XSEM = 0x1400000, - GRCBASE_YSEM = 0x1500000, - GRCBASE_PSEM = 0x1600000, - GRCBASE_RSS = 0x238800, - GRCBASE_TMLD = 0x4d0000, - GRCBASE_MULD = 0x4e0000, - GRCBASE_YULD = 0x4c8000, - GRCBASE_XYLD = 0x4c0000, - GRCBASE_PRM = 0x230000, - GRCBASE_PBF_PB1 = 0xda0000, - GRCBASE_PBF_PB2 = 0xda4000, - GRCBASE_RPB = 0x23c000, - GRCBASE_BTB = 0xdb0000, - GRCBASE_PBF = 0xd80000, - GRCBASE_RDIF = 0x300000, - GRCBASE_TDIF = 0x310000, - GRCBASE_CDU = 0x580000, - GRCBASE_CCFC = 0x2e0000, - GRCBASE_TCFC = 0x2d0000, - GRCBASE_IGU = 0x180000, - GRCBASE_CAU = 0x1c0000, - GRCBASE_UMAC = 0x51000, - GRCBASE_XMAC = 0x210000, - GRCBASE_DBG = 0x10000, - GRCBASE_NIG = 0x500000, - GRCBASE_WOL = 0x600000, - GRCBASE_BMBN = 0x610000, - GRCBASE_IPC = 0x20000, - GRCBASE_NWM = 0x800000, - GRCBASE_NWS = 0x700000, - GRCBASE_MS = 0x6a0000, - GRCBASE_PHY_PCIE = 0x620000, - GRCBASE_MISC_AEU = 0x8000, - GRCBASE_BAR0_MAP = 0x1c00000, + GRCBASE_GRC = 0x50000, + GRCBASE_MISCS = 0x9000, + GRCBASE_MISC = 0x8000, + GRCBASE_DBU = 0xa000, + GRCBASE_PGLUE_B = 0x2a8000, + GRCBASE_CNIG = 0x218000, + GRCBASE_CPMU = 0x30000, + GRCBASE_NCSI = 0x40000, + GRCBASE_OPTE = 0x53000, + GRCBASE_BMB = 0x540000, + GRCBASE_PCIE = 0x54000, + GRCBASE_MCP = 0xe00000, + GRCBASE_MCP2 = 0x52000, + GRCBASE_PSWHST = 0x2a0000, + GRCBASE_PSWHST2 = 0x29e000, + GRCBASE_PSWRD = 0x29c000, + GRCBASE_PSWRD2 = 0x29d000, + GRCBASE_PSWWR = 0x29a000, + GRCBASE_PSWWR2 = 0x29b000, + GRCBASE_PSWRQ = 0x280000, + GRCBASE_PSWRQ2 = 0x240000, + GRCBASE_PGLCS = 0x0, + GRCBASE_DMAE = 0xc000, + GRCBASE_PTU = 0x560000, + GRCBASE_TCM = 0x1180000, + GRCBASE_MCM = 0x1200000, + GRCBASE_UCM = 0x1280000, + GRCBASE_XCM = 0x1000000, + GRCBASE_YCM = 0x1080000, + GRCBASE_PCM = 0x1100000, + GRCBASE_QM = 0x2f0000, + GRCBASE_TM = 0x2c0000, + GRCBASE_DORQ = 0x100000, + GRCBASE_BRB = 0x340000, + GRCBASE_SRC = 0x238000, + GRCBASE_PRS = 0x1f0000, + GRCBASE_TSDM = 0xfb0000, + GRCBASE_MSDM = 0xfc0000, + GRCBASE_USDM = 0xfd0000, + GRCBASE_XSDM = 0xf80000, + GRCBASE_YSDM = 0xf90000, + GRCBASE_PSDM = 0xfa0000, + GRCBASE_TSEM = 0x1700000, + GRCBASE_MSEM = 0x1800000, + GRCBASE_USEM = 0x1900000, + GRCBASE_XSEM = 0x1400000, + GRCBASE_YSEM = 0x1500000, + GRCBASE_PSEM = 0x1600000, + GRCBASE_RSS = 0x238800, + GRCBASE_TMLD = 0x4d0000, + GRCBASE_MULD = 0x4e0000, + GRCBASE_YULD = 0x4c8000, + GRCBASE_XYLD = 0x4c0000, + GRCBASE_PRM = 0x230000, + GRCBASE_PBF_PB1 = 0xda0000, + GRCBASE_PBF_PB2 = 0xda4000, + GRCBASE_RPB = 0x23c000, + GRCBASE_BTB = 0xdb0000, + GRCBASE_PBF = 0xd80000, + GRCBASE_RDIF = 0x300000, + GRCBASE_TDIF = 0x310000, + GRCBASE_CDU = 0x580000, + GRCBASE_CCFC = 0x2e0000, + GRCBASE_TCFC = 0x2d0000, + GRCBASE_IGU = 0x180000, + GRCBASE_CAU = 0x1c0000, + GRCBASE_UMAC = 0x51000, + GRCBASE_XMAC = 0x210000, + GRCBASE_DBG = 0x10000, + GRCBASE_NIG = 0x500000, + GRCBASE_WOL = 0x600000, + GRCBASE_BMBN = 0x610000, + GRCBASE_IPC = 0x20000, + GRCBASE_NWM = 0x800000, + GRCBASE_NWS = 0x700000, + GRCBASE_MS = 0x6a0000, + GRCBASE_PHY_PCIE = 0x620000, + GRCBASE_LED = 0x6b8000, + GRCBASE_MISC_AEU = 0x8000, + GRCBASE_BAR0_MAP = 0x1c00000, MAX_BLOCK_ADDR }; @@ -879,8 +1359,8 @@ enum block_id { BLOCK_PSWRQ, BLOCK_PSWRQ2, BLOCK_PGLCS, - BLOCK_PTU, BLOCK_DMAE, + BLOCK_PTU, BLOCK_TCM, BLOCK_MCM, BLOCK_UCM, @@ -934,141 +1414,216 @@ enum block_id { BLOCK_NWS, BLOCK_MS, BLOCK_PHY_PCIE, + BLOCK_LED, BLOCK_MISC_AEU, BLOCK_BAR0_MAP, MAX_BLOCK_ID }; -enum command_type_bit { - IGU_COMMAND_TYPE_NOP = 0, - IGU_COMMAND_TYPE_SET = 1, - MAX_COMMAND_TYPE_BIT +/* binary debug buffer types */ +enum bin_dbg_buffer_type { + BIN_BUF_DBG_MODE_TREE, + BIN_BUF_DBG_DUMP_REG, + BIN_BUF_DBG_DUMP_MEM, + BIN_BUF_DBG_IDLE_CHK_REGS, + BIN_BUF_DBG_IDLE_CHK_IMMS, + BIN_BUF_DBG_IDLE_CHK_RULES, + BIN_BUF_DBG_IDLE_CHK_PARSING_DATA, + BIN_BUF_DBG_ATTN_BLOCKS, + BIN_BUF_DBG_ATTN_REGS, + BIN_BUF_DBG_ATTN_INDEXES, + BIN_BUF_DBG_ATTN_NAME_OFFSETS, + BIN_BUF_DBG_PARSING_STRINGS, + MAX_BIN_DBG_BUFFER_TYPE }; -struct dmae_cmd { - __le32 opcode; -#define DMAE_CMD_SRC_MASK 0x1 -#define DMAE_CMD_SRC_SHIFT 0 -#define DMAE_CMD_DST_MASK 0x3 -#define DMAE_CMD_DST_SHIFT 1 -#define DMAE_CMD_C_DST_MASK 0x1 -#define DMAE_CMD_C_DST_SHIFT 3 -#define DMAE_CMD_CRC_RESET_MASK 0x1 -#define DMAE_CMD_CRC_RESET_SHIFT 4 -#define DMAE_CMD_SRC_ADDR_RESET_MASK 0x1 -#define DMAE_CMD_SRC_ADDR_RESET_SHIFT 5 -#define DMAE_CMD_DST_ADDR_RESET_MASK 0x1 -#define DMAE_CMD_DST_ADDR_RESET_SHIFT 6 -#define DMAE_CMD_COMP_FUNC_MASK 0x1 -#define DMAE_CMD_COMP_FUNC_SHIFT 7 -#define DMAE_CMD_COMP_WORD_EN_MASK 0x1 -#define DMAE_CMD_COMP_WORD_EN_SHIFT 8 -#define DMAE_CMD_COMP_CRC_EN_MASK 0x1 -#define DMAE_CMD_COMP_CRC_EN_SHIFT 9 -#define DMAE_CMD_COMP_CRC_OFFSET_MASK 0x7 -#define DMAE_CMD_COMP_CRC_OFFSET_SHIFT 10 -#define DMAE_CMD_RESERVED1_MASK 0x1 -#define DMAE_CMD_RESERVED1_SHIFT 13 -#define DMAE_CMD_ENDIANITY_MODE_MASK 0x3 -#define DMAE_CMD_ENDIANITY_MODE_SHIFT 14 -#define DMAE_CMD_ERR_HANDLING_MASK 0x3 -#define DMAE_CMD_ERR_HANDLING_SHIFT 16 -#define DMAE_CMD_PORT_ID_MASK 0x3 -#define DMAE_CMD_PORT_ID_SHIFT 18 -#define DMAE_CMD_SRC_PF_ID_MASK 0xF -#define DMAE_CMD_SRC_PF_ID_SHIFT 20 -#define DMAE_CMD_DST_PF_ID_MASK 0xF -#define DMAE_CMD_DST_PF_ID_SHIFT 24 -#define DMAE_CMD_SRC_VF_ID_VALID_MASK 0x1 -#define DMAE_CMD_SRC_VF_ID_VALID_SHIFT 28 -#define DMAE_CMD_DST_VF_ID_VALID_MASK 0x1 -#define DMAE_CMD_DST_VF_ID_VALID_SHIFT 29 -#define DMAE_CMD_RESERVED2_MASK 0x3 -#define DMAE_CMD_RESERVED2_SHIFT 30 - __le32 src_addr_lo; - __le32 src_addr_hi; - __le32 dst_addr_lo; - __le32 dst_addr_hi; - __le16 length /* Length in DW */; - __le16 opcode_b; -#define DMAE_CMD_SRC_VF_ID_MASK 0xFF /* Source VF id */ -#define DMAE_CMD_SRC_VF_ID_SHIFT 0 -#define DMAE_CMD_DST_VF_ID_MASK 0xFF /* Destination VF id */ -#define DMAE_CMD_DST_VF_ID_SHIFT 8 - __le32 comp_addr_lo /* PCIe completion address low or grc address */; - __le32 comp_addr_hi; - __le32 comp_val /* Value to write to copmletion address */; - __le32 crc32 /* crc16 result */; - __le32 crc_32_c /* crc32_c result */; - __le16 crc16 /* crc16 result */; - __le16 crc16_c /* crc16_c result */; - __le16 crc10 /* crc_t10 result */; - __le16 reserved; - __le16 xsum16 /* checksum16 result */; - __le16 xsum8 /* checksum8 result */; +/* Chip IDs */ +enum chip_ids { + CHIP_RESERVED, + CHIP_BB_B0, + CHIP_RESERVED2, + MAX_CHIP_IDS }; -struct igu_cleanup { - __le32 sb_id_and_flags; -#define IGU_CLEANUP_RESERVED0_MASK 0x7FFFFFF -#define IGU_CLEANUP_RESERVED0_SHIFT 0 -#define IGU_CLEANUP_CLEANUP_SET_MASK 0x1 /* cleanup clear - 0, set - 1 */ -#define IGU_CLEANUP_CLEANUP_SET_SHIFT 27 -#define IGU_CLEANUP_CLEANUP_TYPE_MASK 0x7 -#define IGU_CLEANUP_CLEANUP_TYPE_SHIFT 28 -#define IGU_CLEANUP_COMMAND_TYPE_MASK 0x1 -#define IGU_CLEANUP_COMMAND_TYPE_SHIFT 31 - __le32 reserved1; +/* Attention bit mapping */ +struct dbg_attn_bit_mapping { + __le16 data; +#define DBG_ATTN_BIT_MAPPING_VAL_MASK 0x7FFF +#define DBG_ATTN_BIT_MAPPING_VAL_SHIFT 0 +#define DBG_ATTN_BIT_MAPPING_IS_UNUSED_BIT_CNT_MASK 0x1 +#define DBG_ATTN_BIT_MAPPING_IS_UNUSED_BIT_CNT_SHIFT 15 }; -union igu_command { - struct igu_prod_cons_update prod_cons_update; - struct igu_cleanup cleanup; +/* Attention block per-type data */ +struct dbg_attn_block_type_data { + __le16 names_offset; + __le16 reserved1; + u8 num_regs; + u8 reserved2; + __le16 regs_offset; }; -struct igu_command_reg_ctrl { - __le16 opaque_fid; - __le16 igu_command_reg_ctrl_fields; -#define IGU_COMMAND_REG_CTRL_PXP_BAR_ADDR_MASK 0xFFF -#define IGU_COMMAND_REG_CTRL_PXP_BAR_ADDR_SHIFT 0 -#define IGU_COMMAND_REG_CTRL_RESERVED_MASK 0x7 -#define IGU_COMMAND_REG_CTRL_RESERVED_SHIFT 12 -#define IGU_COMMAND_REG_CTRL_COMMAND_TYPE_MASK 0x1 -#define IGU_COMMAND_REG_CTRL_COMMAND_TYPE_SHIFT 15 +/* Block attentions */ +struct dbg_attn_block { + struct dbg_attn_block_type_data per_type_data[2]; }; -struct igu_mapping_line { - __le32 igu_mapping_line_fields; -#define IGU_MAPPING_LINE_VALID_MASK 0x1 -#define IGU_MAPPING_LINE_VALID_SHIFT 0 -#define IGU_MAPPING_LINE_VECTOR_NUMBER_MASK 0xFF -#define IGU_MAPPING_LINE_VECTOR_NUMBER_SHIFT 1 -#define IGU_MAPPING_LINE_FUNCTION_NUMBER_MASK 0xFF -#define IGU_MAPPING_LINE_FUNCTION_NUMBER_SHIFT 9 -#define IGU_MAPPING_LINE_PF_VALID_MASK 0x1 /* PF-1, VF-0 */ -#define IGU_MAPPING_LINE_PF_VALID_SHIFT 17 -#define IGU_MAPPING_LINE_IPS_GROUP_MASK 0x3F -#define IGU_MAPPING_LINE_IPS_GROUP_SHIFT 18 -#define IGU_MAPPING_LINE_RESERVED_MASK 0xFF -#define IGU_MAPPING_LINE_RESERVED_SHIFT 24 +/* Attention register result */ +struct dbg_attn_reg_result { + __le32 data; +#define DBG_ATTN_REG_RESULT_STS_ADDRESS_MASK 0xFFFFFF +#define DBG_ATTN_REG_RESULT_STS_ADDRESS_SHIFT 0 +#define DBG_ATTN_REG_RESULT_NUM_ATTN_IDX_MASK 0xFF +#define DBG_ATTN_REG_RESULT_NUM_ATTN_IDX_SHIFT 24 + __le16 attn_idx_offset; + __le16 reserved; + __le32 sts_val; + __le32 mask_val; +}; + +/* Attention block result */ +struct dbg_attn_block_result { + u8 block_id; + u8 data; +#define DBG_ATTN_BLOCK_RESULT_ATTN_TYPE_MASK 0x3 +#define DBG_ATTN_BLOCK_RESULT_ATTN_TYPE_SHIFT 0 +#define DBG_ATTN_BLOCK_RESULT_NUM_REGS_MASK 0x3F +#define DBG_ATTN_BLOCK_RESULT_NUM_REGS_SHIFT 2 + __le16 names_offset; + struct dbg_attn_reg_result reg_results[15]; +}; + +/* mode header */ +struct dbg_mode_hdr { + __le16 data; +#define DBG_MODE_HDR_EVAL_MODE_MASK 0x1 +#define DBG_MODE_HDR_EVAL_MODE_SHIFT 0 +#define DBG_MODE_HDR_MODES_BUF_OFFSET_MASK 0x7FFF +#define DBG_MODE_HDR_MODES_BUF_OFFSET_SHIFT 1 +}; + +/* Attention register */ +struct dbg_attn_reg { + struct dbg_mode_hdr mode; + __le16 attn_idx_offset; + __le32 data; +#define DBG_ATTN_REG_STS_ADDRESS_MASK 0xFFFFFF +#define DBG_ATTN_REG_STS_ADDRESS_SHIFT 0 +#define DBG_ATTN_REG_NUM_ATTN_IDX_MASK 0xFF +#define DBG_ATTN_REG_NUM_ATTN_IDX_SHIFT 24 + __le32 sts_clr_address; + __le32 mask_address; +}; + +/* attention types */ +enum dbg_attn_type { + ATTN_TYPE_INTERRUPT, + ATTN_TYPE_PARITY, + MAX_DBG_ATTN_TYPE +}; + +/* Debug status codes */ +enum dbg_status { + DBG_STATUS_OK, + DBG_STATUS_APP_VERSION_NOT_SET, + DBG_STATUS_UNSUPPORTED_APP_VERSION, + DBG_STATUS_DBG_BLOCK_NOT_RESET, + DBG_STATUS_INVALID_ARGS, + DBG_STATUS_OUTPUT_ALREADY_SET, + DBG_STATUS_INVALID_PCI_BUF_SIZE, + DBG_STATUS_PCI_BUF_ALLOC_FAILED, + DBG_STATUS_PCI_BUF_NOT_ALLOCATED, + DBG_STATUS_TOO_MANY_INPUTS, + DBG_STATUS_INPUT_OVERLAP, + DBG_STATUS_HW_ONLY_RECORDING, + DBG_STATUS_STORM_ALREADY_ENABLED, + DBG_STATUS_STORM_NOT_ENABLED, + DBG_STATUS_BLOCK_ALREADY_ENABLED, + DBG_STATUS_BLOCK_NOT_ENABLED, + DBG_STATUS_NO_INPUT_ENABLED, + DBG_STATUS_NO_FILTER_TRIGGER_64B, + DBG_STATUS_FILTER_ALREADY_ENABLED, + DBG_STATUS_TRIGGER_ALREADY_ENABLED, + DBG_STATUS_TRIGGER_NOT_ENABLED, + DBG_STATUS_CANT_ADD_CONSTRAINT, + DBG_STATUS_TOO_MANY_TRIGGER_STATES, + DBG_STATUS_TOO_MANY_CONSTRAINTS, + DBG_STATUS_RECORDING_NOT_STARTED, + DBG_STATUS_DATA_DIDNT_TRIGGER, + DBG_STATUS_NO_DATA_RECORDED, + DBG_STATUS_DUMP_BUF_TOO_SMALL, + DBG_STATUS_DUMP_NOT_CHUNK_ALIGNED, + DBG_STATUS_UNKNOWN_CHIP, + DBG_STATUS_VIRT_MEM_ALLOC_FAILED, + DBG_STATUS_BLOCK_IN_RESET, + DBG_STATUS_INVALID_TRACE_SIGNATURE, + DBG_STATUS_INVALID_NVRAM_BUNDLE, + DBG_STATUS_NVRAM_GET_IMAGE_FAILED, + DBG_STATUS_NON_ALIGNED_NVRAM_IMAGE, + DBG_STATUS_NVRAM_READ_FAILED, + DBG_STATUS_IDLE_CHK_PARSE_FAILED, + DBG_STATUS_MCP_TRACE_BAD_DATA, + DBG_STATUS_MCP_TRACE_NO_META, + DBG_STATUS_MCP_COULD_NOT_HALT, + DBG_STATUS_MCP_COULD_NOT_RESUME, + DBG_STATUS_DMAE_FAILED, + DBG_STATUS_SEMI_FIFO_NOT_EMPTY, + DBG_STATUS_IGU_FIFO_BAD_DATA, + DBG_STATUS_MCP_COULD_NOT_MASK_PRTY, + DBG_STATUS_FW_ASSERTS_PARSE_FAILED, + DBG_STATUS_REG_FIFO_BAD_DATA, + DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA, + DBG_STATUS_DBG_ARRAY_NOT_SET, + MAX_DBG_STATUS }; -struct igu_msix_vector { - struct regpair address; - __le32 data; - __le32 msix_vector_fields; -#define IGU_MSIX_VECTOR_MASK_BIT_MASK 0x1 -#define IGU_MSIX_VECTOR_MASK_BIT_SHIFT 0 -#define IGU_MSIX_VECTOR_RESERVED0_MASK 0x7FFF -#define IGU_MSIX_VECTOR_RESERVED0_SHIFT 1 -#define IGU_MSIX_VECTOR_STEERING_TAG_MASK 0xFF -#define IGU_MSIX_VECTOR_STEERING_TAG_SHIFT 16 -#define IGU_MSIX_VECTOR_RESERVED1_MASK 0xFF -#define IGU_MSIX_VECTOR_RESERVED1_SHIFT 24 +/********************************/ +/* HSI Init Functions constants */ +/********************************/ + +/* Number of VLAN priorities */ +#define NUM_OF_VLAN_PRIORITIES 8 + +/* QM per-port init parameters */ +struct init_qm_port_params { + u8 active; + u8 active_phys_tcs; + __le16 num_pbf_cmd_lines; + __le16 num_btb_blocks; + __le16 reserved; }; +/* QM per-PQ init parameters */ +struct init_qm_pq_params { + u8 vport_id; + u8 tc_id; + u8 wrr_group; + u8 rl_valid; +}; + +/* QM per-vport init parameters */ +struct init_qm_vport_params { + __le32 vport_rl; + __le16 vport_wfq; + __le16 first_tx_pq_id[NUM_OF_TCS]; +}; + +/**************************************/ +/* Init Tool HSI constants and macros */ +/**************************************/ + +/* Width of GRC address in bits (addresses are specified in dwords) */ +#define GRC_ADDR_BITS 23 +#define MAX_GRC_ADDR ((1 << GRC_ADDR_BITS) - 1) + +/* indicates an init that should be applied to any phase ID */ +#define ANY_PHASE_ID 0xffff + +/* Max size in dwords of a zipped array */ +#define MAX_ZIPPED_SIZE 8192 + enum init_modes { - MODE_BB_A0, + MODE_RESERVED, MODE_BB_B0, MODE_RESERVED2, MODE_ASIC, @@ -1083,7 +1638,8 @@ enum init_modes { MODE_PORTS_PER_ENG_2, MODE_PORTS_PER_ENG_4, MODE_100G, - MODE_EAGLE_ENG1_WORKAROUND, + MODE_40G, + MODE_RESERVED7, MAX_INIT_MODES }; @@ -1096,484 +1652,302 @@ enum init_phases { MAX_INIT_PHASES }; -/* per encapsulation type enabling flags */ -struct prs_reg_encapsulation_type_en { - u8 flags; -#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GRE_ENABLE_MASK 0x1 -#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GRE_ENABLE_SHIFT 0 -#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GRE_ENABLE_MASK 0x1 -#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GRE_ENABLE_SHIFT 1 -#define PRS_REG_ENCAPSULATION_TYPE_EN_VXLAN_ENABLE_MASK 0x1 -#define PRS_REG_ENCAPSULATION_TYPE_EN_VXLAN_ENABLE_SHIFT 2 -#define PRS_REG_ENCAPSULATION_TYPE_EN_T_TAG_ENABLE_MASK 0x1 -#define PRS_REG_ENCAPSULATION_TYPE_EN_T_TAG_ENABLE_SHIFT 3 -#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GENEVE_ENABLE_MASK 0x1 -#define PRS_REG_ENCAPSULATION_TYPE_EN_ETH_OVER_GENEVE_ENABLE_SHIFT 4 -#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GENEVE_ENABLE_MASK 0x1 -#define PRS_REG_ENCAPSULATION_TYPE_EN_IP_OVER_GENEVE_ENABLE_SHIFT 5 -#define PRS_REG_ENCAPSULATION_TYPE_EN_RESERVED_MASK 0x3 -#define PRS_REG_ENCAPSULATION_TYPE_EN_RESERVED_SHIFT 6 -}; - -enum pxp_tph_st_hint { - TPH_ST_HINT_BIDIR /* Read/Write access by Host and Device */, - TPH_ST_HINT_REQUESTER /* Read/Write access by Device */, - TPH_ST_HINT_TARGET, - TPH_ST_HINT_TARGET_PRIO, - MAX_PXP_TPH_ST_HINT +enum init_split_types { + SPLIT_TYPE_NONE, + SPLIT_TYPE_PORT, + SPLIT_TYPE_PF, + SPLIT_TYPE_PORT_PF, + SPLIT_TYPE_VF, + MAX_INIT_SPLIT_TYPES }; -/* QM hardware structure of enable bypass credit mask */ -struct qm_rf_bypass_mask { - u8 flags; -#define QM_RF_BYPASS_MASK_LINEVOQ_MASK 0x1 -#define QM_RF_BYPASS_MASK_LINEVOQ_SHIFT 0 -#define QM_RF_BYPASS_MASK_RESERVED0_MASK 0x1 -#define QM_RF_BYPASS_MASK_RESERVED0_SHIFT 1 -#define QM_RF_BYPASS_MASK_PFWFQ_MASK 0x1 -#define QM_RF_BYPASS_MASK_PFWFQ_SHIFT 2 -#define QM_RF_BYPASS_MASK_VPWFQ_MASK 0x1 -#define QM_RF_BYPASS_MASK_VPWFQ_SHIFT 3 -#define QM_RF_BYPASS_MASK_PFRL_MASK 0x1 -#define QM_RF_BYPASS_MASK_PFRL_SHIFT 4 -#define QM_RF_BYPASS_MASK_VPQCNRL_MASK 0x1 -#define QM_RF_BYPASS_MASK_VPQCNRL_SHIFT 5 -#define QM_RF_BYPASS_MASK_FWPAUSE_MASK 0x1 -#define QM_RF_BYPASS_MASK_FWPAUSE_SHIFT 6 -#define QM_RF_BYPASS_MASK_RESERVED1_MASK 0x1 -#define QM_RF_BYPASS_MASK_RESERVED1_SHIFT 7 -}; - -/* QM hardware structure of opportunistic credit mask */ -struct qm_rf_opportunistic_mask { - __le16 flags; -#define QM_RF_OPPORTUNISTIC_MASK_LINEVOQ_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_LINEVOQ_SHIFT 0 -#define QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_BYTEVOQ_SHIFT 1 -#define QM_RF_OPPORTUNISTIC_MASK_PFWFQ_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_PFWFQ_SHIFT 2 -#define QM_RF_OPPORTUNISTIC_MASK_VPWFQ_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_VPWFQ_SHIFT 3 -#define QM_RF_OPPORTUNISTIC_MASK_PFRL_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_PFRL_SHIFT 4 -#define QM_RF_OPPORTUNISTIC_MASK_VPQCNRL_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_VPQCNRL_SHIFT 5 -#define QM_RF_OPPORTUNISTIC_MASK_FWPAUSE_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_FWPAUSE_SHIFT 6 -#define QM_RF_OPPORTUNISTIC_MASK_RESERVED0_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_RESERVED0_SHIFT 7 -#define QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY_MASK 0x1 -#define QM_RF_OPPORTUNISTIC_MASK_QUEUEEMPTY_SHIFT 8 -#define QM_RF_OPPORTUNISTIC_MASK_RESERVED1_MASK 0x7F -#define QM_RF_OPPORTUNISTIC_MASK_RESERVED1_SHIFT 9 -}; - -/* QM hardware structure of QM map memory */ -struct qm_rf_pq_map { - u32 reg; -#define QM_RF_PQ_MAP_PQ_VALID_MASK 0x1 /* PQ active */ -#define QM_RF_PQ_MAP_PQ_VALID_SHIFT 0 -#define QM_RF_PQ_MAP_RL_ID_MASK 0xFF /* RL ID */ -#define QM_RF_PQ_MAP_RL_ID_SHIFT 1 -#define QM_RF_PQ_MAP_VP_PQ_ID_MASK 0x1FF -#define QM_RF_PQ_MAP_VP_PQ_ID_SHIFT 9 -#define QM_RF_PQ_MAP_VOQ_MASK 0x1F /* VOQ */ -#define QM_RF_PQ_MAP_VOQ_SHIFT 18 -#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_MASK 0x3 /* WRR weight */ -#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_SHIFT 23 -#define QM_RF_PQ_MAP_RL_VALID_MASK 0x1 /* RL active */ -#define QM_RF_PQ_MAP_RL_VALID_SHIFT 25 -#define QM_RF_PQ_MAP_RESERVED_MASK 0x3F -#define QM_RF_PQ_MAP_RESERVED_SHIFT 26 -}; - -/* Completion params for aggregated interrupt completion */ -struct sdm_agg_int_comp_params { - __le16 params; -#define SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_MASK 0x3F -#define SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_SHIFT 0 -#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_MASK 0x1 -#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_SHIFT 6 -#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_MASK 0x1FF -#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_SHIFT 7 -}; - -/* SDM operation gen command (generate aggregative interrupt) */ -struct sdm_op_gen { - __le32 command; -#define SDM_OP_GEN_COMP_PARAM_MASK 0xFFFF /* completion parameters 0-15 */ -#define SDM_OP_GEN_COMP_PARAM_SHIFT 0 -#define SDM_OP_GEN_COMP_TYPE_MASK 0xF /* completion type 16-19 */ -#define SDM_OP_GEN_COMP_TYPE_SHIFT 16 -#define SDM_OP_GEN_RESERVED_MASK 0xFFF /* reserved 20-31 */ -#define SDM_OP_GEN_RESERVED_SHIFT 20 -}; - -/*********************************** Init ************************************/ - -/* Width of GRC address in bits (addresses are specified in dwords) */ -#define GRC_ADDR_BITS 23 -#define MAX_GRC_ADDR ((1 << GRC_ADDR_BITS) - 1) - -/* indicates an init that should be applied to any phase ID */ -#define ANY_PHASE_ID 0xffff - -/* init pattern size in bytes */ -#define INIT_PATTERN_SIZE_BITS 4 -#define MAX_INIT_PATTERN_SIZE BIT(INIT_PATTERN_SIZE_BITS) - -/* Max size in dwords of a zipped array */ -#define MAX_ZIPPED_SIZE 8192 - -/* Global PXP window */ -#define NUM_OF_PXP_WIN 19 -#define PXP_WIN_DWORD_SIZE_BITS 10 -#define PXP_WIN_DWORD_SIZE BIT(PXP_WIN_DWORD_SIZE_BITS) -#define PXP_WIN_BYTE_SIZE_BITS (PXP_WIN_DWORD_SIZE_BITS + 2) -#define PXP_WIN_BYTE_SIZE (PXP_WIN_DWORD_SIZE * 4) - -/********************************* GRC Dump **********************************/ - -/* width of GRC dump register sequence length in bits */ -#define DUMP_SEQ_LEN_BITS 8 -#define DUMP_SEQ_LEN_MAX_VAL ((1 << DUMP_SEQ_LEN_BITS) - 1) - -/* width of GRC dump memory length in bits */ -#define DUMP_MEM_LEN_BITS 18 -#define DUMP_MEM_LEN_MAX_VAL ((1 << DUMP_MEM_LEN_BITS) - 1) - -/* width of register type ID in bits */ -#define REG_TYPE_ID_BITS 6 -#define REG_TYPE_ID_MAX_VAL ((1 << REG_TYPE_ID_BITS) - 1) - -/* width of block ID in bits */ -#define BLOCK_ID_BITS 8 -#define BLOCK_ID_MAX_VAL ((1 << BLOCK_ID_BITS) - 1) - -/******************************** Idle Check *********************************/ - -/* max number of idle check predicate immediates */ -#define MAX_IDLE_CHK_PRED_IMM 3 - -/* max number of idle check argument registers */ -#define MAX_IDLE_CHK_READ_REGS 3 - -/* max number of idle check loops */ -#define MAX_IDLE_CHK_LOOPS 0x10000 - -/* max idle check address increment */ -#define MAX_IDLE_CHK_INCREMENT 0x10000 - -/* inicates an undefined idle check line index */ -#define IDLE_CHK_UNDEFINED_LINE_IDX 0xffffff - -/* max number of register values following the idle check header */ -#define IDLE_CHK_MAX_DUMP_REGS 2 - -/* arguments for IDLE_CHK_MACRO_TYPE_QM_RD_WR */ -#define IDLE_CHK_QM_RD_WR_PTR 0 -#define IDLE_CHK_QM_RD_WR_BANK 1 - -/**************************************/ -/* HSI Functions constants and macros */ -/**************************************/ - -/* Number of VLAN priorities */ -#define NUM_OF_VLAN_PRIORITIES 8 - -/* the MCP Trace meta data signautre is duplicated in the perl script that - * generats the NVRAM images. - */ -#define MCP_TRACE_META_IMAGE_SIGNATURE 0x669955aa - /* Binary buffer header */ struct bin_buffer_hdr { - u32 offset; - u32 length /* buffer length in bytes */; + __le32 offset; + __le32 length; }; -/* binary buffer types */ -enum bin_buffer_type { - BIN_BUF_FW_VER_INFO /* fw_ver_info struct */, - BIN_BUF_INIT_CMD /* init commands */, - BIN_BUF_INIT_VAL /* init data */, - BIN_BUF_INIT_MODE_TREE /* init modes tree */, - BIN_BUF_IRO /* internal RAM offsets array */, - MAX_BIN_BUFFER_TYPE -}; - -/* Chip IDs */ -enum chip_ids { - CHIP_BB_A0 /* BB A0 chip ID */, - CHIP_BB_B0 /* BB B0 chip ID */, - CHIP_K2 /* AH chip ID */, - MAX_CHIP_IDS +/* binary init buffer types */ +enum bin_init_buffer_type { + BIN_BUF_FW_VER_INFO, + BIN_BUF_INIT_CMD, + BIN_BUF_INIT_VAL, + BIN_BUF_INIT_MODE_TREE, + BIN_BUF_IRO, + MAX_BIN_INIT_BUFFER_TYPE }; +/* init array header: raw */ struct init_array_raw_hdr { __le32 data; -#define INIT_ARRAY_RAW_HDR_TYPE_MASK 0xF -#define INIT_ARRAY_RAW_HDR_TYPE_SHIFT 0 -#define INIT_ARRAY_RAW_HDR_PARAMS_MASK 0xFFFFFFF /* init array params */ -#define INIT_ARRAY_RAW_HDR_PARAMS_SHIFT 4 +#define INIT_ARRAY_RAW_HDR_TYPE_MASK 0xF +#define INIT_ARRAY_RAW_HDR_TYPE_SHIFT 0 +#define INIT_ARRAY_RAW_HDR_PARAMS_MASK 0xFFFFFFF +#define INIT_ARRAY_RAW_HDR_PARAMS_SHIFT 4 }; +/* init array header: standard */ struct init_array_standard_hdr { __le32 data; -#define INIT_ARRAY_STANDARD_HDR_TYPE_MASK 0xF -#define INIT_ARRAY_STANDARD_HDR_TYPE_SHIFT 0 -#define INIT_ARRAY_STANDARD_HDR_SIZE_MASK 0xFFFFFFF -#define INIT_ARRAY_STANDARD_HDR_SIZE_SHIFT 4 +#define INIT_ARRAY_STANDARD_HDR_TYPE_MASK 0xF +#define INIT_ARRAY_STANDARD_HDR_TYPE_SHIFT 0 +#define INIT_ARRAY_STANDARD_HDR_SIZE_MASK 0xFFFFFFF +#define INIT_ARRAY_STANDARD_HDR_SIZE_SHIFT 4 }; +/* init array header: zipped */ struct init_array_zipped_hdr { __le32 data; -#define INIT_ARRAY_ZIPPED_HDR_TYPE_MASK 0xF -#define INIT_ARRAY_ZIPPED_HDR_TYPE_SHIFT 0 -#define INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE_MASK 0xFFFFFFF -#define INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE_SHIFT 4 +#define INIT_ARRAY_ZIPPED_HDR_TYPE_MASK 0xF +#define INIT_ARRAY_ZIPPED_HDR_TYPE_SHIFT 0 +#define INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE_MASK 0xFFFFFFF +#define INIT_ARRAY_ZIPPED_HDR_ZIPPED_SIZE_SHIFT 4 }; +/* init array header: pattern */ struct init_array_pattern_hdr { __le32 data; -#define INIT_ARRAY_PATTERN_HDR_TYPE_MASK 0xF -#define INIT_ARRAY_PATTERN_HDR_TYPE_SHIFT 0 -#define INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE_MASK 0xF -#define INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE_SHIFT 4 -#define INIT_ARRAY_PATTERN_HDR_REPETITIONS_MASK 0xFFFFFF -#define INIT_ARRAY_PATTERN_HDR_REPETITIONS_SHIFT 8 +#define INIT_ARRAY_PATTERN_HDR_TYPE_MASK 0xF +#define INIT_ARRAY_PATTERN_HDR_TYPE_SHIFT 0 +#define INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE_MASK 0xF +#define INIT_ARRAY_PATTERN_HDR_PATTERN_SIZE_SHIFT 4 +#define INIT_ARRAY_PATTERN_HDR_REPETITIONS_MASK 0xFFFFFF +#define INIT_ARRAY_PATTERN_HDR_REPETITIONS_SHIFT 8 }; +/* init array header union */ union init_array_hdr { - struct init_array_raw_hdr raw /* raw init array header */; - struct init_array_standard_hdr standard; - struct init_array_zipped_hdr zipped /* zipped init array header */; - struct init_array_pattern_hdr pattern /* pattern init array header */; + struct init_array_raw_hdr raw; + struct init_array_standard_hdr standard; + struct init_array_zipped_hdr zipped; + struct init_array_pattern_hdr pattern; }; +/* init array types */ enum init_array_types { - INIT_ARR_STANDARD /* standard init array */, - INIT_ARR_ZIPPED /* zipped init array */, - INIT_ARR_PATTERN /* a repeated pattern */, + INIT_ARR_STANDARD, + INIT_ARR_ZIPPED, + INIT_ARR_PATTERN, MAX_INIT_ARRAY_TYPES }; /* init operation: callback */ struct init_callback_op { - __le32 op_data; -#define INIT_CALLBACK_OP_OP_MASK 0xF -#define INIT_CALLBACK_OP_OP_SHIFT 0 -#define INIT_CALLBACK_OP_RESERVED_MASK 0xFFFFFFF -#define INIT_CALLBACK_OP_RESERVED_SHIFT 4 - __le16 callback_id /* Callback ID */; - __le16 block_id /* Blocks ID */; + __le32 op_data; +#define INIT_CALLBACK_OP_OP_MASK 0xF +#define INIT_CALLBACK_OP_OP_SHIFT 0 +#define INIT_CALLBACK_OP_RESERVED_MASK 0xFFFFFFF +#define INIT_CALLBACK_OP_RESERVED_SHIFT 4 + __le16 callback_id; + __le16 block_id; }; /* init operation: delay */ struct init_delay_op { - __le32 op_data; -#define INIT_DELAY_OP_OP_MASK 0xF -#define INIT_DELAY_OP_OP_SHIFT 0 -#define INIT_DELAY_OP_RESERVED_MASK 0xFFFFFFF -#define INIT_DELAY_OP_RESERVED_SHIFT 4 - __le32 delay /* delay in us */; + __le32 op_data; +#define INIT_DELAY_OP_OP_MASK 0xF +#define INIT_DELAY_OP_OP_SHIFT 0 +#define INIT_DELAY_OP_RESERVED_MASK 0xFFFFFFF +#define INIT_DELAY_OP_RESERVED_SHIFT 4 + __le32 delay; }; /* init operation: if_mode */ struct init_if_mode_op { __le32 op_data; -#define INIT_IF_MODE_OP_OP_MASK 0xF -#define INIT_IF_MODE_OP_OP_SHIFT 0 -#define INIT_IF_MODE_OP_RESERVED1_MASK 0xFFF -#define INIT_IF_MODE_OP_RESERVED1_SHIFT 4 -#define INIT_IF_MODE_OP_CMD_OFFSET_MASK 0xFFFF -#define INIT_IF_MODE_OP_CMD_OFFSET_SHIFT 16 - __le16 reserved2; - __le16 modes_buf_offset; +#define INIT_IF_MODE_OP_OP_MASK 0xF +#define INIT_IF_MODE_OP_OP_SHIFT 0 +#define INIT_IF_MODE_OP_RESERVED1_MASK 0xFFF +#define INIT_IF_MODE_OP_RESERVED1_SHIFT 4 +#define INIT_IF_MODE_OP_CMD_OFFSET_MASK 0xFFFF +#define INIT_IF_MODE_OP_CMD_OFFSET_SHIFT 16 + __le16 reserved2; + __le16 modes_buf_offset; }; -/* init operation: if_phase */ +/* init operation: if_phase */ struct init_if_phase_op { __le32 op_data; -#define INIT_IF_PHASE_OP_OP_MASK 0xF -#define INIT_IF_PHASE_OP_OP_SHIFT 0 -#define INIT_IF_PHASE_OP_DMAE_ENABLE_MASK 0x1 -#define INIT_IF_PHASE_OP_DMAE_ENABLE_SHIFT 4 -#define INIT_IF_PHASE_OP_RESERVED1_MASK 0x7FF -#define INIT_IF_PHASE_OP_RESERVED1_SHIFT 5 -#define INIT_IF_PHASE_OP_CMD_OFFSET_MASK 0xFFFF -#define INIT_IF_PHASE_OP_CMD_OFFSET_SHIFT 16 +#define INIT_IF_PHASE_OP_OP_MASK 0xF +#define INIT_IF_PHASE_OP_OP_SHIFT 0 +#define INIT_IF_PHASE_OP_DMAE_ENABLE_MASK 0x1 +#define INIT_IF_PHASE_OP_DMAE_ENABLE_SHIFT 4 +#define INIT_IF_PHASE_OP_RESERVED1_MASK 0x7FF +#define INIT_IF_PHASE_OP_RESERVED1_SHIFT 5 +#define INIT_IF_PHASE_OP_CMD_OFFSET_MASK 0xFFFF +#define INIT_IF_PHASE_OP_CMD_OFFSET_SHIFT 16 __le32 phase_data; -#define INIT_IF_PHASE_OP_PHASE_MASK 0xFF /* Init phase */ -#define INIT_IF_PHASE_OP_PHASE_SHIFT 0 -#define INIT_IF_PHASE_OP_RESERVED2_MASK 0xFF -#define INIT_IF_PHASE_OP_RESERVED2_SHIFT 8 -#define INIT_IF_PHASE_OP_PHASE_ID_MASK 0xFFFF /* Init phase ID */ -#define INIT_IF_PHASE_OP_PHASE_ID_SHIFT 16 +#define INIT_IF_PHASE_OP_PHASE_MASK 0xFF +#define INIT_IF_PHASE_OP_PHASE_SHIFT 0 +#define INIT_IF_PHASE_OP_RESERVED2_MASK 0xFF +#define INIT_IF_PHASE_OP_RESERVED2_SHIFT 8 +#define INIT_IF_PHASE_OP_PHASE_ID_MASK 0xFFFF +#define INIT_IF_PHASE_OP_PHASE_ID_SHIFT 16 }; /* init mode operators */ enum init_mode_ops { - INIT_MODE_OP_NOT /* init mode not operator */, - INIT_MODE_OP_OR /* init mode or operator */, - INIT_MODE_OP_AND /* init mode and operator */, + INIT_MODE_OP_NOT, + INIT_MODE_OP_OR, + INIT_MODE_OP_AND, MAX_INIT_MODE_OPS }; /* init operation: raw */ struct init_raw_op { - __le32 op_data; -#define INIT_RAW_OP_OP_MASK 0xF -#define INIT_RAW_OP_OP_SHIFT 0 -#define INIT_RAW_OP_PARAM1_MASK 0xFFFFFFF /* init param 1 */ -#define INIT_RAW_OP_PARAM1_SHIFT 4 - __le32 param2 /* Init param 2 */; + __le32 op_data; +#define INIT_RAW_OP_OP_MASK 0xF +#define INIT_RAW_OP_OP_SHIFT 0 +#define INIT_RAW_OP_PARAM1_MASK 0xFFFFFFF +#define INIT_RAW_OP_PARAM1_SHIFT 4 + __le32 param2; }; /* init array params */ struct init_op_array_params { - __le16 size /* array size in dwords */; - __le16 offset /* array start offset in dwords */; + __le16 size; + __le16 offset; }; /* Write init operation arguments */ union init_write_args { - __le32 inline_val; - __le32 zeros_count; - __le32 array_offset; - struct init_op_array_params runtime; + __le32 inline_val; + __le32 zeros_count; + __le32 array_offset; + struct init_op_array_params runtime; }; /* init operation: write */ struct init_write_op { __le32 data; -#define INIT_WRITE_OP_OP_MASK 0xF -#define INIT_WRITE_OP_OP_SHIFT 0 -#define INIT_WRITE_OP_SOURCE_MASK 0x7 -#define INIT_WRITE_OP_SOURCE_SHIFT 4 -#define INIT_WRITE_OP_RESERVED_MASK 0x1 -#define INIT_WRITE_OP_RESERVED_SHIFT 7 -#define INIT_WRITE_OP_WIDE_BUS_MASK 0x1 -#define INIT_WRITE_OP_WIDE_BUS_SHIFT 8 -#define INIT_WRITE_OP_ADDRESS_MASK 0x7FFFFF -#define INIT_WRITE_OP_ADDRESS_SHIFT 9 - union init_write_args args /* Write init operation arguments */; +#define INIT_WRITE_OP_OP_MASK 0xF +#define INIT_WRITE_OP_OP_SHIFT 0 +#define INIT_WRITE_OP_SOURCE_MASK 0x7 +#define INIT_WRITE_OP_SOURCE_SHIFT 4 +#define INIT_WRITE_OP_RESERVED_MASK 0x1 +#define INIT_WRITE_OP_RESERVED_SHIFT 7 +#define INIT_WRITE_OP_WIDE_BUS_MASK 0x1 +#define INIT_WRITE_OP_WIDE_BUS_SHIFT 8 +#define INIT_WRITE_OP_ADDRESS_MASK 0x7FFFFF +#define INIT_WRITE_OP_ADDRESS_SHIFT 9 + union init_write_args args; }; /* init operation: read */ struct init_read_op { __le32 op_data; -#define INIT_READ_OP_OP_MASK 0xF -#define INIT_READ_OP_OP_SHIFT 0 -#define INIT_READ_OP_POLL_TYPE_MASK 0xF -#define INIT_READ_OP_POLL_TYPE_SHIFT 4 -#define INIT_READ_OP_RESERVED_MASK 0x1 -#define INIT_READ_OP_RESERVED_SHIFT 8 -#define INIT_READ_OP_ADDRESS_MASK 0x7FFFFF -#define INIT_READ_OP_ADDRESS_SHIFT 9 +#define INIT_READ_OP_OP_MASK 0xF +#define INIT_READ_OP_OP_SHIFT 0 +#define INIT_READ_OP_POLL_TYPE_MASK 0xF +#define INIT_READ_OP_POLL_TYPE_SHIFT 4 +#define INIT_READ_OP_RESERVED_MASK 0x1 +#define INIT_READ_OP_RESERVED_SHIFT 8 +#define INIT_READ_OP_ADDRESS_MASK 0x7FFFFF +#define INIT_READ_OP_ADDRESS_SHIFT 9 __le32 expected_val; + }; /* Init operations union */ union init_op { - struct init_raw_op raw /* raw init operation */; - struct init_write_op write /* write init operation */; - struct init_read_op read /* read init operation */; - struct init_if_mode_op if_mode /* if_mode init operation */; - struct init_if_phase_op if_phase /* if_phase init operation */; - struct init_callback_op callback /* callback init operation */; - struct init_delay_op delay /* delay init operation */; + struct init_raw_op raw; + struct init_write_op write; + struct init_read_op read; + struct init_if_mode_op if_mode; + struct init_if_phase_op if_phase; + struct init_callback_op callback; + struct init_delay_op delay; }; /* Init command operation types */ enum init_op_types { - INIT_OP_READ /* GRC read init command */, - INIT_OP_WRITE /* GRC write init command */, + INIT_OP_READ, + INIT_OP_WRITE, INIT_OP_IF_MODE, INIT_OP_IF_PHASE, - INIT_OP_DELAY /* delay init command */, - INIT_OP_CALLBACK /* callback init command */, + INIT_OP_DELAY, + INIT_OP_CALLBACK, MAX_INIT_OP_TYPES }; +/* init polling types */ enum init_poll_types { - INIT_POLL_NONE /* No polling */, - INIT_POLL_EQ /* init value is included in the init command */, - INIT_POLL_OR /* init value is all zeros */, - INIT_POLL_AND /* init value is an array of values */, + INIT_POLL_NONE, + INIT_POLL_EQ, + INIT_POLL_OR, + INIT_POLL_AND, MAX_INIT_POLL_TYPES }; /* init source types */ enum init_source_types { - INIT_SRC_INLINE /* init value is included in the init command */, - INIT_SRC_ZEROS /* init value is all zeros */, - INIT_SRC_ARRAY /* init value is an array of values */, - INIT_SRC_RUNTIME /* init value is provided during runtime */, + INIT_SRC_INLINE, + INIT_SRC_ZEROS, + INIT_SRC_ARRAY, + INIT_SRC_RUNTIME, MAX_INIT_SOURCE_TYPES }; /* Internal RAM Offsets macro data */ struct iro { - u32 base /* RAM field offset */; - u16 m1 /* multiplier 1 */; - u16 m2 /* multiplier 2 */; - u16 m3 /* multiplier 3 */; - u16 size /* RAM field size */; + __le32 base; + __le16 m1; + __le16 m2; + __le16 m3; + __le16 size; }; -/* QM per-port init parameters */ -struct init_qm_port_params { - u8 active /* Indicates if this port is active */; - u8 num_active_phys_tcs; - u16 num_pbf_cmd_lines; - u16 num_btb_blocks; - __le16 reserved; -}; - -/* QM per-PQ init parameters */ -struct init_qm_pq_params { - u8 vport_id /* VPORT ID */; - u8 tc_id /* TC ID */; - u8 wrr_group /* WRR group */; - u8 reserved; -}; +/** + * @brief qed_dbg_print_attn - Prints attention registers values in the specified results struct. + * + * @param p_hwfn + * @param results - Pointer to the attention read results + * + * @return error if one of the following holds: + * - the version wasn't set + * Otherwise, returns ok. + */ +enum dbg_status qed_dbg_print_attn(struct qed_hwfn *p_hwfn, + struct dbg_attn_block_result *results); -/* QM per-vport init parameters */ -struct init_qm_vport_params { - u32 vport_rl; - u16 vport_wfq; - u16 first_tx_pq_id[NUM_OF_TCS]; -}; +#define MAX_NAME_LEN 16 /* Win 2 */ #define GTT_BAR0_MAP_REG_IGU_CMD \ 0x00f000UL + /* Win 3 */ #define GTT_BAR0_MAP_REG_TSDM_RAM \ 0x010000UL + /* Win 4 */ #define GTT_BAR0_MAP_REG_MSDM_RAM \ 0x011000UL + /* Win 5 */ #define GTT_BAR0_MAP_REG_MSDM_RAM_1024 \ 0x012000UL + /* Win 6 */ #define GTT_BAR0_MAP_REG_USDM_RAM \ 0x013000UL + /* Win 7 */ #define GTT_BAR0_MAP_REG_USDM_RAM_1024 \ 0x014000UL + /* Win 8 */ #define GTT_BAR0_MAP_REG_USDM_RAM_2048 \ 0x015000UL + /* Win 9 */ #define GTT_BAR0_MAP_REG_XSDM_RAM \ 0x016000UL + /* Win 10 */ #define GTT_BAR0_MAP_REG_YSDM_RAM \ 0x017000UL + /* Win 11 */ #define GTT_BAR0_MAP_REG_PSDM_RAM \ 0x018000UL @@ -1584,785 +1958,718 @@ struct init_qm_vport_params { * Returns the required host memory size in 4KB units. * Must be called before all QM init HSI functions. * - * @param pf_id - physical function ID - * @param num_pf_cids - number of connections used by this PF - * @param num_vf_cids - number of connections used by VFs of this PF - * @param num_tids - number of tasks used by this PF - * @param num_pf_pqs - number of PQs used by this PF - * @param num_vf_pqs - number of PQs used by VFs of this PF + * @param pf_id - physical function ID + * @param num_pf_cids - number of connections used by this PF + * @param num_vf_cids - number of connections used by VFs of this PF + * @param num_tids - number of tasks used by this PF + * @param num_pf_pqs - number of PQs used by this PF + * @param num_vf_pqs - number of PQs used by VFs of this PF * * @return The required host memory size in 4KB units. */ -u32 qed_qm_pf_mem_size(u8 pf_id, - u32 num_pf_cids, - u32 num_vf_cids, - u32 num_tids, - u16 num_pf_pqs, - u16 num_vf_pqs); +u32 qed_qm_pf_mem_size(u8 pf_id, + u32 num_pf_cids, + u32 num_vf_cids, + u32 num_tids, u16 num_pf_pqs, u16 num_vf_pqs); struct qed_qm_common_rt_init_params { - u8 max_ports_per_engine; - u8 max_phys_tcs_per_port; - bool pf_rl_en; - bool pf_wfq_en; - bool vport_rl_en; - bool vport_wfq_en; - struct init_qm_port_params *port_params; + u8 max_ports_per_engine; + u8 max_phys_tcs_per_port; + bool pf_rl_en; + bool pf_wfq_en; + bool vport_rl_en; + bool vport_wfq_en; + struct init_qm_port_params *port_params; }; +int qed_qm_common_rt_init(struct qed_hwfn *p_hwfn, + struct qed_qm_common_rt_init_params *p_params); + +struct qed_qm_pf_rt_init_params { + u8 port_id; + u8 pf_id; + u8 max_phys_tcs_per_port; + bool is_first_pf; + u32 num_pf_cids; + u32 num_vf_cids; + u32 num_tids; + u16 start_pq; + u16 num_pf_pqs; + u16 num_vf_pqs; + u8 start_vport; + u8 num_vports; + u8 pf_wfq; + u32 pf_rl; + struct init_qm_pq_params *pq_params; + struct init_qm_vport_params *vport_params; +}; + +int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_qm_pf_rt_init_params *p_params); + /** - * @brief qed_qm_common_rt_init - Prepare QM runtime init values for the - * engine phase. + * @brief qed_init_pf_wfq - Initializes the WFQ weight of the specified PF * * @param p_hwfn - * @param max_ports_per_engine - max number of ports per engine in HW - * @param max_phys_tcs_per_port - max number of physical TCs per port in HW - * @param pf_rl_en - enable per-PF rate limiters - * @param pf_wfq_en - enable per-PF WFQ - * @param vport_rl_en - enable per-VPORT rate limiters - * @param vport_wfq_en - enable per-VPORT WFQ - * @param port_params - array of size MAX_NUM_PORTS with - * arameters for each port + * @param p_ptt - ptt window used for writing the registers + * @param pf_id - PF ID + * @param pf_wfq - WFQ weight. Must be non-zero. * * @return 0 on success, -1 on error. */ -int qed_qm_common_rt_init( - struct qed_hwfn *p_hwfn, - struct qed_qm_common_rt_init_params *p_params); - -struct qed_qm_pf_rt_init_params { - u8 port_id; - u8 pf_id; - u8 max_phys_tcs_per_port; - bool is_first_pf; - u32 num_pf_cids; - u32 num_vf_cids; - u32 num_tids; - u16 start_pq; - u16 num_pf_pqs; - u16 num_vf_pqs; - u8 start_vport; - u8 num_vports; - u8 pf_wfq; - u32 pf_rl; - struct init_qm_pq_params *pq_params; - struct init_qm_vport_params *vport_params; -}; - -int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_qm_pf_rt_init_params *p_params); +int qed_init_pf_wfq(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 pf_id, u16 pf_wfq); /** - * @brief qed_init_pf_rl Initializes the rate limit of the specified PF + * @brief qed_init_pf_rl - Initializes the rate limit of the specified PF * * @param p_hwfn - * @param p_ptt - ptt window used for writing the registers - * @param pf_id - PF ID - * @param pf_rl - rate limit in Mb/sec units + * @param p_ptt - ptt window used for writing the registers + * @param pf_id - PF ID + * @param pf_rl - rate limit in Mb/sec units * * @return 0 on success, -1 on error. */ -int qed_init_pf_rl(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u8 pf_id, - u32 pf_rl); +int qed_init_pf_rl(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 pf_id, u32 pf_rl); /** - * @brief qed_init_vport_rl Initializes the rate limit of the specified VPORT + * @brief qed_init_vport_wfq Initializes the WFQ weight of the specified VPORT * * @param p_hwfn - * @param p_ptt - ptt window used for writing the registers - * @param vport_id - VPORT ID - * @param vport_rl - rate limit in Mb/sec units + * @param p_ptt - ptt window used for writing the registers + * @param first_tx_pq_id- An array containing the first Tx PQ ID associated + * with the VPORT for each TC. This array is filled by + * qed_qm_pf_rt_init + * @param vport_wfq - WFQ weight. Must be non-zero. * * @return 0 on success, -1 on error. */ +int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u16 first_tx_pq_id[NUM_OF_TCS], u16 vport_wfq); -int qed_init_vport_rl(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u8 vport_id, - u32 vport_rl); +/** + * @brief qed_init_vport_rl - Initializes the rate limit of the specified VPORT + * + * @param p_hwfn + * @param p_ptt - ptt window used for writing the registers + * @param vport_id - VPORT ID + * @param vport_rl - rate limit in Mb/sec units + * + * @return 0 on success, -1 on error. + */ +int qed_init_vport_rl(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 vport_id, u32 vport_rl); /** * @brief qed_send_qm_stop_cmd Sends a stop command to the QM * * @param p_hwfn - * @param p_ptt - ptt window used for writing the registers + * @param p_ptt * @param is_release_cmd - true for release, false for stop. - * @param is_tx_pq - true for Tx PQs, false for Other PQs. - * @param start_pq - first PQ ID to stop - * @param num_pqs - Number of PQs to stop, starting from start_pq. + * @param is_tx_pq - true for Tx PQs, false for Other PQs. + * @param start_pq - first PQ ID to stop + * @param num_pqs - Number of PQs to stop, starting from start_pq. * - * @return bool, true if successful, false if timeout occurred while waiting - * for QM command done. + * @return bool, true if successful, false if timeout occured while waiting for QM command done. */ +bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + bool is_release_cmd, + bool is_tx_pq, u16 start_pq, u16 num_pqs); -bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - bool is_release_cmd, - bool is_tx_pq, - u16 start_pq, - u16 num_pqs); - +/** + * @brief qed_set_vxlan_dest_port - initializes vxlan tunnel destination udp port + * + * @param p_ptt - ptt window used for writing the registers. + * @param dest_port - vxlan destination udp port. + */ void qed_set_vxlan_dest_port(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, u16 dest_port); + struct qed_ptt *p_ptt, u16 dest_port); + +/** + * @brief qed_set_vxlan_enable - enable or disable VXLAN tunnel in HW + * + * @param p_ptt - ptt window used for writing the registers. + * @param vxlan_enable - vxlan enable flag. + */ void qed_set_vxlan_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool vxlan_enable); + +/** + * @brief qed_set_gre_enable - enable or disable GRE tunnel in HW + * + * @param p_ptt - ptt window used for writing the registers. + * @param eth_gre_enable - eth GRE enable enable flag. + * @param ip_gre_enable - IP GRE enable enable flag. + */ void qed_set_gre_enable(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, bool eth_gre_enable, - bool ip_gre_enable); + struct qed_ptt *p_ptt, + bool eth_gre_enable, bool ip_gre_enable); + +/** + * @brief qed_set_geneve_dest_port - initializes geneve tunnel destination udp port + * + * @param p_ptt - ptt window used for writing the registers. + * @param dest_port - geneve destination udp port. + */ void qed_set_geneve_dest_port(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 dest_port); + +/** + * @brief qed_set_gre_enable - enable or disable GRE tunnel in HW + * + * @param p_ptt - ptt window used for writing the registers. + * @param eth_geneve_enable - eth GENEVE enable enable flag. + * @param ip_geneve_enable - IP GENEVE enable enable flag. + */ void qed_set_geneve_enable(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, bool eth_geneve_enable, - bool ip_geneve_enable); - -/* Ystorm flow control mode. Use enum fw_flow_ctrl_mode */ -#define YSTORM_FLOW_CONTROL_MODE_OFFSET (IRO[0].base) -#define YSTORM_FLOW_CONTROL_MODE_SIZE (IRO[0].size) -/* Tstorm port statistics */ -#define TSTORM_PORT_STAT_OFFSET(port_id) (IRO[1].base + ((port_id) * IRO[1].m1)) -#define TSTORM_PORT_STAT_SIZE (IRO[1].size) -/* Tstorm ll2 port statistics */ -#define TSTORM_LL2_PORT_STAT_OFFSET(port_id) \ - (IRO[2].base + ((port_id) * IRO[2].m1)) -#define TSTORM_LL2_PORT_STAT_SIZE (IRO[2].size) -/* Ustorm VF-PF Channel ready flag */ -#define USTORM_VF_PF_CHANNEL_READY_OFFSET(vf_id) \ - (IRO[3].base + ((vf_id) * IRO[3].m1)) -#define USTORM_VF_PF_CHANNEL_READY_SIZE (IRO[3].size) -/* Ustorm Final flr cleanup ack */ -#define USTORM_FLR_FINAL_ACK_OFFSET(pf_id) (IRO[4].base + ((pf_id) * IRO[4].m1)) -#define USTORM_FLR_FINAL_ACK_SIZE (IRO[4].size) -/* Ustorm Event ring consumer */ -#define USTORM_EQE_CONS_OFFSET(pf_id) (IRO[5].base + ((pf_id) * IRO[5].m1)) -#define USTORM_EQE_CONS_SIZE (IRO[5].size) -/* Ustorm Common Queue ring consumer */ -#define USTORM_COMMON_QUEUE_CONS_OFFSET(global_queue_id) \ - (IRO[6].base + ((global_queue_id) * IRO[6].m1)) -#define USTORM_COMMON_QUEUE_CONS_SIZE (IRO[6].size) -/* Xstorm Integration Test Data */ -#define XSTORM_INTEG_TEST_DATA_OFFSET (IRO[7].base) -#define XSTORM_INTEG_TEST_DATA_SIZE (IRO[7].size) -/* Ystorm Integration Test Data */ -#define YSTORM_INTEG_TEST_DATA_OFFSET (IRO[8].base) -#define YSTORM_INTEG_TEST_DATA_SIZE (IRO[8].size) -/* Pstorm Integration Test Data */ -#define PSTORM_INTEG_TEST_DATA_OFFSET (IRO[9].base) -#define PSTORM_INTEG_TEST_DATA_SIZE (IRO[9].size) -/* Tstorm Integration Test Data */ -#define TSTORM_INTEG_TEST_DATA_OFFSET (IRO[10].base) -#define TSTORM_INTEG_TEST_DATA_SIZE (IRO[10].size) -/* Mstorm Integration Test Data */ -#define MSTORM_INTEG_TEST_DATA_OFFSET (IRO[11].base) -#define MSTORM_INTEG_TEST_DATA_SIZE (IRO[11].size) -/* Ustorm Integration Test Data */ -#define USTORM_INTEG_TEST_DATA_OFFSET (IRO[12].base) -#define USTORM_INTEG_TEST_DATA_SIZE (IRO[12].size) -/* Tstorm producers */ -#define TSTORM_LL2_RX_PRODS_OFFSET(core_rx_queue_id) \ - (IRO[13].base + ((core_rx_queue_id) * IRO[13].m1)) -#define TSTORM_LL2_RX_PRODS_SIZE (IRO[13].size) -/* Tstorm LightL2 queue statistics */ -#define CORE_LL2_TSTORM_PER_QUEUE_STAT_OFFSET(core_rx_queue_id) \ - (IRO[14].base + ((core_rx_queue_id) * IRO[14].m1)) -#define CORE_LL2_TSTORM_PER_QUEUE_STAT_SIZE (IRO[14].size) -/* Ustorm LiteL2 queue statistics */ -#define CORE_LL2_USTORM_PER_QUEUE_STAT_OFFSET(core_rx_queue_id) \ - (IRO[15].base + ((core_rx_queue_id) * IRO[15].m1)) -#define CORE_LL2_USTORM_PER_QUEUE_STAT_SIZE (IRO[15].size) -/* Pstorm LiteL2 queue statistics */ -#define CORE_LL2_PSTORM_PER_QUEUE_STAT_OFFSET(core_tx_stats_id) \ - (IRO[16].base + ((core_tx_stats_id) * IRO[16].m1)) -#define CORE_LL2_PSTORM_PER_QUEUE_STAT_SIZE (IRO[16].size) -/* Mstorm queue statistics */ -#define MSTORM_QUEUE_STAT_OFFSET(stat_counter_id) \ - (IRO[17].base + ((stat_counter_id) * IRO[17].m1)) -#define MSTORM_QUEUE_STAT_SIZE (IRO[17].size) -/* Mstorm producers */ -#define MSTORM_PRODS_OFFSET(queue_id) (IRO[18].base + ((queue_id) * IRO[18].m1)) -#define MSTORM_PRODS_SIZE (IRO[18].size) -/* TPA agregation timeout in us resolution (on ASIC) */ -#define MSTORM_TPA_TIMEOUT_US_OFFSET (IRO[19].base) -#define MSTORM_TPA_TIMEOUT_US_SIZE (IRO[19].size) -/* Ustorm queue statistics */ -#define USTORM_QUEUE_STAT_OFFSET(stat_counter_id) \ - (IRO[20].base + ((stat_counter_id) * IRO[20].m1)) -#define USTORM_QUEUE_STAT_SIZE (IRO[20].size) -/* Ustorm queue zone */ -#define USTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) \ - (IRO[21].base + ((queue_id) * IRO[21].m1)) -#define USTORM_ETH_QUEUE_ZONE_SIZE (IRO[21].size) -/* Pstorm queue statistics */ -#define PSTORM_QUEUE_STAT_OFFSET(stat_counter_id) \ - (IRO[22].base + ((stat_counter_id) * IRO[22].m1)) -#define PSTORM_QUEUE_STAT_SIZE (IRO[22].size) -/* Tstorm last parser message */ -#define TSTORM_ETH_PRS_INPUT_OFFSET (IRO[23].base) -#define TSTORM_ETH_PRS_INPUT_SIZE (IRO[23].size) -/* Tstorm Eth limit Rx rate */ -#define ETH_RX_RATE_LIMIT_OFFSET(pf_id) (IRO[24].base + ((pf_id) * IRO[24].m1)) -#define ETH_RX_RATE_LIMIT_SIZE (IRO[24].size) -/* Ystorm queue zone */ -#define YSTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) \ - (IRO[25].base + ((queue_id) * IRO[25].m1)) -#define YSTORM_ETH_QUEUE_ZONE_SIZE (IRO[25].size) -/* Ystorm cqe producer */ -#define YSTORM_TOE_CQ_PROD_OFFSET(rss_id) \ - (IRO[26].base + ((rss_id) * IRO[26].m1)) -#define YSTORM_TOE_CQ_PROD_SIZE (IRO[26].size) -/* Ustorm cqe producer */ -#define USTORM_TOE_CQ_PROD_OFFSET(rss_id) \ - (IRO[27].base + ((rss_id) * IRO[27].m1)) -#define USTORM_TOE_CQ_PROD_SIZE (IRO[27].size) -/* Ustorm grq producer */ -#define USTORM_TOE_GRQ_PROD_OFFSET(pf_id) \ - (IRO[28].base + ((pf_id) * IRO[28].m1)) -#define USTORM_TOE_GRQ_PROD_SIZE (IRO[28].size) -/* Tstorm cmdq-cons of given command queue-id */ -#define TSTORM_SCSI_CMDQ_CONS_OFFSET(cmdq_queue_id) \ - (IRO[29].base + ((cmdq_queue_id) * IRO[29].m1)) -#define TSTORM_SCSI_CMDQ_CONS_SIZE (IRO[29].size) -/* Mstorm rq-cons of given queue-id */ -#define MSTORM_SCSI_RQ_CONS_OFFSET(rq_queue_id) \ - (IRO[30].base + ((rq_queue_id) * IRO[30].m1)) -#define MSTORM_SCSI_RQ_CONS_SIZE (IRO[30].size) -/* Mstorm bdq-external-producer of given BDQ function ID, BDqueue-id */ -#define MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(func_id, bdq_id) \ - (IRO[31].base + ((func_id) * IRO[31].m1) + ((bdq_id) * IRO[31].m2)) -#define MSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[31].size) -/* Tstorm (reflects M-Storm) bdq-external-producer of given fn ID, BDqueue-id */ -#define TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(func_id, bdq_id) \ - (IRO[32].base + ((func_id) * IRO[32].m1) + ((bdq_id) * IRO[32].m2)) -#define TSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[32].size) -/* Tstorm iSCSI RX stats */ -#define TSTORM_ISCSI_RX_STATS_OFFSET(pf_id) \ - (IRO[33].base + ((pf_id) * IRO[33].m1)) -#define TSTORM_ISCSI_RX_STATS_SIZE (IRO[33].size) -/* Mstorm iSCSI RX stats */ -#define MSTORM_ISCSI_RX_STATS_OFFSET(pf_id) \ - (IRO[34].base + ((pf_id) * IRO[34].m1)) -#define MSTORM_ISCSI_RX_STATS_SIZE (IRO[34].size) -/* Ustorm iSCSI RX stats */ -#define USTORM_ISCSI_RX_STATS_OFFSET(pf_id) \ - (IRO[35].base + ((pf_id) * IRO[35].m1)) -#define USTORM_ISCSI_RX_STATS_SIZE (IRO[35].size) -/* Xstorm iSCSI TX stats */ -#define XSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \ - (IRO[36].base + ((pf_id) * IRO[36].m1)) -#define XSTORM_ISCSI_TX_STATS_SIZE (IRO[36].size) -/* Ystorm iSCSI TX stats */ -#define YSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \ - (IRO[37].base + ((pf_id) * IRO[37].m1)) -#define YSTORM_ISCSI_TX_STATS_SIZE (IRO[37].size) -/* Pstorm iSCSI TX stats */ -#define PSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \ - (IRO[38].base + ((pf_id) * IRO[38].m1)) -#define PSTORM_ISCSI_TX_STATS_SIZE (IRO[38].size) -/* Tstorm FCoE RX stats */ -#define TSTORM_FCOE_RX_STATS_OFFSET(pf_id) \ - (IRO[39].base + ((pf_id) * IRO[39].m1)) -#define TSTORM_FCOE_RX_STATS_SIZE (IRO[39].size) -/* Mstorm FCoE RX stats */ -#define MSTORM_FCOE_RX_STATS_OFFSET(pf_id) \ - (IRO[40].base + ((pf_id) * IRO[40].m1)) -#define MSTORM_FCOE_RX_STATS_SIZE (IRO[40].size) -/* Pstorm FCoE TX stats */ -#define PSTORM_FCOE_TX_STATS_OFFSET(pf_id) \ - (IRO[41].base + ((pf_id) * IRO[41].m1)) -#define PSTORM_FCOE_TX_STATS_SIZE (IRO[41].size) -/* Pstorm RoCE statistics */ -#define PSTORM_ROCE_STAT_OFFSET(stat_counter_id) \ - (IRO[42].base + ((stat_counter_id) * IRO[42].m1)) -#define PSTORM_ROCE_STAT_SIZE (IRO[42].size) -/* Tstorm RoCE statistics */ -#define TSTORM_ROCE_STAT_OFFSET(stat_counter_id) \ - (IRO[43].base + ((stat_counter_id) * IRO[43].m1)) -#define TSTORM_ROCE_STAT_SIZE (IRO[43].size) - -static const struct iro iro_arr[44] = { - { 0x10, 0x0, 0x0, 0x0, 0x8 }, - { 0x47c8, 0x60, 0x0, 0x0, 0x60 }, - { 0x5e30, 0x20, 0x0, 0x0, 0x20 }, - { 0x510, 0x8, 0x0, 0x0, 0x4 }, - { 0x490, 0x8, 0x0, 0x0, 0x4 }, - { 0x10, 0x8, 0x0, 0x0, 0x2 }, - { 0x90, 0x8, 0x0, 0x0, 0x2 }, - { 0x4940, 0x0, 0x0, 0x0, 0x78 }, - { 0x3de0, 0x0, 0x0, 0x0, 0x78 }, - { 0x2998, 0x0, 0x0, 0x0, 0x78 }, - { 0x4750, 0x0, 0x0, 0x0, 0x78 }, - { 0x56d0, 0x0, 0x0, 0x0, 0x78 }, - { 0x7e50, 0x0, 0x0, 0x0, 0x78 }, - { 0x100, 0x8, 0x0, 0x0, 0x8 }, - { 0x5c10, 0x10, 0x0, 0x0, 0x10 }, - { 0xb508, 0x30, 0x0, 0x0, 0x30 }, - { 0x95c0, 0x30, 0x0, 0x0, 0x30 }, - { 0x58a0, 0x40, 0x0, 0x0, 0x40 }, - { 0x200, 0x10, 0x0, 0x0, 0x8 }, - { 0xa230, 0x0, 0x0, 0x0, 0x4 }, - { 0x8058, 0x40, 0x0, 0x0, 0x30 }, - { 0xd00, 0x8, 0x0, 0x0, 0x8 }, - { 0x2b30, 0x80, 0x0, 0x0, 0x38 }, - { 0xa808, 0x0, 0x0, 0x0, 0xf0 }, - { 0xa8f8, 0x8, 0x0, 0x0, 0x8 }, - { 0x80, 0x8, 0x0, 0x0, 0x8 }, - { 0xac0, 0x8, 0x0, 0x0, 0x8 }, - { 0x2580, 0x8, 0x0, 0x0, 0x8 }, - { 0x2500, 0x8, 0x0, 0x0, 0x8 }, - { 0x440, 0x8, 0x0, 0x0, 0x2 }, - { 0x1800, 0x8, 0x0, 0x0, 0x2 }, - { 0x1a00, 0x10, 0x8, 0x0, 0x2 }, - { 0x640, 0x10, 0x8, 0x0, 0x2 }, - { 0xd9b8, 0x38, 0x0, 0x0, 0x24 }, - { 0x11048, 0x10, 0x0, 0x0, 0x8 }, - { 0x11678, 0x38, 0x0, 0x0, 0x18 }, - { 0xaec0, 0x30, 0x0, 0x0, 0x10 }, - { 0x8700, 0x28, 0x0, 0x0, 0x18 }, - { 0xec00, 0x10, 0x0, 0x0, 0x10 }, - { 0xde38, 0x40, 0x0, 0x0, 0x30 }, - { 0x121a8, 0x38, 0x0, 0x0, 0x8 }, - { 0xf068, 0x20, 0x0, 0x0, 0x20 }, - { 0x2b68, 0x80, 0x0, 0x0, 0x10 }, - { 0x4ab8, 0x10, 0x0, 0x0, 0x10 }, + struct qed_ptt *p_ptt, + bool eth_geneve_enable, bool ip_geneve_enable); + +#define YSTORM_FLOW_CONTROL_MODE_OFFSET (IRO[0].base) +#define YSTORM_FLOW_CONTROL_MODE_SIZE (IRO[0].size) +#define TSTORM_PORT_STAT_OFFSET(port_id) \ + (IRO[1].base + ((port_id) * IRO[1].m1)) +#define TSTORM_PORT_STAT_SIZE (IRO[1].size) +#define USTORM_VF_PF_CHANNEL_READY_OFFSET(vf_id) \ + (IRO[3].base + ((vf_id) * IRO[3].m1)) +#define USTORM_VF_PF_CHANNEL_READY_SIZE (IRO[3].size) +#define USTORM_FLR_FINAL_ACK_OFFSET(pf_id) \ + (IRO[4].base + (pf_id) * IRO[4].m1) +#define USTORM_FLR_FINAL_ACK_SIZE (IRO[4].size) +#define USTORM_EQE_CONS_OFFSET(pf_id) \ + (IRO[5].base + ((pf_id) * IRO[5].m1)) +#define USTORM_EQE_CONS_SIZE (IRO[5].size) +#define USTORM_ETH_QUEUE_ZONE_OFFSET(queue_zone_id) \ + (IRO[6].base + ((queue_zone_id) * IRO[6].m1)) +#define USTORM_ETH_QUEUE_ZONE_SIZE (IRO[6].size) +#define USTORM_COMMON_QUEUE_CONS_OFFSET(queue_zone_id) \ + (IRO[7].base + ((queue_zone_id) * IRO[7].m1)) +#define USTORM_COMMON_QUEUE_CONS_SIZE (IRO[7].size) +#define MSTORM_QUEUE_STAT_OFFSET(stat_counter_id) \ + (IRO[18].base + ((stat_counter_id) * IRO[18].m1)) +#define MSTORM_QUEUE_STAT_SIZE (IRO[18].size) +#define MSTORM_ETH_PF_PRODS_OFFSET(queue_id) \ + (IRO[19].base + ((queue_id) * IRO[19].m1)) +#define MSTORM_ETH_PF_PRODS_SIZE (IRO[19].size) +#define MSTORM_TPA_TIMEOUT_US_OFFSET (IRO[20].base) +#define MSTORM_TPA_TIMEOUT_US_SIZE (IRO[20].size) +#define MSTORM_ETH_PF_STAT_OFFSET(pf_id) \ + (IRO[21].base + ((pf_id) * IRO[21].m1)) +#define MSTORM_ETH_PF_STAT_SIZE (IRO[21].size) +#define USTORM_QUEUE_STAT_OFFSET(stat_counter_id) \ + (IRO[22].base + ((stat_counter_id) * IRO[22].m1)) +#define USTORM_QUEUE_STAT_SIZE (IRO[22].size) +#define USTORM_ETH_PF_STAT_OFFSET(pf_id) \ + (IRO[23].base + ((pf_id) * IRO[23].m1)) +#define USTORM_ETH_PF_STAT_SIZE (IRO[23].size) +#define PSTORM_QUEUE_STAT_OFFSET(stat_counter_id) \ + (IRO[24].base + ((stat_counter_id) * IRO[24].m1)) +#define PSTORM_QUEUE_STAT_SIZE (IRO[24].size) +#define PSTORM_ETH_PF_STAT_OFFSET(pf_id) \ + (IRO[25].base + ((pf_id) * IRO[25].m1)) +#define PSTORM_ETH_PF_STAT_SIZE (IRO[25].size) +#define PSTORM_CTL_FRAME_ETHTYPE_OFFSET(ethtype) \ + (IRO[26].base + ((ethtype) * IRO[26].m1)) +#define PSTORM_CTL_FRAME_ETHTYPE_SIZE (IRO[26].size) +#define TSTORM_ETH_PRS_INPUT_OFFSET (IRO[27].base) +#define TSTORM_ETH_PRS_INPUT_SIZE (IRO[27].size) +#define ETH_RX_RATE_LIMIT_OFFSET(pf_id) \ + (IRO[28].base + ((pf_id) * IRO[28].m1)) +#define ETH_RX_RATE_LIMIT_SIZE (IRO[28].size) +#define XSTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) \ + (IRO[29].base + ((queue_id) * IRO[29].m1)) +#define XSTORM_ETH_QUEUE_ZONE_SIZE (IRO[29].size) + +static const struct iro iro_arr[46] = { + {0x0, 0x0, 0x0, 0x0, 0x8}, + {0x4cb0, 0x78, 0x0, 0x0, 0x78}, + {0x6318, 0x20, 0x0, 0x0, 0x20}, + {0xb00, 0x8, 0x0, 0x0, 0x4}, + {0xa80, 0x8, 0x0, 0x0, 0x4}, + {0x0, 0x8, 0x0, 0x0, 0x2}, + {0x80, 0x8, 0x0, 0x0, 0x4}, + {0x84, 0x8, 0x0, 0x0, 0x2}, + {0x4bc0, 0x0, 0x0, 0x0, 0x78}, + {0x3df0, 0x0, 0x0, 0x0, 0x78}, + {0x29b0, 0x0, 0x0, 0x0, 0x78}, + {0x4c38, 0x0, 0x0, 0x0, 0x78}, + {0x4a48, 0x0, 0x0, 0x0, 0x78}, + {0x7e48, 0x0, 0x0, 0x0, 0x78}, + {0xa28, 0x8, 0x0, 0x0, 0x8}, + {0x60f8, 0x10, 0x0, 0x0, 0x10}, + {0xb820, 0x30, 0x0, 0x0, 0x30}, + {0x95b8, 0x30, 0x0, 0x0, 0x30}, + {0x4c18, 0x80, 0x0, 0x0, 0x40}, + {0x1f8, 0x4, 0x0, 0x0, 0x4}, + {0xc9a8, 0x0, 0x0, 0x0, 0x4}, + {0x4c58, 0x80, 0x0, 0x0, 0x20}, + {0x8050, 0x40, 0x0, 0x0, 0x30}, + {0xe770, 0x60, 0x0, 0x0, 0x60}, + {0x2b48, 0x80, 0x0, 0x0, 0x38}, + {0xdf88, 0x78, 0x0, 0x0, 0x78}, + {0x1f8, 0x4, 0x0, 0x0, 0x4}, + {0xacf0, 0x0, 0x0, 0x0, 0xf0}, + {0xade0, 0x8, 0x0, 0x0, 0x8}, + {0x1f8, 0x8, 0x0, 0x0, 0x8}, + {0xac0, 0x8, 0x0, 0x0, 0x8}, + {0x2578, 0x8, 0x0, 0x0, 0x8}, + {0x24f8, 0x8, 0x0, 0x0, 0x8}, + {0x0, 0x8, 0x0, 0x0, 0x8}, + {0x200, 0x10, 0x8, 0x0, 0x8}, + {0xb78, 0x10, 0x8, 0x0, 0x2}, + {0xd888, 0x38, 0x0, 0x0, 0x24}, + {0x12120, 0x10, 0x0, 0x0, 0x8}, + {0x11b20, 0x38, 0x0, 0x0, 0x18}, + {0xa8c0, 0x30, 0x0, 0x0, 0x10}, + {0x86f8, 0x28, 0x0, 0x0, 0x18}, + {0xeff8, 0x10, 0x0, 0x0, 0x10}, + {0xdd08, 0x48, 0x0, 0x0, 0x38}, + {0xf460, 0x20, 0x0, 0x0, 0x20}, + {0x2b80, 0x80, 0x0, 0x0, 0x10}, + {0x5000, 0x10, 0x0, 0x0, 0x10}, }; /* Runtime array offsets */ -#define DORQ_REG_PF_MAX_ICID_0_RT_OFFSET 0 -#define DORQ_REG_PF_MAX_ICID_1_RT_OFFSET 1 -#define DORQ_REG_PF_MAX_ICID_2_RT_OFFSET 2 -#define DORQ_REG_PF_MAX_ICID_3_RT_OFFSET 3 -#define DORQ_REG_PF_MAX_ICID_4_RT_OFFSET 4 -#define DORQ_REG_PF_MAX_ICID_5_RT_OFFSET 5 -#define DORQ_REG_PF_MAX_ICID_6_RT_OFFSET 6 -#define DORQ_REG_PF_MAX_ICID_7_RT_OFFSET 7 -#define DORQ_REG_VF_MAX_ICID_0_RT_OFFSET 8 -#define DORQ_REG_VF_MAX_ICID_1_RT_OFFSET 9 -#define DORQ_REG_VF_MAX_ICID_2_RT_OFFSET 10 -#define DORQ_REG_VF_MAX_ICID_3_RT_OFFSET 11 -#define DORQ_REG_VF_MAX_ICID_4_RT_OFFSET 12 -#define DORQ_REG_VF_MAX_ICID_5_RT_OFFSET 13 -#define DORQ_REG_VF_MAX_ICID_6_RT_OFFSET 14 -#define DORQ_REG_VF_MAX_ICID_7_RT_OFFSET 15 -#define DORQ_REG_PF_WAKE_ALL_RT_OFFSET 16 -#define DORQ_REG_TAG1_ETHERTYPE_RT_OFFSET 17 -#define IGU_REG_PF_CONFIGURATION_RT_OFFSET 18 -#define IGU_REG_VF_CONFIGURATION_RT_OFFSET 19 -#define IGU_REG_ATTN_MSG_ADDR_L_RT_OFFSET 20 -#define IGU_REG_ATTN_MSG_ADDR_H_RT_OFFSET 21 -#define IGU_REG_LEADING_EDGE_LATCH_RT_OFFSET 22 -#define IGU_REG_TRAILING_EDGE_LATCH_RT_OFFSET 23 -#define CAU_REG_CQE_AGG_UNIT_SIZE_RT_OFFSET 24 -#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET 761 -#define CAU_REG_SB_VAR_MEMORY_RT_SIZE 736 -#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET 761 -#define CAU_REG_SB_VAR_MEMORY_RT_SIZE 736 -#define CAU_REG_SB_ADDR_MEMORY_RT_OFFSET 1497 -#define CAU_REG_SB_ADDR_MEMORY_RT_SIZE 736 -#define CAU_REG_PI_MEMORY_RT_OFFSET 2233 -#define CAU_REG_PI_MEMORY_RT_SIZE 4416 -#define PRS_REG_SEARCH_RESP_INITIATOR_TYPE_RT_OFFSET 6649 -#define PRS_REG_TASK_ID_MAX_INITIATOR_PF_RT_OFFSET 6650 -#define PRS_REG_TASK_ID_MAX_INITIATOR_VF_RT_OFFSET 6651 -#define PRS_REG_TASK_ID_MAX_TARGET_PF_RT_OFFSET 6652 -#define PRS_REG_TASK_ID_MAX_TARGET_VF_RT_OFFSET 6653 -#define PRS_REG_SEARCH_TCP_RT_OFFSET 6654 -#define PRS_REG_SEARCH_FCOE_RT_OFFSET 6655 -#define PRS_REG_SEARCH_ROCE_RT_OFFSET 6656 -#define PRS_REG_ROCE_DEST_QP_MAX_VF_RT_OFFSET 6657 -#define PRS_REG_ROCE_DEST_QP_MAX_PF_RT_OFFSET 6658 -#define PRS_REG_SEARCH_OPENFLOW_RT_OFFSET 6659 -#define PRS_REG_SEARCH_NON_IP_AS_OPENFLOW_RT_OFFSET 6660 -#define PRS_REG_OPENFLOW_SUPPORT_ONLY_KNOWN_OVER_IP_RT_OFFSET 6661 -#define PRS_REG_OPENFLOW_SEARCH_KEY_MASK_RT_OFFSET 6662 -#define PRS_REG_TAG_ETHERTYPE_0_RT_OFFSET 6663 -#define PRS_REG_LIGHT_L2_ETHERTYPE_EN_RT_OFFSET 6664 -#define SRC_REG_FIRSTFREE_RT_OFFSET 6665 -#define SRC_REG_FIRSTFREE_RT_SIZE 2 -#define SRC_REG_LASTFREE_RT_OFFSET 6667 -#define SRC_REG_LASTFREE_RT_SIZE 2 -#define SRC_REG_COUNTFREE_RT_OFFSET 6669 -#define SRC_REG_NUMBER_HASH_BITS_RT_OFFSET 6670 -#define PSWRQ2_REG_CDUT_P_SIZE_RT_OFFSET 6671 -#define PSWRQ2_REG_CDUC_P_SIZE_RT_OFFSET 6672 -#define PSWRQ2_REG_TM_P_SIZE_RT_OFFSET 6673 -#define PSWRQ2_REG_QM_P_SIZE_RT_OFFSET 6674 -#define PSWRQ2_REG_SRC_P_SIZE_RT_OFFSET 6675 -#define PSWRQ2_REG_TM_FIRST_ILT_RT_OFFSET 6676 -#define PSWRQ2_REG_TM_LAST_ILT_RT_OFFSET 6677 -#define PSWRQ2_REG_QM_FIRST_ILT_RT_OFFSET 6678 -#define PSWRQ2_REG_QM_LAST_ILT_RT_OFFSET 6679 -#define PSWRQ2_REG_SRC_FIRST_ILT_RT_OFFSET 6680 -#define PSWRQ2_REG_SRC_LAST_ILT_RT_OFFSET 6681 -#define PSWRQ2_REG_CDUC_FIRST_ILT_RT_OFFSET 6682 -#define PSWRQ2_REG_CDUC_LAST_ILT_RT_OFFSET 6683 -#define PSWRQ2_REG_CDUT_FIRST_ILT_RT_OFFSET 6684 -#define PSWRQ2_REG_CDUT_LAST_ILT_RT_OFFSET 6685 -#define PSWRQ2_REG_TSDM_FIRST_ILT_RT_OFFSET 6686 -#define PSWRQ2_REG_TSDM_LAST_ILT_RT_OFFSET 6687 -#define PSWRQ2_REG_TM_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6688 -#define PSWRQ2_REG_CDUT_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6689 -#define PSWRQ2_REG_CDUC_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6690 -#define PSWRQ2_REG_TM_VF_BLOCKS_RT_OFFSET 6691 -#define PSWRQ2_REG_CDUT_VF_BLOCKS_RT_OFFSET 6692 -#define PSWRQ2_REG_CDUC_VF_BLOCKS_RT_OFFSET 6693 -#define PSWRQ2_REG_TM_BLOCKS_FACTOR_RT_OFFSET 6694 -#define PSWRQ2_REG_CDUT_BLOCKS_FACTOR_RT_OFFSET 6695 -#define PSWRQ2_REG_CDUC_BLOCKS_FACTOR_RT_OFFSET 6696 -#define PSWRQ2_REG_VF_BASE_RT_OFFSET 6697 -#define PSWRQ2_REG_VF_LAST_ILT_RT_OFFSET 6698 -#define PSWRQ2_REG_WR_MBS0_RT_OFFSET 6699 -#define PSWRQ2_REG_RD_MBS0_RT_OFFSET 6700 -#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET 6701 -#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET 6702 -#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET 6703 -#define PSWRQ2_REG_ILT_MEMORY_RT_SIZE 22000 -#define PGLUE_REG_B_VF_BASE_RT_OFFSET 28703 -#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET 28704 -#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET 28705 -#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET 28706 -#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET 28707 -#define TM_REG_VF_ENABLE_CONN_RT_OFFSET 28708 -#define TM_REG_PF_ENABLE_CONN_RT_OFFSET 28709 -#define TM_REG_PF_ENABLE_TASK_RT_OFFSET 28710 -#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET 28711 -#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET 28712 -#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET 28713 -#define TM_REG_CONFIG_CONN_MEM_RT_SIZE 416 -#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET 29129 -#define TM_REG_CONFIG_TASK_MEM_RT_SIZE 512 -#define QM_REG_MAXPQSIZE_0_RT_OFFSET 29641 -#define QM_REG_MAXPQSIZE_1_RT_OFFSET 29642 -#define QM_REG_MAXPQSIZE_2_RT_OFFSET 29643 -#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET 29644 -#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET 29645 -#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET 29646 -#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET 29647 -#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET 29648 -#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET 29649 -#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET 29650 -#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET 29651 -#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET 29652 -#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET 29653 -#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET 29654 -#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET 29655 -#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET 29656 -#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET 29657 -#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET 29658 -#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET 29659 -#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET 29660 -#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET 29661 -#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET 29662 -#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET 29663 -#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET 29664 -#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET 29665 -#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET 29666 -#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET 29667 -#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET 29668 -#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET 29669 -#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET 29670 -#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET 29671 -#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET 29672 -#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET 29673 -#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET 29674 -#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET 29675 -#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET 29676 -#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET 29677 -#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET 29678 -#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET 29679 -#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET 29680 -#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET 29681 -#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET 29682 -#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET 29683 -#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET 29684 -#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET 29685 -#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET 29686 -#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET 29687 -#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET 29688 -#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET 29689 -#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET 29690 -#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET 29691 -#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET 29692 -#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET 29693 -#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET 29694 -#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET 29695 -#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET 29696 -#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET 29697 -#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET 29698 -#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET 29699 -#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET 29700 -#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET 29701 -#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET 29702 -#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET 29703 -#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET 29704 -#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET 29705 -#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET 29706 -#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET 29707 -#define QM_REG_BASEADDROTHERPQ_RT_OFFSET 29708 -#define QM_REG_BASEADDROTHERPQ_RT_SIZE 128 -#define QM_REG_VOQCRDLINE_RT_OFFSET 29836 -#define QM_REG_VOQCRDLINE_RT_SIZE 20 -#define QM_REG_VOQINITCRDLINE_RT_OFFSET 29856 -#define QM_REG_VOQINITCRDLINE_RT_SIZE 20 -#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET 29876 -#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET 29877 -#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET 29878 -#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET 29879 -#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET 29880 -#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET 29881 -#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET 29882 -#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET 29883 -#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET 29884 -#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET 29885 -#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET 29886 -#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET 29887 -#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET 29888 -#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET 29889 -#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET 29890 -#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET 29891 -#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET 29892 -#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET 29893 -#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET 29894 -#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET 29895 -#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET 29896 -#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET 29897 -#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET 29898 -#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET 29899 -#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET 29900 -#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET 29901 -#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET 29902 -#define QM_REG_PQTX2PF_0_RT_OFFSET 29903 -#define QM_REG_PQTX2PF_1_RT_OFFSET 29904 -#define QM_REG_PQTX2PF_2_RT_OFFSET 29905 -#define QM_REG_PQTX2PF_3_RT_OFFSET 29906 -#define QM_REG_PQTX2PF_4_RT_OFFSET 29907 -#define QM_REG_PQTX2PF_5_RT_OFFSET 29908 -#define QM_REG_PQTX2PF_6_RT_OFFSET 29909 -#define QM_REG_PQTX2PF_7_RT_OFFSET 29910 -#define QM_REG_PQTX2PF_8_RT_OFFSET 29911 -#define QM_REG_PQTX2PF_9_RT_OFFSET 29912 -#define QM_REG_PQTX2PF_10_RT_OFFSET 29913 -#define QM_REG_PQTX2PF_11_RT_OFFSET 29914 -#define QM_REG_PQTX2PF_12_RT_OFFSET 29915 -#define QM_REG_PQTX2PF_13_RT_OFFSET 29916 -#define QM_REG_PQTX2PF_14_RT_OFFSET 29917 -#define QM_REG_PQTX2PF_15_RT_OFFSET 29918 -#define QM_REG_PQTX2PF_16_RT_OFFSET 29919 -#define QM_REG_PQTX2PF_17_RT_OFFSET 29920 -#define QM_REG_PQTX2PF_18_RT_OFFSET 29921 -#define QM_REG_PQTX2PF_19_RT_OFFSET 29922 -#define QM_REG_PQTX2PF_20_RT_OFFSET 29923 -#define QM_REG_PQTX2PF_21_RT_OFFSET 29924 -#define QM_REG_PQTX2PF_22_RT_OFFSET 29925 -#define QM_REG_PQTX2PF_23_RT_OFFSET 29926 -#define QM_REG_PQTX2PF_24_RT_OFFSET 29927 -#define QM_REG_PQTX2PF_25_RT_OFFSET 29928 -#define QM_REG_PQTX2PF_26_RT_OFFSET 29929 -#define QM_REG_PQTX2PF_27_RT_OFFSET 29930 -#define QM_REG_PQTX2PF_28_RT_OFFSET 29931 -#define QM_REG_PQTX2PF_29_RT_OFFSET 29932 -#define QM_REG_PQTX2PF_30_RT_OFFSET 29933 -#define QM_REG_PQTX2PF_31_RT_OFFSET 29934 -#define QM_REG_PQTX2PF_32_RT_OFFSET 29935 -#define QM_REG_PQTX2PF_33_RT_OFFSET 29936 -#define QM_REG_PQTX2PF_34_RT_OFFSET 29937 -#define QM_REG_PQTX2PF_35_RT_OFFSET 29938 -#define QM_REG_PQTX2PF_36_RT_OFFSET 29939 -#define QM_REG_PQTX2PF_37_RT_OFFSET 29940 -#define QM_REG_PQTX2PF_38_RT_OFFSET 29941 -#define QM_REG_PQTX2PF_39_RT_OFFSET 29942 -#define QM_REG_PQTX2PF_40_RT_OFFSET 29943 -#define QM_REG_PQTX2PF_41_RT_OFFSET 29944 -#define QM_REG_PQTX2PF_42_RT_OFFSET 29945 -#define QM_REG_PQTX2PF_43_RT_OFFSET 29946 -#define QM_REG_PQTX2PF_44_RT_OFFSET 29947 -#define QM_REG_PQTX2PF_45_RT_OFFSET 29948 -#define QM_REG_PQTX2PF_46_RT_OFFSET 29949 -#define QM_REG_PQTX2PF_47_RT_OFFSET 29950 -#define QM_REG_PQTX2PF_48_RT_OFFSET 29951 -#define QM_REG_PQTX2PF_49_RT_OFFSET 29952 -#define QM_REG_PQTX2PF_50_RT_OFFSET 29953 -#define QM_REG_PQTX2PF_51_RT_OFFSET 29954 -#define QM_REG_PQTX2PF_52_RT_OFFSET 29955 -#define QM_REG_PQTX2PF_53_RT_OFFSET 29956 -#define QM_REG_PQTX2PF_54_RT_OFFSET 29957 -#define QM_REG_PQTX2PF_55_RT_OFFSET 29958 -#define QM_REG_PQTX2PF_56_RT_OFFSET 29959 -#define QM_REG_PQTX2PF_57_RT_OFFSET 29960 -#define QM_REG_PQTX2PF_58_RT_OFFSET 29961 -#define QM_REG_PQTX2PF_59_RT_OFFSET 29962 -#define QM_REG_PQTX2PF_60_RT_OFFSET 29963 -#define QM_REG_PQTX2PF_61_RT_OFFSET 29964 -#define QM_REG_PQTX2PF_62_RT_OFFSET 29965 -#define QM_REG_PQTX2PF_63_RT_OFFSET 29966 -#define QM_REG_PQOTHER2PF_0_RT_OFFSET 29967 -#define QM_REG_PQOTHER2PF_1_RT_OFFSET 29968 -#define QM_REG_PQOTHER2PF_2_RT_OFFSET 29969 -#define QM_REG_PQOTHER2PF_3_RT_OFFSET 29970 -#define QM_REG_PQOTHER2PF_4_RT_OFFSET 29971 -#define QM_REG_PQOTHER2PF_5_RT_OFFSET 29972 -#define QM_REG_PQOTHER2PF_6_RT_OFFSET 29973 -#define QM_REG_PQOTHER2PF_7_RT_OFFSET 29974 -#define QM_REG_PQOTHER2PF_8_RT_OFFSET 29975 -#define QM_REG_PQOTHER2PF_9_RT_OFFSET 29976 -#define QM_REG_PQOTHER2PF_10_RT_OFFSET 29977 -#define QM_REG_PQOTHER2PF_11_RT_OFFSET 29978 -#define QM_REG_PQOTHER2PF_12_RT_OFFSET 29979 -#define QM_REG_PQOTHER2PF_13_RT_OFFSET 29980 -#define QM_REG_PQOTHER2PF_14_RT_OFFSET 29981 -#define QM_REG_PQOTHER2PF_15_RT_OFFSET 29982 -#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET 29983 -#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET 29984 -#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET 29985 -#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET 29986 -#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET 29987 -#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET 29988 -#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET 29989 -#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET 29990 -#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET 29991 -#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET 29992 -#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET 29993 -#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET 29994 -#define QM_REG_RLGLBLINCVAL_RT_OFFSET 29995 -#define QM_REG_RLGLBLINCVAL_RT_SIZE 256 -#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET 30251 -#define QM_REG_RLGLBLUPPERBOUND_RT_SIZE 256 -#define QM_REG_RLGLBLCRD_RT_OFFSET 30507 -#define QM_REG_RLGLBLCRD_RT_SIZE 256 -#define QM_REG_RLGLBLENABLE_RT_OFFSET 30763 -#define QM_REG_RLPFPERIOD_RT_OFFSET 30764 -#define QM_REG_RLPFPERIODTIMER_RT_OFFSET 30765 -#define QM_REG_RLPFINCVAL_RT_OFFSET 30766 -#define QM_REG_RLPFINCVAL_RT_SIZE 16 -#define QM_REG_RLPFUPPERBOUND_RT_OFFSET 30782 -#define QM_REG_RLPFUPPERBOUND_RT_SIZE 16 -#define QM_REG_RLPFCRD_RT_OFFSET 30798 -#define QM_REG_RLPFCRD_RT_SIZE 16 -#define QM_REG_RLPFENABLE_RT_OFFSET 30814 -#define QM_REG_RLPFVOQENABLE_RT_OFFSET 30815 -#define QM_REG_WFQPFWEIGHT_RT_OFFSET 30816 -#define QM_REG_WFQPFWEIGHT_RT_SIZE 16 -#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET 30832 -#define QM_REG_WFQPFUPPERBOUND_RT_SIZE 16 -#define QM_REG_WFQPFCRD_RT_OFFSET 30848 -#define QM_REG_WFQPFCRD_RT_SIZE 160 -#define QM_REG_WFQPFENABLE_RT_OFFSET 31008 -#define QM_REG_WFQVPENABLE_RT_OFFSET 31009 -#define QM_REG_BASEADDRTXPQ_RT_OFFSET 31010 -#define QM_REG_BASEADDRTXPQ_RT_SIZE 512 -#define QM_REG_TXPQMAP_RT_OFFSET 31522 -#define QM_REG_TXPQMAP_RT_SIZE 512 -#define QM_REG_WFQVPWEIGHT_RT_OFFSET 32034 -#define QM_REG_WFQVPWEIGHT_RT_SIZE 512 -#define QM_REG_WFQVPCRD_RT_OFFSET 32546 -#define QM_REG_WFQVPCRD_RT_SIZE 512 -#define QM_REG_WFQVPMAP_RT_OFFSET 33058 -#define QM_REG_WFQVPMAP_RT_SIZE 512 -#define QM_REG_WFQPFCRD_MSB_RT_OFFSET 33570 -#define QM_REG_WFQPFCRD_MSB_RT_SIZE 160 -#define NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET 33730 -#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET 33731 -#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET 33732 -#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET 33733 -#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET 33734 -#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET 33735 -#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET 33736 -#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET 33737 -#define NIG_REG_LLH_FUNC_TAG_EN_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET 33741 -#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET 33745 -#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_SIZE 4 -#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET 33749 -#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET 33750 -#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_SIZE 32 -#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET 33782 -#define NIG_REG_LLH_FUNC_FILTER_EN_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET 33798 -#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET 33814 -#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_SIZE 16 -#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET 33830 -#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_SIZE 16 -#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET 33846 -#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET 33847 -#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET 33848 -#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET 33849 -#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET 33850 -#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET 33851 -#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET 33852 -#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET 33853 -#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET 33854 -#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET 33855 -#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET 33856 -#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET 33857 -#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET 33858 -#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET 33859 -#define PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET 33860 -#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET 33861 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET 33862 -#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET 33863 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET 33864 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET 33865 -#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET 33866 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET 33867 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET 33868 -#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET 33869 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET 33870 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET 33871 -#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET 33872 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET 33873 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET 33874 -#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET 33875 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET 33876 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET 33877 -#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET 33878 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET 33879 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET 33880 -#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET 33881 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET 33882 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET 33883 -#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET 33884 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET 33885 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET 33886 -#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET 33887 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET 33888 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET 33889 -#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET 33890 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET 33891 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET 33892 -#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET 33893 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET 33894 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET 33895 -#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET 33896 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET 33897 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET 33898 -#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET 33899 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET 33900 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET 33901 -#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET 33902 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET 33903 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET 33904 -#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET 33905 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET 33906 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET 33907 -#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET 33908 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET 33909 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET 33910 -#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET 33911 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET 33912 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET 33913 -#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET 33914 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET 33915 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET 33916 -#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET 33917 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET 33918 -#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET 33919 -#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET 33920 -#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET 33921 -#define XCM_REG_CON_PHY_Q3_RT_OFFSET 33922 - -#define RUNTIME_ARRAY_SIZE 33923 +#define DORQ_REG_PF_MAX_ICID_0_RT_OFFSET 0 +#define DORQ_REG_PF_MAX_ICID_1_RT_OFFSET 1 +#define DORQ_REG_PF_MAX_ICID_2_RT_OFFSET 2 +#define DORQ_REG_PF_MAX_ICID_3_RT_OFFSET 3 +#define DORQ_REG_PF_MAX_ICID_4_RT_OFFSET 4 +#define DORQ_REG_PF_MAX_ICID_5_RT_OFFSET 5 +#define DORQ_REG_PF_MAX_ICID_6_RT_OFFSET 6 +#define DORQ_REG_PF_MAX_ICID_7_RT_OFFSET 7 +#define DORQ_REG_VF_MAX_ICID_0_RT_OFFSET 8 +#define DORQ_REG_VF_MAX_ICID_1_RT_OFFSET 9 +#define DORQ_REG_VF_MAX_ICID_2_RT_OFFSET 10 +#define DORQ_REG_VF_MAX_ICID_3_RT_OFFSET 11 +#define DORQ_REG_VF_MAX_ICID_4_RT_OFFSET 12 +#define DORQ_REG_VF_MAX_ICID_5_RT_OFFSET 13 +#define DORQ_REG_VF_MAX_ICID_6_RT_OFFSET 14 +#define DORQ_REG_VF_MAX_ICID_7_RT_OFFSET 15 +#define DORQ_REG_PF_WAKE_ALL_RT_OFFSET 16 +#define DORQ_REG_TAG1_ETHERTYPE_RT_OFFSET 17 +#define IGU_REG_PF_CONFIGURATION_RT_OFFSET 18 +#define IGU_REG_VF_CONFIGURATION_RT_OFFSET 19 +#define IGU_REG_ATTN_MSG_ADDR_L_RT_OFFSET 20 +#define IGU_REG_ATTN_MSG_ADDR_H_RT_OFFSET 21 +#define IGU_REG_LEADING_EDGE_LATCH_RT_OFFSET 22 +#define IGU_REG_TRAILING_EDGE_LATCH_RT_OFFSET 23 +#define CAU_REG_CQE_AGG_UNIT_SIZE_RT_OFFSET 24 +#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET 761 +#define CAU_REG_SB_VAR_MEMORY_RT_SIZE 736 +#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET 761 +#define CAU_REG_SB_VAR_MEMORY_RT_SIZE 736 +#define CAU_REG_SB_ADDR_MEMORY_RT_OFFSET 1497 +#define CAU_REG_SB_ADDR_MEMORY_RT_SIZE 736 +#define CAU_REG_PI_MEMORY_RT_OFFSET 2233 +#define CAU_REG_PI_MEMORY_RT_SIZE 4416 +#define PRS_REG_SEARCH_RESP_INITIATOR_TYPE_RT_OFFSET 6649 +#define PRS_REG_TASK_ID_MAX_INITIATOR_PF_RT_OFFSET 6650 +#define PRS_REG_TASK_ID_MAX_INITIATOR_VF_RT_OFFSET 6651 +#define PRS_REG_TASK_ID_MAX_TARGET_PF_RT_OFFSET 6652 +#define PRS_REG_TASK_ID_MAX_TARGET_VF_RT_OFFSET 6653 +#define PRS_REG_SEARCH_TCP_RT_OFFSET 6654 +#define PRS_REG_SEARCH_FCOE_RT_OFFSET 6655 +#define PRS_REG_SEARCH_ROCE_RT_OFFSET 6656 +#define PRS_REG_ROCE_DEST_QP_MAX_VF_RT_OFFSET 6657 +#define PRS_REG_ROCE_DEST_QP_MAX_PF_RT_OFFSET 6658 +#define PRS_REG_SEARCH_OPENFLOW_RT_OFFSET 6659 +#define PRS_REG_SEARCH_NON_IP_AS_OPENFLOW_RT_OFFSET 6660 +#define PRS_REG_OPENFLOW_SUPPORT_ONLY_KNOWN_OVER_IP_RT_OFFSET 6661 +#define PRS_REG_OPENFLOW_SEARCH_KEY_MASK_RT_OFFSET 6662 +#define PRS_REG_TAG_ETHERTYPE_0_RT_OFFSET 6663 +#define PRS_REG_LIGHT_L2_ETHERTYPE_EN_RT_OFFSET 6664 +#define SRC_REG_FIRSTFREE_RT_OFFSET 6665 +#define SRC_REG_FIRSTFREE_RT_SIZE 2 +#define SRC_REG_LASTFREE_RT_OFFSET 6667 +#define SRC_REG_LASTFREE_RT_SIZE 2 +#define SRC_REG_COUNTFREE_RT_OFFSET 6669 +#define SRC_REG_NUMBER_HASH_BITS_RT_OFFSET 6670 +#define PSWRQ2_REG_CDUT_P_SIZE_RT_OFFSET 6671 +#define PSWRQ2_REG_CDUC_P_SIZE_RT_OFFSET 6672 +#define PSWRQ2_REG_TM_P_SIZE_RT_OFFSET 6673 +#define PSWRQ2_REG_QM_P_SIZE_RT_OFFSET 6674 +#define PSWRQ2_REG_SRC_P_SIZE_RT_OFFSET 6675 +#define PSWRQ2_REG_TSDM_P_SIZE_RT_OFFSET 6676 +#define PSWRQ2_REG_TM_FIRST_ILT_RT_OFFSET 6677 +#define PSWRQ2_REG_TM_LAST_ILT_RT_OFFSET 6678 +#define PSWRQ2_REG_QM_FIRST_ILT_RT_OFFSET 6679 +#define PSWRQ2_REG_QM_LAST_ILT_RT_OFFSET 6680 +#define PSWRQ2_REG_SRC_FIRST_ILT_RT_OFFSET 6681 +#define PSWRQ2_REG_SRC_LAST_ILT_RT_OFFSET 6682 +#define PSWRQ2_REG_CDUC_FIRST_ILT_RT_OFFSET 6683 +#define PSWRQ2_REG_CDUC_LAST_ILT_RT_OFFSET 6684 +#define PSWRQ2_REG_CDUT_FIRST_ILT_RT_OFFSET 6685 +#define PSWRQ2_REG_CDUT_LAST_ILT_RT_OFFSET 6686 +#define PSWRQ2_REG_TSDM_FIRST_ILT_RT_OFFSET 6687 +#define PSWRQ2_REG_TSDM_LAST_ILT_RT_OFFSET 6688 +#define PSWRQ2_REG_TM_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6689 +#define PSWRQ2_REG_CDUT_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6690 +#define PSWRQ2_REG_CDUC_NUMBER_OF_PF_BLOCKS_RT_OFFSET 6691 +#define PSWRQ2_REG_TM_VF_BLOCKS_RT_OFFSET 6692 +#define PSWRQ2_REG_CDUT_VF_BLOCKS_RT_OFFSET 6693 +#define PSWRQ2_REG_CDUC_VF_BLOCKS_RT_OFFSET 6694 +#define PSWRQ2_REG_TM_BLOCKS_FACTOR_RT_OFFSET 6695 +#define PSWRQ2_REG_CDUT_BLOCKS_FACTOR_RT_OFFSET 6696 +#define PSWRQ2_REG_CDUC_BLOCKS_FACTOR_RT_OFFSET 6697 +#define PSWRQ2_REG_VF_BASE_RT_OFFSET 6698 +#define PSWRQ2_REG_VF_LAST_ILT_RT_OFFSET 6699 +#define PSWRQ2_REG_WR_MBS0_RT_OFFSET 6700 +#define PSWRQ2_REG_RD_MBS0_RT_OFFSET 6701 +#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET 6702 +#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET 6703 +#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET 6704 +#define PSWRQ2_REG_ILT_MEMORY_RT_SIZE 22000 +#define PGLUE_REG_B_VF_BASE_RT_OFFSET 28704 +#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET 28705 +#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET 28706 +#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET 28707 +#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET 28708 +#define TM_REG_VF_ENABLE_CONN_RT_OFFSET 28709 +#define TM_REG_PF_ENABLE_CONN_RT_OFFSET 28710 +#define TM_REG_PF_ENABLE_TASK_RT_OFFSET 28711 +#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET 28712 +#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET 28713 +#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET 28714 +#define TM_REG_CONFIG_CONN_MEM_RT_SIZE 416 +#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET 29130 +#define TM_REG_CONFIG_TASK_MEM_RT_SIZE 512 +#define QM_REG_MAXPQSIZE_0_RT_OFFSET 29642 +#define QM_REG_MAXPQSIZE_1_RT_OFFSET 29643 +#define QM_REG_MAXPQSIZE_2_RT_OFFSET 29644 +#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET 29645 +#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET 29646 +#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET 29647 +#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET 29648 +#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET 29649 +#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET 29650 +#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET 29651 +#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET 29652 +#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET 29653 +#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET 29654 +#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET 29655 +#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET 29656 +#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET 29657 +#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET 29658 +#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET 29659 +#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET 29660 +#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET 29661 +#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET 29662 +#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET 29663 +#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET 29664 +#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET 29665 +#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET 29666 +#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET 29667 +#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET 29668 +#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET 29669 +#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET 29670 +#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET 29671 +#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET 29672 +#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET 29673 +#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET 29674 +#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET 29675 +#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET 29676 +#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET 29677 +#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET 29678 +#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET 29679 +#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET 29680 +#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET 29681 +#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET 29682 +#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET 29683 +#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET 29684 +#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET 29685 +#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET 29686 +#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET 29687 +#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET 29688 +#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET 29689 +#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET 29690 +#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET 29691 +#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET 29692 +#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET 29693 +#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET 29694 +#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET 29695 +#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET 29696 +#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET 29697 +#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET 29698 +#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET 29699 +#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET 29700 +#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET 29701 +#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET 29702 +#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET 29703 +#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET 29704 +#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET 29705 +#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET 29706 +#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET 29707 +#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET 29708 +#define QM_REG_BASEADDROTHERPQ_RT_OFFSET 29709 +#define QM_REG_BASEADDROTHERPQ_RT_SIZE 128 +#define QM_REG_VOQCRDLINE_RT_OFFSET 29837 +#define QM_REG_VOQCRDLINE_RT_SIZE 20 +#define QM_REG_VOQINITCRDLINE_RT_OFFSET 29857 +#define QM_REG_VOQINITCRDLINE_RT_SIZE 20 +#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET 29877 +#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET 29878 +#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET 29879 +#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET 29880 +#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET 29881 +#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET 29882 +#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET 29883 +#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET 29884 +#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET 29885 +#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET 29886 +#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET 29887 +#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET 29888 +#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET 29889 +#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET 29890 +#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET 29891 +#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET 29892 +#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET 29893 +#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET 29894 +#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET 29895 +#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET 29896 +#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET 29897 +#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET 29898 +#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET 29899 +#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET 29900 +#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET 29901 +#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET 29902 +#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET 29903 +#define QM_REG_PQTX2PF_0_RT_OFFSET 29904 +#define QM_REG_PQTX2PF_1_RT_OFFSET 29905 +#define QM_REG_PQTX2PF_2_RT_OFFSET 29906 +#define QM_REG_PQTX2PF_3_RT_OFFSET 29907 +#define QM_REG_PQTX2PF_4_RT_OFFSET 29908 +#define QM_REG_PQTX2PF_5_RT_OFFSET 29909 +#define QM_REG_PQTX2PF_6_RT_OFFSET 29910 +#define QM_REG_PQTX2PF_7_RT_OFFSET 29911 +#define QM_REG_PQTX2PF_8_RT_OFFSET 29912 +#define QM_REG_PQTX2PF_9_RT_OFFSET 29913 +#define QM_REG_PQTX2PF_10_RT_OFFSET 29914 +#define QM_REG_PQTX2PF_11_RT_OFFSET 29915 +#define QM_REG_PQTX2PF_12_RT_OFFSET 29916 +#define QM_REG_PQTX2PF_13_RT_OFFSET 29917 +#define QM_REG_PQTX2PF_14_RT_OFFSET 29918 +#define QM_REG_PQTX2PF_15_RT_OFFSET 29919 +#define QM_REG_PQTX2PF_16_RT_OFFSET 29920 +#define QM_REG_PQTX2PF_17_RT_OFFSET 29921 +#define QM_REG_PQTX2PF_18_RT_OFFSET 29922 +#define QM_REG_PQTX2PF_19_RT_OFFSET 29923 +#define QM_REG_PQTX2PF_20_RT_OFFSET 29924 +#define QM_REG_PQTX2PF_21_RT_OFFSET 29925 +#define QM_REG_PQTX2PF_22_RT_OFFSET 29926 +#define QM_REG_PQTX2PF_23_RT_OFFSET 29927 +#define QM_REG_PQTX2PF_24_RT_OFFSET 29928 +#define QM_REG_PQTX2PF_25_RT_OFFSET 29929 +#define QM_REG_PQTX2PF_26_RT_OFFSET 29930 +#define QM_REG_PQTX2PF_27_RT_OFFSET 29931 +#define QM_REG_PQTX2PF_28_RT_OFFSET 29932 +#define QM_REG_PQTX2PF_29_RT_OFFSET 29933 +#define QM_REG_PQTX2PF_30_RT_OFFSET 29934 +#define QM_REG_PQTX2PF_31_RT_OFFSET 29935 +#define QM_REG_PQTX2PF_32_RT_OFFSET 29936 +#define QM_REG_PQTX2PF_33_RT_OFFSET 29937 +#define QM_REG_PQTX2PF_34_RT_OFFSET 29938 +#define QM_REG_PQTX2PF_35_RT_OFFSET 29939 +#define QM_REG_PQTX2PF_36_RT_OFFSET 29940 +#define QM_REG_PQTX2PF_37_RT_OFFSET 29941 +#define QM_REG_PQTX2PF_38_RT_OFFSET 29942 +#define QM_REG_PQTX2PF_39_RT_OFFSET 29943 +#define QM_REG_PQTX2PF_40_RT_OFFSET 29944 +#define QM_REG_PQTX2PF_41_RT_OFFSET 29945 +#define QM_REG_PQTX2PF_42_RT_OFFSET 29946 +#define QM_REG_PQTX2PF_43_RT_OFFSET 29947 +#define QM_REG_PQTX2PF_44_RT_OFFSET 29948 +#define QM_REG_PQTX2PF_45_RT_OFFSET 29949 +#define QM_REG_PQTX2PF_46_RT_OFFSET 29950 +#define QM_REG_PQTX2PF_47_RT_OFFSET 29951 +#define QM_REG_PQTX2PF_48_RT_OFFSET 29952 +#define QM_REG_PQTX2PF_49_RT_OFFSET 29953 +#define QM_REG_PQTX2PF_50_RT_OFFSET 29954 +#define QM_REG_PQTX2PF_51_RT_OFFSET 29955 +#define QM_REG_PQTX2PF_52_RT_OFFSET 29956 +#define QM_REG_PQTX2PF_53_RT_OFFSET 29957 +#define QM_REG_PQTX2PF_54_RT_OFFSET 29958 +#define QM_REG_PQTX2PF_55_RT_OFFSET 29959 +#define QM_REG_PQTX2PF_56_RT_OFFSET 29960 +#define QM_REG_PQTX2PF_57_RT_OFFSET 29961 +#define QM_REG_PQTX2PF_58_RT_OFFSET 29962 +#define QM_REG_PQTX2PF_59_RT_OFFSET 29963 +#define QM_REG_PQTX2PF_60_RT_OFFSET 29964 +#define QM_REG_PQTX2PF_61_RT_OFFSET 29965 +#define QM_REG_PQTX2PF_62_RT_OFFSET 29966 +#define QM_REG_PQTX2PF_63_RT_OFFSET 29967 +#define QM_REG_PQOTHER2PF_0_RT_OFFSET 29968 +#define QM_REG_PQOTHER2PF_1_RT_OFFSET 29969 +#define QM_REG_PQOTHER2PF_2_RT_OFFSET 29970 +#define QM_REG_PQOTHER2PF_3_RT_OFFSET 29971 +#define QM_REG_PQOTHER2PF_4_RT_OFFSET 29972 +#define QM_REG_PQOTHER2PF_5_RT_OFFSET 29973 +#define QM_REG_PQOTHER2PF_6_RT_OFFSET 29974 +#define QM_REG_PQOTHER2PF_7_RT_OFFSET 29975 +#define QM_REG_PQOTHER2PF_8_RT_OFFSET 29976 +#define QM_REG_PQOTHER2PF_9_RT_OFFSET 29977 +#define QM_REG_PQOTHER2PF_10_RT_OFFSET 29978 +#define QM_REG_PQOTHER2PF_11_RT_OFFSET 29979 +#define QM_REG_PQOTHER2PF_12_RT_OFFSET 29980 +#define QM_REG_PQOTHER2PF_13_RT_OFFSET 29981 +#define QM_REG_PQOTHER2PF_14_RT_OFFSET 29982 +#define QM_REG_PQOTHER2PF_15_RT_OFFSET 29983 +#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET 29984 +#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET 29985 +#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET 29986 +#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET 29987 +#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET 29988 +#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET 29989 +#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET 29990 +#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET 29991 +#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET 29992 +#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET 29993 +#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET 29994 +#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET 29995 +#define QM_REG_RLGLBLINCVAL_RT_OFFSET 29996 +#define QM_REG_RLGLBLINCVAL_RT_SIZE 256 +#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET 30252 +#define QM_REG_RLGLBLUPPERBOUND_RT_SIZE 256 +#define QM_REG_RLGLBLCRD_RT_OFFSET 30508 +#define QM_REG_RLGLBLCRD_RT_SIZE 256 +#define QM_REG_RLGLBLENABLE_RT_OFFSET 30764 +#define QM_REG_RLPFPERIOD_RT_OFFSET 30765 +#define QM_REG_RLPFPERIODTIMER_RT_OFFSET 30766 +#define QM_REG_RLPFINCVAL_RT_OFFSET 30767 +#define QM_REG_RLPFINCVAL_RT_SIZE 16 +#define QM_REG_RLPFUPPERBOUND_RT_OFFSET 30783 +#define QM_REG_RLPFUPPERBOUND_RT_SIZE 16 +#define QM_REG_RLPFCRD_RT_OFFSET 30799 +#define QM_REG_RLPFCRD_RT_SIZE 16 +#define QM_REG_RLPFENABLE_RT_OFFSET 30815 +#define QM_REG_RLPFVOQENABLE_RT_OFFSET 30816 +#define QM_REG_WFQPFWEIGHT_RT_OFFSET 30817 +#define QM_REG_WFQPFWEIGHT_RT_SIZE 16 +#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET 30833 +#define QM_REG_WFQPFUPPERBOUND_RT_SIZE 16 +#define QM_REG_WFQPFCRD_RT_OFFSET 30849 +#define QM_REG_WFQPFCRD_RT_SIZE 160 +#define QM_REG_WFQPFENABLE_RT_OFFSET 31009 +#define QM_REG_WFQVPENABLE_RT_OFFSET 31010 +#define QM_REG_BASEADDRTXPQ_RT_OFFSET 31011 +#define QM_REG_BASEADDRTXPQ_RT_SIZE 512 +#define QM_REG_TXPQMAP_RT_OFFSET 31523 +#define QM_REG_TXPQMAP_RT_SIZE 512 +#define QM_REG_WFQVPWEIGHT_RT_OFFSET 32035 +#define QM_REG_WFQVPWEIGHT_RT_SIZE 512 +#define QM_REG_WFQVPCRD_RT_OFFSET 32547 +#define QM_REG_WFQVPCRD_RT_SIZE 512 +#define QM_REG_WFQVPMAP_RT_OFFSET 33059 +#define QM_REG_WFQVPMAP_RT_SIZE 512 +#define QM_REG_WFQPFCRD_MSB_RT_OFFSET 33571 +#define QM_REG_WFQPFCRD_MSB_RT_SIZE 160 +#define NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET 33731 +#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET 33732 +#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET 33733 +#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET 33734 +#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET 33735 +#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET 33736 +#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET 33737 +#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET 33738 +#define NIG_REG_LLH_FUNC_TAG_EN_RT_SIZE 4 +#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET 33742 +#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_SIZE 4 +#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET 33746 +#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_SIZE 4 +#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET 33750 +#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET 33751 +#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_SIZE 32 +#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET 33783 +#define NIG_REG_LLH_FUNC_FILTER_EN_RT_SIZE 16 +#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET 33799 +#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_SIZE 16 +#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET 33815 +#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_SIZE 16 +#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET 33831 +#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_SIZE 16 +#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET 33847 +#define NIG_REG_ROCE_DUPLICATE_TO_HOST_RT_OFFSET 33848 +#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET 33849 +#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET 33850 +#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET 33851 +#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET 33852 +#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET 33853 +#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET 33854 +#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET 33855 +#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET 33856 +#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET 33857 +#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET 33858 +#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET 33859 +#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET 33860 +#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET 33861 +#define PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET 33862 +#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET 33863 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET 33864 +#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET 33865 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET 33866 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET 33867 +#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET 33868 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET 33869 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET 33870 +#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET 33871 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET 33872 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET 33873 +#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET 33874 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET 33875 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET 33876 +#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET 33877 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET 33878 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET 33879 +#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET 33880 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET 33881 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET 33882 +#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET 33883 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET 33884 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET 33885 +#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET 33886 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET 33887 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET 33888 +#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET 33889 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET 33890 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET 33891 +#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET 33892 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET 33893 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET 33894 +#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET 33895 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET 33896 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET 33897 +#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET 33898 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET 33899 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET 33900 +#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET 33901 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET 33902 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET 33903 +#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET 33904 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET 33905 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET 33906 +#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET 33907 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET 33908 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET 33909 +#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET 33910 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET 33911 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET 33912 +#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET 33913 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET 33914 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET 33915 +#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET 33916 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET 33917 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET 33918 +#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET 33919 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET 33920 +#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET 33921 +#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET 33922 +#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET 33923 +#define XCM_REG_CON_PHY_Q3_RT_OFFSET 33924 + +#define RUNTIME_ARRAY_SIZE 33925 /* The eth storm context for the Tstorm */ struct tstorm_eth_conn_st_ctx { @@ -2380,266 +2687,266 @@ struct xstorm_eth_conn_st_ctx { }; struct xstorm_eth_conn_ag_ctx { - u8 reserved0 /* cdu_validation */; - u8 eth_state /* state */; - u8 flags0; -#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 -#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED1_MASK 0x1 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED1_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED2_MASK 0x1 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED2_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 -#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED3_MASK 0x1 /* bit4 */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED3_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED4_MASK 0x1 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED4_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED5_MASK 0x1 /* bit6 */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED5_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED6_MASK 0x1 /* bit7 */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED6_SHIFT 7 - u8 flags1; -#define XSTORM_ETH_CONN_AG_CTX_RESERVED7_MASK 0x1 /* bit8 */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED7_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED8_MASK 0x1 /* bit9 */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED8_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED9_MASK 0x1 /* bit10 */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED9_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_BIT11_MASK 0x1 /* bit11 */ -#define XSTORM_ETH_CONN_AG_CTX_BIT11_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_BIT12_MASK 0x1 /* bit12 */ -#define XSTORM_ETH_CONN_AG_CTX_BIT12_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_BIT13_MASK 0x1 /* bit13 */ -#define XSTORM_ETH_CONN_AG_CTX_BIT13_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_TX_RULE_ACTIVE_MASK 0x1 /* bit14 */ -#define XSTORM_ETH_CONN_AG_CTX_TX_RULE_ACTIVE_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_ACTIVE_MASK 0x1 /* bit15 */ -#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT 7 + u8 reserved0; + u8 eth_state; + u8 flags0; +#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED1_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED1_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED2_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED3_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED4_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED4_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED5_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED5_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED6_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED6_SHIFT 7 + u8 flags1; +#define XSTORM_ETH_CONN_AG_CTX_RESERVED7_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED7_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED8_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED8_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED9_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED9_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_TX_RULE_ACTIVE_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_TX_RULE_ACTIVE_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_ACTIVE_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT 7 u8 flags2; -#define XSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ -#define XSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ -#define XSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ -#define XSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 -#define XSTORM_ETH_CONN_AG_CTX_CF3_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF3_SHIFT 6 u8 flags3; -#define XSTORM_ETH_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ -#define XSTORM_ETH_CONN_AG_CTX_CF4_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ -#define XSTORM_ETH_CONN_AG_CTX_CF5_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ -#define XSTORM_ETH_CONN_AG_CTX_CF6_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ -#define XSTORM_ETH_CONN_AG_CTX_CF7_SHIFT 6 - u8 flags4; -#define XSTORM_ETH_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ -#define XSTORM_ETH_CONN_AG_CTX_CF8_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ -#define XSTORM_ETH_CONN_AG_CTX_CF9_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ -#define XSTORM_ETH_CONN_AG_CTX_CF10_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_CF11_MASK 0x3 /* cf11 */ -#define XSTORM_ETH_CONN_AG_CTX_CF11_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_CF4_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF5_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF6_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF7_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF7_SHIFT 6 + u8 flags4; +#define XSTORM_ETH_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF11_SHIFT 6 u8 flags5; -#define XSTORM_ETH_CONN_AG_CTX_CF12_MASK 0x3 /* cf12 */ -#define XSTORM_ETH_CONN_AG_CTX_CF12_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_CF13_MASK 0x3 /* cf13 */ -#define XSTORM_ETH_CONN_AG_CTX_CF13_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_CF14_MASK 0x3 /* cf14 */ -#define XSTORM_ETH_CONN_AG_CTX_CF14_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_CF15_MASK 0x3 /* cf15 */ -#define XSTORM_ETH_CONN_AG_CTX_CF15_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF14_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF14_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF15_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_CF15_SHIFT 6 u8 flags6; -#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_MASK 0x3 /* cf16 */ -#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_MASK 0x3 -#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_MASK 0x3 /* cf18 */ -#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_MASK 0x3 /* cf19 */ -#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_SHIFT 6 u8 flags7; -#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 /* cf20 */ -#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED10_MASK 0x3 /* cf21 */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED10_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_MASK 0x3 /* cf22 */ -#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ -#define XSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ -#define XSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 7 +#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED10_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED10_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 7 u8 flags8; -#define XSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ -#define XSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ -#define XSTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ -#define XSTORM_ETH_CONN_AG_CTX_CF4EN_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ -#define XSTORM_ETH_CONN_AG_CTX_CF5EN_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ -#define XSTORM_ETH_CONN_AG_CTX_CF6EN_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ -#define XSTORM_ETH_CONN_AG_CTX_CF7EN_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ -#define XSTORM_ETH_CONN_AG_CTX_CF8EN_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ -#define XSTORM_ETH_CONN_AG_CTX_CF9EN_SHIFT 7 +#define XSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_CF4EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF5EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_CF6EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF7EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF7EN_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF9EN_SHIFT 7 u8 flags9; -#define XSTORM_ETH_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ -#define XSTORM_ETH_CONN_AG_CTX_CF10EN_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_CF11EN_MASK 0x1 /* cf11en */ -#define XSTORM_ETH_CONN_AG_CTX_CF11EN_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_CF12EN_MASK 0x1 /* cf12en */ -#define XSTORM_ETH_CONN_AG_CTX_CF12EN_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_CF13EN_MASK 0x1 /* cf13en */ -#define XSTORM_ETH_CONN_AG_CTX_CF13EN_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_CF14EN_MASK 0x1 /* cf14en */ -#define XSTORM_ETH_CONN_AG_CTX_CF14EN_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_CF15EN_MASK 0x1 /* cf15en */ -#define XSTORM_ETH_CONN_AG_CTX_CF15EN_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_MASK 0x1 /* cf16en */ -#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_EN_MASK 0x1 -#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_EN_SHIFT 7 +#define XSTORM_ETH_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_CF14EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF14EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_CF15EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_MULTI_UNICAST_CF_EN_SHIFT 7 u8 flags10; -#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_EN_MASK 0x1 /* cf18en */ -#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_EN_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_EN_MASK 0x1 /* cf19en */ -#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_EN_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 /* cf20en */ -#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED11_MASK 0x1 /* cf21en */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED11_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 /* cf22en */ -#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_MASK 0x1 /* cf23en */ +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_DQ_CF_EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_TERMINATE_CF_EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED11_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED11_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_MASK 0x1 #define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED12_MASK 0x1 /* rule0en */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED12_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED13_MASK 0x1 /* rule1en */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED13_SHIFT 7 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED12_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED12_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED13_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED13_SHIFT 7 u8 flags11; -#define XSTORM_ETH_CONN_AG_CTX_RESERVED14_MASK 0x1 /* rule2en */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED14_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_RESERVED15_MASK 0x1 /* rule3en */ -#define XSTORM_ETH_CONN_AG_CTX_RESERVED15_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_TX_DEC_RULE_EN_MASK 0x1 /* rule4en */ -#define XSTORM_ETH_CONN_AG_CTX_TX_DEC_RULE_EN_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE6EN_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 /* rule8en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_RULE9EN_MASK 0x1 /* rule9en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE9EN_SHIFT 7 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED14_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED14_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED15_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RESERVED15_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_TX_DEC_RULE_EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_TX_DEC_RULE_EN_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE9EN_SHIFT 7 u8 flags12; -#define XSTORM_ETH_CONN_AG_CTX_RULE10EN_MASK 0x1 /* rule10en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE10EN_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_RULE11EN_MASK 0x1 /* rule11en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE11EN_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 /* rule12en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 /* rule13en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_RULE14EN_MASK 0x1 /* rule14en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE14EN_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_RULE15EN_MASK 0x1 /* rule15en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE15EN_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_RULE16EN_MASK 0x1 /* rule16en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE16EN_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_RULE17EN_MASK 0x1 /* rule17en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE17EN_SHIFT 7 +#define XSTORM_ETH_CONN_AG_CTX_RULE10EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE10EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RULE11EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_RULE14EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE14EN_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_RULE16EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_RULE17EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE17EN_SHIFT 7 u8 flags13; -#define XSTORM_ETH_CONN_AG_CTX_RULE18EN_MASK 0x1 /* rule18en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE18EN_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_RULE19EN_MASK 0x1 /* rule19en */ -#define XSTORM_ETH_CONN_AG_CTX_RULE19EN_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 /* rule20en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 /* rule21en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 /* rule22en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 /* rule23en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 /* rule24en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 /* rule25en */ -#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 +#define XSTORM_ETH_CONN_AG_CTX_RULE18EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE18EN_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_RULE19EN_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_RULE19EN_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 u8 flags14; -#define XSTORM_ETH_CONN_AG_CTX_EDPM_USE_EXT_HDR_MASK 0x1 /* bit16 */ -#define XSTORM_ETH_CONN_AG_CTX_EDPM_USE_EXT_HDR_SHIFT 0 -#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_MASK 0x1 /* bit17 */ -#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_SHIFT 1 -#define XSTORM_ETH_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_MASK 0x1 /* bit18 */ -#define XSTORM_ETH_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_SHIFT 2 -#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_MASK 0x1 /* bit19 */ -#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_SHIFT 3 -#define XSTORM_ETH_CONN_AG_CTX_L2_EDPM_ENABLE_MASK 0x1 /* bit20 */ -#define XSTORM_ETH_CONN_AG_CTX_L2_EDPM_ENABLE_SHIFT 4 -#define XSTORM_ETH_CONN_AG_CTX_ROCE_EDPM_ENABLE_MASK 0x1 /* bit21 */ -#define XSTORM_ETH_CONN_AG_CTX_ROCE_EDPM_ENABLE_SHIFT 5 -#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_MASK 0x3 /* cf23 */ -#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_SHIFT 6 - u8 edpm_event_id /* byte2 */; - __le16 physical_q0 /* physical_q0 */; - __le16 word1 /* physical_q1 */; - __le16 edpm_num_bds /* physical_q2 */; - __le16 tx_bd_cons /* word3 */; - __le16 tx_bd_prod /* word4 */; - __le16 go_to_bd_cons /* word5 */; - __le16 conn_dpi /* conn_dpi */; - u8 byte3 /* byte3 */; - u8 byte4 /* byte4 */; - u8 byte5 /* byte5 */; - u8 byte6 /* byte6 */; - __le32 reg0 /* reg0 */; - __le32 reg1 /* reg1 */; - __le32 reg2 /* reg2 */; - __le32 reg3 /* reg3 */; - __le32 reg4 /* reg4 */; - __le32 reg5 /* cf_array0 */; - __le32 reg6 /* cf_array1 */; - __le16 word7 /* word7 */; - __le16 word8 /* word8 */; - __le16 word9 /* word9 */; - __le16 word10 /* word10 */; - __le32 reg7 /* reg7 */; - __le32 reg8 /* reg8 */; - __le32 reg9 /* reg9 */; - u8 byte7 /* byte7 */; - u8 byte8 /* byte8 */; - u8 byte9 /* byte9 */; - u8 byte10 /* byte10 */; - u8 byte11 /* byte11 */; - u8 byte12 /* byte12 */; - u8 byte13 /* byte13 */; - u8 byte14 /* byte14 */; - u8 byte15 /* byte15 */; - u8 byte16 /* byte16 */; - __le16 word11 /* word11 */; - __le32 reg10 /* reg10 */; - __le32 reg11 /* reg11 */; - __le32 reg12 /* reg12 */; - __le32 reg13 /* reg13 */; - __le32 reg14 /* reg14 */; - __le32 reg15 /* reg15 */; - __le32 reg16 /* reg16 */; - __le32 reg17 /* reg17 */; - __le32 reg18 /* reg18 */; - __le32 reg19 /* reg19 */; - __le16 word12 /* word12 */; - __le16 word13 /* word13 */; - __le16 word14 /* word14 */; - __le16 word15 /* word15 */; +#define XSTORM_ETH_CONN_AG_CTX_EDPM_USE_EXT_HDR_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_USE_EXT_HDR_SHIFT 0 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_SHIFT 1 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_SHIFT 2 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_SHIFT 3 +#define XSTORM_ETH_CONN_AG_CTX_L2_EDPM_ENABLE_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_L2_EDPM_ENABLE_SHIFT 4 +#define XSTORM_ETH_CONN_AG_CTX_ROCE_EDPM_ENABLE_MASK 0x1 +#define XSTORM_ETH_CONN_AG_CTX_ROCE_EDPM_ENABLE_SHIFT 5 +#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_MASK 0x3 +#define XSTORM_ETH_CONN_AG_CTX_TPH_ENABLE_SHIFT 6 + u8 edpm_event_id; + __le16 physical_q0; + __le16 quota; + __le16 edpm_num_bds; + __le16 tx_bd_cons; + __le16 tx_bd_prod; + __le16 tx_class; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le16 word7; + __le16 word8; + __le16 word9; + __le16 word10; + __le32 reg7; + __le32 reg8; + __le32 reg9; + u8 byte7; + u8 byte8; + u8 byte9; + u8 byte10; + u8 byte11; + u8 byte12; + u8 byte13; + u8 byte14; + u8 byte15; + u8 byte16; + __le16 word11; + __le32 reg10; + __le32 reg11; + __le32 reg12; + __le32 reg13; + __le32 reg14; + __le32 reg15; + __le32 reg16; + __le32 reg17; + __le32 reg18; + __le32 reg19; + __le16 word12; + __le16 word13; + __le16 word14; + __le16 word15; }; /* The eth storm context for the Ystorm */ @@ -2648,220 +2955,220 @@ struct ystorm_eth_conn_st_ctx { }; struct ystorm_eth_conn_ag_ctx { - u8 byte0 /* cdu_validation */; - u8 byte1 /* state */; - u8 flags0; -#define YSTORM_ETH_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ -#define YSTORM_ETH_CONN_AG_CTX_BIT0_SHIFT 0 -#define YSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ -#define YSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 -#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_MASK 0x3 /* cf0 */ -#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_SHIFT 2 -#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_MASK 0x3 /* cf1 */ -#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_SHIFT 4 -#define YSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 /* cf2 */ -#define YSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 + u8 byte0; + u8 state; + u8 flags0; +#define YSTORM_ETH_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_MASK 0x3 +#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_SHIFT 2 +#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_MASK 0x3 +#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_SHIFT 4 +#define YSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 u8 flags1; -#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_MASK 0x1 /* cf0en */ -#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_SHIFT 0 -#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_EN_MASK 0x1 /* cf1en */ -#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_EN_SHIFT 1 -#define YSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ -#define YSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 -#define YSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ -#define YSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 3 -#define YSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ -#define YSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 4 -#define YSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ -#define YSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 5 -#define YSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ -#define YSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 6 -#define YSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ -#define YSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 7 - u8 byte2 /* byte2 */; - u8 byte3 /* byte3 */; - __le16 word0 /* word0 */; - __le32 terminate_spqe /* reg0 */; - __le32 reg1 /* reg1 */; - __le16 tx_bd_cons_upd /* word1 */; - __le16 word2 /* word2 */; - __le16 word3 /* word3 */; - __le16 word4 /* word4 */; - __le32 reg2 /* reg2 */; - __le32 reg3 /* reg3 */; +#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_SHIFT 0 +#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_EN_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_EN_SHIFT 1 +#define YSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 tx_q0_int_coallecing_timeset; + u8 byte3; + __le16 word0; + __le32 terminate_spqe; + __le32 reg1; + __le16 tx_bd_cons_upd; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; }; struct tstorm_eth_conn_ag_ctx { - u8 byte0 /* cdu_validation */; - u8 byte1 /* state */; - u8 flags0; -#define TSTORM_ETH_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ -#define TSTORM_ETH_CONN_AG_CTX_BIT0_SHIFT 0 -#define TSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ -#define TSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 -#define TSTORM_ETH_CONN_AG_CTX_BIT2_MASK 0x1 /* bit2 */ -#define TSTORM_ETH_CONN_AG_CTX_BIT2_SHIFT 2 -#define TSTORM_ETH_CONN_AG_CTX_BIT3_MASK 0x1 /* bit3 */ -#define TSTORM_ETH_CONN_AG_CTX_BIT3_SHIFT 3 -#define TSTORM_ETH_CONN_AG_CTX_BIT4_MASK 0x1 /* bit4 */ -#define TSTORM_ETH_CONN_AG_CTX_BIT4_SHIFT 4 -#define TSTORM_ETH_CONN_AG_CTX_BIT5_MASK 0x1 /* bit5 */ -#define TSTORM_ETH_CONN_AG_CTX_BIT5_SHIFT 5 -#define TSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 /* timer0cf */ -#define TSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 6 + u8 byte0; + u8 byte1; + u8 flags0; +#define TSTORM_ETH_CONN_AG_CTX_BIT0_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_BIT0_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_ETH_CONN_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_ETH_CONN_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_ETH_CONN_AG_CTX_CF0_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF0_SHIFT 6 u8 flags1; -#define TSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 /* timer1cf */ -#define TSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 0 -#define TSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ -#define TSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 2 -#define TSTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ -#define TSTORM_ETH_CONN_AG_CTX_CF3_SHIFT 4 -#define TSTORM_ETH_CONN_AG_CTX_CF4_MASK 0x3 /* cf4 */ -#define TSTORM_ETH_CONN_AG_CTX_CF4_SHIFT 6 +#define TSTORM_ETH_CONN_AG_CTX_CF1_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF3_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_CF4_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF4_SHIFT 6 u8 flags2; -#define TSTORM_ETH_CONN_AG_CTX_CF5_MASK 0x3 /* cf5 */ -#define TSTORM_ETH_CONN_AG_CTX_CF5_SHIFT 0 -#define TSTORM_ETH_CONN_AG_CTX_CF6_MASK 0x3 /* cf6 */ -#define TSTORM_ETH_CONN_AG_CTX_CF6_SHIFT 2 -#define TSTORM_ETH_CONN_AG_CTX_CF7_MASK 0x3 /* cf7 */ -#define TSTORM_ETH_CONN_AG_CTX_CF7_SHIFT 4 -#define TSTORM_ETH_CONN_AG_CTX_CF8_MASK 0x3 /* cf8 */ -#define TSTORM_ETH_CONN_AG_CTX_CF8_SHIFT 6 +#define TSTORM_ETH_CONN_AG_CTX_CF5_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_CF6_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_CF7_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_CF8_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF8_SHIFT 6 u8 flags3; -#define TSTORM_ETH_CONN_AG_CTX_CF9_MASK 0x3 /* cf9 */ -#define TSTORM_ETH_CONN_AG_CTX_CF9_SHIFT 0 -#define TSTORM_ETH_CONN_AG_CTX_CF10_MASK 0x3 /* cf10 */ -#define TSTORM_ETH_CONN_AG_CTX_CF10_SHIFT 2 -#define TSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 /* cf0en */ -#define TSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 4 -#define TSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 /* cf1en */ -#define TSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 5 -#define TSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ -#define TSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 6 -#define TSTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ -#define TSTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 7 +#define TSTORM_ETH_CONN_AG_CTX_CF9_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_CF10_MASK 0x3 +#define TSTORM_ETH_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 7 u8 flags4; -#define TSTORM_ETH_CONN_AG_CTX_CF4EN_MASK 0x1 /* cf4en */ -#define TSTORM_ETH_CONN_AG_CTX_CF4EN_SHIFT 0 -#define TSTORM_ETH_CONN_AG_CTX_CF5EN_MASK 0x1 /* cf5en */ -#define TSTORM_ETH_CONN_AG_CTX_CF5EN_SHIFT 1 -#define TSTORM_ETH_CONN_AG_CTX_CF6EN_MASK 0x1 /* cf6en */ -#define TSTORM_ETH_CONN_AG_CTX_CF6EN_SHIFT 2 -#define TSTORM_ETH_CONN_AG_CTX_CF7EN_MASK 0x1 /* cf7en */ -#define TSTORM_ETH_CONN_AG_CTX_CF7EN_SHIFT 3 -#define TSTORM_ETH_CONN_AG_CTX_CF8EN_MASK 0x1 /* cf8en */ -#define TSTORM_ETH_CONN_AG_CTX_CF8EN_SHIFT 4 -#define TSTORM_ETH_CONN_AG_CTX_CF9EN_MASK 0x1 /* cf9en */ -#define TSTORM_ETH_CONN_AG_CTX_CF9EN_SHIFT 5 -#define TSTORM_ETH_CONN_AG_CTX_CF10EN_MASK 0x1 /* cf10en */ -#define TSTORM_ETH_CONN_AG_CTX_CF10EN_SHIFT 6 -#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ -#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 7 +#define TSTORM_ETH_CONN_AG_CTX_CF4EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_CF5EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_ETH_CONN_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_ETH_CONN_AG_CTX_CF8EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_CF9EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_ETH_CONN_AG_CTX_CF10EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 7 u8 flags5; -#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ -#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 0 -#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ -#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 1 -#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ -#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 2 -#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ -#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 3 -#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ -#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 4 -#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_MASK 0x1 /* rule6en */ -#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_SHIFT 5 -#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ -#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 6 -#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ -#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT 7 - __le32 reg0 /* reg0 */; - __le32 reg1 /* reg1 */; - __le32 reg2 /* reg2 */; - __le32 reg3 /* reg3 */; - __le32 reg4 /* reg4 */; - __le32 reg5 /* reg5 */; - __le32 reg6 /* reg6 */; - __le32 reg7 /* reg7 */; - __le32 reg8 /* reg8 */; - u8 byte2 /* byte2 */; - u8 byte3 /* byte3 */; - __le16 rx_bd_cons /* word0 */; - u8 byte4 /* byte4 */; - u8 byte5 /* byte5 */; - __le16 rx_bd_prod /* word1 */; - __le16 word2 /* conn_dpi */; - __le16 word3 /* word3 */; - __le32 reg9 /* reg9 */; - __le32 reg10 /* reg10 */; +#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_SHIFT 5 +#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 byte2; + u8 byte3; + __le16 rx_bd_cons; + u8 byte4; + u8 byte5; + __le16 rx_bd_prod; + __le16 word2; + __le16 word3; + __le32 reg9; + __le32 reg10; }; struct ustorm_eth_conn_ag_ctx { - u8 byte0 /* cdu_validation */; - u8 byte1 /* state */; - u8 flags0; -#define USTORM_ETH_CONN_AG_CTX_BIT0_MASK 0x1 /* exist_in_qm0 */ -#define USTORM_ETH_CONN_AG_CTX_BIT0_SHIFT 0 -#define USTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 /* exist_in_qm1 */ -#define USTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 -#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_MASK 0x3 /* timer0cf */ -#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_SHIFT 2 -#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_MASK 0x3 /* timer1cf */ -#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_SHIFT 4 -#define USTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 /* timer2cf */ -#define USTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 + u8 byte0; + u8 byte1; + u8 flags0; +#define USTORM_ETH_CONN_AG_CTX_BIT0_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_BIT0_SHIFT 0 +#define USTORM_ETH_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_MASK 0x3 +#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_SHIFT 2 +#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_MASK 0x3 +#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_SHIFT 4 +#define USTORM_ETH_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_ETH_CONN_AG_CTX_CF2_SHIFT 6 u8 flags1; -#define USTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 /* timer_stop_all */ -#define USTORM_ETH_CONN_AG_CTX_CF3_SHIFT 0 -#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_MASK 0x3 /* cf4 */ -#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_SHIFT 2 -#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_MASK 0x3 /* cf5 */ -#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_SHIFT 4 -#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_MASK 0x3 /* cf6 */ -#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_SHIFT 6 +#define USTORM_ETH_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_ETH_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_MASK 0x3 +#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_SHIFT 2 +#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_MASK 0x3 +#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_SHIFT 4 +#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_MASK 0x3 +#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_SHIFT 6 u8 flags2; -#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_EN_MASK 0x1 /* cf0en */ -#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_EN_SHIFT 0 -#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_EN_MASK 0x1 /* cf1en */ -#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_EN_SHIFT 1 -#define USTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 /* cf2en */ -#define USTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 -#define USTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 /* cf3en */ -#define USTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 3 -#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_MASK 0x1 /* cf4en */ -#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_SHIFT 4 -#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_MASK 0x1 /* cf5en */ -#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_SHIFT 5 -#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_MASK 0x1 /* cf6en */ -#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_SHIFT 6 -#define USTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 /* rule0en */ -#define USTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 7 +#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_EN_SHIFT 0 +#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_EN_SHIFT 1 +#define USTORM_ETH_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_ETH_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_SHIFT 4 +#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_SHIFT 5 +#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_SHIFT 6 +#define USTORM_ETH_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT 7 u8 flags3; -#define USTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 /* rule1en */ -#define USTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 0 -#define USTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 /* rule2en */ -#define USTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 1 -#define USTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 /* rule3en */ -#define USTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 2 -#define USTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 /* rule4en */ -#define USTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 3 -#define USTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 /* rule5en */ -#define USTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 4 -#define USTORM_ETH_CONN_AG_CTX_RULE6EN_MASK 0x1 /* rule6en */ -#define USTORM_ETH_CONN_AG_CTX_RULE6EN_SHIFT 5 -#define USTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 /* rule7en */ -#define USTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 6 -#define USTORM_ETH_CONN_AG_CTX_RULE8EN_MASK 0x1 /* rule8en */ -#define USTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT 7 - u8 byte2 /* byte2 */; - u8 byte3 /* byte3 */; - __le16 word0 /* conn_dpi */; - __le16 tx_bd_cons /* word1 */; - __le32 reg0 /* reg0 */; - __le32 reg1 /* reg1 */; - __le32 reg2 /* reg2 */; - __le32 tx_int_coallecing_timeset /* reg3 */; - __le16 tx_drv_bd_cons /* word2 */; - __le16 rx_drv_cqe_cons /* word3 */; +#define USTORM_ETH_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define USTORM_ETH_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_ETH_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_ETH_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_ETH_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_ETH_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_ETH_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_ETH_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le16 tx_bd_cons; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 tx_int_coallecing_timeset; + __le16 tx_drv_bd_cons; + __le16 rx_drv_cqe_cons; }; /* The eth storm context for the Ustorm */ @@ -2876,47 +3183,75 @@ struct mstorm_eth_conn_st_ctx { /* eth connection context */ struct eth_conn_context { - struct tstorm_eth_conn_st_ctx tstorm_st_context; - struct regpair tstorm_st_padding[2]; - struct pstorm_eth_conn_st_ctx pstorm_st_context; - struct xstorm_eth_conn_st_ctx xstorm_st_context; - struct xstorm_eth_conn_ag_ctx xstorm_ag_context; - struct ystorm_eth_conn_st_ctx ystorm_st_context; - struct ystorm_eth_conn_ag_ctx ystorm_ag_context; - struct tstorm_eth_conn_ag_ctx tstorm_ag_context; - struct ustorm_eth_conn_ag_ctx ustorm_ag_context; - struct ustorm_eth_conn_st_ctx ustorm_st_context; - struct mstorm_eth_conn_st_ctx mstorm_st_context; + struct tstorm_eth_conn_st_ctx tstorm_st_context; + struct regpair tstorm_st_padding[2]; + struct pstorm_eth_conn_st_ctx pstorm_st_context; + struct xstorm_eth_conn_st_ctx xstorm_st_context; + struct xstorm_eth_conn_ag_ctx xstorm_ag_context; + struct ystorm_eth_conn_st_ctx ystorm_st_context; + struct ystorm_eth_conn_ag_ctx ystorm_ag_context; + struct tstorm_eth_conn_ag_ctx tstorm_ag_context; + struct ustorm_eth_conn_ag_ctx ustorm_ag_context; + struct ustorm_eth_conn_st_ctx ustorm_st_context; + struct mstorm_eth_conn_st_ctx mstorm_st_context; }; +/* opcodes for the event ring */ +enum eth_event_opcode { + ETH_EVENT_UNUSED, + ETH_EVENT_VPORT_START, + ETH_EVENT_VPORT_UPDATE, + ETH_EVENT_VPORT_STOP, + ETH_EVENT_TX_QUEUE_START, + ETH_EVENT_TX_QUEUE_STOP, + ETH_EVENT_RX_QUEUE_START, + ETH_EVENT_RX_QUEUE_UPDATE, + ETH_EVENT_RX_QUEUE_STOP, + ETH_EVENT_FILTERS_UPDATE, + ETH_EVENT_RESERVED, + ETH_EVENT_RESERVED2, + ETH_EVENT_RESERVED3, + ETH_EVENT_RX_ADD_UDP_FILTER, + ETH_EVENT_RX_DELETE_UDP_FILTER, + ETH_EVENT_RESERVED4, + ETH_EVENT_RESERVED5, + MAX_ETH_EVENT_OPCODE +}; + +/* Classify rule types in E2/E3 */ enum eth_filter_action { + ETH_FILTER_ACTION_UNUSED, ETH_FILTER_ACTION_REMOVE, ETH_FILTER_ACTION_ADD, ETH_FILTER_ACTION_REMOVE_ALL, MAX_ETH_FILTER_ACTION }; +/* Command for adding/removing a classification rule $$KEEP_ENDIANNESS$$ */ struct eth_filter_cmd { - u8 type /* Filter Type (MAC/VLAN/Pair/VNI) */; - u8 vport_id /* the vport id */; - u8 action /* filter command action: add/remove/replace */; - u8 reserved0; - __le32 vni; - __le16 mac_lsb; - __le16 mac_mid; - __le16 mac_msb; - __le16 vlan_id; + u8 type; + u8 vport_id; + u8 action; + u8 reserved0; + __le32 vni; + __le16 mac_lsb; + __le16 mac_mid; + __le16 mac_msb; + __le16 vlan_id; }; +/* $$KEEP_ENDIANNESS$$ */ struct eth_filter_cmd_header { - u8 rx; - u8 tx; - u8 cmd_cnt; - u8 assert_on_error; - u8 reserved1[4]; + u8 rx; + u8 tx; + u8 cmd_cnt; + u8 assert_on_error; + u8 reserved1[4]; }; +/* Ethernet filter types: mac/vlan/pair */ enum eth_filter_type { + ETH_FILTER_TYPE_UNUSED, ETH_FILTER_TYPE_MAC, ETH_FILTER_TYPE_VLAN, ETH_FILTER_TYPE_PAIR, @@ -2929,463 +3264,512 @@ enum eth_filter_type { MAX_ETH_FILTER_TYPE }; +/* Ethernet Ramrod Command IDs */ enum eth_ramrod_cmd_id { ETH_RAMROD_UNUSED, - ETH_RAMROD_VPORT_START /* VPort Start Ramrod */, - ETH_RAMROD_VPORT_UPDATE /* VPort Update Ramrod */, - ETH_RAMROD_VPORT_STOP /* VPort Stop Ramrod */, - ETH_RAMROD_RX_QUEUE_START /* RX Queue Start Ramrod */, - ETH_RAMROD_RX_QUEUE_STOP /* RX Queue Stop Ramrod */, - ETH_RAMROD_TX_QUEUE_START /* TX Queue Start Ramrod */, - ETH_RAMROD_TX_QUEUE_STOP /* TX Queue Stop Ramrod */, - ETH_RAMROD_FILTERS_UPDATE /* Add or Remove Mac/Vlan/Pair filters */, - ETH_RAMROD_RX_QUEUE_UPDATE /* RX Queue Update Ramrod */, - ETH_RAMROD_RESERVED, - ETH_RAMROD_RESERVED2, - ETH_RAMROD_RESERVED3, - ETH_RAMROD_RESERVED4, - ETH_RAMROD_RESERVED5, - ETH_RAMROD_RESERVED6, - ETH_RAMROD_RESERVED7, - ETH_RAMROD_RESERVED8, + ETH_RAMROD_VPORT_START, + ETH_RAMROD_VPORT_UPDATE, + ETH_RAMROD_VPORT_STOP, + ETH_RAMROD_RX_QUEUE_START, + ETH_RAMROD_RX_QUEUE_STOP, + ETH_RAMROD_TX_QUEUE_START, + ETH_RAMROD_TX_QUEUE_STOP, + ETH_RAMROD_FILTERS_UPDATE, + ETH_RAMROD_RX_QUEUE_UPDATE, + ETH_RAMROD_RX_CREATE_OPENFLOW_ACTION, + ETH_RAMROD_RX_ADD_OPENFLOW_FILTER, + ETH_RAMROD_RX_DELETE_OPENFLOW_FILTER, + ETH_RAMROD_RX_ADD_UDP_FILTER, + ETH_RAMROD_RX_DELETE_UDP_FILTER, + ETH_RAMROD_RX_CREATE_GFT_ACTION, + ETH_RAMROD_GFT_UPDATE_FILTER, MAX_ETH_RAMROD_CMD_ID }; +/* return code from eth sp ramrods */ +struct eth_return_code { + u8 value; +#define ETH_RETURN_CODE_ERR_CODE_MASK 0x1F +#define ETH_RETURN_CODE_ERR_CODE_SHIFT 0 +#define ETH_RETURN_CODE_RESERVED_MASK 0x3 +#define ETH_RETURN_CODE_RESERVED_SHIFT 5 +#define ETH_RETURN_CODE_RX_TX_MASK 0x1 +#define ETH_RETURN_CODE_RX_TX_SHIFT 7 +}; + +/* What to do in case an error occurs */ enum eth_tx_err { - ETH_TX_ERR_DROP /* Drop erronous packet. */, + ETH_TX_ERR_DROP, ETH_TX_ERR_ASSERT_MALICIOUS, MAX_ETH_TX_ERR }; +/* Array of the different error type behaviors */ struct eth_tx_err_vals { __le16 values; -#define ETH_TX_ERR_VALS_ILLEGAL_VLAN_MODE_MASK 0x1 -#define ETH_TX_ERR_VALS_ILLEGAL_VLAN_MODE_SHIFT 0 -#define ETH_TX_ERR_VALS_PACKET_TOO_SMALL_MASK 0x1 -#define ETH_TX_ERR_VALS_PACKET_TOO_SMALL_SHIFT 1 -#define ETH_TX_ERR_VALS_ANTI_SPOOFING_ERR_MASK 0x1 -#define ETH_TX_ERR_VALS_ANTI_SPOOFING_ERR_SHIFT 2 -#define ETH_TX_ERR_VALS_ILLEGAL_INBAND_TAGS_MASK 0x1 -#define ETH_TX_ERR_VALS_ILLEGAL_INBAND_TAGS_SHIFT 3 -#define ETH_TX_ERR_VALS_VLAN_INSERTION_W_INBAND_TAG_MASK 0x1 -#define ETH_TX_ERR_VALS_VLAN_INSERTION_W_INBAND_TAG_SHIFT 4 -#define ETH_TX_ERR_VALS_MTU_VIOLATION_MASK 0x1 -#define ETH_TX_ERR_VALS_MTU_VIOLATION_SHIFT 5 -#define ETH_TX_ERR_VALS_ILLEGAL_CONTROL_FRAME_MASK 0x1 -#define ETH_TX_ERR_VALS_ILLEGAL_CONTROL_FRAME_SHIFT 6 -#define ETH_TX_ERR_VALS_RESERVED_MASK 0x1FF -#define ETH_TX_ERR_VALS_RESERVED_SHIFT 7 -}; - +#define ETH_TX_ERR_VALS_ILLEGAL_VLAN_MODE_MASK 0x1 +#define ETH_TX_ERR_VALS_ILLEGAL_VLAN_MODE_SHIFT 0 +#define ETH_TX_ERR_VALS_PACKET_TOO_SMALL_MASK 0x1 +#define ETH_TX_ERR_VALS_PACKET_TOO_SMALL_SHIFT 1 +#define ETH_TX_ERR_VALS_ANTI_SPOOFING_ERR_MASK 0x1 +#define ETH_TX_ERR_VALS_ANTI_SPOOFING_ERR_SHIFT 2 +#define ETH_TX_ERR_VALS_ILLEGAL_INBAND_TAGS_MASK 0x1 +#define ETH_TX_ERR_VALS_ILLEGAL_INBAND_TAGS_SHIFT 3 +#define ETH_TX_ERR_VALS_VLAN_INSERTION_W_INBAND_TAG_MASK 0x1 +#define ETH_TX_ERR_VALS_VLAN_INSERTION_W_INBAND_TAG_SHIFT 4 +#define ETH_TX_ERR_VALS_MTU_VIOLATION_MASK 0x1 +#define ETH_TX_ERR_VALS_MTU_VIOLATION_SHIFT 5 +#define ETH_TX_ERR_VALS_ILLEGAL_CONTROL_FRAME_MASK 0x1 +#define ETH_TX_ERR_VALS_ILLEGAL_CONTROL_FRAME_SHIFT 6 +#define ETH_TX_ERR_VALS_RESERVED_MASK 0x1FF +#define ETH_TX_ERR_VALS_RESERVED_SHIFT 7 +}; + +/* vport rss configuration data */ struct eth_vport_rss_config { __le16 capabilities; -#define ETH_VPORT_RSS_CONFIG_IPV4_CAPABILITY_MASK 0x1 -#define ETH_VPORT_RSS_CONFIG_IPV4_CAPABILITY_SHIFT 0 -#define ETH_VPORT_RSS_CONFIG_IPV6_CAPABILITY_MASK 0x1 -#define ETH_VPORT_RSS_CONFIG_IPV6_CAPABILITY_SHIFT 1 -#define ETH_VPORT_RSS_CONFIG_IPV4_TCP_CAPABILITY_MASK 0x1 -#define ETH_VPORT_RSS_CONFIG_IPV4_TCP_CAPABILITY_SHIFT 2 -#define ETH_VPORT_RSS_CONFIG_IPV6_TCP_CAPABILITY_MASK 0x1 -#define ETH_VPORT_RSS_CONFIG_IPV6_TCP_CAPABILITY_SHIFT 3 -#define ETH_VPORT_RSS_CONFIG_IPV4_UDP_CAPABILITY_MASK 0x1 -#define ETH_VPORT_RSS_CONFIG_IPV4_UDP_CAPABILITY_SHIFT 4 -#define ETH_VPORT_RSS_CONFIG_IPV6_UDP_CAPABILITY_MASK 0x1 -#define ETH_VPORT_RSS_CONFIG_IPV6_UDP_CAPABILITY_SHIFT 5 -#define ETH_VPORT_RSS_CONFIG_EN_5_TUPLE_CAPABILITY_MASK 0x1 -#define ETH_VPORT_RSS_CONFIG_EN_5_TUPLE_CAPABILITY_SHIFT 6 -#define ETH_VPORT_RSS_CONFIG_RESERVED0_MASK 0x1FF -#define ETH_VPORT_RSS_CONFIG_RESERVED0_SHIFT 7 - u8 rss_id; - u8 rss_mode; - u8 update_rss_key; - u8 update_rss_ind_table; - u8 update_rss_capabilities; - u8 tbl_size; - __le32 reserved2[2]; - __le16 indirection_table[ETH_RSS_IND_TABLE_ENTRIES_NUM]; - __le32 rss_key[ETH_RSS_KEY_SIZE_REGS]; - __le32 reserved3[2]; -}; - +#define ETH_VPORT_RSS_CONFIG_IPV4_CAPABILITY_MASK 0x1 +#define ETH_VPORT_RSS_CONFIG_IPV4_CAPABILITY_SHIFT 0 +#define ETH_VPORT_RSS_CONFIG_IPV6_CAPABILITY_MASK 0x1 +#define ETH_VPORT_RSS_CONFIG_IPV6_CAPABILITY_SHIFT 1 +#define ETH_VPORT_RSS_CONFIG_IPV4_TCP_CAPABILITY_MASK 0x1 +#define ETH_VPORT_RSS_CONFIG_IPV4_TCP_CAPABILITY_SHIFT 2 +#define ETH_VPORT_RSS_CONFIG_IPV6_TCP_CAPABILITY_MASK 0x1 +#define ETH_VPORT_RSS_CONFIG_IPV6_TCP_CAPABILITY_SHIFT 3 +#define ETH_VPORT_RSS_CONFIG_IPV4_UDP_CAPABILITY_MASK 0x1 +#define ETH_VPORT_RSS_CONFIG_IPV4_UDP_CAPABILITY_SHIFT 4 +#define ETH_VPORT_RSS_CONFIG_IPV6_UDP_CAPABILITY_MASK 0x1 +#define ETH_VPORT_RSS_CONFIG_IPV6_UDP_CAPABILITY_SHIFT 5 +#define ETH_VPORT_RSS_CONFIG_EN_5_TUPLE_CAPABILITY_MASK 0x1 +#define ETH_VPORT_RSS_CONFIG_EN_5_TUPLE_CAPABILITY_SHIFT 6 +#define ETH_VPORT_RSS_CONFIG_RESERVED0_MASK 0x1FF +#define ETH_VPORT_RSS_CONFIG_RESERVED0_SHIFT 7 + u8 rss_id; + u8 rss_mode; + u8 update_rss_key; + u8 update_rss_ind_table; + u8 update_rss_capabilities; + u8 tbl_size; + __le32 reserved2[2]; + __le16 indirection_table[ETH_RSS_IND_TABLE_ENTRIES_NUM]; + + __le32 rss_key[ETH_RSS_KEY_SIZE_REGS]; + __le32 reserved3[2]; +}; + +/* eth vport RSS mode */ enum eth_vport_rss_mode { ETH_VPORT_RSS_MODE_DISABLED, ETH_VPORT_RSS_MODE_REGULAR, MAX_ETH_VPORT_RSS_MODE }; +/* Command for setting classification flags for a vport $$KEEP_ENDIANNESS$$ */ struct eth_vport_rx_mode { __le16 state; -#define ETH_VPORT_RX_MODE_UCAST_DROP_ALL_MASK 0x1 -#define ETH_VPORT_RX_MODE_UCAST_DROP_ALL_SHIFT 0 -#define ETH_VPORT_RX_MODE_UCAST_ACCEPT_ALL_MASK 0x1 -#define ETH_VPORT_RX_MODE_UCAST_ACCEPT_ALL_SHIFT 1 -#define ETH_VPORT_RX_MODE_UCAST_ACCEPT_UNMATCHED_MASK 0x1 -#define ETH_VPORT_RX_MODE_UCAST_ACCEPT_UNMATCHED_SHIFT 2 -#define ETH_VPORT_RX_MODE_MCAST_DROP_ALL_MASK 0x1 -#define ETH_VPORT_RX_MODE_MCAST_DROP_ALL_SHIFT 3 -#define ETH_VPORT_RX_MODE_MCAST_ACCEPT_ALL_MASK 0x1 -#define ETH_VPORT_RX_MODE_MCAST_ACCEPT_ALL_SHIFT 4 -#define ETH_VPORT_RX_MODE_BCAST_ACCEPT_ALL_MASK 0x1 -#define ETH_VPORT_RX_MODE_BCAST_ACCEPT_ALL_SHIFT 5 -#define ETH_VPORT_RX_MODE_RESERVED1_MASK 0x3FF -#define ETH_VPORT_RX_MODE_RESERVED1_SHIFT 6 +#define ETH_VPORT_RX_MODE_UCAST_DROP_ALL_MASK 0x1 +#define ETH_VPORT_RX_MODE_UCAST_DROP_ALL_SHIFT 0 +#define ETH_VPORT_RX_MODE_UCAST_ACCEPT_ALL_MASK 0x1 +#define ETH_VPORT_RX_MODE_UCAST_ACCEPT_ALL_SHIFT 1 +#define ETH_VPORT_RX_MODE_UCAST_ACCEPT_UNMATCHED_MASK 0x1 +#define ETH_VPORT_RX_MODE_UCAST_ACCEPT_UNMATCHED_SHIFT 2 +#define ETH_VPORT_RX_MODE_MCAST_DROP_ALL_MASK 0x1 +#define ETH_VPORT_RX_MODE_MCAST_DROP_ALL_SHIFT 3 +#define ETH_VPORT_RX_MODE_MCAST_ACCEPT_ALL_MASK 0x1 +#define ETH_VPORT_RX_MODE_MCAST_ACCEPT_ALL_SHIFT 4 +#define ETH_VPORT_RX_MODE_BCAST_ACCEPT_ALL_MASK 0x1 +#define ETH_VPORT_RX_MODE_BCAST_ACCEPT_ALL_SHIFT 5 +#define ETH_VPORT_RX_MODE_RESERVED1_MASK 0x3FF +#define ETH_VPORT_RX_MODE_RESERVED1_SHIFT 6 __le16 reserved2[3]; }; +/* Command for setting tpa parameters */ struct eth_vport_tpa_param { - u8 tpa_ipv4_en_flg; - u8 tpa_ipv6_en_flg; - u8 tpa_ipv4_tunn_en_flg; - u8 tpa_ipv6_tunn_en_flg; - u8 tpa_pkt_split_flg; - u8 tpa_hdr_data_split_flg; - u8 tpa_gro_consistent_flg; - u8 tpa_max_aggs_num; - u16 tpa_max_size; - u16 tpa_min_size_to_start; - u16 tpa_min_size_to_cont; - u8 max_buff_num; - u8 reserved; + u8 tpa_ipv4_en_flg; + u8 tpa_ipv6_en_flg; + u8 tpa_ipv4_tunn_en_flg; + u8 tpa_ipv6_tunn_en_flg; + u8 tpa_pkt_split_flg; + u8 tpa_hdr_data_split_flg; + u8 tpa_gro_consistent_flg; + + u8 tpa_max_aggs_num; + + __le16 tpa_max_size; + __le16 tpa_min_size_to_start; + + __le16 tpa_min_size_to_cont; + u8 max_buff_num; + u8 reserved; }; +/* Command for setting classification flags for a vport $$KEEP_ENDIANNESS$$ */ struct eth_vport_tx_mode { __le16 state; -#define ETH_VPORT_TX_MODE_UCAST_DROP_ALL_MASK 0x1 -#define ETH_VPORT_TX_MODE_UCAST_DROP_ALL_SHIFT 0 -#define ETH_VPORT_TX_MODE_UCAST_ACCEPT_ALL_MASK 0x1 -#define ETH_VPORT_TX_MODE_UCAST_ACCEPT_ALL_SHIFT 1 -#define ETH_VPORT_TX_MODE_MCAST_DROP_ALL_MASK 0x1 -#define ETH_VPORT_TX_MODE_MCAST_DROP_ALL_SHIFT 2 -#define ETH_VPORT_TX_MODE_MCAST_ACCEPT_ALL_MASK 0x1 -#define ETH_VPORT_TX_MODE_MCAST_ACCEPT_ALL_SHIFT 3 -#define ETH_VPORT_TX_MODE_BCAST_ACCEPT_ALL_MASK 0x1 -#define ETH_VPORT_TX_MODE_BCAST_ACCEPT_ALL_SHIFT 4 -#define ETH_VPORT_TX_MODE_RESERVED1_MASK 0x7FF -#define ETH_VPORT_TX_MODE_RESERVED1_SHIFT 5 +#define ETH_VPORT_TX_MODE_UCAST_DROP_ALL_MASK 0x1 +#define ETH_VPORT_TX_MODE_UCAST_DROP_ALL_SHIFT 0 +#define ETH_VPORT_TX_MODE_UCAST_ACCEPT_ALL_MASK 0x1 +#define ETH_VPORT_TX_MODE_UCAST_ACCEPT_ALL_SHIFT 1 +#define ETH_VPORT_TX_MODE_MCAST_DROP_ALL_MASK 0x1 +#define ETH_VPORT_TX_MODE_MCAST_DROP_ALL_SHIFT 2 +#define ETH_VPORT_TX_MODE_MCAST_ACCEPT_ALL_MASK 0x1 +#define ETH_VPORT_TX_MODE_MCAST_ACCEPT_ALL_SHIFT 3 +#define ETH_VPORT_TX_MODE_BCAST_ACCEPT_ALL_MASK 0x1 +#define ETH_VPORT_TX_MODE_BCAST_ACCEPT_ALL_SHIFT 4 +#define ETH_VPORT_TX_MODE_RESERVED1_MASK 0x7FF +#define ETH_VPORT_TX_MODE_RESERVED1_SHIFT 5 __le16 reserved2[3]; }; +/* Ramrod data for rx queue start ramrod */ struct rx_queue_start_ramrod_data { - __le16 rx_queue_id; - __le16 num_of_pbl_pages; - __le16 bd_max_bytes; - __le16 sb_id; - u8 sb_index; - u8 vport_id; - u8 default_rss_queue_flg; - u8 complete_cqe_flg; - u8 complete_event_flg; - u8 stats_counter_id; - u8 pin_context; - u8 pxp_tph_valid_bd; - u8 pxp_tph_valid_pkt; - u8 pxp_st_hint; - __le16 pxp_st_index; - u8 pmd_mode; - u8 notify_en; - u8 toggle_val; - u8 reserved[7]; - __le16 reserved1; - struct regpair cqe_pbl_addr; - struct regpair bd_base; - struct regpair reserved2; + __le16 rx_queue_id; + __le16 num_of_pbl_pages; + __le16 bd_max_bytes; + __le16 sb_id; + u8 sb_index; + u8 vport_id; + u8 default_rss_queue_flg; + u8 complete_cqe_flg; + u8 complete_event_flg; + u8 stats_counter_id; + u8 pin_context; + u8 pxp_tph_valid_bd; + u8 pxp_tph_valid_pkt; + u8 pxp_st_hint; + + __le16 pxp_st_index; + u8 pmd_mode; + + u8 notify_en; + u8 toggle_val; + + u8 vf_rx_prod_index; + + u8 reserved[6]; + __le16 reserved1; + struct regpair cqe_pbl_addr; + struct regpair bd_base; + struct regpair reserved2; }; +/* Ramrod data for rx queue start ramrod */ struct rx_queue_stop_ramrod_data { - __le16 rx_queue_id; - u8 complete_cqe_flg; - u8 complete_event_flg; - u8 vport_id; - u8 reserved[3]; + __le16 rx_queue_id; + u8 complete_cqe_flg; + u8 complete_event_flg; + u8 vport_id; + u8 reserved[3]; }; +/* Ramrod data for rx queue update ramrod */ struct rx_queue_update_ramrod_data { - __le16 rx_queue_id; - u8 complete_cqe_flg; - u8 complete_event_flg; - u8 vport_id; - u8 reserved[4]; - u8 reserved1; - u8 reserved2; - u8 reserved3; - __le16 reserved4; - __le16 reserved5; + __le16 rx_queue_id; + u8 complete_cqe_flg; + u8 complete_event_flg; + u8 vport_id; + u8 reserved[4]; + u8 reserved1; + u8 reserved2; + u8 reserved3; + __le16 reserved4; + __le16 reserved5; struct regpair reserved6; }; -struct tx_queue_start_ramrod_data { - __le16 sb_id; - u8 sb_index; - u8 vport_id; - u8 reserved0; - u8 stats_counter_id; - __le16 qm_pq_id; - u8 flags; -#define TX_QUEUE_START_RAMROD_DATA_DISABLE_OPPORTUNISTIC_MASK 0x1 -#define TX_QUEUE_START_RAMROD_DATA_DISABLE_OPPORTUNISTIC_SHIFT 0 -#define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_PKT_DUP_MASK 0x1 -#define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_PKT_DUP_SHIFT 1 -#define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_TX_DEST_MASK 0x1 -#define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_TX_DEST_SHIFT 2 -#define TX_QUEUE_START_RAMROD_DATA_PMD_MODE_MASK 0x1 -#define TX_QUEUE_START_RAMROD_DATA_PMD_MODE_SHIFT 3 -#define TX_QUEUE_START_RAMROD_DATA_NOTIFY_EN_MASK 0x1 -#define TX_QUEUE_START_RAMROD_DATA_NOTIFY_EN_SHIFT 4 -#define TX_QUEUE_START_RAMROD_DATA_PIN_CONTEXT_MASK 0x1 -#define TX_QUEUE_START_RAMROD_DATA_PIN_CONTEXT_SHIFT 5 -#define TX_QUEUE_START_RAMROD_DATA_RESERVED1_MASK 0x3 -#define TX_QUEUE_START_RAMROD_DATA_RESERVED1_SHIFT 6 - u8 pxp_st_hint; - u8 pxp_tph_valid_bd; - u8 pxp_tph_valid_pkt; - __le16 pxp_st_index; - __le16 comp_agg_size; - __le16 queue_zone_id; - __le16 test_dup_count; - __le16 pbl_size; - __le16 tx_queue_id; - struct regpair pbl_base_addr; - struct regpair bd_cons_address; +/* Ramrod data for rx Add UDP Filter */ +struct rx_udp_filter_data { + __le16 action_icid; + __le16 vlan_id; + u8 ip_type; + u8 tenant_id_exists; + __le16 reserved1; + __le32 ip_dst_addr[4]; + __le32 ip_src_addr[4]; + __le16 udp_dst_port; + __le16 udp_src_port; + __le32 tenant_id; }; +/* Ramrod data for rx queue start ramrod */ +struct tx_queue_start_ramrod_data { + __le16 sb_id; + u8 sb_index; + u8 vport_id; + u8 reserved0; + u8 stats_counter_id; + __le16 qm_pq_id; + u8 flags; +#define TX_QUEUE_START_RAMROD_DATA_DISABLE_OPPORTUNISTIC_MASK 0x1 +#define TX_QUEUE_START_RAMROD_DATA_DISABLE_OPPORTUNISTIC_SHIFT 0 +#define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_PKT_DUP_MASK 0x1 +#define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_PKT_DUP_SHIFT 1 +#define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_TX_DEST_MASK 0x1 +#define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_TX_DEST_SHIFT 2 +#define TX_QUEUE_START_RAMROD_DATA_PMD_MODE_MASK 0x1 +#define TX_QUEUE_START_RAMROD_DATA_PMD_MODE_SHIFT 3 +#define TX_QUEUE_START_RAMROD_DATA_NOTIFY_EN_MASK 0x1 +#define TX_QUEUE_START_RAMROD_DATA_NOTIFY_EN_SHIFT 4 +#define TX_QUEUE_START_RAMROD_DATA_PIN_CONTEXT_MASK 0x1 +#define TX_QUEUE_START_RAMROD_DATA_PIN_CONTEXT_SHIFT 5 +#define TX_QUEUE_START_RAMROD_DATA_RESERVED1_MASK 0x3 +#define TX_QUEUE_START_RAMROD_DATA_RESERVED1_SHIFT 6 + u8 pxp_st_hint; + u8 pxp_tph_valid_bd; + u8 pxp_tph_valid_pkt; + __le16 pxp_st_index; + __le16 comp_agg_size; + __le16 queue_zone_id; + __le16 test_dup_count; + __le16 pbl_size; + __le16 tx_queue_id; + + struct regpair pbl_base_addr; + struct regpair bd_cons_address; +}; + +/* Ramrod data for tx queue stop ramrod */ struct tx_queue_stop_ramrod_data { __le16 reserved[4]; }; +/* Ramrod data for vport update ramrod */ struct vport_filter_update_ramrod_data { - struct eth_filter_cmd_header filter_cmd_hdr; - struct eth_filter_cmd filter_cmds[ETH_FILTER_RULES_COUNT]; + struct eth_filter_cmd_header filter_cmd_hdr; + struct eth_filter_cmd filter_cmds[ETH_FILTER_RULES_COUNT]; }; +/* Ramrod data for vport start ramrod */ struct vport_start_ramrod_data { - u8 vport_id; - u8 sw_fid; - __le16 mtu; - u8 drop_ttl0_en; - u8 inner_vlan_removal_en; - struct eth_vport_rx_mode rx_mode; - struct eth_vport_tx_mode tx_mode; - struct eth_vport_tpa_param tpa_param; - __le16 default_vlan; - u8 tx_switching_en; - u8 anti_spoofing_en; - u8 default_vlan_en; - u8 handle_ptp_pkts; - u8 silent_vlan_removal_en; - u8 untagged; - struct eth_tx_err_vals tx_err_behav; - u8 zero_placement_offset; - u8 reserved[7]; -}; - + u8 vport_id; + u8 sw_fid; + __le16 mtu; + u8 drop_ttl0_en; + u8 inner_vlan_removal_en; + struct eth_vport_rx_mode rx_mode; + struct eth_vport_tx_mode tx_mode; + struct eth_vport_tpa_param tpa_param; + __le16 default_vlan; + u8 tx_switching_en; + u8 anti_spoofing_en; + + u8 default_vlan_en; + + u8 handle_ptp_pkts; + u8 silent_vlan_removal_en; + u8 untagged; + struct eth_tx_err_vals tx_err_behav; + + u8 zero_placement_offset; + u8 ctl_frame_mac_check_en; + u8 ctl_frame_ethtype_check_en; + u8 reserved[5]; +}; + +/* Ramrod data for vport stop ramrod */ struct vport_stop_ramrod_data { - u8 vport_id; - u8 reserved[7]; + u8 vport_id; + u8 reserved[7]; }; +/* Ramrod data for vport update ramrod */ struct vport_update_ramrod_data_cmn { - u8 vport_id; - u8 update_rx_active_flg; - u8 rx_active_flg; - u8 update_tx_active_flg; - u8 tx_active_flg; - u8 update_rx_mode_flg; - u8 update_tx_mode_flg; - u8 update_approx_mcast_flg; - u8 update_rss_flg; - u8 update_inner_vlan_removal_en_flg; - u8 inner_vlan_removal_en; - u8 update_tpa_param_flg; - u8 update_tpa_en_flg; - u8 update_tx_switching_en_flg; - u8 tx_switching_en; - u8 update_anti_spoofing_en_flg; - u8 anti_spoofing_en; - u8 update_handle_ptp_pkts; - u8 handle_ptp_pkts; - u8 update_default_vlan_en_flg; - u8 default_vlan_en; - u8 update_default_vlan_flg; - __le16 default_vlan; - u8 update_accept_any_vlan_flg; - u8 accept_any_vlan; - u8 silent_vlan_removal_en; - u8 update_mtu_flg; - __le16 mtu; - u8 reserved[2]; + u8 vport_id; + u8 update_rx_active_flg; + u8 rx_active_flg; + u8 update_tx_active_flg; + u8 tx_active_flg; + u8 update_rx_mode_flg; + u8 update_tx_mode_flg; + u8 update_approx_mcast_flg; + + u8 update_rss_flg; + u8 update_inner_vlan_removal_en_flg; + + u8 inner_vlan_removal_en; + u8 update_tpa_param_flg; + u8 update_tpa_en_flg; + u8 update_tx_switching_en_flg; + + u8 tx_switching_en; + u8 update_anti_spoofing_en_flg; + + u8 anti_spoofing_en; + u8 update_handle_ptp_pkts; + + u8 handle_ptp_pkts; + u8 update_default_vlan_en_flg; + + u8 default_vlan_en; + + u8 update_default_vlan_flg; + + __le16 default_vlan; + u8 update_accept_any_vlan_flg; + + u8 accept_any_vlan; + u8 silent_vlan_removal_en; + u8 update_mtu_flg; + + __le16 mtu; + u8 reserved[2]; }; struct vport_update_ramrod_mcast { __le32 bins[ETH_MULTICAST_MAC_BINS_IN_REGS]; }; +/* Ramrod data for vport update ramrod */ struct vport_update_ramrod_data { - struct vport_update_ramrod_data_cmn common; - struct eth_vport_rx_mode rx_mode; - struct eth_vport_tx_mode tx_mode; - struct eth_vport_tpa_param tpa_param; - struct vport_update_ramrod_mcast approx_mcast; - struct eth_vport_rss_config rss_config; + struct vport_update_ramrod_data_cmn common; + + struct eth_vport_rx_mode rx_mode; + struct eth_vport_tx_mode tx_mode; + struct eth_vport_tpa_param tpa_param; + struct vport_update_ramrod_mcast approx_mcast; + struct eth_vport_rss_config rss_config; }; -#define VF_MAX_STATIC 192 /* In case of K2 */ +#define VF_MAX_STATIC 192 -#define MCP_GLOB_PATH_MAX 2 -#define MCP_PORT_MAX 2 /* Global */ -#define MCP_GLOB_PORT_MAX 4 /* Global */ -#define MCP_GLOB_FUNC_MAX 16 /* Global */ +#define MCP_GLOB_PATH_MAX 2 +#define MCP_PORT_MAX 2 +#define MCP_GLOB_PORT_MAX 4 +#define MCP_GLOB_FUNC_MAX 16 -typedef u32 offsize_t; /* In DWORDS !!! */ /* Offset from the beginning of the MCP scratchpad */ -#define OFFSIZE_OFFSET_SHIFT 0 -#define OFFSIZE_OFFSET_MASK 0x0000ffff +#define OFFSIZE_OFFSET_SHIFT 0 +#define OFFSIZE_OFFSET_MASK 0x0000ffff /* Size of specific element (not the whole array if any) */ -#define OFFSIZE_SIZE_SHIFT 16 -#define OFFSIZE_SIZE_MASK 0xffff0000 +#define OFFSIZE_SIZE_SHIFT 16 +#define OFFSIZE_SIZE_MASK 0xffff0000 -/* SECTION_OFFSET is calculating the offset in bytes out of offsize */ -#define SECTION_OFFSET(_offsize) ((((_offsize & \ - OFFSIZE_OFFSET_MASK) >> \ - OFFSIZE_OFFSET_SHIFT) << 2)) +#define SECTION_OFFSET(_offsize) ((((_offsize & \ + OFFSIZE_OFFSET_MASK) >> \ + OFFSIZE_OFFSET_SHIFT) << 2)) -/* QED_SECTION_SIZE is calculating the size in bytes out of offsize */ -#define QED_SECTION_SIZE(_offsize) (((_offsize & \ - OFFSIZE_SIZE_MASK) >> \ - OFFSIZE_SIZE_SHIFT) << 2) +#define QED_SECTION_SIZE(_offsize) (((_offsize & \ + OFFSIZE_SIZE_MASK) >> \ + OFFSIZE_SIZE_SHIFT) << 2) -/* SECTION_ADDR returns the GRC addr of a section, given offsize and index - * within section. - */ -#define SECTION_ADDR(_offsize, idx) (MCP_REG_SCRATCH + \ - SECTION_OFFSET(_offsize) + \ - (QED_SECTION_SIZE(_offsize) * idx)) +#define SECTION_ADDR(_offsize, idx) (MCP_REG_SCRATCH + \ + SECTION_OFFSET(_offsize) + \ + (QED_SECTION_SIZE(_offsize) * idx)) + +#define SECTION_OFFSIZE_ADDR(_pub_base, _section) \ + (_pub_base + offsetof(struct mcp_public_data, sections[_section])) -/* SECTION_OFFSIZE_ADDR returns the GRC addr to the offsize address. - * Use offsetof, since the OFFSETUP collide with the firmware definition - */ -#define SECTION_OFFSIZE_ADDR(_pub_base, _section) (_pub_base + \ - offsetof(struct \ - mcp_public_data, \ - sections[_section])) /* PHY configuration */ -struct pmm_phy_cfg { - u32 speed; -#define PMM_SPEED_AUTONEG 0 - - u32 pause; /* bitmask */ -#define PMM_PAUSE_NONE 0x0 -#define PMM_PAUSE_AUTONEG 0x1 -#define PMM_PAUSE_RX 0x2 -#define PMM_PAUSE_TX 0x4 - - u32 adv_speed; /* Default should be the speed_cap_mask */ - u32 loopback_mode; -#define PMM_LOOPBACK_NONE 0 -#define PMM_LOOPBACK_INT_PHY 1 -#define PMM_LOOPBACK_EXT_PHY 2 -#define PMM_LOOPBACK_EXT 3 -#define PMM_LOOPBACK_MAC 4 - - /* features */ +struct eth_phy_cfg { + u32 speed; +#define ETH_SPEED_AUTONEG 0 +#define ETH_SPEED_SMARTLINQ 0x8 + + u32 pause; +#define ETH_PAUSE_NONE 0x0 +#define ETH_PAUSE_AUTONEG 0x1 +#define ETH_PAUSE_RX 0x2 +#define ETH_PAUSE_TX 0x4 + + u32 adv_speed; + u32 loopback_mode; +#define ETH_LOOPBACK_NONE (0) +#define ETH_LOOPBACK_INT_PHY (1) +#define ETH_LOOPBACK_EXT_PHY (2) +#define ETH_LOOPBACK_EXT (3) +#define ETH_LOOPBACK_MAC (4) + u32 feature_config_flags; +#define ETH_EEE_MODE_ADV_LPI (1 << 0) }; struct port_mf_cfg { - u32 dynamic_cfg; /* device control channel */ -#define PORT_MF_CFG_OV_TAG_MASK 0x0000ffff -#define PORT_MF_CFG_OV_TAG_SHIFT 0 -#define PORT_MF_CFG_OV_TAG_DEFAULT PORT_MF_CFG_OV_TAG_MASK - - u32 reserved[1]; -}; - -/* DO NOT add new fields in the middle - * MUST be synced with struct pmm_stats_map - */ -struct pmm_stats { - u64 r64; /* 0x00 (Offset 0x00 ) RX 64-byte frame counter*/ - u64 r127; /* 0x01 (Offset 0x08 ) RX 65 to 127 byte frame counter*/ - u64 r255; - u64 r511; - u64 r1023; - u64 r1518; - u64 r1522; - u64 r2047; - u64 r4095; - u64 r9216; - u64 r16383; - u64 rfcs; /* 0x0F (Offset 0x58 ) RX FCS error frame counter*/ - u64 rxcf; /* 0x10 (Offset 0x60 ) RX control frame counter*/ - u64 rxpf; /* 0x11 (Offset 0x68 ) RX pause frame counter*/ - u64 rxpp; /* 0x12 (Offset 0x70 ) RX PFC frame counter*/ - u64 raln; /* 0x16 (Offset 0x78 ) RX alignment error counter*/ - u64 rfcr; /* 0x19 (Offset 0x80 ) RX false carrier counter */ - u64 rovr; /* 0x1A (Offset 0x88 ) RX oversized frame counter*/ - u64 rjbr; /* 0x1B (Offset 0x90 ) RX jabber frame counter */ - u64 rund; /* 0x34 (Offset 0x98 ) RX undersized frame counter */ - u64 rfrg; /* 0x35 (Offset 0xa0 ) RX fragment counter */ - u64 t64; /* 0x40 (Offset 0xa8 ) TX 64-byte frame counter */ - u64 t127; - u64 t255; - u64 t511; - u64 t1023; - u64 t1518; - u64 t2047; - u64 t4095; - u64 t9216; - u64 t16383; - u64 txpf; /* 0x50 (Offset 0xf8 ) TX pause frame counter */ - u64 txpp; /* 0x51 (Offset 0x100) TX PFC frame counter */ - u64 tlpiec; - u64 tncl; - u64 rbyte; /* 0x3d (Offset 0x118) RX byte counter */ - u64 rxuca; /* 0x0c (Offset 0x120) RX UC frame counter */ - u64 rxmca; /* 0x0d (Offset 0x128) RX MC frame counter */ - u64 rxbca; /* 0x0e (Offset 0x130) RX BC frame counter */ - u64 rxpok; - u64 tbyte; /* 0x6f (Offset 0x140) TX byte counter */ - u64 txuca; /* 0x4d (Offset 0x148) TX UC frame counter */ - u64 txmca; /* 0x4e (Offset 0x150) TX MC frame counter */ - u64 txbca; /* 0x4f (Offset 0x158) TX BC frame counter */ - u64 txcf; /* 0x54 (Offset 0x160) TX control frame counter */ + u32 dynamic_cfg; +#define PORT_MF_CFG_OV_TAG_MASK 0x0000ffff +#define PORT_MF_CFG_OV_TAG_SHIFT 0 +#define PORT_MF_CFG_OV_TAG_DEFAULT PORT_MF_CFG_OV_TAG_MASK + + u32 reserved[1]; +}; + +struct eth_stats { + u64 r64; + u64 r127; + u64 r255; + u64 r511; + u64 r1023; + u64 r1518; + u64 r1522; + u64 r2047; + u64 r4095; + u64 r9216; + u64 r16383; + u64 rfcs; + u64 rxcf; + u64 rxpf; + u64 rxpp; + u64 raln; + u64 rfcr; + u64 rovr; + u64 rjbr; + u64 rund; + u64 rfrg; + u64 t64; + u64 t127; + u64 t255; + u64 t511; + u64 t1023; + u64 t1518; + u64 t2047; + u64 t4095; + u64 t9216; + u64 t16383; + u64 txpf; + u64 txpp; + u64 tlpiec; + u64 tncl; + u64 rbyte; + u64 rxuca; + u64 rxmca; + u64 rxbca; + u64 rxpok; + u64 tbyte; + u64 txuca; + u64 txmca; + u64 txbca; + u64 txcf; }; struct brb_stats { - u64 brb_truncate[8]; - u64 brb_discard[8]; + u64 brb_truncate[8]; + u64 brb_discard[8]; }; struct port_stats { - struct brb_stats brb; - struct pmm_stats pmm; + struct brb_stats brb; + struct eth_stats eth; }; -#define CMT_TEAM0 0 -#define CMT_TEAM1 1 -#define CMT_TEAM_MAX 2 - struct couple_mode_teaming { u8 port_cmt[MCP_GLOB_PORT_MAX]; -#define PORT_CMT_IN_TEAM BIT(0) +#define PORT_CMT_IN_TEAM (1 << 0) -#define PORT_CMT_PORT_ROLE BIT(1) -#define PORT_CMT_PORT_INACTIVE (0 << 1) -#define PORT_CMT_PORT_ACTIVE BIT(1) +#define PORT_CMT_PORT_ROLE (1 << 1) +#define PORT_CMT_PORT_INACTIVE (0 << 1) +#define PORT_CMT_PORT_ACTIVE (1 << 1) -#define PORT_CMT_TEAM_MASK BIT(2) -#define PORT_CMT_TEAM0 (0 << 2) -#define PORT_CMT_TEAM1 BIT(2) +#define PORT_CMT_TEAM_MASK (1 << 2) +#define PORT_CMT_TEAM0 (0 << 2) +#define PORT_CMT_TEAM1 (1 << 2) }; -/************************************** -* LLDP and DCBX HSI structures -**************************************/ -#define LLDP_CHASSIS_ID_STAT_LEN 4 -#define LLDP_PORT_ID_STAT_LEN 4 -#define DCBX_MAX_APP_PROTOCOL 32 -#define MAX_SYSTEM_LLDP_TLV_DATA 32 +#define LLDP_CHASSIS_ID_STAT_LEN 4 +#define LLDP_PORT_ID_STAT_LEN 4 +#define DCBX_MAX_APP_PROTOCOL 32 +#define MAX_SYSTEM_LLDP_TLV_DATA 32 -enum lldp_agent_e { +enum _lldp_agent { LLDP_NEAREST_BRIDGE = 0, LLDP_NEAREST_NON_TPMR_BRIDGE, LLDP_NEAREST_CUSTOMER_BRIDGE, @@ -3394,689 +3778,512 @@ enum lldp_agent_e { struct lldp_config_params_s { u32 config; -#define LLDP_CONFIG_TX_INTERVAL_MASK 0x000000ff -#define LLDP_CONFIG_TX_INTERVAL_SHIFT 0 -#define LLDP_CONFIG_HOLD_MASK 0x00000f00 -#define LLDP_CONFIG_HOLD_SHIFT 8 -#define LLDP_CONFIG_MAX_CREDIT_MASK 0x0000f000 -#define LLDP_CONFIG_MAX_CREDIT_SHIFT 12 -#define LLDP_CONFIG_ENABLE_RX_MASK 0x40000000 -#define LLDP_CONFIG_ENABLE_RX_SHIFT 30 -#define LLDP_CONFIG_ENABLE_TX_MASK 0x80000000 -#define LLDP_CONFIG_ENABLE_TX_SHIFT 31 - u32 local_chassis_id[LLDP_CHASSIS_ID_STAT_LEN]; - u32 local_port_id[LLDP_PORT_ID_STAT_LEN]; +#define LLDP_CONFIG_TX_INTERVAL_MASK 0x000000ff +#define LLDP_CONFIG_TX_INTERVAL_SHIFT 0 +#define LLDP_CONFIG_HOLD_MASK 0x00000f00 +#define LLDP_CONFIG_HOLD_SHIFT 8 +#define LLDP_CONFIG_MAX_CREDIT_MASK 0x0000f000 +#define LLDP_CONFIG_MAX_CREDIT_SHIFT 12 +#define LLDP_CONFIG_ENABLE_RX_MASK 0x40000000 +#define LLDP_CONFIG_ENABLE_RX_SHIFT 30 +#define LLDP_CONFIG_ENABLE_TX_MASK 0x80000000 +#define LLDP_CONFIG_ENABLE_TX_SHIFT 31 + u32 local_chassis_id[LLDP_CHASSIS_ID_STAT_LEN]; + u32 local_port_id[LLDP_PORT_ID_STAT_LEN]; }; struct lldp_status_params_s { - u32 prefix_seq_num; - u32 status; /* TBD */ - - /* Holds remote Chassis ID TLV header, subtype and 9B of payload. */ - u32 peer_chassis_id[LLDP_CHASSIS_ID_STAT_LEN]; - - /* Holds remote Port ID TLV header, subtype and 9B of payload. */ - u32 peer_port_id[LLDP_PORT_ID_STAT_LEN]; - u32 suffix_seq_num; + u32 prefix_seq_num; + u32 status; + u32 peer_chassis_id[LLDP_CHASSIS_ID_STAT_LEN]; + u32 peer_port_id[LLDP_PORT_ID_STAT_LEN]; + u32 suffix_seq_num; }; struct dcbx_ets_feature { u32 flags; -#define DCBX_ETS_ENABLED_MASK 0x00000001 -#define DCBX_ETS_ENABLED_SHIFT 0 -#define DCBX_ETS_WILLING_MASK 0x00000002 -#define DCBX_ETS_WILLING_SHIFT 1 -#define DCBX_ETS_ERROR_MASK 0x00000004 -#define DCBX_ETS_ERROR_SHIFT 2 -#define DCBX_ETS_CBS_MASK 0x00000008 -#define DCBX_ETS_CBS_SHIFT 3 -#define DCBX_ETS_MAX_TCS_MASK 0x000000f0 -#define DCBX_ETS_MAX_TCS_SHIFT 4 - u32 pri_tc_tbl[1]; -#define DCBX_ISCSI_OOO_TC 4 -#define NIG_ETS_ISCSI_OOO_CLIENT_OFFSET (DCBX_ISCSI_OOO_TC + 1) - u32 tc_bw_tbl[2]; - u32 tc_tsa_tbl[2]; -#define DCBX_ETS_TSA_STRICT 0 -#define DCBX_ETS_TSA_CBS 1 -#define DCBX_ETS_TSA_ETS 2 +#define DCBX_ETS_ENABLED_MASK 0x00000001 +#define DCBX_ETS_ENABLED_SHIFT 0 +#define DCBX_ETS_WILLING_MASK 0x00000002 +#define DCBX_ETS_WILLING_SHIFT 1 +#define DCBX_ETS_ERROR_MASK 0x00000004 +#define DCBX_ETS_ERROR_SHIFT 2 +#define DCBX_ETS_CBS_MASK 0x00000008 +#define DCBX_ETS_CBS_SHIFT 3 +#define DCBX_ETS_MAX_TCS_MASK 0x000000f0 +#define DCBX_ETS_MAX_TCS_SHIFT 4 +#define DCBX_ISCSI_OOO_TC_MASK 0x00000f00 +#define DCBX_ISCSI_OOO_TC_SHIFT 8 + u32 pri_tc_tbl[1]; +#define DCBX_ISCSI_OOO_TC (4) + +#define NIG_ETS_ISCSI_OOO_CLIENT_OFFSET (DCBX_ISCSI_OOO_TC + 1) +#define DCBX_CEE_STRICT_PRIORITY 0xf + u32 tc_bw_tbl[2]; + u32 tc_tsa_tbl[2]; +#define DCBX_ETS_TSA_STRICT 0 +#define DCBX_ETS_TSA_CBS 1 +#define DCBX_ETS_TSA_ETS 2 }; struct dcbx_app_priority_entry { u32 entry; -#define DCBX_APP_PRI_MAP_MASK 0x000000ff -#define DCBX_APP_PRI_MAP_SHIFT 0 -#define DCBX_APP_PRI_0 0x01 -#define DCBX_APP_PRI_1 0x02 -#define DCBX_APP_PRI_2 0x04 -#define DCBX_APP_PRI_3 0x08 -#define DCBX_APP_PRI_4 0x10 -#define DCBX_APP_PRI_5 0x20 -#define DCBX_APP_PRI_6 0x40 -#define DCBX_APP_PRI_7 0x80 -#define DCBX_APP_SF_MASK 0x00000300 -#define DCBX_APP_SF_SHIFT 8 -#define DCBX_APP_SF_ETHTYPE 0 -#define DCBX_APP_SF_PORT 1 -#define DCBX_APP_PROTOCOL_ID_MASK 0xffff0000 -#define DCBX_APP_PROTOCOL_ID_SHIFT 16 -}; - -/* FW structure in BE */ +#define DCBX_APP_PRI_MAP_MASK 0x000000ff +#define DCBX_APP_PRI_MAP_SHIFT 0 +#define DCBX_APP_PRI_0 0x01 +#define DCBX_APP_PRI_1 0x02 +#define DCBX_APP_PRI_2 0x04 +#define DCBX_APP_PRI_3 0x08 +#define DCBX_APP_PRI_4 0x10 +#define DCBX_APP_PRI_5 0x20 +#define DCBX_APP_PRI_6 0x40 +#define DCBX_APP_PRI_7 0x80 +#define DCBX_APP_SF_MASK 0x00000300 +#define DCBX_APP_SF_SHIFT 8 +#define DCBX_APP_SF_ETHTYPE 0 +#define DCBX_APP_SF_PORT 1 +#define DCBX_APP_PROTOCOL_ID_MASK 0xffff0000 +#define DCBX_APP_PROTOCOL_ID_SHIFT 16 +}; + struct dcbx_app_priority_feature { u32 flags; -#define DCBX_APP_ENABLED_MASK 0x00000001 -#define DCBX_APP_ENABLED_SHIFT 0 -#define DCBX_APP_WILLING_MASK 0x00000002 -#define DCBX_APP_WILLING_SHIFT 1 -#define DCBX_APP_ERROR_MASK 0x00000004 -#define DCBX_APP_ERROR_SHIFT 2 -/* Not in use - * #define DCBX_APP_DEFAULT_PRI_MASK 0x00000f00 - * #define DCBX_APP_DEFAULT_PRI_SHIFT 8 - */ -#define DCBX_APP_MAX_TCS_MASK 0x0000f000 -#define DCBX_APP_MAX_TCS_SHIFT 12 -#define DCBX_APP_NUM_ENTRIES_MASK 0x00ff0000 -#define DCBX_APP_NUM_ENTRIES_SHIFT 16 +#define DCBX_APP_ENABLED_MASK 0x00000001 +#define DCBX_APP_ENABLED_SHIFT 0 +#define DCBX_APP_WILLING_MASK 0x00000002 +#define DCBX_APP_WILLING_SHIFT 1 +#define DCBX_APP_ERROR_MASK 0x00000004 +#define DCBX_APP_ERROR_SHIFT 2 +#define DCBX_APP_MAX_TCS_MASK 0x0000f000 +#define DCBX_APP_MAX_TCS_SHIFT 12 +#define DCBX_APP_NUM_ENTRIES_MASK 0x00ff0000 +#define DCBX_APP_NUM_ENTRIES_SHIFT 16 struct dcbx_app_priority_entry app_pri_tbl[DCBX_MAX_APP_PROTOCOL]; }; -/* FW structure in BE */ struct dcbx_features { - /* PG feature */ struct dcbx_ets_feature ets; + u32 pfc; +#define DCBX_PFC_PRI_EN_BITMAP_MASK 0x000000ff +#define DCBX_PFC_PRI_EN_BITMAP_SHIFT 0 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_0 0x01 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_1 0x02 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_2 0x04 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_3 0x08 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_4 0x10 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_5 0x20 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_6 0x40 +#define DCBX_PFC_PRI_EN_BITMAP_PRI_7 0x80 + +#define DCBX_PFC_FLAGS_MASK 0x0000ff00 +#define DCBX_PFC_FLAGS_SHIFT 8 +#define DCBX_PFC_CAPS_MASK 0x00000f00 +#define DCBX_PFC_CAPS_SHIFT 8 +#define DCBX_PFC_MBC_MASK 0x00004000 +#define DCBX_PFC_MBC_SHIFT 14 +#define DCBX_PFC_WILLING_MASK 0x00008000 +#define DCBX_PFC_WILLING_SHIFT 15 +#define DCBX_PFC_ENABLED_MASK 0x00010000 +#define DCBX_PFC_ENABLED_SHIFT 16 +#define DCBX_PFC_ERROR_MASK 0x00020000 +#define DCBX_PFC_ERROR_SHIFT 17 - /* PFC feature */ - u32 pfc; -#define DCBX_PFC_PRI_EN_BITMAP_MASK 0x000000ff -#define DCBX_PFC_PRI_EN_BITMAP_SHIFT 0 -#define DCBX_PFC_PRI_EN_BITMAP_PRI_0 0x01 -#define DCBX_PFC_PRI_EN_BITMAP_PRI_1 0x02 -#define DCBX_PFC_PRI_EN_BITMAP_PRI_2 0x04 -#define DCBX_PFC_PRI_EN_BITMAP_PRI_3 0x08 -#define DCBX_PFC_PRI_EN_BITMAP_PRI_4 0x10 -#define DCBX_PFC_PRI_EN_BITMAP_PRI_5 0x20 -#define DCBX_PFC_PRI_EN_BITMAP_PRI_6 0x40 -#define DCBX_PFC_PRI_EN_BITMAP_PRI_7 0x80 - -#define DCBX_PFC_FLAGS_MASK 0x0000ff00 -#define DCBX_PFC_FLAGS_SHIFT 8 -#define DCBX_PFC_CAPS_MASK 0x00000f00 -#define DCBX_PFC_CAPS_SHIFT 8 -#define DCBX_PFC_MBC_MASK 0x00004000 -#define DCBX_PFC_MBC_SHIFT 14 -#define DCBX_PFC_WILLING_MASK 0x00008000 -#define DCBX_PFC_WILLING_SHIFT 15 -#define DCBX_PFC_ENABLED_MASK 0x00010000 -#define DCBX_PFC_ENABLED_SHIFT 16 -#define DCBX_PFC_ERROR_MASK 0x00020000 -#define DCBX_PFC_ERROR_SHIFT 17 - - /* APP feature */ struct dcbx_app_priority_feature app; }; struct dcbx_local_params { u32 config; -#define DCBX_CONFIG_VERSION_MASK 0x00000003 -#define DCBX_CONFIG_VERSION_SHIFT 0 -#define DCBX_CONFIG_VERSION_DISABLED 0 -#define DCBX_CONFIG_VERSION_IEEE 1 -#define DCBX_CONFIG_VERSION_CEE 2 +#define DCBX_CONFIG_VERSION_MASK 0x00000007 +#define DCBX_CONFIG_VERSION_SHIFT 0 +#define DCBX_CONFIG_VERSION_DISABLED 0 +#define DCBX_CONFIG_VERSION_IEEE 1 +#define DCBX_CONFIG_VERSION_CEE 2 +#define DCBX_CONFIG_VERSION_STATIC 4 - u32 flags; - struct dcbx_features features; + u32 flags; + struct dcbx_features features; }; struct dcbx_mib { - u32 prefix_seq_num; - u32 flags; - struct dcbx_features features; - u32 suffix_seq_num; + u32 prefix_seq_num; + u32 flags; + struct dcbx_features features; + u32 suffix_seq_num; }; struct lldp_system_tlvs_buffer_s { - u16 valid; - u16 length; - u32 data[MAX_SYSTEM_LLDP_TLV_DATA]; + u16 valid; + u16 length; + u32 data[MAX_SYSTEM_LLDP_TLV_DATA]; }; -/**************************************/ -/* */ -/* P U B L I C G L O B A L */ -/* */ -/**************************************/ -struct public_global { - u32 max_path; -#define MAX_PATH_BIG_BEAR 2 -#define MAX_PATH_K2 1 - u32 max_ports; -#define MODE_1P 1 -#define MODE_2P 2 -#define MODE_3P 3 -#define MODE_4P 4 - u32 debug_mb_offset; - u32 phymod_dbg_mb_offset; - struct couple_mode_teaming cmt; - s32 internal_temperature; - u32 mfw_ver; - u32 running_bundle_id; +struct dcb_dscp_map { + u32 flags; +#define DCB_DSCP_ENABLE_MASK 0x1 +#define DCB_DSCP_ENABLE_SHIFT 0 +#define DCB_DSCP_ENABLE 1 + u32 dscp_pri_map[8]; }; -/**************************************/ -/* */ -/* P U B L I C P A T H */ -/* */ -/**************************************/ +struct public_global { + u32 max_path; + u32 max_ports; + u32 debug_mb_offset; + u32 phymod_dbg_mb_offset; + struct couple_mode_teaming cmt; + s32 internal_temperature; + u32 mfw_ver; + u32 running_bundle_id; + s32 external_temperature; + u32 mdump_reason; +}; -/**************************************************************************** -* Shared Memory 2 Region * -****************************************************************************/ -/* The fw_flr_ack is actually built in the following way: */ -/* 8 bit: PF ack */ -/* 128 bit: VF ack */ -/* 8 bit: ios_dis_ack */ -/* In order to maintain endianity in the mailbox hsi, we want to keep using */ -/* u32. The fw must have the VF right after the PF since this is how it */ -/* access arrays(it expects always the VF to reside after the PF, and that */ -/* makes the calculation much easier for it. ) */ -/* In order to answer both limitations, and keep the struct small, the code */ -/* will abuse the structure defined here to achieve the actual partition */ -/* above */ -/****************************************************************************/ struct fw_flr_mb { - u32 aggint; - u32 opgen_addr; - u32 accum_ack; /* 0..15:PF, 16..207:VF, 256..271:IOV_DIS */ -#define ACCUM_ACK_PF_BASE 0 -#define ACCUM_ACK_PF_SHIFT 0 - -#define ACCUM_ACK_VF_BASE 8 -#define ACCUM_ACK_VF_SHIFT 3 - -#define ACCUM_ACK_IOV_DIS_BASE 256 -#define ACCUM_ACK_IOV_DIS_SHIFT 8 + u32 aggint; + u32 opgen_addr; + u32 accum_ack; }; struct public_path { - struct fw_flr_mb flr_mb; - u32 mcp_vf_disabled[VF_MAX_STATIC / 32]; - - u32 process_kill; -#define PROCESS_KILL_COUNTER_MASK 0x0000ffff -#define PROCESS_KILL_COUNTER_SHIFT 0 -#define PROCESS_KILL_GLOB_AEU_BIT_MASK 0xffff0000 -#define PROCESS_KILL_GLOB_AEU_BIT_SHIFT 16 + struct fw_flr_mb flr_mb; + u32 mcp_vf_disabled[VF_MAX_STATIC / 32]; + + u32 process_kill; +#define PROCESS_KILL_COUNTER_MASK 0x0000ffff +#define PROCESS_KILL_COUNTER_SHIFT 0 +#define PROCESS_KILL_GLOB_AEU_BIT_MASK 0xffff0000 +#define PROCESS_KILL_GLOB_AEU_BIT_SHIFT 16 #define GLOBAL_AEU_BIT(aeu_reg_id, aeu_bit) (aeu_reg_id * 32 + aeu_bit) }; -/**************************************/ -/* */ -/* P U B L I C P O R T */ -/* */ -/**************************************/ - -/**************************************************************************** -* Driver <-> FW Mailbox * -****************************************************************************/ - struct public_port { - u32 validity_map; /* 0x0 (4*2 = 0x8) */ - - /* validity bits */ -#define MCP_VALIDITY_PCI_CFG 0x00100000 -#define MCP_VALIDITY_MB 0x00200000 -#define MCP_VALIDITY_DEV_INFO 0x00400000 -#define MCP_VALIDITY_RESERVED 0x00000007 - - /* One licensing bit should be set */ -#define MCP_VALIDITY_LIC_KEY_IN_EFFECT_MASK 0x00000038 -#define MCP_VALIDITY_LIC_MANUF_KEY_IN_EFFECT 0x00000008 -#define MCP_VALIDITY_LIC_UPGRADE_KEY_IN_EFFECT 0x00000010 -#define MCP_VALIDITY_LIC_NO_KEY_IN_EFFECT 0x00000020 - - /* Active MFW */ -#define MCP_VALIDITY_ACTIVE_MFW_UNKNOWN 0x00000000 -#define MCP_VALIDITY_ACTIVE_MFW_MASK 0x000001c0 -#define MCP_VALIDITY_ACTIVE_MFW_NCSI 0x00000040 -#define MCP_VALIDITY_ACTIVE_MFW_NONE 0x000001c0 + u32 validity_map; u32 link_status; -#define LINK_STATUS_LINK_UP \ - 0x00000001 -#define LINK_STATUS_SPEED_AND_DUPLEX_MASK 0x0000001e -#define LINK_STATUS_SPEED_AND_DUPLEX_1000THD BIT(1) -#define LINK_STATUS_SPEED_AND_DUPLEX_1000TFD (2 << 1) -#define LINK_STATUS_SPEED_AND_DUPLEX_10G (3 << 1) -#define LINK_STATUS_SPEED_AND_DUPLEX_20G (4 << 1) -#define LINK_STATUS_SPEED_AND_DUPLEX_40G (5 << 1) -#define LINK_STATUS_SPEED_AND_DUPLEX_50G (6 << 1) -#define LINK_STATUS_SPEED_AND_DUPLEX_100G (7 << 1) -#define LINK_STATUS_SPEED_AND_DUPLEX_25G (8 << 1) - -#define LINK_STATUS_AUTO_NEGOTIATE_ENABLED 0x00000020 - -#define LINK_STATUS_AUTO_NEGOTIATE_COMPLETE 0x00000040 -#define LINK_STATUS_PARALLEL_DETECTION_USED 0x00000080 - -#define LINK_STATUS_PFC_ENABLED \ - 0x00000100 -#define LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE 0x00000200 -#define LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE 0x00000400 -#define LINK_STATUS_LINK_PARTNER_10G_CAPABLE 0x00000800 -#define LINK_STATUS_LINK_PARTNER_20G_CAPABLE 0x00001000 -#define LINK_STATUS_LINK_PARTNER_40G_CAPABLE 0x00002000 -#define LINK_STATUS_LINK_PARTNER_50G_CAPABLE 0x00004000 -#define LINK_STATUS_LINK_PARTNER_100G_CAPABLE 0x00008000 -#define LINK_STATUS_LINK_PARTNER_25G_CAPABLE 0x00010000 - -#define LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK 0x000C0000 -#define LINK_STATUS_LINK_PARTNER_NOT_PAUSE_CAPABLE (0 << 18) -#define LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE BIT(18) -#define LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE (2 << 18) -#define LINK_STATUS_LINK_PARTNER_BOTH_PAUSE (3 << 18) - -#define LINK_STATUS_SFP_TX_FAULT \ - 0x00100000 -#define LINK_STATUS_TX_FLOW_CONTROL_ENABLED 0x00200000 -#define LINK_STATUS_RX_FLOW_CONTROL_ENABLED 0x00400000 - - u32 link_status1; - u32 ext_phy_fw_version; - u32 drv_phy_cfg_addr; - - u32 port_stx; - - u32 stat_nig_timer; - - struct port_mf_cfg port_mf_config; - struct port_stats stats; - - u32 media_type; -#define MEDIA_UNSPECIFIED 0x0 -#define MEDIA_SFPP_10G_FIBER 0x1 -#define MEDIA_XFP_FIBER 0x2 -#define MEDIA_DA_TWINAX 0x3 -#define MEDIA_BASE_T 0x4 -#define MEDIA_SFP_1G_FIBER 0x5 -#define MEDIA_KR 0xf0 -#define MEDIA_NOT_PRESENT 0xff +#define LINK_STATUS_LINK_UP 0x00000001 +#define LINK_STATUS_SPEED_AND_DUPLEX_MASK 0x0000001e +#define LINK_STATUS_SPEED_AND_DUPLEX_1000THD (1 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_1000TFD (2 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_10G (3 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_20G (4 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_40G (5 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_50G (6 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_100G (7 << 1) +#define LINK_STATUS_SPEED_AND_DUPLEX_25G (8 << 1) + +#define LINK_STATUS_AUTO_NEGOTIATE_ENABLED 0x00000020 + +#define LINK_STATUS_AUTO_NEGOTIATE_COMPLETE 0x00000040 +#define LINK_STATUS_PARALLEL_DETECTION_USED 0x00000080 + +#define LINK_STATUS_PFC_ENABLED 0x00000100 +#define LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE 0x00000200 +#define LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE 0x00000400 +#define LINK_STATUS_LINK_PARTNER_10G_CAPABLE 0x00000800 +#define LINK_STATUS_LINK_PARTNER_20G_CAPABLE 0x00001000 +#define LINK_STATUS_LINK_PARTNER_40G_CAPABLE 0x00002000 +#define LINK_STATUS_LINK_PARTNER_50G_CAPABLE 0x00004000 +#define LINK_STATUS_LINK_PARTNER_100G_CAPABLE 0x00008000 +#define LINK_STATUS_LINK_PARTNER_25G_CAPABLE 0x00010000 + +#define LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK 0x000C0000 +#define LINK_STATUS_LINK_PARTNER_NOT_PAUSE_CAPABLE (0 << 18) +#define LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE (1 << 18) +#define LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE (2 << 18) +#define LINK_STATUS_LINK_PARTNER_BOTH_PAUSE (3 << 18) + +#define LINK_STATUS_SFP_TX_FAULT 0x00100000 +#define LINK_STATUS_TX_FLOW_CONTROL_ENABLED 0x00200000 +#define LINK_STATUS_RX_FLOW_CONTROL_ENABLED 0x00400000 +#define LINK_STATUS_RX_SIGNAL_PRESENT 0x00800000 +#define LINK_STATUS_MAC_LOCAL_FAULT 0x01000000 +#define LINK_STATUS_MAC_REMOTE_FAULT 0x02000000 +#define LINK_STATUS_UNSUPPORTED_SPD_REQ 0x04000000 + + u32 link_status1; + u32 ext_phy_fw_version; + u32 drv_phy_cfg_addr; + + u32 port_stx; + + u32 stat_nig_timer; + + struct port_mf_cfg port_mf_config; + struct port_stats stats; + + u32 media_type; +#define MEDIA_UNSPECIFIED 0x0 +#define MEDIA_SFPP_10G_FIBER 0x1 +#define MEDIA_XFP_FIBER 0x2 +#define MEDIA_DA_TWINAX 0x3 +#define MEDIA_BASE_T 0x4 +#define MEDIA_SFP_1G_FIBER 0x5 +#define MEDIA_MODULE_FIBER 0x6 +#define MEDIA_KR 0xf0 +#define MEDIA_NOT_PRESENT 0xff u32 lfa_status; -#define LFA_LINK_FLAP_REASON_OFFSET 0 -#define LFA_LINK_FLAP_REASON_MASK 0x000000ff -#define LFA_NO_REASON (0 << 0) -#define LFA_LINK_DOWN BIT(0) -#define LFA_FORCE_INIT BIT(1) -#define LFA_LOOPBACK_MISMATCH BIT(2) -#define LFA_SPEED_MISMATCH BIT(3) -#define LFA_FLOW_CTRL_MISMATCH BIT(4) -#define LFA_ADV_SPEED_MISMATCH BIT(5) -#define LINK_FLAP_AVOIDANCE_COUNT_OFFSET 8 -#define LINK_FLAP_AVOIDANCE_COUNT_MASK 0x0000ff00 -#define LINK_FLAP_COUNT_OFFSET 16 -#define LINK_FLAP_COUNT_MASK 0x00ff0000 - - u32 link_change_count; - - /* LLDP params */ - struct lldp_config_params_s lldp_config_params[ - LLDP_MAX_LLDP_AGENTS]; - struct lldp_status_params_s lldp_status_params[ - LLDP_MAX_LLDP_AGENTS]; - struct lldp_system_tlvs_buffer_s system_lldp_tlvs_buf; + u32 link_change_count; + + struct lldp_config_params_s lldp_config_params[LLDP_MAX_LLDP_AGENTS]; + struct lldp_status_params_s lldp_status_params[LLDP_MAX_LLDP_AGENTS]; + struct lldp_system_tlvs_buffer_s system_lldp_tlvs_buf; /* DCBX related MIB */ - struct dcbx_local_params local_admin_dcbx_mib; - struct dcbx_mib remote_dcbx_mib; - struct dcbx_mib operational_dcbx_mib; + struct dcbx_local_params local_admin_dcbx_mib; + struct dcbx_mib remote_dcbx_mib; + struct dcbx_mib operational_dcbx_mib; - u32 fc_npiv_nvram_tbl_addr; - u32 fc_npiv_nvram_tbl_size; - u32 transceiver_data; -#define PMM_TRANSCEIVER_STATE_MASK 0x000000FF -#define PMM_TRANSCEIVER_STATE_SHIFT 0x00000000 -#define PMM_TRANSCEIVER_STATE_PRESENT 0x00000001 -}; + u32 reserved[2]; + u32 transceiver_data; +#define ETH_TRANSCEIVER_STATE_MASK 0x000000FF +#define ETH_TRANSCEIVER_STATE_SHIFT 0x00000000 +#define ETH_TRANSCEIVER_STATE_UNPLUGGED 0x00000000 +#define ETH_TRANSCEIVER_STATE_PRESENT 0x00000001 +#define ETH_TRANSCEIVER_STATE_VALID 0x00000003 +#define ETH_TRANSCEIVER_STATE_UPDATING 0x00000008 -/**************************************/ -/* */ -/* P U B L I C F U N C */ -/* */ -/**************************************/ + u32 wol_info; + u32 wol_pkt_len; + u32 wol_pkt_details; + struct dcb_dscp_map dcb_dscp_map; +}; struct public_func { - u32 iscsi_boot_signature; - u32 iscsi_boot_block_offset; - - u32 mtu_size; - u32 c2s_pcp_map_lower; - u32 c2s_pcp_map_upper; - u32 c2s_pcp_map_default; - u32 reserved[4]; - - u32 config; - - /* E/R/I/D */ - /* function 0 of each port cannot be hidden */ -#define FUNC_MF_CFG_FUNC_HIDE 0x00000001 -#define FUNC_MF_CFG_PAUSE_ON_HOST_RING 0x00000002 -#define FUNC_MF_CFG_PAUSE_ON_HOST_RING_SHIFT 0x00000001 - -#define FUNC_MF_CFG_PROTOCOL_MASK 0x000000f0 -#define FUNC_MF_CFG_PROTOCOL_SHIFT 4 -#define FUNC_MF_CFG_PROTOCOL_ETHERNET 0x00000000 -#define FUNC_MF_CFG_PROTOCOL_ISCSI 0x00000010 -#define FUNC_MF_CFG_PROTOCOL_FCOE 0x00000020 -#define FUNC_MF_CFG_PROTOCOL_ROCE 0x00000030 -#define FUNC_MF_CFG_PROTOCOL_MAX 0x00000030 - - /* MINBW, MAXBW */ - /* value range - 0..100, increments in 1 % */ -#define FUNC_MF_CFG_MIN_BW_MASK 0x0000ff00 -#define FUNC_MF_CFG_MIN_BW_SHIFT 8 -#define FUNC_MF_CFG_MIN_BW_DEFAULT 0x00000000 -#define FUNC_MF_CFG_MAX_BW_MASK 0x00ff0000 -#define FUNC_MF_CFG_MAX_BW_SHIFT 16 -#define FUNC_MF_CFG_MAX_BW_DEFAULT 0x00640000 - - u32 status; -#define FUNC_STATUS_VLINK_DOWN 0x00000001 - - u32 mac_upper; /* MAC */ -#define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff -#define FUNC_MF_CFG_UPPERMAC_SHIFT 0 -#define FUNC_MF_CFG_UPPERMAC_DEFAULT FUNC_MF_CFG_UPPERMAC_MASK - u32 mac_lower; -#define FUNC_MF_CFG_LOWERMAC_DEFAULT 0xffffffff - - u32 fcoe_wwn_port_name_upper; - u32 fcoe_wwn_port_name_lower; - - u32 fcoe_wwn_node_name_upper; - u32 fcoe_wwn_node_name_lower; - - u32 ovlan_stag; /* tags */ -#define FUNC_MF_CFG_OV_STAG_MASK 0x0000ffff -#define FUNC_MF_CFG_OV_STAG_SHIFT 0 -#define FUNC_MF_CFG_OV_STAG_DEFAULT FUNC_MF_CFG_OV_STAG_MASK - - u32 pf_allocation; /* vf per pf */ - - u32 preserve_data; /* Will be used bt CCM */ - - u32 driver_last_activity_ts; - - u32 drv_ack_vf_disabled[VF_MAX_STATIC / 32]; /* 0x0044 */ - - u32 drv_id; -#define DRV_ID_PDA_COMP_VER_MASK 0x0000ffff -#define DRV_ID_PDA_COMP_VER_SHIFT 0 - -#define DRV_ID_MCP_HSI_VER_MASK 0x00ff0000 -#define DRV_ID_MCP_HSI_VER_SHIFT 16 -#define DRV_ID_MCP_HSI_VER_CURRENT BIT(DRV_ID_MCP_HSI_VER_SHIFT) - -#define DRV_ID_DRV_TYPE_MASK 0x7f000000 -#define DRV_ID_DRV_TYPE_SHIFT 24 -#define DRV_ID_DRV_TYPE_UNKNOWN (0 << DRV_ID_DRV_TYPE_SHIFT) -#define DRV_ID_DRV_TYPE_LINUX (1 << DRV_ID_DRV_TYPE_SHIFT) -#define DRV_ID_DRV_TYPE_WINDOWS (2 << DRV_ID_DRV_TYPE_SHIFT) -#define DRV_ID_DRV_TYPE_DIAG (3 << DRV_ID_DRV_TYPE_SHIFT) -#define DRV_ID_DRV_TYPE_PREBOOT (4 << DRV_ID_DRV_TYPE_SHIFT) -#define DRV_ID_DRV_TYPE_SOLARIS (5 << DRV_ID_DRV_TYPE_SHIFT) -#define DRV_ID_DRV_TYPE_VMWARE (6 << DRV_ID_DRV_TYPE_SHIFT) -#define DRV_ID_DRV_TYPE_FREEBSD (7 << DRV_ID_DRV_TYPE_SHIFT) -#define DRV_ID_DRV_TYPE_AIX (8 << DRV_ID_DRV_TYPE_SHIFT) - -#define DRV_ID_DRV_INIT_HW_MASK 0x80000000 -#define DRV_ID_DRV_INIT_HW_SHIFT 31 -#define DRV_ID_DRV_INIT_HW_FLAG BIT(DRV_ID_DRV_INIT_HW_SHIFT) -}; + u32 reserved0[2]; -/**************************************/ -/* */ -/* P U B L I C M B */ -/* */ -/**************************************/ -/* This is the only section that the driver can write to, and each */ -/* Basically each driver request to set feature parameters, - * will be done using a different command, which will be linked - * to a specific data structure from the union below. - * For huge strucuture, the common blank structure should be used. - */ + u32 mtu_size; + + u32 reserved[7]; + + u32 config; +#define FUNC_MF_CFG_FUNC_HIDE 0x00000001 +#define FUNC_MF_CFG_PAUSE_ON_HOST_RING 0x00000002 +#define FUNC_MF_CFG_PAUSE_ON_HOST_RING_SHIFT 0x00000001 + +#define FUNC_MF_CFG_PROTOCOL_MASK 0x000000f0 +#define FUNC_MF_CFG_PROTOCOL_SHIFT 4 +#define FUNC_MF_CFG_PROTOCOL_ETHERNET 0x00000000 +#define FUNC_MF_CFG_PROTOCOL_MAX 0x00000030 + +#define FUNC_MF_CFG_MIN_BW_MASK 0x0000ff00 +#define FUNC_MF_CFG_MIN_BW_SHIFT 8 +#define FUNC_MF_CFG_MIN_BW_DEFAULT 0x00000000 +#define FUNC_MF_CFG_MAX_BW_MASK 0x00ff0000 +#define FUNC_MF_CFG_MAX_BW_SHIFT 16 +#define FUNC_MF_CFG_MAX_BW_DEFAULT 0x00640000 + + u32 status; +#define FUNC_STATUS_VLINK_DOWN 0x00000001 + + u32 mac_upper; +#define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff +#define FUNC_MF_CFG_UPPERMAC_SHIFT 0 +#define FUNC_MF_CFG_UPPERMAC_DEFAULT FUNC_MF_CFG_UPPERMAC_MASK + u32 mac_lower; +#define FUNC_MF_CFG_LOWERMAC_DEFAULT 0xffffffff + + u32 fcoe_wwn_port_name_upper; + u32 fcoe_wwn_port_name_lower; + + u32 fcoe_wwn_node_name_upper; + u32 fcoe_wwn_node_name_lower; + + u32 ovlan_stag; +#define FUNC_MF_CFG_OV_STAG_MASK 0x0000ffff +#define FUNC_MF_CFG_OV_STAG_SHIFT 0 +#define FUNC_MF_CFG_OV_STAG_DEFAULT FUNC_MF_CFG_OV_STAG_MASK + + u32 pf_allocation; + + u32 preserve_data; + + u32 driver_last_activity_ts; + + u32 drv_ack_vf_disabled[VF_MAX_STATIC / 32]; + + u32 drv_id; +#define DRV_ID_PDA_COMP_VER_MASK 0x0000ffff +#define DRV_ID_PDA_COMP_VER_SHIFT 0 + +#define DRV_ID_MCP_HSI_VER_MASK 0x00ff0000 +#define DRV_ID_MCP_HSI_VER_SHIFT 16 +#define DRV_ID_MCP_HSI_VER_CURRENT (1 << DRV_ID_MCP_HSI_VER_SHIFT) + +#define DRV_ID_DRV_TYPE_MASK 0x7f000000 +#define DRV_ID_DRV_TYPE_SHIFT 24 +#define DRV_ID_DRV_TYPE_UNKNOWN (0 << DRV_ID_DRV_TYPE_SHIFT) +#define DRV_ID_DRV_TYPE_LINUX (1 << DRV_ID_DRV_TYPE_SHIFT) + +#define DRV_ID_DRV_INIT_HW_MASK 0x80000000 +#define DRV_ID_DRV_INIT_HW_SHIFT 31 +#define DRV_ID_DRV_INIT_HW_FLAG (1 << DRV_ID_DRV_INIT_HW_SHIFT) +}; struct mcp_mac { - u32 mac_upper; /* Upper 16 bits are always zeroes */ - u32 mac_lower; + u32 mac_upper; + u32 mac_lower; }; struct mcp_val64 { - u32 lo; - u32 hi; + u32 lo; + u32 hi; }; struct mcp_file_att { - u32 nvm_start_addr; - u32 len; + u32 nvm_start_addr; + u32 len; +}; + +struct bist_nvm_image_att { + u32 return_code; + u32 image_type; + u32 nvm_start_addr; + u32 len; }; #define MCP_DRV_VER_STR_SIZE 16 #define MCP_DRV_VER_STR_SIZE_DWORD (MCP_DRV_VER_STR_SIZE / sizeof(u32)) #define MCP_DRV_NVM_BUF_LEN 32 struct drv_version_stc { - u32 version; - u8 name[MCP_DRV_VER_STR_SIZE - 4]; + u32 version; + u8 name[MCP_DRV_VER_STR_SIZE - 4]; +}; + +struct lan_stats_stc { + u64 ucast_rx_pkts; + u64 ucast_tx_pkts; + u32 fcs_err; + u32 rserved; +}; + +struct ocbb_data_stc { + u32 ocbb_host_addr; + u32 ocsd_host_addr; + u32 ocsd_req_update_interval; +}; + +#define MAX_NUM_OF_SENSORS 7 +struct temperature_status_stc { + u32 num_of_sensors; + u32 sensor[MAX_NUM_OF_SENSORS]; +}; + +/* crash dump configuration header */ +struct mdump_config_stc { + u32 version; + u32 config; + u32 epoc; + u32 num_of_logs; + u32 valid_logs; }; union drv_union_data { - u32 ver_str[MCP_DRV_VER_STR_SIZE_DWORD]; - struct mcp_mac wol_mac; + u32 ver_str[MCP_DRV_VER_STR_SIZE_DWORD]; + struct mcp_mac wol_mac; + + struct eth_phy_cfg drv_phy_cfg; - struct pmm_phy_cfg drv_phy_cfg; + struct mcp_val64 val64; - struct mcp_val64 val64; /* For PHY / AVS commands */ + u8 raw_data[MCP_DRV_NVM_BUF_LEN]; - u8 raw_data[MCP_DRV_NVM_BUF_LEN]; + struct mcp_file_att file_att; - struct mcp_file_att file_att; + u32 ack_vf_disabled[VF_MAX_STATIC / 32]; - u32 ack_vf_disabled[VF_MAX_STATIC / 32]; + struct drv_version_stc drv_version; - struct drv_version_stc drv_version; + struct lan_stats_stc lan_stats; + u64 reserved_stats[11]; + struct ocbb_data_stc ocbb_info; + struct temperature_status_stc temp_info; + struct bist_nvm_image_att nvm_image_att; + struct mdump_config_stc mdump_config; }; struct public_drv_mb { u32 drv_mb_header; -#define DRV_MSG_CODE_MASK 0xffff0000 -#define DRV_MSG_CODE_LOAD_REQ 0x10000000 -#define DRV_MSG_CODE_LOAD_DONE 0x11000000 -#define DRV_MSG_CODE_INIT_HW 0x12000000 -#define DRV_MSG_CODE_UNLOAD_REQ 0x20000000 -#define DRV_MSG_CODE_UNLOAD_DONE 0x21000000 -#define DRV_MSG_CODE_INIT_PHY 0x22000000 - /* Params - FORCE - Reinitialize the link regardless of LFA */ - /* - DONT_CARE - Don't flap the link if up */ -#define DRV_MSG_CODE_LINK_RESET 0x23000000 - -#define DRV_MSG_CODE_SET_LLDP 0x24000000 -#define DRV_MSG_CODE_SET_DCBX 0x25000000 +#define DRV_MSG_CODE_MASK 0xffff0000 +#define DRV_MSG_CODE_LOAD_REQ 0x10000000 +#define DRV_MSG_CODE_LOAD_DONE 0x11000000 +#define DRV_MSG_CODE_INIT_HW 0x12000000 +#define DRV_MSG_CODE_UNLOAD_REQ 0x20000000 +#define DRV_MSG_CODE_UNLOAD_DONE 0x21000000 +#define DRV_MSG_CODE_INIT_PHY 0x22000000 +#define DRV_MSG_CODE_LINK_RESET 0x23000000 +#define DRV_MSG_CODE_SET_DCBX 0x25000000 + #define DRV_MSG_CODE_BW_UPDATE_ACK 0x32000000 -#define DRV_MSG_CODE_NIG_DRAIN 0x30000000 - -#define DRV_MSG_CODE_INITIATE_FLR 0x02000000 -#define DRV_MSG_CODE_VF_DISABLED_DONE 0xc0000000 -#define DRV_MSG_CODE_CFG_VF_MSIX 0xc0010000 -#define DRV_MSG_CODE_NVM_PUT_FILE_BEGIN 0x00010000 -#define DRV_MSG_CODE_NVM_PUT_FILE_DATA 0x00020000 -#define DRV_MSG_CODE_NVM_GET_FILE_ATT 0x00030000 -#define DRV_MSG_CODE_NVM_READ_NVRAM 0x00050000 -#define DRV_MSG_CODE_NVM_WRITE_NVRAM 0x00060000 -#define DRV_MSG_CODE_NVM_DEL_FILE 0x00080000 -#define DRV_MSG_CODE_MCP_RESET 0x00090000 -#define DRV_MSG_CODE_SET_SECURE_MODE 0x000a0000 -#define DRV_MSG_CODE_PHY_RAW_READ 0x000b0000 -#define DRV_MSG_CODE_PHY_RAW_WRITE 0x000c0000 -#define DRV_MSG_CODE_PHY_CORE_READ 0x000d0000 -#define DRV_MSG_CODE_PHY_CORE_WRITE 0x000e0000 -#define DRV_MSG_CODE_SET_VERSION 0x000f0000 - -#define DRV_MSG_CODE_BIST_TEST 0x001e0000 -#define DRV_MSG_CODE_SET_LED_MODE 0x00200000 - -#define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff +#define DRV_MSG_CODE_NIG_DRAIN 0x30000000 +#define DRV_MSG_CODE_VF_DISABLED_DONE 0xc0000000 +#define DRV_MSG_CODE_CFG_VF_MSIX 0xc0010000 +#define DRV_MSG_CODE_MCP_RESET 0x00090000 +#define DRV_MSG_CODE_SET_VERSION 0x000f0000 + +#define DRV_MSG_CODE_BIST_TEST 0x001e0000 +#define DRV_MSG_CODE_SET_LED_MODE 0x00200000 + +#define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff u32 drv_mb_param; +#define DRV_MB_PARAM_UNLOAD_WOL_MCP 0x00000001 +#define DRV_MB_PARAM_DCBX_NOTIFY_MASK 0x000000FF +#define DRV_MB_PARAM_DCBX_NOTIFY_SHIFT 3 +#define DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT 0 +#define DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK 0x000000FF +#define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT 8 +#define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK 0x0000FF00 + +#define DRV_MB_PARAM_SET_LED_MODE_OPER 0x0 +#define DRV_MB_PARAM_SET_LED_MODE_ON 0x1 +#define DRV_MB_PARAM_SET_LED_MODE_OFF 0x2 - /* UNLOAD_REQ params */ -#define DRV_MB_PARAM_UNLOAD_WOL_UNKNOWN 0x00000000 -#define DRV_MB_PARAM_UNLOAD_WOL_MCP 0x00000001 -#define DRV_MB_PARAM_UNLOAD_WOL_DISABLED 0x00000002 -#define DRV_MB_PARAM_UNLOAD_WOL_ENABLED 0x00000003 - - /* UNLOAD_DONE_params */ -#define DRV_MB_PARAM_UNLOAD_NON_D3_POWER 0x00000001 - - /* INIT_PHY params */ -#define DRV_MB_PARAM_INIT_PHY_FORCE 0x00000001 -#define DRV_MB_PARAM_INIT_PHY_DONT_CARE 0x00000002 - - /* LLDP / DCBX params*/ -#define DRV_MB_PARAM_LLDP_SEND_MASK 0x00000001 -#define DRV_MB_PARAM_LLDP_SEND_SHIFT 0 -#define DRV_MB_PARAM_LLDP_AGENT_MASK 0x00000006 -#define DRV_MB_PARAM_LLDP_AGENT_SHIFT 1 -#define DRV_MB_PARAM_DCBX_NOTIFY_MASK 0x00000008 -#define DRV_MB_PARAM_DCBX_NOTIFY_SHIFT 3 - -#define DRV_MB_PARAM_NIG_DRAIN_PERIOD_MS_MASK 0x000000FF -#define DRV_MB_PARAM_NIG_DRAIN_PERIOD_MS_SHIFT 0 - -#define DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_MFW 0x1 -#define DRV_MB_PARAM_NVM_PUT_FILE_BEGIN_IMAGE 0x2 - -#define DRV_MB_PARAM_NVM_OFFSET_SHIFT 0 -#define DRV_MB_PARAM_NVM_OFFSET_MASK 0x00FFFFFF -#define DRV_MB_PARAM_NVM_LEN_SHIFT 24 -#define DRV_MB_PARAM_NVM_LEN_MASK 0xFF000000 - -#define DRV_MB_PARAM_PHY_ADDR_SHIFT 0 -#define DRV_MB_PARAM_PHY_ADDR_MASK 0x1FF0FFFF -#define DRV_MB_PARAM_PHY_LANE_SHIFT 16 -#define DRV_MB_PARAM_PHY_LANE_MASK 0x000F0000 -#define DRV_MB_PARAM_PHY_SELECT_PORT_SHIFT 29 -#define DRV_MB_PARAM_PHY_SELECT_PORT_MASK 0x20000000 -#define DRV_MB_PARAM_PHY_PORT_SHIFT 30 -#define DRV_MB_PARAM_PHY_PORT_MASK 0xc0000000 - -/* configure vf MSIX params*/ -#define DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT 0 -#define DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK 0x000000FF -#define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT 8 -#define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK 0x0000FF00 - -#define DRV_MB_PARAM_SET_LED_MODE_OPER 0x0 -#define DRV_MB_PARAM_SET_LED_MODE_ON 0x1 -#define DRV_MB_PARAM_SET_LED_MODE_OFF 0x2 - -#define DRV_MB_PARAM_BIST_UNKNOWN_TEST 0 -#define DRV_MB_PARAM_BIST_REGISTER_TEST 1 -#define DRV_MB_PARAM_BIST_CLOCK_TEST 2 - -#define DRV_MB_PARAM_BIST_RC_UNKNOWN 0 -#define DRV_MB_PARAM_BIST_RC_PASSED 1 -#define DRV_MB_PARAM_BIST_RC_FAILED 2 -#define DRV_MB_PARAM_BIST_RC_INVALID_PARAMETER 3 - -#define DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT 0 -#define DRV_MB_PARAM_BIST_TEST_INDEX_MASK 0x000000FF +#define DRV_MB_PARAM_BIST_REGISTER_TEST 1 +#define DRV_MB_PARAM_BIST_CLOCK_TEST 2 + +#define DRV_MB_PARAM_BIST_RC_UNKNOWN 0 +#define DRV_MB_PARAM_BIST_RC_PASSED 1 +#define DRV_MB_PARAM_BIST_RC_FAILED 2 +#define DRV_MB_PARAM_BIST_RC_INVALID_PARAMETER 3 + +#define DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT 0 +#define DRV_MB_PARAM_BIST_TEST_INDEX_MASK 0x000000FF u32 fw_mb_header; -#define FW_MSG_CODE_MASK 0xffff0000 -#define FW_MSG_CODE_DRV_LOAD_ENGINE 0x10100000 -#define FW_MSG_CODE_DRV_LOAD_PORT 0x10110000 -#define FW_MSG_CODE_DRV_LOAD_FUNCTION 0x10120000 -#define FW_MSG_CODE_DRV_LOAD_REFUSED_PDA 0x10200000 -#define FW_MSG_CODE_DRV_LOAD_REFUSED_HSI 0x10210000 -#define FW_MSG_CODE_DRV_LOAD_REFUSED_DIAG 0x10220000 -#define FW_MSG_CODE_DRV_LOAD_DONE 0x11100000 -#define FW_MSG_CODE_DRV_UNLOAD_ENGINE 0x20110000 -#define FW_MSG_CODE_DRV_UNLOAD_PORT 0x20120000 -#define FW_MSG_CODE_DRV_UNLOAD_FUNCTION 0x20130000 -#define FW_MSG_CODE_DRV_UNLOAD_DONE 0x21100000 -#define FW_MSG_CODE_INIT_PHY_DONE 0x21200000 -#define FW_MSG_CODE_INIT_PHY_ERR_INVALID_ARGS 0x21300000 -#define FW_MSG_CODE_LINK_RESET_DONE 0x23000000 -#define FW_MSG_CODE_SET_LLDP_DONE 0x24000000 -#define FW_MSG_CODE_SET_LLDP_UNSUPPORTED_AGENT 0x24010000 -#define FW_MSG_CODE_SET_DCBX_DONE 0x25000000 -#define FW_MSG_CODE_NIG_DRAIN_DONE 0x30000000 -#define FW_MSG_CODE_VF_DISABLED_DONE 0xb0000000 -#define FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE 0xb0010000 -#define FW_MSG_CODE_FLR_ACK 0x02000000 -#define FW_MSG_CODE_FLR_NACK 0x02100000 - -#define FW_MSG_CODE_NVM_OK 0x00010000 -#define FW_MSG_CODE_NVM_INVALID_MODE 0x00020000 -#define FW_MSG_CODE_NVM_PREV_CMD_WAS_NOT_FINISHED 0x00030000 -#define FW_MSG_CODE_NVM_FAILED_TO_ALLOCATE_PAGE 0x00040000 -#define FW_MSG_CODE_NVM_INVALID_DIR_FOUND 0x00050000 -#define FW_MSG_CODE_NVM_PAGE_NOT_FOUND 0x00060000 -#define FW_MSG_CODE_NVM_FAILED_PARSING_BNDLE_HEADER 0x00070000 -#define FW_MSG_CODE_NVM_FAILED_PARSING_IMAGE_HEADER 0x00080000 -#define FW_MSG_CODE_NVM_PARSING_OUT_OF_SYNC 0x00090000 -#define FW_MSG_CODE_NVM_FAILED_UPDATING_DIR 0x000a0000 -#define FW_MSG_CODE_NVM_FAILED_TO_FREE_PAGE 0x000b0000 -#define FW_MSG_CODE_NVM_FILE_NOT_FOUND 0x000c0000 -#define FW_MSG_CODE_NVM_OPERATION_FAILED 0x000d0000 -#define FW_MSG_CODE_NVM_FAILED_UNALIGNED 0x000e0000 -#define FW_MSG_CODE_NVM_BAD_OFFSET 0x000f0000 -#define FW_MSG_CODE_NVM_BAD_SIGNATURE 0x00100000 -#define FW_MSG_CODE_NVM_FILE_READ_ONLY 0x00200000 -#define FW_MSG_CODE_NVM_UNKNOWN_FILE 0x00300000 -#define FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK 0x00400000 -#define FW_MSG_CODE_MCP_RESET_REJECT 0x00600000 -#define FW_MSG_CODE_PHY_OK 0x00110000 -#define FW_MSG_CODE_PHY_ERROR 0x00120000 -#define FW_MSG_CODE_SET_SECURE_MODE_ERROR 0x00130000 -#define FW_MSG_CODE_SET_SECURE_MODE_OK 0x00140000 -#define FW_MSG_MODE_PHY_PRIVILEGE_ERROR 0x00150000 -#define FW_MSG_CODE_OK 0x00160000 - -#define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff - - u32 fw_mb_param; - - u32 drv_pulse_mb; -#define DRV_PULSE_SEQ_MASK 0x00007fff -#define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000 -#define DRV_PULSE_ALWAYS_ALIVE 0x00008000 +#define FW_MSG_CODE_MASK 0xffff0000 +#define FW_MSG_CODE_DRV_LOAD_ENGINE 0x10100000 +#define FW_MSG_CODE_DRV_LOAD_PORT 0x10110000 +#define FW_MSG_CODE_DRV_LOAD_FUNCTION 0x10120000 +#define FW_MSG_CODE_DRV_LOAD_REFUSED_PDA 0x10200000 +#define FW_MSG_CODE_DRV_LOAD_REFUSED_HSI 0x10210000 +#define FW_MSG_CODE_DRV_LOAD_REFUSED_DIAG 0x10220000 +#define FW_MSG_CODE_DRV_LOAD_DONE 0x11100000 +#define FW_MSG_CODE_DRV_UNLOAD_ENGINE 0x20110000 +#define FW_MSG_CODE_DRV_UNLOAD_PORT 0x20120000 +#define FW_MSG_CODE_DRV_UNLOAD_FUNCTION 0x20130000 +#define FW_MSG_CODE_DRV_UNLOAD_DONE 0x21100000 +#define FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE 0xb0010000 +#define FW_MSG_CODE_OK 0x00160000 + +#define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff + + u32 fw_mb_param; + + u32 drv_pulse_mb; +#define DRV_PULSE_SEQ_MASK 0x00007fff +#define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000 +#define DRV_PULSE_ALWAYS_ALIVE 0x00008000 + u32 mcp_pulse_mb; -#define MCP_PULSE_SEQ_MASK 0x00007fff -#define MCP_PULSE_ALWAYS_ALIVE 0x00008000 -#define MCP_EVENT_MASK 0xffff0000 -#define MCP_EVENT_OTHER_DRIVER_RESET_REQ 0x00010000 +#define MCP_PULSE_SEQ_MASK 0x00007fff +#define MCP_PULSE_ALWAYS_ALIVE 0x00008000 +#define MCP_EVENT_MASK 0xffff0000 +#define MCP_EVENT_OTHER_DRIVER_RESET_REQ 0x00010000 union drv_union_data union_data; }; -/* MFW - DRV MB */ -/********************************************************************** -* Description -* Incremental Aggregative -* 8-bit MFW counter per message -* 8-bit ack-counter per message -* Capabilities -* Provides up to 256 aggregative message per type -* Provides 4 message types in dword -* Message type pointers to byte offset -* Backward Compatibility by using sizeof for the counters. -* No lock requires for 32bit messages -* Limitations: -* In case of messages greater than 32bit, a dedicated mechanism(e.g lock) -* is required to prevent data corruption. -**********************************************************************/ enum MFW_DRV_MSG_TYPE { MFW_DRV_MSG_LINK_CHANGE, MFW_DRV_MSG_FLR_FW_ACK_FAILED, @@ -4084,37 +4291,33 @@ enum MFW_DRV_MSG_TYPE { MFW_DRV_MSG_LLDP_DATA_UPDATED, MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED, MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED, - MFW_DRV_MSG_ERROR_RECOVERY, + MFW_DRV_MSG_RESERVED4, MFW_DRV_MSG_BW_UPDATE, - MFW_DRV_MSG_S_TAG_UPDATE, - MFW_DRV_MSG_GET_LAN_STATS, - MFW_DRV_MSG_GET_FCOE_STATS, - MFW_DRV_MSG_GET_ISCSI_STATS, - MFW_DRV_MSG_GET_RDMA_STATS, - MFW_DRV_MSG_FAILURE_DETECTED, + MFW_DRV_MSG_BW_UPDATE5, + MFW_DRV_MSG_BW_UPDATE6, + MFW_DRV_MSG_BW_UPDATE7, + MFW_DRV_MSG_BW_UPDATE8, + MFW_DRV_MSG_BW_UPDATE9, + MFW_DRV_MSG_BW_UPDATE10, MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE, + MFW_DRV_MSG_BW_UPDATE11, MFW_DRV_MSG_MAX }; -#define MFW_DRV_MSG_MAX_DWORDS(msgs) (((msgs - 1) >> 2) + 1) -#define MFW_DRV_MSG_DWORD(msg_id) (msg_id >> 2) -#define MFW_DRV_MSG_OFFSET(msg_id) ((msg_id & 0x3) << 3) -#define MFW_DRV_MSG_MASK(msg_id) (0xff << MFW_DRV_MSG_OFFSET(msg_id)) +#define MFW_DRV_MSG_MAX_DWORDS(msgs) (((msgs - 1) >> 2) + 1) +#define MFW_DRV_MSG_DWORD(msg_id) (msg_id >> 2) +#define MFW_DRV_MSG_OFFSET(msg_id) ((msg_id & 0x3) << 3) +#define MFW_DRV_MSG_MASK(msg_id) (0xff << MFW_DRV_MSG_OFFSET(msg_id)) struct public_mfw_mb { - u32 sup_msgs; - u32 msg[MFW_DRV_MSG_MAX_DWORDS(MFW_DRV_MSG_MAX)]; - u32 ack[MFW_DRV_MSG_MAX_DWORDS(MFW_DRV_MSG_MAX)]; + u32 sup_msgs; + u32 msg[MFW_DRV_MSG_MAX_DWORDS(MFW_DRV_MSG_MAX)]; + u32 ack[MFW_DRV_MSG_MAX_DWORDS(MFW_DRV_MSG_MAX)]; }; -/**************************************/ -/* */ -/* P U B L I C D A T A */ -/* */ -/**************************************/ enum public_sections { - PUBLIC_DRV_MB, /* Points to the first drv_mb of path0 */ - PUBLIC_MFW_MB, /* Points to the first mfw_mb of path0 */ + PUBLIC_DRV_MB, + PUBLIC_MFW_MB, PUBLIC_GLOBAL, PUBLIC_PATH, PUBLIC_PORT, @@ -4122,1080 +4325,177 @@ enum public_sections { PUBLIC_MAX_SECTIONS }; -struct drv_ver_info_stc { - u32 ver; - u8 name[32]; -}; - struct mcp_public_data { - /* The sections fields is an array */ - u32 num_sections; - offsize_t sections[PUBLIC_MAX_SECTIONS]; - struct public_drv_mb drv_mb[MCP_GLOB_FUNC_MAX]; - struct public_mfw_mb mfw_mb[MCP_GLOB_FUNC_MAX]; - struct public_global global; - struct public_path path[MCP_GLOB_PATH_MAX]; - struct public_port port[MCP_GLOB_PORT_MAX]; - struct public_func func[MCP_GLOB_FUNC_MAX]; - struct drv_ver_info_stc drv_info; + u32 num_sections; + u32 sections[PUBLIC_MAX_SECTIONS]; + struct public_drv_mb drv_mb[MCP_GLOB_FUNC_MAX]; + struct public_mfw_mb mfw_mb[MCP_GLOB_FUNC_MAX]; + struct public_global global; + struct public_path path[MCP_GLOB_PATH_MAX]; + struct public_port port[MCP_GLOB_PORT_MAX]; + struct public_func func[MCP_GLOB_FUNC_MAX]; }; struct nvm_cfg_mac_address { - u32 mac_addr_hi; -#define NVM_CFG_MAC_ADDRESS_HI_MASK 0x0000FFFF -#define NVM_CFG_MAC_ADDRESS_HI_OFFSET 0 - - u32 mac_addr_lo; + u32 mac_addr_hi; +#define NVM_CFG_MAC_ADDRESS_HI_MASK 0x0000FFFF +#define NVM_CFG_MAC_ADDRESS_HI_OFFSET 0 + u32 mac_addr_lo; }; -/****************************************** -* nvm_cfg1 structs -******************************************/ - struct nvm_cfg1_glob { - u32 generic_cont0; /* 0x0 */ -#define NVM_CFG1_GLOB_BOARD_SWAP_MASK 0x0000000F -#define NVM_CFG1_GLOB_BOARD_SWAP_OFFSET 0 -#define NVM_CFG1_GLOB_BOARD_SWAP_NONE 0x0 -#define NVM_CFG1_GLOB_BOARD_SWAP_PATH 0x1 -#define NVM_CFG1_GLOB_BOARD_SWAP_PORT 0x2 -#define NVM_CFG1_GLOB_BOARD_SWAP_BOTH 0x3 -#define NVM_CFG1_GLOB_MF_MODE_MASK 0x00000FF0 -#define NVM_CFG1_GLOB_MF_MODE_OFFSET 4 -#define NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED 0x0 -#define NVM_CFG1_GLOB_MF_MODE_DEFAULT 0x1 -#define NVM_CFG1_GLOB_MF_MODE_SPIO4 0x2 -#define NVM_CFG1_GLOB_MF_MODE_NPAR1_0 0x3 -#define NVM_CFG1_GLOB_MF_MODE_NPAR1_5 0x4 -#define NVM_CFG1_GLOB_MF_MODE_NPAR2_0 0x5 -#define NVM_CFG1_GLOB_MF_MODE_BD 0x6 -#define NVM_CFG1_GLOB_MF_MODE_UFP 0x7 -#define NVM_CFG1_GLOB_FAN_FAILURE_ENFORCEMENT_MASK 0x00001000 -#define NVM_CFG1_GLOB_FAN_FAILURE_ENFORCEMENT_OFFSET 12 -#define NVM_CFG1_GLOB_FAN_FAILURE_ENFORCEMENT_DISABLED 0x0 -#define NVM_CFG1_GLOB_FAN_FAILURE_ENFORCEMENT_ENABLED 0x1 -#define NVM_CFG1_GLOB_AVS_MARGIN_LOW_MASK 0x001FE000 -#define NVM_CFG1_GLOB_AVS_MARGIN_LOW_OFFSET 13 -#define NVM_CFG1_GLOB_AVS_MARGIN_HIGH_MASK 0x1FE00000 -#define NVM_CFG1_GLOB_AVS_MARGIN_HIGH_OFFSET 21 -#define NVM_CFG1_GLOB_ENABLE_SRIOV_MASK 0x20000000 -#define NVM_CFG1_GLOB_ENABLE_SRIOV_OFFSET 29 -#define NVM_CFG1_GLOB_ENABLE_SRIOV_DISABLED 0x0 -#define NVM_CFG1_GLOB_ENABLE_SRIOV_ENABLED 0x1 -#define NVM_CFG1_GLOB_ENABLE_ATC_MASK 0x40000000 -#define NVM_CFG1_GLOB_ENABLE_ATC_OFFSET 30 -#define NVM_CFG1_GLOB_ENABLE_ATC_DISABLED 0x0 -#define NVM_CFG1_GLOB_ENABLE_ATC_ENABLED 0x1 -#define NVM_CFG1_GLOB_CLOCK_SLOWDOWN_MASK 0x80000000 -#define NVM_CFG1_GLOB_CLOCK_SLOWDOWN_OFFSET 31 -#define NVM_CFG1_GLOB_CLOCK_SLOWDOWN_DISABLED 0x0 -#define NVM_CFG1_GLOB_CLOCK_SLOWDOWN_ENABLED 0x1 - - u32 engineering_change[3]; /* 0x4 */ - - u32 manufacturing_id; /* 0x10 */ - - u32 serial_number[4]; /* 0x14 */ - - u32 pcie_cfg; /* 0x24 */ -#define NVM_CFG1_GLOB_PCI_GEN_MASK 0x00000003 -#define NVM_CFG1_GLOB_PCI_GEN_OFFSET 0 -#define NVM_CFG1_GLOB_PCI_GEN_PCI_GEN1 0x0 -#define NVM_CFG1_GLOB_PCI_GEN_PCI_GEN2 0x1 -#define NVM_CFG1_GLOB_PCI_GEN_PCI_GEN3 0x2 -#define NVM_CFG1_GLOB_BEACON_WOL_ENABLED_MASK 0x00000004 -#define NVM_CFG1_GLOB_BEACON_WOL_ENABLED_OFFSET 2 -#define NVM_CFG1_GLOB_BEACON_WOL_ENABLED_DISABLED 0x0 -#define NVM_CFG1_GLOB_BEACON_WOL_ENABLED_ENABLED 0x1 -#define NVM_CFG1_GLOB_ASPM_SUPPORT_MASK 0x00000018 -#define NVM_CFG1_GLOB_ASPM_SUPPORT_OFFSET 3 -#define NVM_CFG1_GLOB_ASPM_SUPPORT_L0S_L1_ENABLED 0x0 -#define NVM_CFG1_GLOB_ASPM_SUPPORT_L0S_DISABLED 0x1 -#define NVM_CFG1_GLOB_ASPM_SUPPORT_L1_DISABLED 0x2 -#define NVM_CFG1_GLOB_ASPM_SUPPORT_L0S_L1_DISABLED 0x3 -#define NVM_CFG1_GLOB_PREVENT_PCIE_L1_MENTRY_MASK 0x00000020 -#define NVM_CFG1_GLOB_PREVENT_PCIE_L1_MENTRY_OFFSET 5 -#define NVM_CFG1_GLOB_PREVENT_PCIE_L1_MENTRY_DISABLED 0x0 -#define NVM_CFG1_GLOB_PREVENT_PCIE_L1_MENTRY_ENABLED 0x1 -#define NVM_CFG1_GLOB_PCIE_G2_TX_AMPLITUDE_MASK 0x000003C0 -#define NVM_CFG1_GLOB_PCIE_G2_TX_AMPLITUDE_OFFSET 6 -#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_MASK 0x00001C00 -#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_OFFSET 10 -#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_HW 0x0 -#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_0DB 0x1 -#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_3_5DB 0x2 -#define NVM_CFG1_GLOB_PCIE_PREEMPHASIS_6_0DB 0x3 -#define NVM_CFG1_GLOB_WWN_NODE_PREFIX0_MASK 0x001FE000 -#define NVM_CFG1_GLOB_WWN_NODE_PREFIX0_OFFSET 13 -#define NVM_CFG1_GLOB_WWN_NODE_PREFIX1_MASK 0x1FE00000 -#define NVM_CFG1_GLOB_WWN_NODE_PREFIX1_OFFSET 21 -#define NVM_CFG1_GLOB_NCSI_PACKAGE_ID_MASK 0x60000000 -#define NVM_CFG1_GLOB_NCSI_PACKAGE_ID_OFFSET 29 - - u32 mgmt_traffic; /* 0x28 */ -#define NVM_CFG1_GLOB_RESERVED60_MASK 0x00000001 -#define NVM_CFG1_GLOB_RESERVED60_OFFSET 0 -#define NVM_CFG1_GLOB_RESERVED60_100KHZ 0x0 -#define NVM_CFG1_GLOB_RESERVED60_400KHZ 0x1 -#define NVM_CFG1_GLOB_WWN_PORT_PREFIX0_MASK 0x000001FE -#define NVM_CFG1_GLOB_WWN_PORT_PREFIX0_OFFSET 1 -#define NVM_CFG1_GLOB_WWN_PORT_PREFIX1_MASK 0x0001FE00 -#define NVM_CFG1_GLOB_WWN_PORT_PREFIX1_OFFSET 9 -#define NVM_CFG1_GLOB_SMBUS_ADDRESS_MASK 0x01FE0000 -#define NVM_CFG1_GLOB_SMBUS_ADDRESS_OFFSET 17 -#define NVM_CFG1_GLOB_SIDEBAND_MODE_MASK 0x06000000 -#define NVM_CFG1_GLOB_SIDEBAND_MODE_OFFSET 25 -#define NVM_CFG1_GLOB_SIDEBAND_MODE_DISABLED 0x0 -#define NVM_CFG1_GLOB_SIDEBAND_MODE_RMII 0x1 -#define NVM_CFG1_GLOB_SIDEBAND_MODE_SGMII 0x2 - - u32 core_cfg; /* 0x2C */ -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK 0x000000FF -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET 0 -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X40G 0x0 -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X50G 0x1 -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X100G 0x2 -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X10G_F 0x3 -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X10G_E 0x4 -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_4X20G 0x5 -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X40G 0xB -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_2X25G 0xC -#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_DE_1X25G 0xD -#define NVM_CFG1_GLOB_EAGLE_ENFORCE_TX_FIR_CFG_MASK 0x00000100 -#define NVM_CFG1_GLOB_EAGLE_ENFORCE_TX_FIR_CFG_OFFSET 8 -#define NVM_CFG1_GLOB_EAGLE_ENFORCE_TX_FIR_CFG_DISABLED 0x0 -#define NVM_CFG1_GLOB_EAGLE_ENFORCE_TX_FIR_CFG_ENABLED 0x1 -#define NVM_CFG1_GLOB_FALCON_ENFORCE_TX_FIR_CFG_MASK 0x00000200 -#define NVM_CFG1_GLOB_FALCON_ENFORCE_TX_FIR_CFG_OFFSET 9 -#define NVM_CFG1_GLOB_FALCON_ENFORCE_TX_FIR_CFG_DISABLED 0x0 -#define NVM_CFG1_GLOB_FALCON_ENFORCE_TX_FIR_CFG_ENABLED 0x1 -#define NVM_CFG1_GLOB_EAGLE_CORE_ADDR_MASK 0x0003FC00 -#define NVM_CFG1_GLOB_EAGLE_CORE_ADDR_OFFSET 10 -#define NVM_CFG1_GLOB_FALCON_CORE_ADDR_MASK 0x03FC0000 -#define NVM_CFG1_GLOB_FALCON_CORE_ADDR_OFFSET 18 -#define NVM_CFG1_GLOB_AVS_MODE_MASK 0x1C000000 -#define NVM_CFG1_GLOB_AVS_MODE_OFFSET 26 -#define NVM_CFG1_GLOB_AVS_MODE_CLOSE_LOOP 0x0 -#define NVM_CFG1_GLOB_AVS_MODE_OPEN_LOOP 0x1 -#define NVM_CFG1_GLOB_AVS_MODE_DISABLED 0x3 -#define NVM_CFG1_GLOB_OVERRIDE_SECURE_MODE_MASK 0x60000000 -#define NVM_CFG1_GLOB_OVERRIDE_SECURE_MODE_OFFSET 29 -#define NVM_CFG1_GLOB_OVERRIDE_SECURE_MODE_DISABLED 0x0 -#define NVM_CFG1_GLOB_OVERRIDE_SECURE_MODE_ENABLED 0x1 - - u32 e_lane_cfg1; /* 0x30 */ -#define NVM_CFG1_GLOB_RX_LANE0_SWAP_MASK 0x0000000F -#define NVM_CFG1_GLOB_RX_LANE0_SWAP_OFFSET 0 -#define NVM_CFG1_GLOB_RX_LANE1_SWAP_MASK 0x000000F0 -#define NVM_CFG1_GLOB_RX_LANE1_SWAP_OFFSET 4 -#define NVM_CFG1_GLOB_RX_LANE2_SWAP_MASK 0x00000F00 -#define NVM_CFG1_GLOB_RX_LANE2_SWAP_OFFSET 8 -#define NVM_CFG1_GLOB_RX_LANE3_SWAP_MASK 0x0000F000 -#define NVM_CFG1_GLOB_RX_LANE3_SWAP_OFFSET 12 -#define NVM_CFG1_GLOB_TX_LANE0_SWAP_MASK 0x000F0000 -#define NVM_CFG1_GLOB_TX_LANE0_SWAP_OFFSET 16 -#define NVM_CFG1_GLOB_TX_LANE1_SWAP_MASK 0x00F00000 -#define NVM_CFG1_GLOB_TX_LANE1_SWAP_OFFSET 20 -#define NVM_CFG1_GLOB_TX_LANE2_SWAP_MASK 0x0F000000 -#define NVM_CFG1_GLOB_TX_LANE2_SWAP_OFFSET 24 -#define NVM_CFG1_GLOB_TX_LANE3_SWAP_MASK 0xF0000000 -#define NVM_CFG1_GLOB_TX_LANE3_SWAP_OFFSET 28 - - u32 e_lane_cfg2; /* 0x34 */ -#define NVM_CFG1_GLOB_RX_LANE0_POL_FLIP_MASK 0x00000001 -#define NVM_CFG1_GLOB_RX_LANE0_POL_FLIP_OFFSET 0 -#define NVM_CFG1_GLOB_RX_LANE1_POL_FLIP_MASK 0x00000002 -#define NVM_CFG1_GLOB_RX_LANE1_POL_FLIP_OFFSET 1 -#define NVM_CFG1_GLOB_RX_LANE2_POL_FLIP_MASK 0x00000004 -#define NVM_CFG1_GLOB_RX_LANE2_POL_FLIP_OFFSET 2 -#define NVM_CFG1_GLOB_RX_LANE3_POL_FLIP_MASK 0x00000008 -#define NVM_CFG1_GLOB_RX_LANE3_POL_FLIP_OFFSET 3 -#define NVM_CFG1_GLOB_TX_LANE0_POL_FLIP_MASK 0x00000010 -#define NVM_CFG1_GLOB_TX_LANE0_POL_FLIP_OFFSET 4 -#define NVM_CFG1_GLOB_TX_LANE1_POL_FLIP_MASK 0x00000020 -#define NVM_CFG1_GLOB_TX_LANE1_POL_FLIP_OFFSET 5 -#define NVM_CFG1_GLOB_TX_LANE2_POL_FLIP_MASK 0x00000040 -#define NVM_CFG1_GLOB_TX_LANE2_POL_FLIP_OFFSET 6 -#define NVM_CFG1_GLOB_TX_LANE3_POL_FLIP_MASK 0x00000080 -#define NVM_CFG1_GLOB_TX_LANE3_POL_FLIP_OFFSET 7 -#define NVM_CFG1_GLOB_SMBUS_MODE_MASK 0x00000F00 -#define NVM_CFG1_GLOB_SMBUS_MODE_OFFSET 8 -#define NVM_CFG1_GLOB_SMBUS_MODE_DISABLED 0x0 -#define NVM_CFG1_GLOB_SMBUS_MODE_100KHZ 0x1 -#define NVM_CFG1_GLOB_SMBUS_MODE_400KHZ 0x2 -#define NVM_CFG1_GLOB_NCSI_MASK 0x0000F000 -#define NVM_CFG1_GLOB_NCSI_OFFSET 12 -#define NVM_CFG1_GLOB_NCSI_DISABLED 0x0 -#define NVM_CFG1_GLOB_NCSI_ENABLED 0x1 - - u32 f_lane_cfg1; /* 0x38 */ -#define NVM_CFG1_GLOB_RX_LANE0_SWAP_MASK 0x0000000F -#define NVM_CFG1_GLOB_RX_LANE0_SWAP_OFFSET 0 -#define NVM_CFG1_GLOB_RX_LANE1_SWAP_MASK 0x000000F0 -#define NVM_CFG1_GLOB_RX_LANE1_SWAP_OFFSET 4 -#define NVM_CFG1_GLOB_RX_LANE2_SWAP_MASK 0x00000F00 -#define NVM_CFG1_GLOB_RX_LANE2_SWAP_OFFSET 8 -#define NVM_CFG1_GLOB_RX_LANE3_SWAP_MASK 0x0000F000 -#define NVM_CFG1_GLOB_RX_LANE3_SWAP_OFFSET 12 -#define NVM_CFG1_GLOB_TX_LANE0_SWAP_MASK 0x000F0000 -#define NVM_CFG1_GLOB_TX_LANE0_SWAP_OFFSET 16 -#define NVM_CFG1_GLOB_TX_LANE1_SWAP_MASK 0x00F00000 -#define NVM_CFG1_GLOB_TX_LANE1_SWAP_OFFSET 20 -#define NVM_CFG1_GLOB_TX_LANE2_SWAP_MASK 0x0F000000 -#define NVM_CFG1_GLOB_TX_LANE2_SWAP_OFFSET 24 -#define NVM_CFG1_GLOB_TX_LANE3_SWAP_MASK 0xF0000000 -#define NVM_CFG1_GLOB_TX_LANE3_SWAP_OFFSET 28 - - u32 f_lane_cfg2; /* 0x3C */ -#define NVM_CFG1_GLOB_RX_LANE0_POL_FLIP_MASK 0x00000001 -#define NVM_CFG1_GLOB_RX_LANE0_POL_FLIP_OFFSET 0 -#define NVM_CFG1_GLOB_RX_LANE1_POL_FLIP_MASK 0x00000002 -#define NVM_CFG1_GLOB_RX_LANE1_POL_FLIP_OFFSET 1 -#define NVM_CFG1_GLOB_RX_LANE2_POL_FLIP_MASK 0x00000004 -#define NVM_CFG1_GLOB_RX_LANE2_POL_FLIP_OFFSET 2 -#define NVM_CFG1_GLOB_RX_LANE3_POL_FLIP_MASK 0x00000008 -#define NVM_CFG1_GLOB_RX_LANE3_POL_FLIP_OFFSET 3 -#define NVM_CFG1_GLOB_TX_LANE0_POL_FLIP_MASK 0x00000010 -#define NVM_CFG1_GLOB_TX_LANE0_POL_FLIP_OFFSET 4 -#define NVM_CFG1_GLOB_TX_LANE1_POL_FLIP_MASK 0x00000020 -#define NVM_CFG1_GLOB_TX_LANE1_POL_FLIP_OFFSET 5 -#define NVM_CFG1_GLOB_TX_LANE2_POL_FLIP_MASK 0x00000040 -#define NVM_CFG1_GLOB_TX_LANE2_POL_FLIP_OFFSET 6 -#define NVM_CFG1_GLOB_TX_LANE3_POL_FLIP_MASK 0x00000080 -#define NVM_CFG1_GLOB_TX_LANE3_POL_FLIP_OFFSET 7 - - u32 eagle_preemphasis; /* 0x40 */ -#define NVM_CFG1_GLOB_LANE0_PREEMP_MASK 0x000000FF -#define NVM_CFG1_GLOB_LANE0_PREEMP_OFFSET 0 -#define NVM_CFG1_GLOB_LANE1_PREEMP_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_LANE1_PREEMP_OFFSET 8 -#define NVM_CFG1_GLOB_LANE2_PREEMP_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_LANE2_PREEMP_OFFSET 16 -#define NVM_CFG1_GLOB_LANE3_PREEMP_MASK 0xFF000000 -#define NVM_CFG1_GLOB_LANE3_PREEMP_OFFSET 24 - - u32 eagle_driver_current; /* 0x44 */ -#define NVM_CFG1_GLOB_LANE0_AMP_MASK 0x000000FF -#define NVM_CFG1_GLOB_LANE0_AMP_OFFSET 0 -#define NVM_CFG1_GLOB_LANE1_AMP_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_LANE1_AMP_OFFSET 8 -#define NVM_CFG1_GLOB_LANE2_AMP_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_LANE2_AMP_OFFSET 16 -#define NVM_CFG1_GLOB_LANE3_AMP_MASK 0xFF000000 -#define NVM_CFG1_GLOB_LANE3_AMP_OFFSET 24 - - u32 falcon_preemphasis; /* 0x48 */ -#define NVM_CFG1_GLOB_LANE0_PREEMP_MASK 0x000000FF -#define NVM_CFG1_GLOB_LANE0_PREEMP_OFFSET 0 -#define NVM_CFG1_GLOB_LANE1_PREEMP_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_LANE1_PREEMP_OFFSET 8 -#define NVM_CFG1_GLOB_LANE2_PREEMP_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_LANE2_PREEMP_OFFSET 16 -#define NVM_CFG1_GLOB_LANE3_PREEMP_MASK 0xFF000000 -#define NVM_CFG1_GLOB_LANE3_PREEMP_OFFSET 24 - - u32 falcon_driver_current; /* 0x4C */ -#define NVM_CFG1_GLOB_LANE0_AMP_MASK 0x000000FF -#define NVM_CFG1_GLOB_LANE0_AMP_OFFSET 0 -#define NVM_CFG1_GLOB_LANE1_AMP_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_LANE1_AMP_OFFSET 8 -#define NVM_CFG1_GLOB_LANE2_AMP_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_LANE2_AMP_OFFSET 16 -#define NVM_CFG1_GLOB_LANE3_AMP_MASK 0xFF000000 -#define NVM_CFG1_GLOB_LANE3_AMP_OFFSET 24 - - u32 pci_id; /* 0x50 */ -#define NVM_CFG1_GLOB_VENDOR_ID_MASK 0x0000FFFF -#define NVM_CFG1_GLOB_VENDOR_ID_OFFSET 0 - - u32 pci_subsys_id; /* 0x54 */ -#define NVM_CFG1_GLOB_SUBSYSTEM_VENDOR_ID_MASK 0x0000FFFF -#define NVM_CFG1_GLOB_SUBSYSTEM_VENDOR_ID_OFFSET 0 -#define NVM_CFG1_GLOB_SUBSYSTEM_DEVICE_ID_MASK 0xFFFF0000 -#define NVM_CFG1_GLOB_SUBSYSTEM_DEVICE_ID_OFFSET 16 - - u32 bar; /* 0x58 */ -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_MASK 0x0000000F -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_OFFSET 0 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_DISABLED 0x0 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_2K 0x1 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_4K 0x2 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_8K 0x3 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_16K 0x4 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_32K 0x5 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_64K 0x6 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_128K 0x7 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_256K 0x8 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_512K 0x9 -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_1M 0xA -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_2M 0xB -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_4M 0xC -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_8M 0xD -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_16M 0xE -#define NVM_CFG1_GLOB_EXPANSION_ROM_SIZE_32M 0xF -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_MASK 0x000000F0 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_OFFSET 4 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_DISABLED 0x0 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_4K 0x1 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_8K 0x2 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_16K 0x3 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_32K 0x4 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_64K 0x5 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_128K 0x6 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_256K 0x7 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_512K 0x8 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_1M 0x9 -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_2M 0xA -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_4M 0xB -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_8M 0xC -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_16M 0xD -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_32M 0xE -#define NVM_CFG1_GLOB_VF_PCI_BAR2_SIZE_64M 0xF -#define NVM_CFG1_GLOB_BAR2_SIZE_MASK 0x00000F00 -#define NVM_CFG1_GLOB_BAR2_SIZE_OFFSET 8 -#define NVM_CFG1_GLOB_BAR2_SIZE_DISABLED 0x0 -#define NVM_CFG1_GLOB_BAR2_SIZE_64K 0x1 -#define NVM_CFG1_GLOB_BAR2_SIZE_128K 0x2 -#define NVM_CFG1_GLOB_BAR2_SIZE_256K 0x3 -#define NVM_CFG1_GLOB_BAR2_SIZE_512K 0x4 -#define NVM_CFG1_GLOB_BAR2_SIZE_1M 0x5 -#define NVM_CFG1_GLOB_BAR2_SIZE_2M 0x6 -#define NVM_CFG1_GLOB_BAR2_SIZE_4M 0x7 -#define NVM_CFG1_GLOB_BAR2_SIZE_8M 0x8 -#define NVM_CFG1_GLOB_BAR2_SIZE_16M 0x9 -#define NVM_CFG1_GLOB_BAR2_SIZE_32M 0xA -#define NVM_CFG1_GLOB_BAR2_SIZE_64M 0xB -#define NVM_CFG1_GLOB_BAR2_SIZE_128M 0xC -#define NVM_CFG1_GLOB_BAR2_SIZE_256M 0xD -#define NVM_CFG1_GLOB_BAR2_SIZE_512M 0xE -#define NVM_CFG1_GLOB_BAR2_SIZE_1G 0xF - - u32 eagle_txfir_main; /* 0x5C */ -#define NVM_CFG1_GLOB_LANE0_TXFIR_MAIN_MASK 0x000000FF -#define NVM_CFG1_GLOB_LANE0_TXFIR_MAIN_OFFSET 0 -#define NVM_CFG1_GLOB_LANE1_TXFIR_MAIN_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_LANE1_TXFIR_MAIN_OFFSET 8 -#define NVM_CFG1_GLOB_LANE2_TXFIR_MAIN_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_LANE2_TXFIR_MAIN_OFFSET 16 -#define NVM_CFG1_GLOB_LANE3_TXFIR_MAIN_MASK 0xFF000000 -#define NVM_CFG1_GLOB_LANE3_TXFIR_MAIN_OFFSET 24 - - u32 eagle_txfir_post; /* 0x60 */ -#define NVM_CFG1_GLOB_LANE0_TXFIR_POST_MASK 0x000000FF -#define NVM_CFG1_GLOB_LANE0_TXFIR_POST_OFFSET 0 -#define NVM_CFG1_GLOB_LANE1_TXFIR_POST_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_LANE1_TXFIR_POST_OFFSET 8 -#define NVM_CFG1_GLOB_LANE2_TXFIR_POST_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_LANE2_TXFIR_POST_OFFSET 16 -#define NVM_CFG1_GLOB_LANE3_TXFIR_POST_MASK 0xFF000000 -#define NVM_CFG1_GLOB_LANE3_TXFIR_POST_OFFSET 24 - - u32 falcon_txfir_main; /* 0x64 */ -#define NVM_CFG1_GLOB_LANE0_TXFIR_MAIN_MASK 0x000000FF -#define NVM_CFG1_GLOB_LANE0_TXFIR_MAIN_OFFSET 0 -#define NVM_CFG1_GLOB_LANE1_TXFIR_MAIN_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_LANE1_TXFIR_MAIN_OFFSET 8 -#define NVM_CFG1_GLOB_LANE2_TXFIR_MAIN_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_LANE2_TXFIR_MAIN_OFFSET 16 -#define NVM_CFG1_GLOB_LANE3_TXFIR_MAIN_MASK 0xFF000000 -#define NVM_CFG1_GLOB_LANE3_TXFIR_MAIN_OFFSET 24 - - u32 falcon_txfir_post; /* 0x68 */ -#define NVM_CFG1_GLOB_LANE0_TXFIR_POST_MASK 0x000000FF -#define NVM_CFG1_GLOB_LANE0_TXFIR_POST_OFFSET 0 -#define NVM_CFG1_GLOB_LANE1_TXFIR_POST_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_LANE1_TXFIR_POST_OFFSET 8 -#define NVM_CFG1_GLOB_LANE2_TXFIR_POST_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_LANE2_TXFIR_POST_OFFSET 16 -#define NVM_CFG1_GLOB_LANE3_TXFIR_POST_MASK 0xFF000000 -#define NVM_CFG1_GLOB_LANE3_TXFIR_POST_OFFSET 24 - - u32 manufacture_ver; /* 0x6C */ -#define NVM_CFG1_GLOB_MANUF0_VER_MASK 0x0000003F -#define NVM_CFG1_GLOB_MANUF0_VER_OFFSET 0 -#define NVM_CFG1_GLOB_MANUF1_VER_MASK 0x00000FC0 -#define NVM_CFG1_GLOB_MANUF1_VER_OFFSET 6 -#define NVM_CFG1_GLOB_MANUF2_VER_MASK 0x0003F000 -#define NVM_CFG1_GLOB_MANUF2_VER_OFFSET 12 -#define NVM_CFG1_GLOB_MANUF3_VER_MASK 0x00FC0000 -#define NVM_CFG1_GLOB_MANUF3_VER_OFFSET 18 -#define NVM_CFG1_GLOB_MANUF4_VER_MASK 0x3F000000 -#define NVM_CFG1_GLOB_MANUF4_VER_OFFSET 24 - - u32 manufacture_time; /* 0x70 */ -#define NVM_CFG1_GLOB_MANUF0_TIME_MASK 0x0000003F -#define NVM_CFG1_GLOB_MANUF0_TIME_OFFSET 0 -#define NVM_CFG1_GLOB_MANUF1_TIME_MASK 0x00000FC0 -#define NVM_CFG1_GLOB_MANUF1_TIME_OFFSET 6 -#define NVM_CFG1_GLOB_MANUF2_TIME_MASK 0x0003F000 -#define NVM_CFG1_GLOB_MANUF2_TIME_OFFSET 12 - - u32 led_global_settings; /* 0x74 */ -#define NVM_CFG1_GLOB_LED_SWAP_0_MASK 0x0000000F -#define NVM_CFG1_GLOB_LED_SWAP_0_OFFSET 0 -#define NVM_CFG1_GLOB_LED_SWAP_1_MASK 0x000000F0 -#define NVM_CFG1_GLOB_LED_SWAP_1_OFFSET 4 -#define NVM_CFG1_GLOB_LED_SWAP_2_MASK 0x00000F00 -#define NVM_CFG1_GLOB_LED_SWAP_2_OFFSET 8 -#define NVM_CFG1_GLOB_LED_SWAP_3_MASK 0x0000F000 -#define NVM_CFG1_GLOB_LED_SWAP_3_OFFSET 12 - - u32 generic_cont1; /* 0x78 */ -#define NVM_CFG1_GLOB_AVS_DAC_CODE_MASK 0x000003FF -#define NVM_CFG1_GLOB_AVS_DAC_CODE_OFFSET 0 - - u32 mbi_version; /* 0x7C */ -#define NVM_CFG1_GLOB_MBI_VERSION_0_MASK 0x000000FF -#define NVM_CFG1_GLOB_MBI_VERSION_0_OFFSET 0 -#define NVM_CFG1_GLOB_MBI_VERSION_1_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_MBI_VERSION_1_OFFSET 8 -#define NVM_CFG1_GLOB_MBI_VERSION_2_MASK 0x00FF0000 -#define NVM_CFG1_GLOB_MBI_VERSION_2_OFFSET 16 - - u32 mbi_date; /* 0x80 */ - - u32 misc_sig; /* 0x84 */ - - /* Define the GPIO mapping to switch i2c mux */ -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO_0_MASK 0x000000FF -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO_0_OFFSET 0 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO_1_MASK 0x0000FF00 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO_1_OFFSET 8 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__NA 0x0 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO0 0x1 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO1 0x2 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO2 0x3 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO3 0x4 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO4 0x5 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO5 0x6 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO6 0x7 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO7 0x8 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO8 0x9 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO9 0xA -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO10 0xB -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO11 0xC -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO12 0xD -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO13 0xE -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO14 0xF -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO15 0x10 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO16 0x11 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO17 0x12 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO18 0x13 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO19 0x14 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO20 0x15 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO21 0x16 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO22 0x17 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO23 0x18 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO24 0x19 -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO25 0x1A -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO26 0x1B -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO27 0x1C -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO28 0x1D -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO29 0x1E -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO30 0x1F -#define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO31 0x20 - u32 device_capabilities; /* 0x88 */ -#define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET 0x1 - u32 power_dissipated; /* 0x8C */ - u32 power_consumed; /* 0x90 */ - u32 efi_version; /* 0x94 */ - u32 reserved[42]; /* 0x98 */ + u32 generic_cont0; +#define NVM_CFG1_GLOB_MF_MODE_MASK 0x00000FF0 +#define NVM_CFG1_GLOB_MF_MODE_OFFSET 4 +#define NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED 0x0 +#define NVM_CFG1_GLOB_MF_MODE_DEFAULT 0x1 +#define NVM_CFG1_GLOB_MF_MODE_SPIO4 0x2 +#define NVM_CFG1_GLOB_MF_MODE_NPAR1_0 0x3 +#define NVM_CFG1_GLOB_MF_MODE_NPAR1_5 0x4 +#define NVM_CFG1_GLOB_MF_MODE_NPAR2_0 0x5 +#define NVM_CFG1_GLOB_MF_MODE_BD 0x6 +#define NVM_CFG1_GLOB_MF_MODE_UFP 0x7 + u32 engineering_change[3]; + u32 manufacturing_id; + u32 serial_number[4]; + u32 pcie_cfg; + u32 mgmt_traffic; + u32 core_cfg; +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_MASK 0x000000FF +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_OFFSET 0 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_2X40G 0x0 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X50G 0x1 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_1X100G 0x2 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X10G_F 0x3 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X10G_E 0x4 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_BB_4X20G 0x5 +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X40G 0xB +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_2X25G 0xC +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_1X25G 0xD +#define NVM_CFG1_GLOB_NETWORK_PORT_MODE_4X25G 0xE + u32 e_lane_cfg1; + u32 e_lane_cfg2; + u32 f_lane_cfg1; + u32 f_lane_cfg2; + u32 mps10_preemphasis; + u32 mps10_driver_current; + u32 mps25_preemphasis; + u32 mps25_driver_current; + u32 pci_id; + u32 pci_subsys_id; + u32 bar; + u32 mps10_txfir_main; + u32 mps10_txfir_post; + u32 mps25_txfir_main; + u32 mps25_txfir_post; + u32 manufacture_ver; + u32 manufacture_time; + u32 led_global_settings; + u32 generic_cont1; + u32 mbi_version; + u32 mbi_date; + u32 misc_sig; + u32 device_capabilities; +#define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET 0x1 + u32 power_dissipated; + u32 power_consumed; + u32 efi_version; + u32 multi_network_modes_capability; + u32 reserved[41]; }; struct nvm_cfg1_path { - u32 reserved[30]; /* 0x0 */ + u32 reserved[30]; }; struct nvm_cfg1_port { - u32 reserved__m_relocated_to_option_123; /* 0x0 */ - u32 reserved__m_relocated_to_option_124; /* 0x4 */ - u32 generic_cont0; /* 0x8 */ -#define NVM_CFG1_PORT_LED_MODE_MASK 0x000000FF -#define NVM_CFG1_PORT_LED_MODE_OFFSET 0 -#define NVM_CFG1_PORT_LED_MODE_MAC1 0x0 -#define NVM_CFG1_PORT_LED_MODE_PHY1 0x1 -#define NVM_CFG1_PORT_LED_MODE_PHY2 0x2 -#define NVM_CFG1_PORT_LED_MODE_PHY3 0x3 -#define NVM_CFG1_PORT_LED_MODE_MAC2 0x4 -#define NVM_CFG1_PORT_LED_MODE_PHY4 0x5 -#define NVM_CFG1_PORT_LED_MODE_PHY5 0x6 -#define NVM_CFG1_PORT_LED_MODE_PHY6 0x7 -#define NVM_CFG1_PORT_LED_MODE_MAC3 0x8 -#define NVM_CFG1_PORT_LED_MODE_PHY7 0x9 -#define NVM_CFG1_PORT_LED_MODE_PHY8 0xA -#define NVM_CFG1_PORT_LED_MODE_PHY9 0xB -#define NVM_CFG1_PORT_LED_MODE_MAC4 0xC -#define NVM_CFG1_PORT_LED_MODE_PHY10 0xD -#define NVM_CFG1_PORT_LED_MODE_PHY11 0xE -#define NVM_CFG1_PORT_LED_MODE_PHY12 0xF -#define NVM_CFG1_PORT_ROCE_PRIORITY_MASK 0x0000FF00 -#define NVM_CFG1_PORT_ROCE_PRIORITY_OFFSET 8 -#define NVM_CFG1_PORT_DCBX_MODE_MASK 0x000F0000 -#define NVM_CFG1_PORT_DCBX_MODE_OFFSET 16 -#define NVM_CFG1_PORT_DCBX_MODE_DISABLED 0x0 -#define NVM_CFG1_PORT_DCBX_MODE_IEEE 0x1 -#define NVM_CFG1_PORT_DCBX_MODE_CEE 0x2 -#define NVM_CFG1_PORT_DCBX_MODE_DYNAMIC 0x3 -#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_MASK 0x00F00000 -#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_OFFSET 20 -#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_ETHERNET 0x1 - u32 pcie_cfg; /* 0xC */ -#define NVM_CFG1_PORT_RESERVED15_MASK 0x00000007 -#define NVM_CFG1_PORT_RESERVED15_OFFSET 0 - - u32 features; /* 0x10 */ -#define NVM_CFG1_PORT_ENABLE_WOL_ON_ACPI_PATTERN_MASK 0x00000001 -#define NVM_CFG1_PORT_ENABLE_WOL_ON_ACPI_PATTERN_OFFSET 0 -#define NVM_CFG1_PORT_ENABLE_WOL_ON_ACPI_PATTERN_DISABLED 0x0 -#define NVM_CFG1_PORT_ENABLE_WOL_ON_ACPI_PATTERN_ENABLED 0x1 -#define NVM_CFG1_PORT_MAGIC_PACKET_WOL_MASK 0x00000002 -#define NVM_CFG1_PORT_MAGIC_PACKET_WOL_OFFSET 1 -#define NVM_CFG1_PORT_MAGIC_PACKET_WOL_DISABLED 0x0 -#define NVM_CFG1_PORT_MAGIC_PACKET_WOL_ENABLED 0x1 - - u32 speed_cap_mask; /* 0x14 */ -#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_MASK 0x0000FFFF -#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_OFFSET 0 -#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G 0x1 -#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G 0x2 -#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G 0x8 -#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G 0x10 -#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G 0x20 -#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_100G 0x40 -#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_MASK 0xFFFF0000 -#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_OFFSET 16 -#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_1G 0x1 -#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_10G 0x2 -#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_25G 0x8 -#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_40G 0x10 -#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_50G 0x20 -#define NVM_CFG1_PORT_MFW_SPEED_CAPABILITY_MASK_100G 0x40 - - u32 link_settings; /* 0x18 */ -#define NVM_CFG1_PORT_DRV_LINK_SPEED_MASK 0x0000000F -#define NVM_CFG1_PORT_DRV_LINK_SPEED_OFFSET 0 -#define NVM_CFG1_PORT_DRV_LINK_SPEED_AUTONEG 0x0 -#define NVM_CFG1_PORT_DRV_LINK_SPEED_1G 0x1 -#define NVM_CFG1_PORT_DRV_LINK_SPEED_10G 0x2 -#define NVM_CFG1_PORT_DRV_LINK_SPEED_25G 0x4 -#define NVM_CFG1_PORT_DRV_LINK_SPEED_40G 0x5 -#define NVM_CFG1_PORT_DRV_LINK_SPEED_50G 0x6 -#define NVM_CFG1_PORT_DRV_LINK_SPEED_100G 0x7 -#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK 0x00000070 -#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET 4 -#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG 0x1 -#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX 0x2 -#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX 0x4 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_MASK 0x00000780 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_OFFSET 7 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_AUTONEG 0x0 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_1G 0x1 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_10G 0x2 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_25G 0x4 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_40G 0x5 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_50G 0x6 -#define NVM_CFG1_PORT_MFW_LINK_SPEED_100G 0x7 -#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_MASK 0x00003800 -#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_OFFSET 11 -#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_AUTONEG 0x1 -#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_RX 0x2 -#define NVM_CFG1_PORT_MFW_FLOW_CONTROL_TX 0x4 -#define NVM_CFG1_PORT_OPTIC_MODULE_VENDOR_ENFORCEMENT_MASK 0x00004000 -#define NVM_CFG1_PORT_OPTIC_MODULE_VENDOR_ENFORCEMENT_OFFSET 14 -#define NVM_CFG1_PORT_OPTIC_MODULE_VENDOR_ENFORCEMENT_DISABLED 0x0 -#define NVM_CFG1_PORT_OPTIC_MODULE_VENDOR_ENFORCEMENT_ENABLED 0x1 - - u32 phy_cfg; /* 0x1C */ -#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_MASK 0x0000FFFF -#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_OFFSET 0 -#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_HIGIG 0x1 -#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_SCRAMBLER 0x2 -#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_FIBER 0x4 -#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_DISABLE_CL72_AN 0x8 -#define NVM_CFG1_PORT_OPTIONAL_LINK_MODES_DISABLE_FEC_AN 0x10 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_MASK 0x00FF0000 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_OFFSET 16 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_BYPASS 0x0 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_KR 0x2 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_KR2 0x3 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_KR4 0x4 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XFI 0x8 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_SFI 0x9 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_1000X 0xB -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_SGMII 0xC -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XLAUI 0x11 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XLPPI 0x12 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_CAUI 0x21 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_CPPI 0x22 -#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_25GAUI 0x31 -#define NVM_CFG1_PORT_AN_MODE_MASK 0xFF000000 -#define NVM_CFG1_PORT_AN_MODE_OFFSET 24 -#define NVM_CFG1_PORT_AN_MODE_NONE 0x0 -#define NVM_CFG1_PORT_AN_MODE_CL73 0x1 -#define NVM_CFG1_PORT_AN_MODE_CL37 0x2 -#define NVM_CFG1_PORT_AN_MODE_CL73_BAM 0x3 -#define NVM_CFG1_PORT_AN_MODE_CL37_BAM 0x4 -#define NVM_CFG1_PORT_AN_MODE_HPAM 0x5 -#define NVM_CFG1_PORT_AN_MODE_SGMII 0x6 - - u32 mgmt_traffic; /* 0x20 */ -#define NVM_CFG1_PORT_RESERVED61_MASK 0x0000000F -#define NVM_CFG1_PORT_RESERVED61_OFFSET 0 - - u32 ext_phy; /* 0x24 */ -#define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_MASK 0x000000FF -#define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_OFFSET 0 -#define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_NONE 0x0 -#define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_BCM84844 0x1 -#define NVM_CFG1_PORT_EXTERNAL_PHY_ADDRESS_MASK 0x0000FF00 -#define NVM_CFG1_PORT_EXTERNAL_PHY_ADDRESS_OFFSET 8 - - u32 mba_cfg1; /* 0x28 */ -#define NVM_CFG1_PORT_PREBOOT_OPROM_MASK 0x00000001 -#define NVM_CFG1_PORT_PREBOOT_OPROM_OFFSET 0 -#define NVM_CFG1_PORT_PREBOOT_OPROM_DISABLED 0x0 -#define NVM_CFG1_PORT_PREBOOT_OPROM_ENABLED 0x1 -#define NVM_CFG1_PORT_RESERVED__M_MBA_BOOT_TYPE_MASK 0x00000006 -#define NVM_CFG1_PORT_RESERVED__M_MBA_BOOT_TYPE_OFFSET 1 -#define NVM_CFG1_PORT_MBA_DELAY_TIME_MASK 0x00000078 -#define NVM_CFG1_PORT_MBA_DELAY_TIME_OFFSET 3 -#define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_MASK 0x00000080 -#define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_OFFSET 7 -#define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_CTRL_S 0x0 -#define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_CTRL_B 0x1 -#define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_MASK 0x00000100 -#define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_OFFSET 8 -#define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_DISABLED 0x0 -#define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_ENABLED 0x1 -#define NVM_CFG1_PORT_RESERVED5_MASK 0x0001FE00 -#define NVM_CFG1_PORT_RESERVED5_OFFSET 9 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_MASK 0x001E0000 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_OFFSET 17 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_AUTONEG 0x0 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_1G 0x1 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_10G 0x2 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_25G 0x4 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_40G 0x5 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_50G 0x6 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_100G 0x7 -#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_SMARTLINQ 0x8 -#define NVM_CFG1_PORT_RESERVED__M_MBA_BOOT_RETRY_COUNT_MASK 0x00E00000 -#define NVM_CFG1_PORT_RESERVED__M_MBA_BOOT_RETRY_COUNT_OFFSET 21 - - u32 mba_cfg2; /* 0x2C */ -#define NVM_CFG1_PORT_RESERVED65_MASK 0x0000FFFF -#define NVM_CFG1_PORT_RESERVED65_OFFSET 0 -#define NVM_CFG1_PORT_RESERVED66_MASK 0x00010000 -#define NVM_CFG1_PORT_RESERVED66_OFFSET 16 - - u32 vf_cfg; /* 0x30 */ -#define NVM_CFG1_PORT_RESERVED8_MASK 0x0000FFFF -#define NVM_CFG1_PORT_RESERVED8_OFFSET 0 -#define NVM_CFG1_PORT_RESERVED6_MASK 0x000F0000 -#define NVM_CFG1_PORT_RESERVED6_OFFSET 16 - - struct nvm_cfg_mac_address lldp_mac_address; /* 0x34 */ - - u32 led_port_settings; /* 0x3C */ -#define NVM_CFG1_PORT_LANE_LED_SPD_0_SEL_MASK 0x000000FF -#define NVM_CFG1_PORT_LANE_LED_SPD_0_SEL_OFFSET 0 -#define NVM_CFG1_PORT_LANE_LED_SPD_1_SEL_MASK 0x0000FF00 -#define NVM_CFG1_PORT_LANE_LED_SPD_1_SEL_OFFSET 8 -#define NVM_CFG1_PORT_LANE_LED_SPD_2_SEL_MASK 0x00FF0000 -#define NVM_CFG1_PORT_LANE_LED_SPD_2_SEL_OFFSET 16 -#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_1G 0x1 -#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_10G 0x2 -#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_25G 0x8 -#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_40G 0x10 -#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_50G 0x20 -#define NVM_CFG1_PORT_LANE_LED_SPD__SEL_100G 0x40 - - u32 transceiver_00; /* 0x40 */ - - /* Define for mapping of transceiver signal module absent */ -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_MASK 0x000000FF -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_OFFSET 0 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_NA 0x0 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO0 0x1 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO1 0x2 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO2 0x3 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO3 0x4 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO4 0x5 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO5 0x6 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO6 0x7 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO7 0x8 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO8 0x9 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO9 0xA -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO10 0xB -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO11 0xC -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO12 0xD -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO13 0xE -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO14 0xF -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO15 0x10 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO16 0x11 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO17 0x12 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO18 0x13 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO19 0x14 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO20 0x15 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO21 0x16 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO22 0x17 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO23 0x18 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO24 0x19 -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO25 0x1A -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO26 0x1B -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO27 0x1C -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO28 0x1D -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO29 0x1E -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO30 0x1F -#define NVM_CFG1_PORT_TRANS_MODULE_ABS_GPIO31 0x20 - /* Define the GPIO mux settings to switch i2c mux to this port */ -#define NVM_CFG1_PORT_I2C_MUX_SEL_VALUE_0_MASK 0x00000F00 -#define NVM_CFG1_PORT_I2C_MUX_SEL_VALUE_0_OFFSET 8 -#define NVM_CFG1_PORT_I2C_MUX_SEL_VALUE_1_MASK 0x0000F000 -#define NVM_CFG1_PORT_I2C_MUX_SEL_VALUE_1_OFFSET 12 - - u32 reserved[133]; /* 0x44 */ + u32 reserved__m_relocated_to_option_123; + u32 reserved__m_relocated_to_option_124; + u32 generic_cont0; +#define NVM_CFG1_PORT_DCBX_MODE_MASK 0x000F0000 +#define NVM_CFG1_PORT_DCBX_MODE_OFFSET 16 +#define NVM_CFG1_PORT_DCBX_MODE_DISABLED 0x0 +#define NVM_CFG1_PORT_DCBX_MODE_IEEE 0x1 +#define NVM_CFG1_PORT_DCBX_MODE_CEE 0x2 +#define NVM_CFG1_PORT_DCBX_MODE_DYNAMIC 0x3 +#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_MASK 0x00F00000 +#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_OFFSET 20 +#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_ETHERNET 0x1 +#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_FCOE 0x2 +#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_ISCSI 0x4 + u32 pcie_cfg; + u32 features; + u32 speed_cap_mask; +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_MASK 0x0000FFFF +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_OFFSET 0 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G 0x1 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G 0x2 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G 0x8 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G 0x10 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G 0x20 +#define NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G 0x40 + u32 link_settings; +#define NVM_CFG1_PORT_DRV_LINK_SPEED_MASK 0x0000000F +#define NVM_CFG1_PORT_DRV_LINK_SPEED_OFFSET 0 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_AUTONEG 0x0 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_1G 0x1 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_10G 0x2 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_25G 0x4 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_40G 0x5 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_50G 0x6 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_BB_100G 0x7 +#define NVM_CFG1_PORT_DRV_LINK_SPEED_SMARTLINQ 0x8 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK 0x00000070 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET 4 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_AUTONEG 0x1 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_RX 0x2 +#define NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX 0x4 + u32 phy_cfg; + u32 mgmt_traffic; + u32 ext_phy; + u32 mba_cfg1; + u32 mba_cfg2; + u32 vf_cfg; + struct nvm_cfg_mac_address lldp_mac_address; + u32 led_port_settings; + u32 transceiver_00; + u32 device_ids; + u32 board_cfg; + u32 mnm_10g_cap; + u32 mnm_10g_ctrl; + u32 mnm_10g_misc; + u32 mnm_25g_cap; + u32 mnm_25g_ctrl; + u32 mnm_25g_misc; + u32 mnm_40g_cap; + u32 mnm_40g_ctrl; + u32 mnm_40g_misc; + u32 mnm_50g_cap; + u32 mnm_50g_ctrl; + u32 mnm_50g_misc; + u32 mnm_100g_cap; + u32 mnm_100g_ctrl; + u32 mnm_100g_misc; + u32 reserved[116]; }; struct nvm_cfg1_func { - struct nvm_cfg_mac_address mac_address; /* 0x0 */ - - u32 rsrv1; /* 0x8 */ -#define NVM_CFG1_FUNC_RESERVED1_MASK 0x0000FFFF -#define NVM_CFG1_FUNC_RESERVED1_OFFSET 0 -#define NVM_CFG1_FUNC_RESERVED2_MASK 0xFFFF0000 -#define NVM_CFG1_FUNC_RESERVED2_OFFSET 16 - - u32 rsrv2; /* 0xC */ -#define NVM_CFG1_FUNC_RESERVED3_MASK 0x0000FFFF -#define NVM_CFG1_FUNC_RESERVED3_OFFSET 0 -#define NVM_CFG1_FUNC_RESERVED4_MASK 0xFFFF0000 -#define NVM_CFG1_FUNC_RESERVED4_OFFSET 16 - - u32 device_id; /* 0x10 */ -#define NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_MASK 0x0000FFFF -#define NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_OFFSET 0 -#define NVM_CFG1_FUNC_RESERVED77_MASK 0xFFFF0000 -#define NVM_CFG1_FUNC_RESERVED77_OFFSET 16 - - u32 cmn_cfg; /* 0x14 */ -#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_MASK 0x00000007 -#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_OFFSET 0 -#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_PXE 0x0 -#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_ISCSI_BOOT 0x3 -#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_FCOE_BOOT 0x4 -#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_NONE 0x7 -#define NVM_CFG1_FUNC_VF_PCI_DEVICE_ID_MASK 0x0007FFF8 -#define NVM_CFG1_FUNC_VF_PCI_DEVICE_ID_OFFSET 3 -#define NVM_CFG1_FUNC_PERSONALITY_MASK 0x00780000 -#define NVM_CFG1_FUNC_PERSONALITY_OFFSET 19 -#define NVM_CFG1_FUNC_PERSONALITY_ETHERNET 0x0 -#define NVM_CFG1_FUNC_PERSONALITY_ISCSI 0x1 -#define NVM_CFG1_FUNC_PERSONALITY_FCOE 0x2 -#define NVM_CFG1_FUNC_PERSONALITY_ROCE 0x3 -#define NVM_CFG1_FUNC_BANDWIDTH_WEIGHT_MASK 0x7F800000 -#define NVM_CFG1_FUNC_BANDWIDTH_WEIGHT_OFFSET 23 -#define NVM_CFG1_FUNC_PAUSE_ON_HOST_RING_MASK 0x80000000 -#define NVM_CFG1_FUNC_PAUSE_ON_HOST_RING_OFFSET 31 -#define NVM_CFG1_FUNC_PAUSE_ON_HOST_RING_DISABLED 0x0 -#define NVM_CFG1_FUNC_PAUSE_ON_HOST_RING_ENABLED 0x1 - - u32 pci_cfg; /* 0x18 */ -#define NVM_CFG1_FUNC_NUMBER_OF_VFS_PER_PF_MASK 0x0000007F -#define NVM_CFG1_FUNC_NUMBER_OF_VFS_PER_PF_OFFSET 0 -#define NVM_CFG1_FUNC_RESERVESD12_MASK 0x00003F80 -#define NVM_CFG1_FUNC_RESERVESD12_OFFSET 7 -#define NVM_CFG1_FUNC_BAR1_SIZE_MASK 0x0003C000 -#define NVM_CFG1_FUNC_BAR1_SIZE_OFFSET 14 -#define NVM_CFG1_FUNC_BAR1_SIZE_DISABLED 0x0 -#define NVM_CFG1_FUNC_BAR1_SIZE_64K 0x1 -#define NVM_CFG1_FUNC_BAR1_SIZE_128K 0x2 -#define NVM_CFG1_FUNC_BAR1_SIZE_256K 0x3 -#define NVM_CFG1_FUNC_BAR1_SIZE_512K 0x4 -#define NVM_CFG1_FUNC_BAR1_SIZE_1M 0x5 -#define NVM_CFG1_FUNC_BAR1_SIZE_2M 0x6 -#define NVM_CFG1_FUNC_BAR1_SIZE_4M 0x7 -#define NVM_CFG1_FUNC_BAR1_SIZE_8M 0x8 -#define NVM_CFG1_FUNC_BAR1_SIZE_16M 0x9 -#define NVM_CFG1_FUNC_BAR1_SIZE_32M 0xA -#define NVM_CFG1_FUNC_BAR1_SIZE_64M 0xB -#define NVM_CFG1_FUNC_BAR1_SIZE_128M 0xC -#define NVM_CFG1_FUNC_BAR1_SIZE_256M 0xD -#define NVM_CFG1_FUNC_BAR1_SIZE_512M 0xE -#define NVM_CFG1_FUNC_BAR1_SIZE_1G 0xF -#define NVM_CFG1_FUNC_MAX_BANDWIDTH_MASK 0x03FC0000 -#define NVM_CFG1_FUNC_MAX_BANDWIDTH_OFFSET 18 - - struct nvm_cfg_mac_address fcoe_node_wwn_mac_addr; /* 0x1C */ - - struct nvm_cfg_mac_address fcoe_port_wwn_mac_addr; /* 0x24 */ - u32 preboot_generic_cfg; /* 0x2C */ - u32 reserved[8]; /* 0x30 */ + struct nvm_cfg_mac_address mac_address; + u32 rsrv1; + u32 rsrv2; + u32 device_id; + u32 cmn_cfg; + u32 pci_cfg; + struct nvm_cfg_mac_address fcoe_node_wwn_mac_addr; + struct nvm_cfg_mac_address fcoe_port_wwn_mac_addr; + u32 preboot_generic_cfg; + u32 reserved[8]; }; struct nvm_cfg1 { - struct nvm_cfg1_glob glob; /* 0x0 */ - - struct nvm_cfg1_path path[MCP_GLOB_PATH_MAX]; /* 0x140 */ - - struct nvm_cfg1_port port[MCP_GLOB_PORT_MAX]; /* 0x230 */ - - struct nvm_cfg1_func func[MCP_GLOB_FUNC_MAX]; /* 0xB90 */ -}; - -/****************************************** -* nvm_cfg structs -******************************************/ - -enum nvm_cfg_sections { - NVM_CFG_SECTION_NVM_CFG1, - NVM_CFG_SECTION_MAX -}; - -struct nvm_cfg { - u32 num_sections; - u32 sections_offset[NVM_CFG_SECTION_MAX]; - struct nvm_cfg1 cfg1; -}; - -#define PORT_0 0 -#define PORT_1 1 -#define PORT_2 2 -#define PORT_3 3 - -extern struct spad_layout g_spad; - -#define MCP_SPAD_SIZE 0x00028000 /* 160 KB */ - -#define SPAD_OFFSET(addr) (((u32)addr - (u32)CPU_SPAD_BASE)) - -#define TO_OFFSIZE(_offset, _size) \ - (u32)((((u32)(_offset) >> 2) << OFFSIZE_OFFSET_SHIFT) | \ - (((u32)(_size) >> 2) << OFFSIZE_SIZE_SHIFT)) - -enum spad_sections { - SPAD_SECTION_TRACE, - SPAD_SECTION_NVM_CFG, - SPAD_SECTION_PUBLIC, - SPAD_SECTION_PRIVATE, - SPAD_SECTION_MAX -}; - -struct spad_layout { - struct nvm_cfg nvm_cfg; - struct mcp_public_data public_data; + struct nvm_cfg1_glob glob; + struct nvm_cfg1_path path[MCP_GLOB_PATH_MAX]; + struct nvm_cfg1_port port[MCP_GLOB_PORT_MAX]; + struct nvm_cfg1_func func[MCP_GLOB_FUNC_MAX]; }; - -#define CRC_MAGIC_VALUE 0xDEBB20E3 -#define CRC32_POLYNOMIAL 0xEDB88320 -#define NVM_CRC_SIZE (sizeof(u32)) - -enum nvm_sw_arbitrator { - NVM_SW_ARB_HOST, - NVM_SW_ARB_MCP, - NVM_SW_ARB_UART, - NVM_SW_ARB_RESERVED -}; - -/**************************************************************************** -* Boot Strap Region * -****************************************************************************/ -struct legacy_bootstrap_region { - u32 magic_value; -#define NVM_MAGIC_VALUE 0x669955aa - u32 sram_start_addr; - u32 code_len; /* boot code length (in dwords) */ - u32 code_start_addr; - u32 crc; /* 32-bit CRC */ -}; - -/**************************************************************************** -* Directories Region * -****************************************************************************/ -struct nvm_code_entry { - u32 image_type; /* Image type */ - u32 nvm_start_addr; /* NVM address of the image */ - u32 len; /* Include CRC */ - u32 sram_start_addr; - u32 sram_run_addr; /* Relevant in case of MIM only */ -}; - -enum nvm_image_type { - NVM_TYPE_TIM1 = 0x01, - NVM_TYPE_TIM2 = 0x02, - NVM_TYPE_MIM1 = 0x03, - NVM_TYPE_MIM2 = 0x04, - NVM_TYPE_MBA = 0x05, - NVM_TYPE_MODULES_PN = 0x06, - NVM_TYPE_VPD = 0x07, - NVM_TYPE_MFW_TRACE1 = 0x08, - NVM_TYPE_MFW_TRACE2 = 0x09, - NVM_TYPE_NVM_CFG1 = 0x0a, - NVM_TYPE_L2B = 0x0b, - NVM_TYPE_DIR1 = 0x0c, - NVM_TYPE_EAGLE_FW1 = 0x0d, - NVM_TYPE_FALCON_FW1 = 0x0e, - NVM_TYPE_PCIE_FW1 = 0x0f, - NVM_TYPE_HW_SET = 0x10, - NVM_TYPE_LIM = 0x11, - NVM_TYPE_AVS_FW1 = 0x12, - NVM_TYPE_DIR2 = 0x13, - NVM_TYPE_CCM = 0x14, - NVM_TYPE_EAGLE_FW2 = 0x15, - NVM_TYPE_FALCON_FW2 = 0x16, - NVM_TYPE_PCIE_FW2 = 0x17, - NVM_TYPE_AVS_FW2 = 0x18, - - NVM_TYPE_MAX, -}; - -#define MAX_NVM_DIR_ENTRIES 200 - -struct nvm_dir { - s32 seq; -#define NVM_DIR_NEXT_MFW_MASK 0x00000001 -#define NVM_DIR_SEQ_MASK 0xfffffffe -#define NVM_DIR_NEXT_MFW(seq) ((seq) & NVM_DIR_NEXT_MFW_MASK) - -#define IS_DIR_SEQ_VALID(seq) ((seq & NVM_DIR_SEQ_MASK) != NVM_DIR_SEQ_MASK) - - u32 num_images; - u32 rsrv; - struct nvm_code_entry code[1]; /* Up to MAX_NVM_DIR_ENTRIES */ -}; - -#define NVM_DIR_SIZE(_num_images) (sizeof(struct nvm_dir) + \ - (_num_images - \ - 1) * sizeof(struct nvm_code_entry) + \ - NVM_CRC_SIZE) - -struct nvm_vpd_image { - u32 format_revision; -#define VPD_IMAGE_VERSION 1 - - /* This array length depends on the number of VPD fields */ - u8 vpd_data[1]; -}; - -/**************************************************************************** -* NVRAM FULL MAP * -****************************************************************************/ -#define DIR_ID_1 (0) -#define DIR_ID_2 (1) -#define MAX_DIR_IDS (2) - -#define MFW_BUNDLE_1 (0) -#define MFW_BUNDLE_2 (1) -#define MAX_MFW_BUNDLES (2) - -#define FLASH_PAGE_SIZE 0x1000 -#define NVM_DIR_MAX_SIZE (FLASH_PAGE_SIZE) /* 4Kb */ -#define ASIC_MIM_MAX_SIZE (300 * FLASH_PAGE_SIZE) /* 1.2Mb */ -#define FPGA_MIM_MAX_SIZE (25 * FLASH_PAGE_SIZE) /* 60Kb */ - -#define LIM_MAX_SIZE ((2 * \ - FLASH_PAGE_SIZE) - \ - sizeof(struct legacy_bootstrap_region) - \ - NVM_RSV_SIZE) -#define LIM_OFFSET (NVM_OFFSET(lim_image)) -#define NVM_RSV_SIZE (44) -#define MIM_MAX_SIZE(is_asic) ((is_asic) ? ASIC_MIM_MAX_SIZE : \ - FPGA_MIM_MAX_SIZE) -#define MIM_OFFSET(idx, is_asic) (NVM_OFFSET(dir[MAX_MFW_BUNDLES]) + \ - ((idx == \ - NVM_TYPE_MIM2) ? MIM_MAX_SIZE(is_asic) : 0)) -#define NVM_FIXED_AREA_SIZE(is_asic) (sizeof(struct nvm_image) + \ - MIM_MAX_SIZE(is_asic) * 2) - -union nvm_dir_union { - struct nvm_dir dir; - u8 page[FLASH_PAGE_SIZE]; -}; - -/* Address - * +-------------------+ 0x000000 - * | Bootstrap: | - * | magic_number | - * | sram_start_addr | - * | code_len | - * | code_start_addr | - * | crc | - * +-------------------+ 0x000014 - * | rsrv | - * +-------------------+ 0x000040 - * | LIM | - * +-------------------+ 0x002000 - * | Dir1 | - * +-------------------+ 0x003000 - * | Dir2 | - * +-------------------+ 0x004000 - * | MIM1 | - * +-------------------+ 0x130000 - * | MIM2 | - * +-------------------+ 0x25C000 - * | Rest Images: | - * | TIM1/2 | - * | MFW_TRACE1/2 | - * | Eagle/Falcon FW | - * | PCIE/AVS FW | - * | MBA/CCM/L2B | - * | VPD | - * | optic_modules | - * | ... | - * +-------------------+ 0x400000 - */ -struct nvm_image { -/*********** !!! FIXED SECTIONS !!! DO NOT MODIFY !!! **********************/ - /* NVM Offset (size) */ - struct legacy_bootstrap_region bootstrap; - u8 rsrv[NVM_RSV_SIZE]; - u8 lim_image[LIM_MAX_SIZE]; - union nvm_dir_union dir[MAX_MFW_BUNDLES]; - - /* MIM1_IMAGE 0x004000 (0x12c000) */ - /* MIM2_IMAGE 0x130000 (0x12c000) */ -/*********** !!! FIXED SECTIONS !!! DO NOT MODIFY !!! **********************/ -}; /* 0x134 */ - -#define NVM_OFFSET(f) ((u32_t)((int_ptr_t)(&(((struct nvm_image *)0)->f)))) - -struct hw_set_info { - u32 reg_type; -#define GRC_REG_TYPE 1 -#define PHY_REG_TYPE 2 -#define PCI_REG_TYPE 4 - - u32 bank_num; - u32 pf_num; - u32 operation; -#define READ_OP 1 -#define WRITE_OP 2 -#define RMW_SET_OP 3 -#define RMW_CLR_OP 4 - - u32 reg_addr; - u32 reg_data; - - u32 reset_type; -#define POR_RESET_TYPE BIT(0) -#define HARD_RESET_TYPE BIT(1) -#define CORE_RESET_TYPE BIT(2) -#define MCP_RESET_TYPE BIT(3) -#define PERSET_ASSERT BIT(4) -#define PERSET_DEASSERT BIT(5) -}; - -struct hw_set_image { - u32 format_version; -#define HW_SET_IMAGE_VERSION 1 - u32 no_hw_sets; - - /* This array length depends on the no_hw_sets */ - struct hw_set_info hw_sets[1]; -}; - -int qed_init_pf_wfq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u8 pf_id, u16 pf_wfq); -int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u16 first_tx_pq_id[NUM_OF_TCS], u16 vport_wfq); #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c index 0ada7fdb91bc..7363d2bcc978 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hw.c +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c @@ -446,7 +446,7 @@ qed_dmae_post_command(struct qed_hwfn *p_hwfn, idx_cmd, le32_to_cpu(command->opcode), le16_to_cpu(command->opcode_b), - le16_to_cpu(command->length), + le16_to_cpu(command->length_dw), le32_to_cpu(command->src_addr_hi), le32_to_cpu(command->src_addr_lo), le32_to_cpu(command->dst_addr_hi), @@ -461,7 +461,7 @@ qed_dmae_post_command(struct qed_hwfn *p_hwfn, idx_cmd, le32_to_cpu(command->opcode), le16_to_cpu(command->opcode_b), - le16_to_cpu(command->length), + le16_to_cpu(command->length_dw), le32_to_cpu(command->src_addr_hi), le32_to_cpu(command->src_addr_lo), le32_to_cpu(command->dst_addr_hi), @@ -645,7 +645,7 @@ static int qed_dmae_execute_sub_operation(struct qed_hwfn *p_hwfn, return -EINVAL; } - cmd->length = cpu_to_le16((u16)length); + cmd->length_dw = cpu_to_le16((u16)length); qed_dmae_post_command(p_hwfn, p_ptt); diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c index e8a3b9da59b5..23e455f22adc 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c @@ -31,7 +31,6 @@ enum cminterface { }; /* general constants */ -#define QM_PQ_ELEMENT_SIZE 4 /* in bytes */ #define QM_PQ_MEM_4KB(pq_size) (pq_size ? DIV_ROUND_UP((pq_size + 1) * \ QM_PQ_ELEMENT_SIZE, \ 0x1000) : 0) @@ -44,28 +43,28 @@ enum cminterface { /* other PQ constants */ #define QM_OTHER_PQS_PER_PF 4 /* WFQ constants */ -#define QM_WFQ_UPPER_BOUND 6250000 +#define QM_WFQ_UPPER_BOUND 62500000 #define QM_WFQ_VP_PQ_VOQ_SHIFT 0 #define QM_WFQ_VP_PQ_PF_SHIFT 5 #define QM_WFQ_INC_VAL(weight) ((weight) * 0x9000) -#define QM_WFQ_MAX_INC_VAL 4375000 -#define QM_WFQ_INIT_CRD(inc_val) (2 * (inc_val)) +#define QM_WFQ_MAX_INC_VAL 43750000 + /* RL constants */ -#define QM_RL_UPPER_BOUND 6250000 +#define QM_RL_UPPER_BOUND 62500000 #define QM_RL_PERIOD 5 /* in us */ #define QM_RL_PERIOD_CLK_25M (25 * QM_RL_PERIOD) +#define QM_RL_MAX_INC_VAL 43750000 #define QM_RL_INC_VAL(rate) max_t(u32, \ - (((rate ? rate : 1000000) \ - * QM_RL_PERIOD) / 8), 1) -#define QM_RL_MAX_INC_VAL 4375000 + (u32)(((rate ? rate : \ + 1000000) * \ + QM_RL_PERIOD * \ + 101) / (8 * 100)), 1) /* AFullOprtnstcCrdMask constants */ #define QM_OPPOR_LINE_VOQ_DEF 1 #define QM_OPPOR_FW_STOP_DEF 0 #define QM_OPPOR_PQ_EMPTY_DEF 1 -#define EAGLE_WORKAROUND_TC 7 /* Command Queue constants */ #define PBF_CMDQ_PURE_LB_LINES 150 -#define PBF_CMDQ_EAGLE_WORKAROUND_LINES 8 #define PBF_CMDQ_LINES_RT_OFFSET(voq) ( \ PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET + voq * \ (PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET - \ @@ -80,7 +79,6 @@ enum cminterface { /* BTB: blocks constants (block size = 256B) */ #define BTB_JUMBO_PKT_BLOCKS 38 #define BTB_HEADROOM_BLOCKS BTB_JUMBO_PKT_BLOCKS -#define BTB_EAGLE_WORKAROUND_BLOCKS 4 #define BTB_PURE_LB_FACTOR 10 #define BTB_PURE_LB_RATIO 7 /* QM stop command constants */ @@ -107,9 +105,9 @@ enum cminterface { cmd ## _ ## field, \ value) /* QM: VOQ macros */ -#define PHYS_VOQ(port, tc, max_phy_tcs_pr_port) ((port) * \ - (max_phy_tcs_pr_port) \ - + (tc)) +#define PHYS_VOQ(port, tc, max_phys_tcs_per_port) ((port) * \ + (max_phys_tcs_per_port) + \ + (tc)) #define LB_VOQ(port) ( \ MAX_PHYS_VOQS + (port)) #define VOQ(port, tc, max_phy_tcs_pr_port) \ @@ -120,8 +118,7 @@ enum cminterface { : LB_VOQ(port)) /******************** INTERNAL IMPLEMENTATION *********************/ /* Prepare PF RL enable/disable runtime init values */ -static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, - bool pf_rl_en) +static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, bool pf_rl_en) { STORE_RT_REG(p_hwfn, QM_REG_RLPFENABLE_RT_OFFSET, pf_rl_en ? 1 : 0); if (pf_rl_en) { @@ -130,8 +127,7 @@ static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, (1 << MAX_NUM_VOQS) - 1); /* write RL period */ STORE_RT_REG(p_hwfn, - QM_REG_RLPFPERIOD_RT_OFFSET, - QM_RL_PERIOD_CLK_25M); + QM_REG_RLPFPERIOD_RT_OFFSET, QM_RL_PERIOD_CLK_25M); STORE_RT_REG(p_hwfn, QM_REG_RLPFPERIODTIMER_RT_OFFSET, QM_RL_PERIOD_CLK_25M); @@ -144,8 +140,7 @@ static void qed_enable_pf_rl(struct qed_hwfn *p_hwfn, } /* Prepare PF WFQ enable/disable runtime init values */ -static void qed_enable_pf_wfq(struct qed_hwfn *p_hwfn, - bool pf_wfq_en) +static void qed_enable_pf_wfq(struct qed_hwfn *p_hwfn, bool pf_wfq_en) { STORE_RT_REG(p_hwfn, QM_REG_WFQPFENABLE_RT_OFFSET, pf_wfq_en ? 1 : 0); /* set credit threshold for QM bypass flow */ @@ -156,8 +151,7 @@ static void qed_enable_pf_wfq(struct qed_hwfn *p_hwfn, } /* Prepare VPORT RL enable/disable runtime init values */ -static void qed_enable_vport_rl(struct qed_hwfn *p_hwfn, - bool vport_rl_en) +static void qed_enable_vport_rl(struct qed_hwfn *p_hwfn, bool vport_rl_en) { STORE_RT_REG(p_hwfn, QM_REG_RLGLBLENABLE_RT_OFFSET, vport_rl_en ? 1 : 0); @@ -178,8 +172,7 @@ static void qed_enable_vport_rl(struct qed_hwfn *p_hwfn, } /* Prepare VPORT WFQ enable/disable runtime init values */ -static void qed_enable_vport_wfq(struct qed_hwfn *p_hwfn, - bool vport_wfq_en) +static void qed_enable_vport_wfq(struct qed_hwfn *p_hwfn, bool vport_wfq_en) { STORE_RT_REG(p_hwfn, QM_REG_WFQVPENABLE_RT_OFFSET, vport_wfq_en ? 1 : 0); @@ -194,8 +187,7 @@ static void qed_enable_vport_wfq(struct qed_hwfn *p_hwfn, * the specified VOQ */ static void qed_cmdq_lines_voq_rt_init(struct qed_hwfn *p_hwfn, - u8 voq, - u16 cmdq_lines) + u8 voq, u16 cmdq_lines) { u32 qm_line_crd; @@ -221,7 +213,7 @@ static void qed_cmdq_lines_rt_init( u8 max_phys_tcs_per_port, struct init_qm_port_params port_params[MAX_NUM_PORTS]) { - u8 tc, voq, port_id; + u8 tc, voq, port_id, num_tcs_in_port; /* clear PBF lines for all VOQs */ for (voq = 0; voq < MAX_NUM_VOQS; voq++) @@ -229,22 +221,31 @@ static void qed_cmdq_lines_rt_init( for (port_id = 0; port_id < max_ports_per_engine; port_id++) { if (port_params[port_id].active) { u16 phys_lines, phys_lines_per_tc; - u8 phys_tcs = port_params[port_id].num_active_phys_tcs; - /* find #lines to divide between the active - * physical TCs. - */ + /* find #lines to divide between active phys TCs */ phys_lines = port_params[port_id].num_pbf_cmd_lines - PBF_CMDQ_PURE_LB_LINES; /* find #lines per active physical TC */ - phys_lines_per_tc = phys_lines / phys_tcs; + num_tcs_in_port = 0; + for (tc = 0; tc < NUM_OF_PHYS_TCS; tc++) { + if (((port_params[port_id].active_phys_tcs >> + tc) & 0x1) == 1) + num_tcs_in_port++; + } + + phys_lines_per_tc = phys_lines / num_tcs_in_port; /* init registers per active TC */ - for (tc = 0; tc < phys_tcs; tc++) { + for (tc = 0; tc < NUM_OF_PHYS_TCS; tc++) { + if (((port_params[port_id].active_phys_tcs >> + tc) & 0x1) != 1) + continue; + voq = PHYS_VOQ(port_id, tc, max_phys_tcs_per_port); qed_cmdq_lines_voq_rt_init(p_hwfn, voq, phys_lines_per_tc); } + /* init registers for pure LB TC */ qed_cmdq_lines_voq_rt_init(p_hwfn, LB_VOQ(port_id), PBF_CMDQ_PURE_LB_LINES); @@ -259,34 +260,42 @@ static void qed_btb_blocks_rt_init( struct init_qm_port_params port_params[MAX_NUM_PORTS]) { u32 usable_blocks, pure_lb_blocks, phys_blocks; - u8 tc, voq, port_id; + u8 tc, voq, port_id, num_tcs_in_port; for (port_id = 0; port_id < max_ports_per_engine; port_id++) { u32 temp; - u8 phys_tcs; if (!port_params[port_id].active) continue; - phys_tcs = port_params[port_id].num_active_phys_tcs; - /* subtract headroom blocks */ usable_blocks = port_params[port_id].num_btb_blocks - BTB_HEADROOM_BLOCKS; - /* find blocks per physical TC. use factor to avoid - * floating arithmethic. - */ + /* find blocks per physical TC */ + num_tcs_in_port = 0; + for (tc = 0; tc < NUM_OF_PHYS_TCS; tc++) { + if (((port_params[port_id].active_phys_tcs >> + tc) & 0x1) == 1) + num_tcs_in_port++; + } + pure_lb_blocks = (usable_blocks * BTB_PURE_LB_FACTOR) / - (phys_tcs * BTB_PURE_LB_FACTOR + + (num_tcs_in_port * BTB_PURE_LB_FACTOR + BTB_PURE_LB_RATIO); pure_lb_blocks = max_t(u32, BTB_JUMBO_PKT_BLOCKS, pure_lb_blocks / BTB_PURE_LB_FACTOR); - phys_blocks = (usable_blocks - pure_lb_blocks) / phys_tcs; + phys_blocks = (usable_blocks - pure_lb_blocks) / + num_tcs_in_port; /* init physical TCs */ - for (tc = 0; tc < phys_tcs; tc++) { - voq = PHYS_VOQ(port_id, tc, max_phys_tcs_per_port); + for (tc = 0; tc < NUM_OF_PHYS_TCS; tc++) { + if (((port_params[port_id].active_phys_tcs >> + tc) & 0x1) != 1) + continue; + + voq = PHYS_VOQ(port_id, tc, + max_phys_tcs_per_port); STORE_RT_REG(p_hwfn, PBF_BTB_GUARANTEED_RT_OFFSET(voq), phys_blocks); } @@ -360,10 +369,11 @@ static void qed_tx_pq_map_rt_init( memset(&tx_pq_map, 0, sizeof(tx_pq_map)); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_PQ_VALID, 1); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_RL_VALID, - is_vf_pq ? 1 : 0); + p_params->pq_params[i].rl_valid ? 1 : 0); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_VP_PQ_ID, first_tx_pq_id); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_RL_ID, - is_vf_pq ? p_params->pq_params[i].vport_id : 0); + p_params->pq_params[i].rl_valid ? + p_params->pq_params[i].vport_id : 0); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_VOQ, voq); SET_FIELD(tx_pq_map.reg, QM_RF_PQ_MAP_WRR_WEIGHT_GROUP, p_params->pq_params[i].wrr_group); @@ -390,25 +400,11 @@ static void qed_tx_pq_map_rt_init( /* store Tx PQ VF mask to size select register */ for (i = 0; i < num_tx_pq_vf_masks; i++) { if (tx_pq_vf_mask[i]) { - if (is_bb_a0) { - u32 curr_mask = 0, addr; - - addr = QM_REG_MAXPQSIZETXSEL_0 + (i * 4); - if (!p_params->is_first_pf) - curr_mask = qed_rd(p_hwfn, p_ptt, - addr); - - addr = QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i; - - STORE_RT_REG(p_hwfn, addr, - curr_mask | tx_pq_vf_mask[i]); - } else { - u32 addr; + u32 addr; - addr = QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i; - STORE_RT_REG(p_hwfn, addr, - tx_pq_vf_mask[i]); - } + addr = QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET + i; + STORE_RT_REG(p_hwfn, addr, + tx_pq_vf_mask[i]); } } } @@ -418,8 +414,7 @@ static void qed_other_pq_map_rt_init(struct qed_hwfn *p_hwfn, u8 port_id, u8 pf_id, u32 num_pf_cids, - u32 num_tids, - u32 base_mem_addr_4kb) + u32 num_tids, u32 base_mem_addr_4kb) { u16 i, pq_id; @@ -465,15 +460,10 @@ static int qed_pf_wfq_rt_init(struct qed_hwfn *p_hwfn, (p_params->pf_id % MAX_NUM_PFS_BB); inc_val = QM_WFQ_INC_VAL(p_params->pf_wfq); - if (inc_val > QM_WFQ_MAX_INC_VAL) { + if (!inc_val || inc_val > QM_WFQ_MAX_INC_VAL) { DP_NOTICE(p_hwfn, "Invalid PF WFQ weight configuration"); return -1; } - STORE_RT_REG(p_hwfn, QM_REG_WFQPFWEIGHT_RT_OFFSET + p_params->pf_id, - inc_val); - STORE_RT_REG(p_hwfn, - QM_REG_WFQPFUPPERBOUND_RT_OFFSET + p_params->pf_id, - QM_WFQ_UPPER_BOUND | QM_WFQ_CRD_REG_SIGN_BIT); for (i = 0; i < num_tx_pqs; i++) { u8 voq = VOQ(p_params->port_id, p_params->pq_params[i].tc_id, @@ -481,19 +471,21 @@ static int qed_pf_wfq_rt_init(struct qed_hwfn *p_hwfn, OVERWRITE_RT_REG(p_hwfn, crd_reg_offset + voq * MAX_NUM_PFS_BB, - QM_WFQ_INIT_CRD(inc_val) | QM_WFQ_CRD_REG_SIGN_BIT); } + STORE_RT_REG(p_hwfn, QM_REG_WFQPFWEIGHT_RT_OFFSET + p_params->pf_id, + inc_val); + STORE_RT_REG(p_hwfn, + QM_REG_WFQPFUPPERBOUND_RT_OFFSET + p_params->pf_id, + QM_WFQ_UPPER_BOUND | QM_WFQ_CRD_REG_SIGN_BIT); return 0; } /* Prepare PF RL runtime init values for the specified PF. * Return -1 on error. */ -static int qed_pf_rl_rt_init(struct qed_hwfn *p_hwfn, - u8 pf_id, - u32 pf_rl) +static int qed_pf_rl_rt_init(struct qed_hwfn *p_hwfn, u8 pf_id, u32 pf_rl) { u32 inc_val = QM_RL_INC_VAL(pf_rl); @@ -607,9 +599,7 @@ static bool qed_poll_on_qm_cmd_ready(struct qed_hwfn *p_hwfn, static bool qed_send_qm_cmd(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u32 cmd_addr, - u32 cmd_data_lsb, - u32 cmd_data_msb) + u32 cmd_addr, u32 cmd_data_lsb, u32 cmd_data_msb) { if (!qed_poll_on_qm_cmd_ready(p_hwfn, p_ptt)) return false; @@ -627,9 +617,7 @@ static bool qed_send_qm_cmd(struct qed_hwfn *p_hwfn, u32 qed_qm_pf_mem_size(u8 pf_id, u32 num_pf_cids, u32 num_vf_cids, - u32 num_tids, - u16 num_pf_pqs, - u16 num_vf_pqs) + u32 num_tids, u16 num_pf_pqs, u16 num_vf_pqs) { return QM_PQ_MEM_4KB(num_pf_cids) * num_pf_pqs + QM_PQ_MEM_4KB(num_vf_cids) * num_vf_pqs + @@ -713,8 +701,7 @@ int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn, } int qed_init_pf_wfq(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u8 pf_id, u16 pf_wfq) + struct qed_ptt *p_ptt, u8 pf_id, u16 pf_wfq) { u32 inc_val = QM_WFQ_INC_VAL(pf_wfq); @@ -728,9 +715,7 @@ int qed_init_pf_wfq(struct qed_hwfn *p_hwfn, } int qed_init_pf_rl(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u8 pf_id, - u32 pf_rl) + struct qed_ptt *p_ptt, u8 pf_id, u32 pf_rl) { u32 inc_val = QM_RL_INC_VAL(pf_rl); @@ -749,8 +734,7 @@ int qed_init_pf_rl(struct qed_hwfn *p_hwfn, int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - u16 first_tx_pq_id[NUM_OF_TCS], - u16 vport_wfq) + u16 first_tx_pq_id[NUM_OF_TCS], u16 vport_wfq) { u32 inc_val = QM_WFQ_INC_VAL(vport_wfq); u8 tc; @@ -773,9 +757,7 @@ int qed_init_vport_wfq(struct qed_hwfn *p_hwfn, } int qed_init_vport_rl(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u8 vport_id, - u32 vport_rl) + struct qed_ptt *p_ptt, u8 vport_id, u32 vport_rl) { u32 inc_val = QM_RL_INC_VAL(vport_rl); @@ -795,9 +777,7 @@ int qed_init_vport_rl(struct qed_hwfn *p_hwfn, bool qed_send_qm_stop_cmd(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool is_release_cmd, - bool is_tx_pq, - u16 start_pq, - u16 num_pqs) + bool is_tx_pq, u16 start_pq, u16 num_pqs) { u32 cmd_arr[QM_CMD_STRUCT_SIZE(QM_STOP_CMD)] = { 0 }; u32 pq_mask = 0, last_pq = start_pq + num_pqs - 1, pq_id; @@ -841,17 +821,15 @@ qed_set_tunnel_type_enable_bit(unsigned long *var, int bit, bool enable) #define PRS_ETH_TUNN_FIC_FORMAT -188897008 void qed_set_vxlan_dest_port(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u16 dest_port) + struct qed_ptt *p_ptt, u16 dest_port) { qed_wr(p_hwfn, p_ptt, PRS_REG_VXLAN_PORT, dest_port); - qed_wr(p_hwfn, p_ptt, NIG_REG_VXLAN_PORT, dest_port); + qed_wr(p_hwfn, p_ptt, NIG_REG_VXLAN_CTRL, dest_port); qed_wr(p_hwfn, p_ptt, PBF_REG_VXLAN_PORT, dest_port); } void qed_set_vxlan_enable(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - bool vxlan_enable) + struct qed_ptt *p_ptt, bool vxlan_enable) { unsigned long reg_val = 0; u8 shift; @@ -908,8 +886,7 @@ void qed_set_gre_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, } void qed_set_geneve_dest_port(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u16 dest_port) + struct qed_ptt *p_ptt, u16 dest_port) { qed_wr(p_hwfn, p_ptt, PRS_REG_NGE_PORT, dest_port); qed_wr(p_hwfn, p_ptt, NIG_REG_NGE_PORT, dest_port); @@ -918,8 +895,7 @@ void qed_set_geneve_dest_port(struct qed_hwfn *p_hwfn, void qed_set_geneve_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - bool eth_geneve_enable, - bool ip_geneve_enable) + bool eth_geneve_enable, bool ip_geneve_enable) { unsigned long reg_val = 0; u8 shift; diff --git a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c index d358c3bb1308..9866a20d2128 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_init_ops.c +++ b/drivers/net/ethernet/qlogic/qed/qed_init_ops.c @@ -543,8 +543,7 @@ void qed_gtt_init(struct qed_hwfn *p_hwfn) pxp_global_win[i]); } -int qed_init_fw_data(struct qed_dev *cdev, - const u8 *data) +int qed_init_fw_data(struct qed_dev *cdev, const u8 *data) { struct qed_fw_data *fw = cdev->fw_data; struct bin_buffer_hdr *buf_hdr; @@ -555,7 +554,11 @@ int qed_init_fw_data(struct qed_dev *cdev, return -EINVAL; } - buf_hdr = (struct bin_buffer_hdr *)data; + /* First Dword contains metadata and should be skipped */ + buf_hdr = (struct bin_buffer_hdr *)(data + sizeof(u32)); + + offset = buf_hdr[BIN_BUF_FW_VER_INFO].offset; + fw->fw_ver_info = (struct fw_ver_info *)(data + offset); offset = buf_hdr[BIN_BUF_INIT_CMD].offset; fw->init_ops = (union init_op *)(data + offset); diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 8fba87dd48af..2ee496e26df6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -575,9 +575,12 @@ int qed_sp_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn, p_ramrod->num_of_pbl_pages = cpu_to_le16(cqe_pbl_size); DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, cqe_pbl_addr); - rc = qed_spq_post(p_hwfn, p_ent, NULL); + p_ramrod->vf_rx_prod_index = params->vf_qid; + if (params->vf_qid) + DP_VERBOSE(p_hwfn, QED_MSG_SP, + "Queue is meant for VF rxq[%04x]\n", params->vf_qid); - return rc; + return qed_spq_post(p_hwfn, p_ent, NULL); } static int @@ -615,7 +618,7 @@ qed_sp_eth_rx_queue_start(struct qed_hwfn *p_hwfn, *pp_prod = (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_MSDM_RAM + - MSTORM_PRODS_OFFSET(abs_l2_queue); + MSTORM_ETH_PF_PRODS_OFFSET(abs_l2_queue); /* Init the rcq, rx bd and rx sge (if valid) producers to 0 */ __internal_ram_wr(p_hwfn, *pp_prod, sizeof(u64), @@ -759,9 +762,9 @@ int qed_sp_eth_txq_start_ramrod(struct qed_hwfn *p_hwfn, struct qed_spq_entry *p_ent = NULL; struct qed_sp_init_data init_data; struct qed_hw_cid_data *p_tx_cid; - u8 abs_vport_id; + u16 pq_id, abs_tx_q_id = 0; int rc = -EINVAL; - u16 pq_id; + u8 abs_vport_id; /* Store information for the stop */ p_tx_cid = &p_hwfn->p_tx_cids[p_params->queue_id]; @@ -772,6 +775,10 @@ int qed_sp_eth_txq_start_ramrod(struct qed_hwfn *p_hwfn, if (rc) return rc; + rc = qed_fw_l2_queue(p_hwfn, p_params->queue_id, &abs_tx_q_id); + if (rc) + return rc; + /* Get SPQ entry */ memset(&init_data, 0, sizeof(init_data)); init_data.cid = cid; @@ -791,6 +798,7 @@ int qed_sp_eth_txq_start_ramrod(struct qed_hwfn *p_hwfn, p_ramrod->sb_index = p_params->sb_idx; p_ramrod->stats_counter_id = stats_id; + p_ramrod->queue_zone_id = cpu_to_le16(abs_tx_q_id); p_ramrod->pbl_size = cpu_to_le16(pbl_size); DMA_REGPAIR_LE(p_ramrod->pbl_base_addr, pbl_addr); @@ -1485,51 +1493,51 @@ static void __qed_get_vport_port_stats(struct qed_hwfn *p_hwfn, offsetof(struct public_port, stats), sizeof(port_stats)); - p_stats->rx_64_byte_packets += port_stats.pmm.r64; - p_stats->rx_65_to_127_byte_packets += port_stats.pmm.r127; - p_stats->rx_128_to_255_byte_packets += port_stats.pmm.r255; - p_stats->rx_256_to_511_byte_packets += port_stats.pmm.r511; - p_stats->rx_512_to_1023_byte_packets += port_stats.pmm.r1023; - p_stats->rx_1024_to_1518_byte_packets += port_stats.pmm.r1518; - p_stats->rx_1519_to_1522_byte_packets += port_stats.pmm.r1522; - p_stats->rx_1519_to_2047_byte_packets += port_stats.pmm.r2047; - p_stats->rx_2048_to_4095_byte_packets += port_stats.pmm.r4095; - p_stats->rx_4096_to_9216_byte_packets += port_stats.pmm.r9216; - p_stats->rx_9217_to_16383_byte_packets += port_stats.pmm.r16383; - p_stats->rx_crc_errors += port_stats.pmm.rfcs; - p_stats->rx_mac_crtl_frames += port_stats.pmm.rxcf; - p_stats->rx_pause_frames += port_stats.pmm.rxpf; - p_stats->rx_pfc_frames += port_stats.pmm.rxpp; - p_stats->rx_align_errors += port_stats.pmm.raln; - p_stats->rx_carrier_errors += port_stats.pmm.rfcr; - p_stats->rx_oversize_packets += port_stats.pmm.rovr; - p_stats->rx_jabbers += port_stats.pmm.rjbr; - p_stats->rx_undersize_packets += port_stats.pmm.rund; - p_stats->rx_fragments += port_stats.pmm.rfrg; - p_stats->tx_64_byte_packets += port_stats.pmm.t64; - p_stats->tx_65_to_127_byte_packets += port_stats.pmm.t127; - p_stats->tx_128_to_255_byte_packets += port_stats.pmm.t255; - p_stats->tx_256_to_511_byte_packets += port_stats.pmm.t511; - p_stats->tx_512_to_1023_byte_packets += port_stats.pmm.t1023; - p_stats->tx_1024_to_1518_byte_packets += port_stats.pmm.t1518; - p_stats->tx_1519_to_2047_byte_packets += port_stats.pmm.t2047; - p_stats->tx_2048_to_4095_byte_packets += port_stats.pmm.t4095; - p_stats->tx_4096_to_9216_byte_packets += port_stats.pmm.t9216; - p_stats->tx_9217_to_16383_byte_packets += port_stats.pmm.t16383; - p_stats->tx_pause_frames += port_stats.pmm.txpf; - p_stats->tx_pfc_frames += port_stats.pmm.txpp; - p_stats->tx_lpi_entry_count += port_stats.pmm.tlpiec; - p_stats->tx_total_collisions += port_stats.pmm.tncl; - p_stats->rx_mac_bytes += port_stats.pmm.rbyte; - p_stats->rx_mac_uc_packets += port_stats.pmm.rxuca; - p_stats->rx_mac_mc_packets += port_stats.pmm.rxmca; - p_stats->rx_mac_bc_packets += port_stats.pmm.rxbca; - p_stats->rx_mac_frames_ok += port_stats.pmm.rxpok; - p_stats->tx_mac_bytes += port_stats.pmm.tbyte; - p_stats->tx_mac_uc_packets += port_stats.pmm.txuca; - p_stats->tx_mac_mc_packets += port_stats.pmm.txmca; - p_stats->tx_mac_bc_packets += port_stats.pmm.txbca; - p_stats->tx_mac_ctrl_frames += port_stats.pmm.txcf; + p_stats->rx_64_byte_packets += port_stats.eth.r64; + p_stats->rx_65_to_127_byte_packets += port_stats.eth.r127; + p_stats->rx_128_to_255_byte_packets += port_stats.eth.r255; + p_stats->rx_256_to_511_byte_packets += port_stats.eth.r511; + p_stats->rx_512_to_1023_byte_packets += port_stats.eth.r1023; + p_stats->rx_1024_to_1518_byte_packets += port_stats.eth.r1518; + p_stats->rx_1519_to_1522_byte_packets += port_stats.eth.r1522; + p_stats->rx_1519_to_2047_byte_packets += port_stats.eth.r2047; + p_stats->rx_2048_to_4095_byte_packets += port_stats.eth.r4095; + p_stats->rx_4096_to_9216_byte_packets += port_stats.eth.r9216; + p_stats->rx_9217_to_16383_byte_packets += port_stats.eth.r16383; + p_stats->rx_crc_errors += port_stats.eth.rfcs; + p_stats->rx_mac_crtl_frames += port_stats.eth.rxcf; + p_stats->rx_pause_frames += port_stats.eth.rxpf; + p_stats->rx_pfc_frames += port_stats.eth.rxpp; + p_stats->rx_align_errors += port_stats.eth.raln; + p_stats->rx_carrier_errors += port_stats.eth.rfcr; + p_stats->rx_oversize_packets += port_stats.eth.rovr; + p_stats->rx_jabbers += port_stats.eth.rjbr; + p_stats->rx_undersize_packets += port_stats.eth.rund; + p_stats->rx_fragments += port_stats.eth.rfrg; + p_stats->tx_64_byte_packets += port_stats.eth.t64; + p_stats->tx_65_to_127_byte_packets += port_stats.eth.t127; + p_stats->tx_128_to_255_byte_packets += port_stats.eth.t255; + p_stats->tx_256_to_511_byte_packets += port_stats.eth.t511; + p_stats->tx_512_to_1023_byte_packets += port_stats.eth.t1023; + p_stats->tx_1024_to_1518_byte_packets += port_stats.eth.t1518; + p_stats->tx_1519_to_2047_byte_packets += port_stats.eth.t2047; + p_stats->tx_2048_to_4095_byte_packets += port_stats.eth.t4095; + p_stats->tx_4096_to_9216_byte_packets += port_stats.eth.t9216; + p_stats->tx_9217_to_16383_byte_packets += port_stats.eth.t16383; + p_stats->tx_pause_frames += port_stats.eth.txpf; + p_stats->tx_pfc_frames += port_stats.eth.txpp; + p_stats->tx_lpi_entry_count += port_stats.eth.tlpiec; + p_stats->tx_total_collisions += port_stats.eth.tncl; + p_stats->rx_mac_bytes += port_stats.eth.rbyte; + p_stats->rx_mac_uc_packets += port_stats.eth.rxuca; + p_stats->rx_mac_mc_packets += port_stats.eth.rxmca; + p_stats->rx_mac_bc_packets += port_stats.eth.rxbca; + p_stats->rx_mac_frames_ok += port_stats.eth.rxpok; + p_stats->tx_mac_bytes += port_stats.eth.tbyte; + p_stats->tx_mac_uc_packets += port_stats.eth.txuca; + p_stats->tx_mac_mc_packets += port_stats.eth.txmca; + p_stats->tx_mac_bc_packets += port_stats.eth.txbca; + p_stats->tx_mac_ctrl_frames += port_stats.eth.txcf; for (j = 0; j < 8; j++) { p_stats->brb_truncates += port_stats.brb.brb_truncate[j]; p_stats->brb_discards += port_stats.brb.brb_discard[j]; diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 753064679bde..c807f67a02c5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -832,7 +832,8 @@ static int qed_slowpath_start(struct qed_dev *cdev, goto err2; } - data = cdev->firmware->data; + /* First Dword used to diffrentiate between various sources */ + data = cdev->firmware->data + sizeof(u32); } memset(&tunn_info, 0, sizeof(tunn_info)); @@ -991,8 +992,7 @@ static bool qed_can_link_change(struct qed_dev *cdev) return true; } -static int qed_set_link(struct qed_dev *cdev, - struct qed_link_params *params) +static int qed_set_link(struct qed_dev *cdev, struct qed_link_params *params) { struct qed_hwfn *hwfn; struct qed_mcp_link_params *link_params; @@ -1032,7 +1032,7 @@ static int qed_set_link(struct qed_dev *cdev, NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G; if (params->adv_speeds & 0) link_params->speed.advertised_speeds |= - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_100G; + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G; } if (params->override_flags & QED_LINK_OVERRIDE_SPEED_FORCED_SPEED) link_params->speed.forced_speed = params->forced_speed; @@ -1053,19 +1053,19 @@ static int qed_set_link(struct qed_dev *cdev, if (params->override_flags & QED_LINK_OVERRIDE_LOOPBACK_MODE) { switch (params->loopback_mode) { case QED_LINK_LOOPBACK_INT_PHY: - link_params->loopback_mode = PMM_LOOPBACK_INT_PHY; + link_params->loopback_mode = ETH_LOOPBACK_INT_PHY; break; case QED_LINK_LOOPBACK_EXT_PHY: - link_params->loopback_mode = PMM_LOOPBACK_EXT_PHY; + link_params->loopback_mode = ETH_LOOPBACK_EXT_PHY; break; case QED_LINK_LOOPBACK_EXT: - link_params->loopback_mode = PMM_LOOPBACK_EXT; + link_params->loopback_mode = ETH_LOOPBACK_EXT; break; case QED_LINK_LOOPBACK_MAC: - link_params->loopback_mode = PMM_LOOPBACK_MAC; + link_params->loopback_mode = ETH_LOOPBACK_MAC; break; default: - link_params->loopback_mode = PMM_LOOPBACK_NONE; + link_params->loopback_mode = ETH_LOOPBACK_NONE; break; } } @@ -1157,7 +1157,7 @@ static void qed_fill_link(struct qed_hwfn *hwfn, NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) if_link->advertised_caps |= 0; if (params.speed.advertised_speeds & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_100G) + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) if_link->advertised_caps |= 0; if (link_caps.speed_capabilities & @@ -1174,7 +1174,7 @@ static void qed_fill_link(struct qed_hwfn *hwfn, NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G) if_link->supported_caps |= 0; if (link_caps.speed_capabilities & - NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_100G) + NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G) if_link->supported_caps |= 0; if (link.link_up) diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 1182361798b5..2c143b33c002 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -531,9 +531,9 @@ static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, transceiver_data))); transceiver_state = GET_FIELD(transceiver_state, - PMM_TRANSCEIVER_STATE); + ETH_TRANSCEIVER_STATE); - if (transceiver_state == PMM_TRANSCEIVER_STATE_PRESENT) + if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) DP_NOTICE(p_hwfn, "Transceiver is present.\n"); else DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); @@ -668,14 +668,12 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, qed_link_update(p_hwfn); } -int qed_mcp_set_link(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - bool b_up) +int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) { struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; struct qed_mcp_mb_params mb_params; union drv_union_data union_data; - struct pmm_phy_cfg *phy_cfg; + struct eth_phy_cfg *phy_cfg; int rc = 0; u32 cmd; @@ -685,9 +683,9 @@ int qed_mcp_set_link(struct qed_hwfn *p_hwfn, cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; if (!params->speed.autoneg) phy_cfg->speed = params->speed.forced_speed; - phy_cfg->pause |= (params->pause.autoneg) ? PMM_PAUSE_AUTONEG : 0; - phy_cfg->pause |= (params->pause.forced_rx) ? PMM_PAUSE_RX : 0; - phy_cfg->pause |= (params->pause.forced_tx) ? PMM_PAUSE_TX : 0; + phy_cfg->pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; + phy_cfg->pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; + phy_cfg->pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; phy_cfg->adv_speed = params->speed.advertised_speeds; phy_cfg->loopback_mode = params->loopback_mode; @@ -773,6 +771,34 @@ static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, return size; } +int qed_hw_init_first_eth(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 *p_pf) +{ + struct public_func shmem_info; + int i; + + /* Find first Ethernet interface in port */ + for (i = 0; i < NUM_OF_ENG_PFS(p_hwfn->cdev); + i += p_hwfn->cdev->num_ports_in_engines) { + qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, + MCP_PF_ID_BY_REL(p_hwfn, i)); + + if (shmem_info.config & FUNC_MF_CFG_FUNC_HIDE) + continue; + + if ((shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK) == + FUNC_MF_CFG_PROTOCOL_ETHERNET) { + *p_pf = (u8)i; + return 0; + } + } + + DP_NOTICE(p_hwfn, + "Failed to find on port an ethernet interface in MF_SI mode\n"); + + return -EINVAL; +} + static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 6dd59eb7f4c6..7f319aa1b229 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -457,4 +457,7 @@ int __qed_configure_pf_min_bandwidth(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_mcp_link_state *p_link, u8 min_bw); + +int qed_hw_init_first_eth(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, u8 *p_pf); #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 3a6c506f0d71..b889585bb987 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -167,6 +167,10 @@ 0x1800004UL #define NIG_REG_CM_HDR \ 0x500840UL +#define NIG_REG_LLH_TAGMAC_DEF_PF_VECTOR \ + 0x50196cUL +#define NIG_REG_LLH_CLS_TYPE_DUALMODE \ + 0x501964UL #define NCSI_REG_CONFIG \ 0x040200UL #define PBF_REG_INIT \ @@ -219,6 +223,8 @@ 0x230000UL #define PRS_REG_SOFT_RST \ 0x1f0000UL +#define PRS_REG_MSG_INFO \ + 0x1f0a1cUL #define PSDM_REG_ENABLE_IN1 \ 0xfa0004UL #define PSEM_REG_ENABLE_IN \ @@ -460,7 +466,7 @@ #define NIG_REG_ENC_TYPE_ENABLE_VXLAN_ENABLE (0x1 << 2) #define NIG_REG_ENC_TYPE_ENABLE_VXLAN_ENABLE_SHIFT 2 -#define NIG_REG_VXLAN_PORT 0x50105cUL +#define NIG_REG_VXLAN_CTRL 0x50105cUL #define PBF_REG_VXLAN_PORT 0xd80518UL #define PBF_REG_NGE_PORT 0xd8051cUL #define PRS_REG_NGE_PORT 0x1f086cUL diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c index 67f6ce3c84c8..122506416478 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -332,7 +332,7 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, p_ramrod->path_id = QED_PATH_ID(p_hwfn); p_ramrod->dont_log_ramrods = 0; p_ramrod->log_type_mask = cpu_to_le16(0xf); - p_ramrod->mf_mode = mode; + switch (mode) { case QED_MF_DEFAULT: case QED_MF_NPAR: @@ -368,6 +368,8 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, p_ramrod->base_vf_id = (u8) p_iov->first_vf_in_pf; p_ramrod->num_vfs = (u8) p_iov->total_vfs; } + p_ramrod->hsi_fp_ver.major_ver_arr[ETH_VER_KEY] = ETH_HSI_VER_MAJOR; + p_ramrod->hsi_fp_ver.minor_ver_arr[ETH_VER_KEY] = ETH_HSI_VER_MINOR; DP_VERBOSE(p_hwfn, QED_MSG_SPQ, "Setting event_ring_sb [id %04x index %02x], outer_tag [%d]\n", diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index c325ee857ecd..eb75b8234a7c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -47,6 +47,8 @@ static int qed_sp_vf_start(struct qed_hwfn *p_hwfn, p_ramrod->opaque_fid = cpu_to_le16(opaque_vfid); p_ramrod->personality = PERSONALITY_ETH; + p_ramrod->hsi_fp_ver.major_ver_arr[ETH_VER_KEY] = ETH_HSI_VER_MAJOR; + p_ramrod->hsi_fp_ver.minor_ver_arr[ETH_VER_KEY] = ETH_HSI_VER_MINOR; return qed_spq_post(p_hwfn, p_ent, NULL); } @@ -1585,10 +1587,6 @@ static void qed_iov_vf_mbx_stop_vport(struct qed_hwfn *p_hwfn, sizeof(struct pfvf_def_resp_tlv), status); } -#define TSTORM_QZONE_START PXP_VF_BAR0_START_SDM_ZONE_A -#define MSTORM_QZONE_START(dev) (TSTORM_QZONE_START + \ - (TSTORM_QZONE_SIZE * NUM_OF_L2_QUEUES(dev))) - static void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_vf_info *vf, u8 status) @@ -1606,16 +1604,11 @@ static void qed_iov_vf_mbx_start_rxq_resp(struct qed_hwfn *p_hwfn, /* Update the TLV with the response */ if (status == PFVF_STATUS_SUCCESS) { - u16 hw_qid = 0; - req = &mbx->req_virt->start_rxq; - qed_fw_l2_queue(p_hwfn, vf->vf_queues[req->rx_qid].fw_rx_qid, - &hw_qid); - - p_tlv->offset = MSTORM_QZONE_START(p_hwfn->cdev) + - hw_qid * MSTORM_QZONE_SIZE + - offsetof(struct mstorm_eth_queue_zone, - rx_producers); + p_tlv->offset = PXP_VF_BAR0_START_MSDM_ZONE_B + + offsetof(struct mstorm_vf_zone, + non_trigger.eth_rx_queue_producers) + + sizeof(struct eth_rx_prod_data) * req->rx_qid; } qed_iov_send_response(p_hwfn, p_ptt, vf, sizeof(*p_tlv), status); @@ -1634,6 +1627,7 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn, memset(¶ms, 0, sizeof(params)); req = &mbx->req_virt->start_rxq; params.queue_id = vf->vf_queues[req->rx_qid].fw_rx_qid; + params.vf_qid = req->rx_qid; params.vport_id = vf->vport_id; params.sb = req->hw_sb; params.sb_idx = req->sb_index; diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index ad3cae3b7243..6836d44b6b89 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -910,6 +910,8 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, memset(first_bd, 0, sizeof(*first_bd)); val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT; first_bd->data.bd_flags.bitfields = val; + val = skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK; + first_bd->data.bitfields |= (val << ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT); /* Map skb linear data for DMA and set in the first BD */ mapping = dma_map_single(&edev->pdev->dev, skb->data, diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 5d00d1404bfc..4f352476db31 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -577,8 +577,6 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, /* Fill the parsing flags & params according to the requested offload */ if (xmit_type & XMIT_L4_CSUM) { - u16 temp = 1 << ETH_TX_DATA_1ST_BD_TUNN_CFG_OVERRIDE_SHIFT; - /* We don't re-calculate IP checksum as it is already done by * the upper stack */ @@ -588,14 +586,8 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, if (xmit_type & XMIT_ENC) { first_bd->data.bd_flags.bitfields |= 1 << ETH_TX_1ST_BD_FLAGS_IP_CSUM_SHIFT; - } else { - /* In cases when OS doesn't indicate for inner offloads - * when packet is tunnelled, we need to override the HW - * tunnel configuration so that packets are treated as - * regular non tunnelled packets and no inner offloads - * are done by the hardware. - */ - first_bd->data.bitfields |= cpu_to_le16(temp); + first_bd->data.bitfields |= + 1 << ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT; } /* If the packet is IPv6 with extension header, indicate that @@ -653,6 +645,10 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb, tx_data_bd = (struct eth_tx_bd *)third_bd; data_split = true; } + } else { + first_bd->data.bitfields |= + (skb->len & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) << + ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT; } /* Handle fragmented skb */ diff --git a/include/linux/qed/common_hsi.h b/include/linux/qed/common_hsi.h index 3f14c7efe68f..285189a5ea6d 100644 --- a/include/linux/qed/common_hsi.h +++ b/include/linux/qed/common_hsi.h @@ -13,9 +13,19 @@ #define X_FINAL_CLEANUP_AGG_INT 1 +/* Queue Zone sizes in bytes */ +#define TSTORM_QZONE_SIZE 8 +#define MSTORM_QZONE_SIZE 0 +#define USTORM_QZONE_SIZE 8 +#define XSTORM_QZONE_SIZE 8 +#define YSTORM_QZONE_SIZE 0 +#define PSTORM_QZONE_SIZE 0 + +#define ETH_MAX_NUM_RX_QUEUES_PER_VF 16 + #define FW_MAJOR_VERSION 8 -#define FW_MINOR_VERSION 7 -#define FW_REVISION_VERSION 3 +#define FW_MINOR_VERSION 10 +#define FW_REVISION_VERSION 5 #define FW_ENGINEERING_VERSION 0 /***********************/ @@ -97,45 +107,86 @@ #define DQ_XCM_AGG_VAL_SEL_REG6 7 /* XCM agg val selection */ -#define DQ_XCM_ETH_EDPM_NUM_BDS_CMD \ - DQ_XCM_AGG_VAL_SEL_WORD2 -#define DQ_XCM_ETH_TX_BD_CONS_CMD \ - DQ_XCM_AGG_VAL_SEL_WORD3 -#define DQ_XCM_CORE_TX_BD_CONS_CMD \ - DQ_XCM_AGG_VAL_SEL_WORD3 -#define DQ_XCM_ETH_TX_BD_PROD_CMD \ - DQ_XCM_AGG_VAL_SEL_WORD4 -#define DQ_XCM_CORE_TX_BD_PROD_CMD \ - DQ_XCM_AGG_VAL_SEL_WORD4 -#define DQ_XCM_CORE_SPQ_PROD_CMD \ - DQ_XCM_AGG_VAL_SEL_WORD4 -#define DQ_XCM_ETH_GO_TO_BD_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD5 +#define DQ_XCM_CORE_TX_BD_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD3 +#define DQ_XCM_CORE_TX_BD_PROD_CMD DQ_XCM_AGG_VAL_SEL_WORD4 +#define DQ_XCM_CORE_SPQ_PROD_CMD DQ_XCM_AGG_VAL_SEL_WORD4 +#define DQ_XCM_ETH_EDPM_NUM_BDS_CMD DQ_XCM_AGG_VAL_SEL_WORD2 +#define DQ_XCM_ETH_TX_BD_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD3 +#define DQ_XCM_ETH_TX_BD_PROD_CMD DQ_XCM_AGG_VAL_SEL_WORD4 +#define DQ_XCM_ETH_GO_TO_BD_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD5 + +/* UCM agg val selection (HW) */ +#define DQ_UCM_AGG_VAL_SEL_WORD0 0 +#define DQ_UCM_AGG_VAL_SEL_WORD1 1 +#define DQ_UCM_AGG_VAL_SEL_WORD2 2 +#define DQ_UCM_AGG_VAL_SEL_WORD3 3 +#define DQ_UCM_AGG_VAL_SEL_REG0 4 +#define DQ_UCM_AGG_VAL_SEL_REG1 5 +#define DQ_UCM_AGG_VAL_SEL_REG2 6 +#define DQ_UCM_AGG_VAL_SEL_REG3 7 + +/* UCM agg val selection (FW) */ +#define DQ_UCM_ETH_PMD_TX_CONS_CMD DQ_UCM_AGG_VAL_SEL_WORD2 +#define DQ_UCM_ETH_PMD_RX_CONS_CMD DQ_UCM_AGG_VAL_SEL_WORD3 +#define DQ_UCM_ROCE_CQ_CONS_CMD DQ_UCM_AGG_VAL_SEL_REG0 +#define DQ_UCM_ROCE_CQ_PROD_CMD DQ_UCM_AGG_VAL_SEL_REG2 + +/* TCM agg val selection (HW) */ +#define DQ_TCM_AGG_VAL_SEL_WORD0 0 +#define DQ_TCM_AGG_VAL_SEL_WORD1 1 +#define DQ_TCM_AGG_VAL_SEL_WORD2 2 +#define DQ_TCM_AGG_VAL_SEL_WORD3 3 +#define DQ_TCM_AGG_VAL_SEL_REG1 4 +#define DQ_TCM_AGG_VAL_SEL_REG2 5 +#define DQ_TCM_AGG_VAL_SEL_REG6 6 +#define DQ_TCM_AGG_VAL_SEL_REG9 7 + +/* TCM agg val selection (FW) */ +#define DQ_TCM_L2B_BD_PROD_CMD \ + DQ_TCM_AGG_VAL_SEL_WORD1 +#define DQ_TCM_ROCE_RQ_PROD_CMD \ + DQ_TCM_AGG_VAL_SEL_WORD0 /* XCM agg counter flag selection */ -#define DQ_XCM_AGG_FLG_SHIFT_BIT14 0 -#define DQ_XCM_AGG_FLG_SHIFT_BIT15 1 -#define DQ_XCM_AGG_FLG_SHIFT_CF12 2 -#define DQ_XCM_AGG_FLG_SHIFT_CF13 3 -#define DQ_XCM_AGG_FLG_SHIFT_CF18 4 -#define DQ_XCM_AGG_FLG_SHIFT_CF19 5 -#define DQ_XCM_AGG_FLG_SHIFT_CF22 6 -#define DQ_XCM_AGG_FLG_SHIFT_CF23 7 +#define DQ_XCM_AGG_FLG_SHIFT_BIT14 0 +#define DQ_XCM_AGG_FLG_SHIFT_BIT15 1 +#define DQ_XCM_AGG_FLG_SHIFT_CF12 2 +#define DQ_XCM_AGG_FLG_SHIFT_CF13 3 +#define DQ_XCM_AGG_FLG_SHIFT_CF18 4 +#define DQ_XCM_AGG_FLG_SHIFT_CF19 5 +#define DQ_XCM_AGG_FLG_SHIFT_CF22 6 +#define DQ_XCM_AGG_FLG_SHIFT_CF23 7 /* XCM agg counter flag selection */ -#define DQ_XCM_ETH_DQ_CF_CMD (1 << \ - DQ_XCM_AGG_FLG_SHIFT_CF18) -#define DQ_XCM_CORE_DQ_CF_CMD (1 << \ - DQ_XCM_AGG_FLG_SHIFT_CF18) -#define DQ_XCM_ETH_TERMINATE_CMD (1 << \ - DQ_XCM_AGG_FLG_SHIFT_CF19) -#define DQ_XCM_CORE_TERMINATE_CMD (1 << \ - DQ_XCM_AGG_FLG_SHIFT_CF19) -#define DQ_XCM_ETH_SLOW_PATH_CMD (1 << \ - DQ_XCM_AGG_FLG_SHIFT_CF22) -#define DQ_XCM_CORE_SLOW_PATH_CMD (1 << \ - DQ_XCM_AGG_FLG_SHIFT_CF22) -#define DQ_XCM_ETH_TPH_EN_CMD (1 << \ - DQ_XCM_AGG_FLG_SHIFT_CF23) +#define DQ_XCM_CORE_DQ_CF_CMD (1 << DQ_XCM_AGG_FLG_SHIFT_CF18) +#define DQ_XCM_CORE_TERMINATE_CMD (1 << DQ_XCM_AGG_FLG_SHIFT_CF19) +#define DQ_XCM_CORE_SLOW_PATH_CMD (1 << DQ_XCM_AGG_FLG_SHIFT_CF22) +#define DQ_XCM_ETH_DQ_CF_CMD (1 << DQ_XCM_AGG_FLG_SHIFT_CF18) +#define DQ_XCM_ETH_TERMINATE_CMD (1 << DQ_XCM_AGG_FLG_SHIFT_CF19) +#define DQ_XCM_ETH_SLOW_PATH_CMD (1 << DQ_XCM_AGG_FLG_SHIFT_CF22) +#define DQ_XCM_ETH_TPH_EN_CMD (1 << DQ_XCM_AGG_FLG_SHIFT_CF23) + +/* UCM agg counter flag selection (HW) */ +#define DQ_UCM_AGG_FLG_SHIFT_CF0 0 +#define DQ_UCM_AGG_FLG_SHIFT_CF1 1 +#define DQ_UCM_AGG_FLG_SHIFT_CF3 2 +#define DQ_UCM_AGG_FLG_SHIFT_CF4 3 +#define DQ_UCM_AGG_FLG_SHIFT_CF5 4 +#define DQ_UCM_AGG_FLG_SHIFT_CF6 5 +#define DQ_UCM_AGG_FLG_SHIFT_RULE0EN 6 +#define DQ_UCM_AGG_FLG_SHIFT_RULE1EN 7 + +/* UCM agg counter flag selection (FW) */ +#define DQ_UCM_ETH_PMD_TX_ARM_CMD (1 << DQ_UCM_AGG_FLG_SHIFT_CF4) +#define DQ_UCM_ETH_PMD_RX_ARM_CMD (1 << DQ_UCM_AGG_FLG_SHIFT_CF5) + +#define DQ_REGION_SHIFT (12) + +/* DPM */ +#define DQ_DPM_WQE_BUFF_SIZE (320) + +/* Conn type ranges */ +#define DQ_CONN_TYPE_RANGE_SHIFT (4) /*****************/ /* QM CONSTANTS */ @@ -282,8 +333,6 @@ (PXP_EXTERNAL_BAR_GLOBAL_WINDOW_START + \ PXP_EXTERNAL_BAR_GLOBAL_WINDOW_LENGTH - 1) -#define PXP_ILT_PAGE_SIZE_NUM_BITS_MIN 12 -#define PXP_ILT_BLOCK_FACTOR_MULTIPLIER 1024 #define PXP_VF_BAR0_START_IGU 0 #define PXP_VF_BAR0_IGU_LENGTH 0x3000 @@ -342,6 +391,9 @@ #define PXP_VF_BAR0_GRC_WINDOW_LENGTH 32 +#define PXP_ILT_PAGE_SIZE_NUM_BITS_MIN 12 +#define PXP_ILT_BLOCK_FACTOR_MULTIPLIER 1024 + /* ILT Records */ #define PXP_NUM_ILT_RECORDS_BB 7600 #define PXP_NUM_ILT_RECORDS_K2 11000 @@ -379,6 +431,38 @@ struct async_data { u8 fw_debug_param; }; +struct coalescing_timeset { + u8 value; +#define COALESCING_TIMESET_TIMESET_MASK 0x7F +#define COALESCING_TIMESET_TIMESET_SHIFT 0 +#define COALESCING_TIMESET_VALID_MASK 0x1 +#define COALESCING_TIMESET_VALID_SHIFT 7 +}; + +struct common_prs_pf_msg_info { + __le32 value; +#define COMMON_PRS_PF_MSG_INFO_NPAR_DEFAULT_PF_MASK 0x1 +#define COMMON_PRS_PF_MSG_INFO_NPAR_DEFAULT_PF_SHIFT 0 +#define COMMON_PRS_PF_MSG_INFO_FW_DEBUG_1_MASK 0x1 +#define COMMON_PRS_PF_MSG_INFO_FW_DEBUG_1_SHIFT 1 +#define COMMON_PRS_PF_MSG_INFO_FW_DEBUG_2_MASK 0x1 +#define COMMON_PRS_PF_MSG_INFO_FW_DEBUG_2_SHIFT 2 +#define COMMON_PRS_PF_MSG_INFO_FW_DEBUG_3_MASK 0x1 +#define COMMON_PRS_PF_MSG_INFO_FW_DEBUG_3_SHIFT 3 +#define COMMON_PRS_PF_MSG_INFO_RESERVED_MASK 0xFFFFFFF +#define COMMON_PRS_PF_MSG_INFO_RESERVED_SHIFT 4 +}; + +struct common_queue_zone { + __le16 ring_drv_data_consumer; + __le16 reserved; +}; + +struct eth_rx_prod_data { + __le16 bd_prod; + __le16 cqe_prod; +}; + struct regpair { __le32 lo; __le32 hi; @@ -388,11 +472,23 @@ struct vf_pf_channel_eqe_data { struct regpair msg_addr; }; +struct malicious_vf_eqe_data { + u8 vf_id; + u8 err_id; + __le16 reserved[3]; +}; + +struct initial_cleanup_eqe_data { + u8 vf_id; + u8 reserved[7]; +}; + /* Event Data Union */ union event_ring_data { - u8 bytes[8]; - struct vf_pf_channel_eqe_data vf_pf_channel; - struct async_data async_info; + u8 bytes[8]; + struct vf_pf_channel_eqe_data vf_pf_channel; + struct malicious_vf_eqe_data malicious_vf; + struct initial_cleanup_eqe_data vf_init_cleanup; }; /* Event Ring Entry */ @@ -433,6 +529,16 @@ enum protocol_type { MAX_PROTOCOL_TYPE }; +struct ustorm_eth_queue_zone { + struct coalescing_timeset int_coalescing_timeset; + u8 reserved[3]; +}; + +struct ustorm_queue_zone { + struct ustorm_eth_queue_zone eth; + struct common_queue_zone common; +}; + /* status block structure */ struct cau_pi_entry { u32 prod; @@ -683,19 +789,4 @@ struct status_block { #define STATUS_BLOCK_ZERO_PAD3_SHIFT 24 }; -struct tunnel_parsing_flags { - u8 flags; -#define TUNNEL_PARSING_FLAGS_TYPE_MASK 0x3 -#define TUNNEL_PARSING_FLAGS_TYPE_SHIFT 0 -#define TUNNEL_PARSING_FLAGS_TENNANT_ID_EXIST_MASK 0x1 -#define TUNNEL_PARSING_FLAGS_TENNANT_ID_EXIST_SHIFT 2 -#define TUNNEL_PARSING_FLAGS_NEXT_PROTOCOL_MASK 0x3 -#define TUNNEL_PARSING_FLAGS_NEXT_PROTOCOL_SHIFT 3 -#define TUNNEL_PARSING_FLAGS_FIRSTHDRIPMATCH_MASK 0x1 -#define TUNNEL_PARSING_FLAGS_FIRSTHDRIPMATCH_SHIFT 5 -#define TUNNEL_PARSING_FLAGS_IPV4_FRAGMENT_MASK 0x1 -#define TUNNEL_PARSING_FLAGS_IPV4_FRAGMENT_SHIFT 6 -#define TUNNEL_PARSING_FLAGS_IPV4_OPTIONS_MASK 0x1 -#define TUNNEL_PARSING_FLAGS_IPV4_OPTIONS_SHIFT 7 -}; #endif /* __COMMON_HSI__ */ diff --git a/include/linux/qed/eth_common.h b/include/linux/qed/eth_common.h index 092cb0c1afcb..b5ebc697d05f 100644 --- a/include/linux/qed/eth_common.h +++ b/include/linux/qed/eth_common.h @@ -12,6 +12,8 @@ /********************/ /* ETH FW CONSTANTS */ /********************/ +#define ETH_HSI_VER_MAJOR 3 +#define ETH_HSI_VER_MINOR 0 #define ETH_CACHE_LINE_SIZE 64 #define ETH_MAX_RAMROD_PER_CON 8 @@ -57,19 +59,6 @@ #define ETH_TPA_CQE_CONT_LEN_LIST_SIZE 6 #define ETH_TPA_CQE_END_LEN_LIST_SIZE 4 -/* Queue Zone sizes */ -#define TSTORM_QZONE_SIZE 0 -#define MSTORM_QZONE_SIZE sizeof(struct mstorm_eth_queue_zone) -#define USTORM_QZONE_SIZE sizeof(struct ustorm_eth_queue_zone) -#define XSTORM_QZONE_SIZE 0 -#define YSTORM_QZONE_SIZE sizeof(struct ystorm_eth_queue_zone) -#define PSTORM_QZONE_SIZE 0 - -/* Interrupt coalescing TimeSet */ -struct coalescing_timeset { - u8 timeset; - u8 valid; -}; struct eth_tx_1st_bd_flags { u8 bitfields; @@ -97,12 +86,12 @@ struct eth_tx_data_1st_bd { u8 nbds; struct eth_tx_1st_bd_flags bd_flags; __le16 bitfields; -#define ETH_TX_DATA_1ST_BD_TUNN_CFG_OVERRIDE_MASK 0x1 -#define ETH_TX_DATA_1ST_BD_TUNN_CFG_OVERRIDE_SHIFT 0 +#define ETH_TX_DATA_1ST_BD_TUNN_FLAG_MASK 0x1 +#define ETH_TX_DATA_1ST_BD_TUNN_FLAG_SHIFT 0 #define ETH_TX_DATA_1ST_BD_RESERVED0_MASK 0x1 #define ETH_TX_DATA_1ST_BD_RESERVED0_SHIFT 1 -#define ETH_TX_DATA_1ST_BD_FW_USE_ONLY_MASK 0x3FFF -#define ETH_TX_DATA_1ST_BD_FW_USE_ONLY_SHIFT 2 +#define ETH_TX_DATA_1ST_BD_PKT_LEN_MASK 0x3FFF +#define ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT 2 }; /* The parsing information data for the second tx bd of a given packet. */ @@ -136,28 +125,51 @@ struct eth_tx_data_2nd_bd { #define ETH_TX_DATA_2ND_BD_RESERVED0_SHIFT 13 }; +struct eth_fast_path_cqe_fw_debug { + u8 reserved0; + u8 reserved1; + __le16 reserved2; +}; + +/* tunneling parsing flags */ +struct eth_tunnel_parsing_flags { + u8 flags; +#define ETH_TUNNEL_PARSING_FLAGS_TYPE_MASK 0x3 +#define ETH_TUNNEL_PARSING_FLAGS_TYPE_SHIFT 0 +#define ETH_TUNNEL_PARSING_FLAGS_TENNANT_ID_EXIST_MASK 0x1 +#define ETH_TUNNEL_PARSING_FLAGS_TENNANT_ID_EXIST_SHIFT 2 +#define ETH_TUNNEL_PARSING_FLAGS_NEXT_PROTOCOL_MASK 0x3 +#define ETH_TUNNEL_PARSING_FLAGS_NEXT_PROTOCOL_SHIFT 3 +#define ETH_TUNNEL_PARSING_FLAGS_FIRSTHDRIPMATCH_MASK 0x1 +#define ETH_TUNNEL_PARSING_FLAGS_FIRSTHDRIPMATCH_SHIFT 5 +#define ETH_TUNNEL_PARSING_FLAGS_IPV4_FRAGMENT_MASK 0x1 +#define ETH_TUNNEL_PARSING_FLAGS_IPV4_FRAGMENT_SHIFT 6 +#define ETH_TUNNEL_PARSING_FLAGS_IPV4_OPTIONS_MASK 0x1 +#define ETH_TUNNEL_PARSING_FLAGS_IPV4_OPTIONS_SHIFT 7 +}; + /* Regular ETH Rx FP CQE. */ struct eth_fast_path_rx_reg_cqe { - u8 type; - u8 bitfields; + u8 type; + u8 bitfields; #define ETH_FAST_PATH_RX_REG_CQE_RSS_HASH_TYPE_MASK 0x7 #define ETH_FAST_PATH_RX_REG_CQE_RSS_HASH_TYPE_SHIFT 0 #define ETH_FAST_PATH_RX_REG_CQE_TC_MASK 0xF #define ETH_FAST_PATH_RX_REG_CQE_TC_SHIFT 3 #define ETH_FAST_PATH_RX_REG_CQE_RESERVED0_MASK 0x1 #define ETH_FAST_PATH_RX_REG_CQE_RESERVED0_SHIFT 7 - __le16 pkt_len; - struct parsing_and_err_flags pars_flags; - __le16 vlan_tag; - __le32 rss_hash; - __le16 len_on_first_bd; - u8 placement_offset; - struct tunnel_parsing_flags tunnel_pars_flags; - u8 bd_num; - u8 reserved[7]; - u32 fw_debug; - u8 reserved1[3]; - u8 flags; + __le16 pkt_len; + struct parsing_and_err_flags pars_flags; + __le16 vlan_tag; + __le32 rss_hash; + __le16 len_on_first_bd; + u8 placement_offset; + struct eth_tunnel_parsing_flags tunnel_pars_flags; + u8 bd_num; + u8 reserved[7]; + struct eth_fast_path_cqe_fw_debug fw_debug; + u8 reserved1[3]; + u8 flags; #define ETH_FAST_PATH_RX_REG_CQE_VALID_MASK 0x1 #define ETH_FAST_PATH_RX_REG_CQE_VALID_SHIFT 0 #define ETH_FAST_PATH_RX_REG_CQE_VALID_TOGGLE_MASK 0x1 @@ -207,11 +219,11 @@ struct eth_fast_path_rx_tpa_start_cqe { __le32 rss_hash; __le16 len_on_first_bd; u8 placement_offset; - struct tunnel_parsing_flags tunnel_pars_flags; + struct eth_tunnel_parsing_flags tunnel_pars_flags; u8 tpa_agg_index; u8 header_len; __le16 ext_bd_len_list[ETH_TPA_CQE_START_LEN_LIST_SIZE]; - u32 fw_debug; + struct eth_fast_path_cqe_fw_debug fw_debug; }; /* The L4 pseudo checksum mode for Ethernet */ @@ -264,12 +276,25 @@ enum eth_rx_cqe_type { MAX_ETH_RX_CQE_TYPE }; -/* ETH Rx producers data */ -struct eth_rx_prod_data { - __le16 bd_prod; - __le16 cqe_prod; - __le16 reserved; - __le16 reserved1; +enum eth_rx_tunn_type { + ETH_RX_NO_TUNN, + ETH_RX_TUNN_GENEVE, + ETH_RX_TUNN_GRE, + ETH_RX_TUNN_VXLAN, + MAX_ETH_RX_TUNN_TYPE +}; + +/* Aggregation end reason. */ +enum eth_tpa_end_reason { + ETH_AGG_END_UNUSED, + ETH_AGG_END_SP_UPDATE, + ETH_AGG_END_MAX_LEN, + ETH_AGG_END_LAST_SEG, + ETH_AGG_END_TIMEOUT, + ETH_AGG_END_NOT_CONSISTENT, + ETH_AGG_END_OUT_OF_ORDER, + ETH_AGG_END_NON_TPA_SEG, + MAX_ETH_TPA_END_REASON }; /* The first tx bd of a given packet */ @@ -337,21 +362,18 @@ union eth_tx_bd_types { }; /* Mstorm Queue Zone */ -struct mstorm_eth_queue_zone { - struct eth_rx_prod_data rx_producers; - __le32 reserved[2]; -}; - -/* Ustorm Queue Zone */ -struct ustorm_eth_queue_zone { - struct coalescing_timeset int_coalescing_timeset; - __le16 reserved[3]; +enum eth_tx_tunn_type { + ETH_TX_TUNN_GENEVE, + ETH_TX_TUNN_TTAG, + ETH_TX_TUNN_GRE, + ETH_TX_TUNN_VXLAN, + MAX_ETH_TX_TUNN_TYPE }; /* Ystorm Queue Zone */ -struct ystorm_eth_queue_zone { - struct coalescing_timeset int_coalescing_timeset; - __le16 reserved[3]; +struct xstorm_eth_queue_zone { + struct coalescing_timeset int_coalescing_timeset; + u8 reserved[7]; }; /* ETH doorbell data */ diff --git a/include/linux/qed/qed_eth_if.h b/include/linux/qed/qed_eth_if.h index 6ae8cb4a61d3..f8ff71126d9e 100644 --- a/include/linux/qed/qed_eth_if.h +++ b/include/linux/qed/qed_eth_if.h @@ -113,6 +113,7 @@ struct qed_queue_start_common_params { u8 vport_id; u16 sb; u16 sb_idx; + u16 vf_qid; }; struct qed_tunn_params { -- cgit v1.2.3 From 150593bf869393d10a79f6bd3df2585ecc20a9bb Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 18 May 2016 19:02:18 +0200 Subject: sched/api: Introduce task_rcu_dereference() and try_get_task_struct() Generally task_struct is only protected by RCU if it was found on a RCU protected list (say, for_each_process() or find_task_by_vpid()). As Kirill pointed out rq->curr isn't protected by RCU, the scheduler drops the (potentially) last reference without RCU gp, this means that we need to fix the code which uses foreign_rq->curr under rcu_read_lock(). Add a new helper which can be used to dereference rq->curr or any other pointer to task_struct assuming that it should be cleared or updated before the final put_task_struct(). It returns non-NULL only if this task can't go away before rcu_read_unlock(). ( Also add try_get_task_struct() to make it easier to use this API correctly. ) Suggested-by: Kirill Tkhai Signed-off-by: Oleg Nesterov [ Updated comments; added try_get_task_struct()] Signed-off-by: Peter Zijlstra (Intel) Cc: Chris Metcalf Cc: Christoph Lameter Cc: Kirill Tkhai Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vladimir Davydov Link: http://lkml.kernel.org/r/20160518170218.GY3192@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- include/linux/sched.h | 3 ++ kernel/exit.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 6e42ada26345..dee41bf59e6b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2139,6 +2139,9 @@ static inline void put_task_struct(struct task_struct *t) __put_task_struct(t); } +struct task_struct *task_rcu_dereference(struct task_struct **ptask); +struct task_struct *try_get_task_struct(struct task_struct **ptask); + #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN extern void task_cputime(struct task_struct *t, cputime_t *utime, cputime_t *stime); diff --git a/kernel/exit.c b/kernel/exit.c index 9e6e1356e6bb..2fb4d44c51b1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -210,6 +210,82 @@ repeat: goto repeat; } +/* + * Note that if this function returns a valid task_struct pointer (!NULL) + * task->usage must remain >0 for the duration of the RCU critical section. + */ +struct task_struct *task_rcu_dereference(struct task_struct **ptask) +{ + struct sighand_struct *sighand; + struct task_struct *task; + + /* + * We need to verify that release_task() was not called and thus + * delayed_put_task_struct() can't run and drop the last reference + * before rcu_read_unlock(). We check task->sighand != NULL, + * but we can read the already freed and reused memory. + */ +retry: + task = rcu_dereference(*ptask); + if (!task) + return NULL; + + probe_kernel_address(&task->sighand, sighand); + + /* + * Pairs with atomic_dec_and_test() in put_task_struct(). If this task + * was already freed we can not miss the preceding update of this + * pointer. + */ + smp_rmb(); + if (unlikely(task != READ_ONCE(*ptask))) + goto retry; + + /* + * We've re-checked that "task == *ptask", now we have two different + * cases: + * + * 1. This is actually the same task/task_struct. In this case + * sighand != NULL tells us it is still alive. + * + * 2. This is another task which got the same memory for task_struct. + * We can't know this of course, and we can not trust + * sighand != NULL. + * + * In this case we actually return a random value, but this is + * correct. + * + * If we return NULL - we can pretend that we actually noticed that + * *ptask was updated when the previous task has exited. Or pretend + * that probe_slab_address(&sighand) reads NULL. + * + * If we return the new task (because sighand is not NULL for any + * reason) - this is fine too. This (new) task can't go away before + * another gp pass. + * + * And note: We could even eliminate the false positive if re-read + * task->sighand once again to avoid the falsely NULL. But this case + * is very unlikely so we don't care. + */ + if (!sighand) + return NULL; + + return task; +} + +struct task_struct *try_get_task_struct(struct task_struct **ptask) +{ + struct task_struct *task; + + rcu_read_lock(); + task = task_rcu_dereference(ptask); + if (task) + get_task_struct(task); + rcu_read_unlock(); + + return task; +} + /* * Determine if a process group is "orphaned", according to the POSIX * definition in 2.2.2.52. Orphaned process groups are not to be affected -- cgit v1.2.3 From f2fb6bef92514432398a653df1c2f1041d79ac46 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Wed, 23 Mar 2016 11:24:37 -0700 Subject: perf/core: Optimize side-band event delivery The perf_event_aux() function iterates all PMUs and all events in their respective per-CPU contexts to find the events to deliver side-band records to. For example, the brk test case in lkp triggers many mmap() operations, which, if we're also running perf, results in many perf_event_aux() invocations. If we enable uncore PMU support (even when uncore events are not used), dozens of uncore PMUs will be iterated, which can significantly decrease brk_test's throughput. For example, the brk throughput: without uncore PMUs: 2647573 ops_per_sec with uncore PMUs: 1768444 ops_per_sec ... a 33% reduction. To get at the per-CPU events that need side-band records, this patch puts these events on a per-CPU list, this avoids iterating the PMUs and any events that do not need side-band records. Per task events are unchanged to avoid extra overhead on the context switch paths. Suggested-by: Peter Zijlstra (Intel) Reported-by: Huang, Ying Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1458757477-3781-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 6 ++++ kernel/events/core.c | 85 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 79 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 0e43355c7aad..92e9ce737432 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -517,6 +517,11 @@ struct swevent_hlist { struct perf_cgroup; struct ring_buffer; +struct pmu_event_list { + raw_spinlock_t lock; + struct list_head list; +}; + /** * struct perf_event - performance event kernel representation: */ @@ -675,6 +680,7 @@ struct perf_event { int cgrp_defer_enabled; #endif + struct list_head sb_list; #endif /* CONFIG_PERF_EVENTS */ }; diff --git a/kernel/events/core.c b/kernel/events/core.c index 79363f298445..6615c8922ee3 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -335,6 +335,7 @@ static atomic_t perf_sched_count; static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static DEFINE_PER_CPU(int, perf_sched_cb_usages); +static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events); static atomic_t nr_mmap_events __read_mostly; static atomic_t nr_comm_events __read_mostly; @@ -3665,6 +3666,26 @@ static void free_event_rcu(struct rcu_head *head) static void ring_buffer_attach(struct perf_event *event, struct ring_buffer *rb); +static void detach_sb_event(struct perf_event *event) +{ + struct pmu_event_list *pel = per_cpu_ptr(&pmu_sb_events, event->cpu); + + raw_spin_lock(&pel->lock); + list_del_rcu(&event->sb_list); + raw_spin_unlock(&pel->lock); +} + +static void unaccount_pmu_sb_event(struct perf_event *event) +{ + if (event->parent) + return; + + if (event->attach_state & PERF_ATTACH_TASK) + return; + + detach_sb_event(event); +} + static void unaccount_event_cpu(struct perf_event *event, int cpu) { if (event->parent) @@ -3728,6 +3749,8 @@ static void unaccount_event(struct perf_event *event) } unaccount_event_cpu(event, event->cpu); + + unaccount_pmu_sb_event(event); } static void perf_sched_delayed(struct work_struct *work) @@ -5888,13 +5911,25 @@ perf_event_aux_task_ctx(perf_event_aux_output_cb output, void *data, rcu_read_unlock(); } +static void perf_event_sb_iterate(perf_event_aux_output_cb output, void *data) +{ + struct pmu_event_list *pel = this_cpu_ptr(&pmu_sb_events); + struct perf_event *event; + + list_for_each_entry_rcu(event, &pel->list, sb_list) { + if (event->state < PERF_EVENT_STATE_INACTIVE) + continue; + if (!event_filter_match(event)) + continue; + output(event, data); + } +} + static void perf_event_aux(perf_event_aux_output_cb output, void *data, struct perf_event_context *task_ctx) { - struct perf_cpu_context *cpuctx; struct perf_event_context *ctx; - struct pmu *pmu; int ctxn; /* @@ -5909,20 +5944,15 @@ perf_event_aux(perf_event_aux_output_cb output, void *data, } rcu_read_lock(); - list_for_each_entry_rcu(pmu, &pmus, entry) { - cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); - if (cpuctx->unique_pmu != pmu) - goto next; - perf_event_aux_ctx(&cpuctx->ctx, output, data, false); - ctxn = pmu->task_ctx_nr; - if (ctxn < 0) - goto next; + preempt_disable(); + perf_event_sb_iterate(output, data); + + for_each_task_context_nr(ctxn) { ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); if (ctx) perf_event_aux_ctx(ctx, output, data, false); -next: - put_cpu_ptr(pmu->pmu_cpu_context); } + preempt_enable(); rcu_read_unlock(); } @@ -8615,6 +8645,32 @@ unlock: return pmu; } +static void attach_sb_event(struct perf_event *event) +{ + struct pmu_event_list *pel = per_cpu_ptr(&pmu_sb_events, event->cpu); + + raw_spin_lock(&pel->lock); + list_add_rcu(&event->sb_list, &pel->list); + raw_spin_unlock(&pel->lock); +} + +static void account_pmu_sb_event(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + + if (event->parent) + return; + + if (event->attach_state & PERF_ATTACH_TASK) + return; + + if (attr->mmap || attr->mmap_data || attr->mmap2 || + attr->comm || attr->comm_exec || + attr->task || + attr->context_switch) + attach_sb_event(event); +} + static void account_event_cpu(struct perf_event *event, int cpu) { if (event->parent) @@ -8695,6 +8751,8 @@ static void account_event(struct perf_event *event) enabled: account_event_cpu(event, event->cpu); + + account_pmu_sb_event(event); } /* @@ -10203,6 +10261,9 @@ static void __init perf_event_init_all_cpus(void) swhash = &per_cpu(swevent_htable, cpu); mutex_init(&swhash->hlist_mutex); INIT_LIST_HEAD(&per_cpu(active_ctx_list, cpu)); + + INIT_LIST_HEAD(&per_cpu(pmu_sb_events.list, cpu)); + raw_spin_lock_init(&per_cpu(pmu_sb_events.lock, cpu)); } } -- cgit v1.2.3 From fc07e9f983b4b11922c22b6cccadc1f342f05a4c Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 19 May 2016 17:09:56 -0700 Subject: perf/x86: Support sysfs files depending on SMT status Add a way to show different sysfs events attributes depending on HyperThreading is on or off. This is difficult to determine early at boot, so we just do it dynamically when the sysfs attribute is read. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1463703002-19686-3-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar --- arch/x86/events/core.c | 23 +++++++++++++++++++++++ arch/x86/events/perf_event.h | 10 ++++++++++ include/linux/perf_event.h | 7 +++++++ 3 files changed, 40 insertions(+) (limited to 'include/linux') diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 33787ee817f0..929655db5084 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1622,6 +1622,29 @@ ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, cha } EXPORT_SYMBOL_GPL(events_sysfs_show); +ssize_t events_ht_sysfs_show(struct device *dev, struct device_attribute *attr, + char *page) +{ + struct perf_pmu_events_ht_attr *pmu_attr = + container_of(attr, struct perf_pmu_events_ht_attr, attr); + + /* + * Report conditional events depending on Hyper-Threading. + * + * This is overly conservative as usually the HT special + * handling is not needed if the other CPU thread is idle. + * + * Note this does not (and cannot) handle the case when thread + * siblings are invisible, for example with virtualization + * if they are owned by some other guest. The user tool + * has to re-read when a thread sibling gets onlined later. + */ + return sprintf(page, "%s", + topology_max_smt_threads() > 1 ? + pmu_attr->event_str_ht : + pmu_attr->event_str_noht); +} + EVENT_ATTR(cpu-cycles, CPU_CYCLES ); EVENT_ATTR(instructions, INSTRUCTIONS ); EVENT_ATTR(cache-references, CACHE_REFERENCES ); diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 8bd764df815d..e2d7285a2dac 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -668,6 +668,14 @@ static struct perf_pmu_events_attr event_attr_##v = { \ .event_str = str, \ }; +#define EVENT_ATTR_STR_HT(_name, v, noht, ht) \ +static struct perf_pmu_events_ht_attr event_attr_##v = { \ + .attr = __ATTR(_name, 0444, events_ht_sysfs_show, NULL),\ + .id = 0, \ + .event_str_noht = noht, \ + .event_str_ht = ht, \ +} + extern struct x86_pmu x86_pmu __read_mostly; static inline bool x86_pmu_has_lbr_callstack(void) @@ -803,6 +811,8 @@ struct attribute **merge_attr(struct attribute **a, struct attribute **b); ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr, char *page); +ssize_t events_ht_sysfs_show(struct device *dev, struct device_attribute *attr, + char *page); #ifdef CONFIG_CPU_SUP_AMD diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 92e9ce737432..a7593d653b40 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1334,6 +1334,13 @@ struct perf_pmu_events_attr { const char *event_str; }; +struct perf_pmu_events_ht_attr { + struct device_attribute attr; + u64 id; + const char *event_str_ht; + const char *event_str_noht; +}; + ssize_t perf_event_sysfs_show(struct device *dev, struct device_attribute *attr, char *page); -- cgit v1.2.3 From 59ce4039727ef408769ab0e1263ece893abe22bb Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 24 May 2016 15:31:24 +0200 Subject: of: reserved_mem: add support for using more than one region for given device This patch allows device drivers to initialize more than one reserved memory region assigned to given device. When driver needs to use more than one reserved memory region, it should allocate child devices and initialize regions by index for each of its child devices. Signed-off-by: Marek Szyprowski Acked-by: Rob Herring Signed-off-by: Sylwester Nawrocki --- drivers/of/of_reserved_mem.c | 85 +++++++++++++++++++++++++++++++---------- include/linux/of_reserved_mem.h | 25 ++++++++++-- 2 files changed, 86 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index ed01c0172e4a..04e4fe58fb0c 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MAX_RESERVED_REGIONS 16 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; @@ -289,53 +290,95 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) return NULL; } +struct rmem_assigned_device { + struct device *dev; + struct reserved_mem *rmem; + struct list_head list; +}; + +static LIST_HEAD(of_rmem_assigned_device_list); +static DEFINE_MUTEX(of_rmem_assigned_device_mutex); + /** - * of_reserved_mem_device_init() - assign reserved memory region to given device + * of_reserved_mem_device_init_by_idx() - assign reserved memory region to + * given device + * @dev: Pointer to the device to configure + * @np: Pointer to the device_node with 'reserved-memory' property + * @idx: Index of selected region * - * This function assign memory region pointed by "memory-region" device tree - * property to the given device. + * This function assigns respective DMA-mapping operations based on reserved + * memory region specified by 'memory-region' property in @np node to the @dev + * device. When driver needs to use more than one reserved memory region, it + * should allocate child devices and initialize regions by name for each of + * child device. + * + * Returns error code or zero on success. */ -int of_reserved_mem_device_init(struct device *dev) +int of_reserved_mem_device_init_by_idx(struct device *dev, + struct device_node *np, int idx) { + struct rmem_assigned_device *rd; + struct device_node *target; struct reserved_mem *rmem; - struct device_node *np; int ret; - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return -ENODEV; + if (!np || !dev) + return -EINVAL; + + target = of_parse_phandle(np, "memory-region", idx); + if (!target) + return -EINVAL; - rmem = __find_rmem(np); - of_node_put(np); + rmem = __find_rmem(target); + of_node_put(target); if (!rmem || !rmem->ops || !rmem->ops->device_init) return -EINVAL; + rd = kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL); + if (!rd) + return -ENOMEM; + ret = rmem->ops->device_init(rmem, dev); - if (ret == 0) + if (ret == 0) { + rd->dev = dev; + rd->rmem = rmem; + + mutex_lock(&of_rmem_assigned_device_mutex); + list_add(&rd->list, &of_rmem_assigned_device_list); + mutex_unlock(&of_rmem_assigned_device_mutex); + dev_info(dev, "assigned reserved memory node %s\n", rmem->name); + } else { + kfree(rd); + } return ret; } -EXPORT_SYMBOL_GPL(of_reserved_mem_device_init); +EXPORT_SYMBOL_GPL(of_reserved_mem_device_init_by_idx); /** * of_reserved_mem_device_release() - release reserved memory device structures + * @dev: Pointer to the device to deconfigure * * This function releases structures allocated for memory region handling for * the given device. */ void of_reserved_mem_device_release(struct device *dev) { - struct reserved_mem *rmem; - struct device_node *np; - - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return; - - rmem = __find_rmem(np); - of_node_put(np); + struct rmem_assigned_device *rd; + struct reserved_mem *rmem = NULL; + + mutex_lock(&of_rmem_assigned_device_mutex); + list_for_each_entry(rd, &of_rmem_assigned_device_list, list) { + if (rd->dev == dev) { + rmem = rd->rmem; + list_del(&rd->list); + kfree(rd); + break; + } + } + mutex_unlock(&of_rmem_assigned_device_mutex); if (!rmem || !rmem->ops || !rmem->ops->device_release) return; diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index ad2f67054372..1779cda99ef7 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -1,7 +1,8 @@ #ifndef __OF_RESERVED_MEM_H #define __OF_RESERVED_MEM_H -struct device; +#include + struct of_phandle_args; struct reserved_mem_ops; @@ -28,14 +29,17 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem); _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn) #ifdef CONFIG_OF_RESERVED_MEM -int of_reserved_mem_device_init(struct device *dev); + +int of_reserved_mem_device_init_by_idx(struct device *dev, + struct device_node *np, int idx); void of_reserved_mem_device_release(struct device *dev); void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); #else -static inline int of_reserved_mem_device_init(struct device *dev) +static inline int of_reserved_mem_device_init_by_idx(struct device *dev, + struct device_node *np, int idx) { return -ENOSYS; } @@ -46,4 +50,19 @@ static inline void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size) { } #endif +/** + * of_reserved_mem_device_init() - assign reserved memory region to given device + * @dev: Pointer to the device to configure + * + * This function assigns respective DMA-mapping operations based on the first + * reserved memory region specified by 'memory-region' property in device tree + * node of the given device. + * + * Returns error code or zero on success. + */ +static inline int of_reserved_mem_device_init(struct device *dev) +{ + return of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0); +} + #endif /* __OF_RESERVED_MEM_H */ -- cgit v1.2.3 From ed8ebd1d514126c0e54fbdbd231427dc91c877c2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 25 May 2016 16:11:57 -0400 Subject: percpu, locking: Revert ("percpu: Replace smp_read_barrier_depends() with lockless_dereference()") lockless_dereference() is planned to grow a sanity check to ensure that the input parameter is a pointer. __ref_is_percpu() passes in an unsinged long value which is a combination of a pointer and a flag. While it can be casted to a pointer lvalue, the casting looks messy and it's a special case anyway. Let's revert back to open-coding READ_ONCE() and explicit barrier. This doesn't cause any functional changes. Signed-off-by: Tejun Heo Signed-off-by: Peter Zijlstra (Intel) Cc: Alexey Dobriyan Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Paul McKenney Cc: Peter Zijlstra Cc: Pranith Kumar Cc: Thomas Gleixner Cc: kernel-team@fb.com Link: http://lkml.kernel.org/g/20160522185040.GA23664@p183.telecom.by Signed-off-by: Ingo Molnar --- include/linux/percpu-refcount.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h index 84f542df7ff5..1c7eec09e5eb 100644 --- a/include/linux/percpu-refcount.h +++ b/include/linux/percpu-refcount.h @@ -136,14 +136,12 @@ static inline bool __ref_is_percpu(struct percpu_ref *ref, * used as a pointer. If the compiler generates a separate fetch * when using it as a pointer, __PERCPU_REF_ATOMIC may be set in * between contaminating the pointer value, meaning that - * ACCESS_ONCE() is required when fetching it. - * - * Also, we need a data dependency barrier to be paired with - * smp_store_release() in __percpu_ref_switch_to_percpu(). - * - * Use lockless deref which contains both. + * READ_ONCE() is required when fetching it. */ - percpu_ptr = lockless_dereference(ref->percpu_count_ptr); + percpu_ptr = READ_ONCE(ref->percpu_count_ptr); + + /* paired with smp_store_release() in __percpu_ref_switch_to_percpu() */ + smp_read_barrier_depends(); /* * Theoretically, the following could test just ATOMIC; however, -- cgit v1.2.3 From 5ab788d7383289bfc141ab357767bc6c11bbf77f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 30 May 2016 20:57:50 +0200 Subject: rtc: cmos: move mc146818rtc code out of asm-generic/rtc.h Drivers should not really include stuff from asm-generic directly, and the PC-style cmos rtc driver does this in order to reuse the mc146818 implementation of get_rtc_time/set_rtc_time rather than the architecture specific one for the architecture it gets built for. To make it more obvious what is going on, this moves and renames the two functions into include/linux/mc146818rtc.h, which holds the other mc146818 specific code. Ideally it would be in a .c file, but that would require extra infrastructure as the functions are called by multiple drivers with conflicting dependencies. With this change, the asm-generic/rtc.h header also becomes much more generic, so it can be reused more easily across any architecture that still relies on the genrtc driver. The only caller of the internal __get_rtc_time/__set_rtc_time functions is in arch/alpha/kernel/rtc.c, and we just change those over to the new naming. Signed-off-by: Arnd Bergmann Acked-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni --- arch/alpha/kernel/rtc.c | 6 +- arch/x86/include/asm/mc146818rtc.h | 1 - arch/x86/platform/efi/efi_64.c | 1 + arch/x86/platform/intel-mid/intel_mid_vrtc.c | 1 + drivers/rtc/rtc-cmos.c | 12 +- include/asm-generic/rtc.h | 206 +-------------------------- include/linux/mc146818rtc.h | 194 +++++++++++++++++++++++++ 7 files changed, 209 insertions(+), 212 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/rtc.c b/arch/alpha/kernel/rtc.c index f535a3fd0f60..ceed68c7500b 100644 --- a/arch/alpha/kernel/rtc.c +++ b/arch/alpha/kernel/rtc.c @@ -15,8 +15,6 @@ #include #include -#include - #include "proto.h" @@ -81,7 +79,7 @@ init_rtc_epoch(void) static int alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) { - __get_rtc_time(tm); + mc146818_get_time(tm); /* Adjust for non-default epochs. It's easier to depend on the generic __get_rtc_time and adjust the epoch here than create @@ -112,7 +110,7 @@ alpha_rtc_set_time(struct device *dev, struct rtc_time *tm) tm = &xtm; } - return __set_rtc_time(tm); + return mc146818_set_time(tm); } static int diff --git a/arch/x86/include/asm/mc146818rtc.h b/arch/x86/include/asm/mc146818rtc.h index 0f555cc31984..24acd9ba7837 100644 --- a/arch/x86/include/asm/mc146818rtc.h +++ b/arch/x86/include/asm/mc146818rtc.h @@ -6,7 +6,6 @@ #include #include -#include #ifndef RTC_PORT #define RTC_PORT(x) (0x70 + (x)) diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 6e7242be1c87..663c282801f3 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/platform/intel-mid/intel_mid_vrtc.c b/arch/x86/platform/intel-mid/intel_mid_vrtc.c index ee40fcb6e54d..58024862a7eb 100644 --- a/arch/x86/platform/intel-mid/intel_mid_vrtc.c +++ b/arch/x86/platform/intel-mid/intel_mid_vrtc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index fbe9c72438e1..cf8eb98382ce 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -43,7 +43,7 @@ #include /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ -#include +#include struct cmos_rtc { struct rtc_device *rtc; @@ -190,10 +190,10 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr) static int cmos_read_time(struct device *dev, struct rtc_time *t) { /* REVISIT: if the clock has a "century" register, use - * that instead of the heuristic in get_rtc_time(). + * that instead of the heuristic in mc146818_get_time(). * That'll make Y3K compatility (year > 2070) easy! */ - get_rtc_time(t); + mc146818_get_time(t); return 0; } @@ -205,7 +205,7 @@ static int cmos_set_time(struct device *dev, struct rtc_time *t) * takes effect exactly 500ms after we write the register. * (Also queueing and other delays before we get this far.) */ - return set_rtc_time(t); + return mc146818_set_time(t); } static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t) @@ -1142,14 +1142,14 @@ static __init void cmos_of_init(struct platform_device *pdev) if (val) CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT); - get_rtc_time(&time); + cmos_read_time(&pdev->dev, &time); ret = rtc_valid_tm(&time); if (ret) { struct rtc_time def_time = { .tm_year = 1, .tm_mday = 1, }; - set_rtc_time(&def_time); + cmos_set_time(&pdev->dev, &def_time); } } #else diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h index 4e3b6558331e..4fcff22cd707 100644 --- a/include/asm-generic/rtc.h +++ b/include/asm-generic/rtc.h @@ -12,12 +12,12 @@ #ifndef __ASM_RTC_H__ #define __ASM_RTC_H__ -#include #include -#include -#include -#ifdef CONFIG_ACPI -#include + +#ifndef get_rtc_time +#include +#define get_rtc_time mc146818_get_time +#define set_rtc_time mc146818_set_time #endif #define RTC_PIE 0x40 /* periodic interrupt enable */ @@ -31,202 +31,6 @@ #define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ #define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ -/* - * Returns true if a clock update is in progress - */ -static inline unsigned char rtc_is_updating(void) -{ - unsigned char uip; - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); - uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - spin_unlock_irqrestore(&rtc_lock, flags); - return uip; -} - -static inline unsigned int __get_rtc_time(struct rtc_time *time) -{ - unsigned char ctrl; - unsigned long flags; - unsigned char century = 0; - -#ifdef CONFIG_MACH_DECSTATION - unsigned int real_year; -#endif - - /* - * read RTC once any update in progress is done. The update - * can take just over 2ms. We wait 20ms. There is no need to - * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. - * If you need to know *exactly* when a second has started, enable - * periodic update complete interrupts, (via ioctl) and then - * immediately read /dev/rtc which will block until you get the IRQ. - * Once the read clears, read the RTC time (again via ioctl). Easy. - */ - if (rtc_is_updating()) - mdelay(20); - - /* - * Only the values that we read from the RTC are set. We leave - * tm_wday, tm_yday and tm_isdst untouched. Even though the - * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated - * by the RTC when initially set to a non-zero value. - */ - spin_lock_irqsave(&rtc_lock, flags); - time->tm_sec = CMOS_READ(RTC_SECONDS); - time->tm_min = CMOS_READ(RTC_MINUTES); - time->tm_hour = CMOS_READ(RTC_HOURS); - time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); - time->tm_mon = CMOS_READ(RTC_MONTH); - time->tm_year = CMOS_READ(RTC_YEAR); -#ifdef CONFIG_MACH_DECSTATION - real_year = CMOS_READ(RTC_DEC_YEAR); -#endif -#ifdef CONFIG_ACPI - if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && - acpi_gbl_FADT.century) - century = CMOS_READ(acpi_gbl_FADT.century); -#endif - ctrl = CMOS_READ(RTC_CONTROL); - spin_unlock_irqrestore(&rtc_lock, flags); - - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { - time->tm_sec = bcd2bin(time->tm_sec); - time->tm_min = bcd2bin(time->tm_min); - time->tm_hour = bcd2bin(time->tm_hour); - time->tm_mday = bcd2bin(time->tm_mday); - time->tm_mon = bcd2bin(time->tm_mon); - time->tm_year = bcd2bin(time->tm_year); - century = bcd2bin(century); - } - -#ifdef CONFIG_MACH_DECSTATION - time->tm_year += real_year - 72; -#endif - - if (century) - time->tm_year += (century - 19) * 100; - - /* - * Account for differences between how the RTC uses the values - * and how they are defined in a struct rtc_time; - */ - if (time->tm_year <= 69) - time->tm_year += 100; - - time->tm_mon--; - - return RTC_24H; -} - -#ifndef get_rtc_time -#define get_rtc_time __get_rtc_time -#endif - -/* Set the current date and time in the real time clock. */ -static inline int __set_rtc_time(struct rtc_time *time) -{ - unsigned long flags; - unsigned char mon, day, hrs, min, sec; - unsigned char save_control, save_freq_select; - unsigned int yrs; -#ifdef CONFIG_MACH_DECSTATION - unsigned int real_yrs, leap_yr; -#endif - unsigned char century = 0; - - yrs = time->tm_year; - mon = time->tm_mon + 1; /* tm_mon starts at zero */ - day = time->tm_mday; - hrs = time->tm_hour; - min = time->tm_min; - sec = time->tm_sec; - - if (yrs > 255) /* They are unsigned */ - return -EINVAL; - - spin_lock_irqsave(&rtc_lock, flags); -#ifdef CONFIG_MACH_DECSTATION - real_yrs = yrs; - leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || - !((yrs + 1900) % 400)); - yrs = 72; - - /* - * We want to keep the year set to 73 until March - * for non-leap years, so that Feb, 29th is handled - * correctly. - */ - if (!leap_yr && mon < 3) { - real_yrs--; - yrs = 73; - } -#endif - -#ifdef CONFIG_ACPI - if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && - acpi_gbl_FADT.century) { - century = (yrs + 1900) / 100; - yrs %= 100; - } -#endif - - /* These limits and adjustments are independent of - * whether the chip is in binary mode or not. - */ - if (yrs > 169) { - spin_unlock_irqrestore(&rtc_lock, flags); - return -EINVAL; - } - - if (yrs >= 100) - yrs -= 100; - - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) { - sec = bin2bcd(sec); - min = bin2bcd(min); - hrs = bin2bcd(hrs); - day = bin2bcd(day); - mon = bin2bcd(mon); - yrs = bin2bcd(yrs); - century = bin2bcd(century); - } - - save_control = CMOS_READ(RTC_CONTROL); - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - -#ifdef CONFIG_MACH_DECSTATION - CMOS_WRITE(real_yrs, RTC_DEC_YEAR); -#endif - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DAY_OF_MONTH); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); -#ifdef CONFIG_ACPI - if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && - acpi_gbl_FADT.century) - CMOS_WRITE(century, acpi_gbl_FADT.century); -#endif - - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - spin_unlock_irqrestore(&rtc_lock, flags); - - return 0; -} - -#ifndef set_rtc_time -#define set_rtc_time __set_rtc_time -#endif - static inline unsigned int get_rtc_ss(void) { struct rtc_time h; diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h index 433e0c74d643..e9e346b37846 100644 --- a/include/linux/mc146818rtc.h +++ b/include/linux/mc146818rtc.h @@ -14,6 +14,12 @@ #include #include /* get the user-level API */ #include /* register access macros */ +#include +#include + +#ifdef CONFIG_ACPI +#include +#endif #ifdef __KERNEL__ #include /* spinlock_t */ @@ -120,4 +126,192 @@ struct cmos_rtc_board_info { #define RTC_IO_EXTENT_USED RTC_IO_EXTENT #endif /* ARCH_RTC_LOCATION */ +/* + * Returns true if a clock update is in progress + */ +static inline unsigned char mc146818_is_updating(void) +{ + unsigned char uip; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + spin_unlock_irqrestore(&rtc_lock, flags); + return uip; +} + +static inline unsigned int mc146818_get_time(struct rtc_time *time) +{ + unsigned char ctrl; + unsigned long flags; + unsigned char century = 0; + +#ifdef CONFIG_MACH_DECSTATION + unsigned int real_year; +#endif + + /* + * read RTC once any update in progress is done. The update + * can take just over 2ms. We wait 20ms. There is no need to + * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. + * If you need to know *exactly* when a second has started, enable + * periodic update complete interrupts, (via ioctl) and then + * immediately read /dev/rtc which will block until you get the IRQ. + * Once the read clears, read the RTC time (again via ioctl). Easy. + */ + if (mc146818_is_updating()) + mdelay(20); + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + spin_lock_irqsave(&rtc_lock, flags); + time->tm_sec = CMOS_READ(RTC_SECONDS); + time->tm_min = CMOS_READ(RTC_MINUTES); + time->tm_hour = CMOS_READ(RTC_HOURS); + time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); + time->tm_mon = CMOS_READ(RTC_MONTH); + time->tm_year = CMOS_READ(RTC_YEAR); +#ifdef CONFIG_MACH_DECSTATION + real_year = CMOS_READ(RTC_DEC_YEAR); +#endif +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century = CMOS_READ(acpi_gbl_FADT.century); +#endif + ctrl = CMOS_READ(RTC_CONTROL); + spin_unlock_irqrestore(&rtc_lock, flags); + + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + time->tm_sec = bcd2bin(time->tm_sec); + time->tm_min = bcd2bin(time->tm_min); + time->tm_hour = bcd2bin(time->tm_hour); + time->tm_mday = bcd2bin(time->tm_mday); + time->tm_mon = bcd2bin(time->tm_mon); + time->tm_year = bcd2bin(time->tm_year); + century = bcd2bin(century); + } + +#ifdef CONFIG_MACH_DECSTATION + time->tm_year += real_year - 72; +#endif + + if (century) + time->tm_year += (century - 19) * 100; + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if (time->tm_year <= 69) + time->tm_year += 100; + + time->tm_mon--; + + return RTC_24H; +} + +/* Set the current date and time in the real time clock. */ +static inline int mc146818_set_time(struct rtc_time *time) +{ + unsigned long flags; + unsigned char mon, day, hrs, min, sec; + unsigned char save_control, save_freq_select; + unsigned int yrs; +#ifdef CONFIG_MACH_DECSTATION + unsigned int real_yrs, leap_yr; +#endif + unsigned char century = 0; + + yrs = time->tm_year; + mon = time->tm_mon + 1; /* tm_mon starts at zero */ + day = time->tm_mday; + hrs = time->tm_hour; + min = time->tm_min; + sec = time->tm_sec; + + if (yrs > 255) /* They are unsigned */ + return -EINVAL; + + spin_lock_irqsave(&rtc_lock, flags); +#ifdef CONFIG_MACH_DECSTATION + real_yrs = yrs; + leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || + !((yrs + 1900) % 400)); + yrs = 72; + + /* + * We want to keep the year set to 73 until March + * for non-leap years, so that Feb, 29th is handled + * correctly. + */ + if (!leap_yr && mon < 3) { + real_yrs--; + yrs = 73; + } +#endif + +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) { + century = (yrs + 1900) / 100; + yrs %= 100; + } +#endif + + /* These limits and adjustments are independent of + * whether the chip is in binary mode or not. + */ + if (yrs > 169) { + spin_unlock_irqrestore(&rtc_lock, flags); + return -EINVAL; + } + + if (yrs >= 100) + yrs -= 100; + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) + || RTC_ALWAYS_BCD) { + sec = bin2bcd(sec); + min = bin2bcd(min); + hrs = bin2bcd(hrs); + day = bin2bcd(day); + mon = bin2bcd(mon); + yrs = bin2bcd(yrs); + century = bin2bcd(century); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + +#ifdef CONFIG_MACH_DECSTATION + CMOS_WRITE(real_yrs, RTC_DEC_YEAR); +#endif + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + CMOS_WRITE(century, acpi_gbl_FADT.century); +#endif + + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + spin_unlock_irqrestore(&rtc_lock, flags); + + return 0; +} + #endif /* _MC146818RTC_H */ -- cgit v1.2.3 From 3953c46c3ac7eef31a9935427371c6f54a22f1ba Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Thu, 2 Jun 2016 15:05:40 -0300 Subject: sk_buff: allow segmenting based on frag sizes This patch allows segmenting a skb based on its frags sizes instead of based on a fixed value. Signed-off-by: Marcelo Ricardo Leitner Tested-by: Xin Long Signed-off-by: David S. Miller --- include/linux/skbuff.h | 5 +++++ net/core/skbuff.c | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ee38a4127475..329a0a9ef671 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -301,6 +301,11 @@ struct sk_buff; #endif extern int sysctl_max_skb_frags; +/* Set skb_shinfo(skb)->gso_size to this in case you want skb_segment to + * segment using its current segmentation instead. + */ +#define GSO_BY_FRAGS 0xFFFF + typedef struct skb_frag_struct skb_frag_t; struct skb_frag_struct { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4724bcf9b0ca..97c32c75e704 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3116,9 +3116,13 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, int hsize; int size; - len = head_skb->len - offset; - if (len > mss) - len = mss; + if (unlikely(mss == GSO_BY_FRAGS)) { + len = list_skb->len; + } else { + len = head_skb->len - offset; + if (len > mss) + len = mss; + } hsize = skb_headlen(head_skb) - offset; if (hsize < 0) -- cgit v1.2.3 From ae7ef81ef000adeee7a87585b9135ff8a8064acc Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Thu, 2 Jun 2016 15:05:41 -0300 Subject: skbuff: introduce skb_gso_validate_mtu skb_gso_network_seglen is not enough for checking fragment sizes if skb is using GSO_BY_FRAGS as we have to check frag per frag. This patch introduces skb_gso_validate_mtu, based on the former, which will wrap the use case inside it as all calls to skb_gso_network_seglen were to validate if it fits on a given TMU, and improve the check. Signed-off-by: Marcelo Ricardo Leitner Tested-by: Xin Long Signed-off-by: David S. Miller --- include/linux/skbuff.h | 1 + net/core/skbuff.c | 31 +++++++++++++++++++++++++++++++ net/ipv4/ip_forward.c | 2 +- net/ipv4/ip_output.c | 2 +- net/ipv6/ip6_output.c | 2 +- net/mpls/af_mpls.c | 2 +- 6 files changed, 36 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 329a0a9ef671..aa3f9d7e8d5c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2992,6 +2992,7 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); void skb_scrub_packet(struct sk_buff *skb, bool xnet); unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); +bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu); struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); struct sk_buff *skb_vlan_untag(struct sk_buff *skb); int skb_ensure_writable(struct sk_buff *skb, int write_len); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 97c32c75e704..5ca562b56ec3 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4392,6 +4392,37 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) } EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); +/** + * skb_gso_validate_mtu - Return in case such skb fits a given MTU + * + * @skb: GSO skb + * + * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU + * once split. + */ +bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) +{ + const struct skb_shared_info *shinfo = skb_shinfo(skb); + const struct sk_buff *iter; + unsigned int hlen; + + hlen = skb_gso_network_seglen(skb); + + if (shinfo->gso_size != GSO_BY_FRAGS) + return hlen <= mtu; + + /* Undo this so we can re-use header sizes */ + hlen -= GSO_BY_FRAGS; + + skb_walk_frags(skb, iter) { + if (hlen + skb_headlen(iter) > mtu) + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); + static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) { if (skb_cow(skb, skb_headroom(skb)) < 0) { diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index cbfb1808fcc4..9f0a7b96646f 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -54,7 +54,7 @@ static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) if (skb->ignore_df) return false; - if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) + if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) return false; return true; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 124bf0a66328..cbac493c913a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -225,7 +225,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk, /* common case: locally created skb or seglen is <= mtu */ if (((IPCB(skb)->flags & IPSKB_FORWARDED) == 0) || - skb_gso_network_seglen(skb) <= mtu) + skb_gso_validate_mtu(skb, mtu)) return ip_finish_output2(net, sk, skb); /* Slowpath - GSO segment length is exceeding the dst MTU. diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index cbf127ae7c67..6b2f60a5c1de 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -368,7 +368,7 @@ static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) if (skb->ignore_df) return false; - if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) + if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) return false; return true; diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 0b80a7140cc4..7a4aa3450dd7 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -91,7 +91,7 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) if (skb->len <= mtu) return false; - if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) + if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) return false; return true; -- cgit v1.2.3 From 90017accff61ae89283ad9a51f9ac46ca01633fb Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Thu, 2 Jun 2016 15:05:43 -0300 Subject: sctp: Add GSO support SCTP has this pecualiarity that its packets cannot be just segmented to (P)MTU. Its chunks must be contained in IP segments, padding respected. So we can't just generate a big skb, set gso_size to the fragmentation point and deliver it to IP layer. This patch takes a different approach. SCTP will now build a skb as it would be if it was received using GRO. That is, there will be a cover skb with protocol headers and children ones containing the actual segments, already segmented to a way that respects SCTP RFCs. With that, we can tell skb_segment() to just split based on frag_list, trusting its sizes are already in accordance. This way SCTP can benefit from GSO and instead of passing several packets through the stack, it can pass a single large packet. v2: - Added support for receiving GSO frames, as requested by Dave Miller. - Clear skb->cb if packet is GSO (otherwise it's not used by SCTP) - Added heuristics similar to what we have in TCP for not generating single GSO packets that fills cwnd. v3: - consider sctphdr size in skb_gso_transport_seglen() - rebased due to 5c7cdf339af5 ("gso: Remove arbitrary checks for unsupported GSO") Signed-off-by: Marcelo Ricardo Leitner Tested-by: Xin Long Signed-off-by: David S. Miller --- include/linux/netdev_features.h | 7 +- include/linux/netdevice.h | 1 + include/linux/skbuff.h | 2 + include/net/sctp/sctp.h | 4 + include/net/sctp/structs.h | 5 + net/core/ethtool.c | 1 + net/core/skbuff.c | 3 + net/sctp/Makefile | 3 +- net/sctp/input.c | 12 +- net/sctp/inqueue.c | 51 +++++- net/sctp/offload.c | 98 +++++++++++ net/sctp/output.c | 363 +++++++++++++++++++++++++++------------- net/sctp/protocol.c | 3 + net/sctp/socket.c | 2 + 14 files changed, 429 insertions(+), 126 deletions(-) create mode 100644 net/sctp/offload.c (limited to 'include/linux') diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index aa7b2400f98c..9c6c8ef2e9e7 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -53,8 +53,9 @@ enum { * headers in software. */ NETIF_F_GSO_TUNNEL_REMCSUM_BIT, /* ... TUNNEL with TSO & REMCSUM */ + NETIF_F_GSO_SCTP_BIT, /* ... SCTP fragmentation */ /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ - NETIF_F_GSO_TUNNEL_REMCSUM_BIT, + NETIF_F_GSO_SCTP_BIT, NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ NETIF_F_SCTP_CRC_BIT, /* SCTP checksum offload */ @@ -128,6 +129,7 @@ enum { #define NETIF_F_TSO_MANGLEID __NETIF_F(TSO_MANGLEID) #define NETIF_F_GSO_PARTIAL __NETIF_F(GSO_PARTIAL) #define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM) +#define NETIF_F_GSO_SCTP __NETIF_F(GSO_SCTP) #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) #define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) @@ -166,7 +168,8 @@ enum { NETIF_F_FSO) /* List of features with software fallbacks. */ -#define NETIF_F_GSO_SOFTWARE (NETIF_F_ALL_TSO | NETIF_F_UFO) +#define NETIF_F_GSO_SOFTWARE (NETIF_F_ALL_TSO | NETIF_F_UFO | \ + NETIF_F_GSO_SCTP) /* * If one device supports one of these features, then enable them diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f45929ce8157..fa6df2699532 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4012,6 +4012,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type) BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_PARTIAL != (NETIF_F_GSO_PARTIAL >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_SCTP != (NETIF_F_GSO_SCTP >> NETIF_F_GSO_SHIFT)); return (features & feature) == feature; } diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index aa3f9d7e8d5c..dc0fca747c5e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -487,6 +487,8 @@ enum { SKB_GSO_PARTIAL = 1 << 13, SKB_GSO_TUNNEL_REMCSUM = 1 << 14, + + SKB_GSO_SCTP = 1 << 15, }; #if BITS_PER_LONG > 32 diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index b392ac8382f2..632e205ca54b 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -186,6 +186,10 @@ void sctp_assocs_proc_exit(struct net *net); int sctp_remaddr_proc_init(struct net *net); void sctp_remaddr_proc_exit(struct net *net); +/* + * sctp/offload.c + */ +int sctp_offload_init(void); /* * Module global variables diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 16b013a6191c..83c5ec58b93a 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -566,6 +566,9 @@ struct sctp_chunk { /* This points to the sk_buff containing the actual data. */ struct sk_buff *skb; + /* In case of GSO packets, this will store the head one */ + struct sk_buff *head_skb; + /* These are the SCTP headers by reverse order in a packet. * Note that some of these may happen more than once. In that * case, we point at the "current" one, whatever that means @@ -696,6 +699,8 @@ struct sctp_packet { size_t overhead; /* This is the total size of all chunks INCLUDING padding. */ size_t size; + /* This is the maximum size this packet may have */ + size_t max_size; /* The packet is destined for this transport address. * The function we finally use to pass down to the next lower diff --git a/net/core/ethtool.c b/net/core/ethtool.c index f4034817d255..977489820eb9 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -89,6 +89,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", [NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation", [NETIF_F_GSO_PARTIAL_BIT] = "tx-gso-partial", + [NETIF_F_GSO_SCTP_BIT] = "tx-sctp-segmentation", [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc", [NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp", diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 5ca562b56ec3..b6e0f95bef36 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #ifdef CONFIG_NET_CLS_ACT #include @@ -4383,6 +4384,8 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) thlen += inner_tcp_hdrlen(skb); } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { thlen = tcp_hdrlen(skb); + } else if (unlikely(shinfo->gso_type & SKB_GSO_SCTP)) { + thlen = sizeof(struct sctphdr); } /* UFO sets gso_size to the size of the fragmentation * payload, i.e. the size of the L4 (UDP) header is already diff --git a/net/sctp/Makefile b/net/sctp/Makefile index 0fca5824ad0e..6c4f7496cec6 100644 --- a/net/sctp/Makefile +++ b/net/sctp/Makefile @@ -11,7 +11,8 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ transport.o chunk.o sm_make_chunk.o ulpevent.o \ inqueue.o outqueue.o ulpqueue.o \ tsnmap.o bind_addr.o socket.o primitive.o \ - output.o input.o debug.o ssnmap.o auth.o + output.o input.o debug.o ssnmap.o auth.o \ + offload.o sctp_probe-y := probe.o diff --git a/net/sctp/input.c b/net/sctp/input.c index 5cff2546c3dd..6f8e676d285e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -139,7 +139,9 @@ int sctp_rcv(struct sk_buff *skb) skb->csum_valid = 0; /* Previous value not applicable */ if (skb_csum_unnecessary(skb)) __skb_decr_checksum_unnecessary(skb); - else if (!sctp_checksum_disable && sctp_rcv_checksum(net, skb) < 0) + else if (!sctp_checksum_disable && + !(skb_shinfo(skb)->gso_type & SKB_GSO_SCTP) && + sctp_rcv_checksum(net, skb) < 0) goto discard_it; skb->csum_valid = 1; @@ -1175,6 +1177,14 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net, { sctp_chunkhdr_t *ch; + /* We do not allow GSO frames here as we need to linearize and + * then cannot guarantee frame boundaries. This shouldn't be an + * issue as packets hitting this are mostly INIT or INIT-ACK and + * those cannot be on GSO-style anyway. + */ + if ((skb_shinfo(skb)->gso_type & SKB_GSO_SCTP) == SKB_GSO_SCTP) + return NULL; + if (skb_linearize(skb)) return NULL; diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 5ba08ceda3ab..edabbbdfca54 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -138,6 +138,17 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) if (chunk->singleton || chunk->end_of_packet || chunk->pdiscard) { + if (chunk->head_skb == chunk->skb) { + chunk->skb = skb_shinfo(chunk->skb)->frag_list; + goto new_skb; + } + if (chunk->skb->next) { + chunk->skb = chunk->skb->next; + goto new_skb; + } + + if (chunk->head_skb) + chunk->skb = chunk->head_skb; sctp_chunk_free(chunk); chunk = queue->in_progress = NULL; } else { @@ -155,15 +166,15 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) next_chunk: /* Is the queue empty? */ - if (list_empty(&queue->in_chunk_list)) + entry = sctp_list_dequeue(&queue->in_chunk_list); + if (!entry) return NULL; - entry = queue->in_chunk_list.next; chunk = list_entry(entry, struct sctp_chunk, list); - list_del_init(entry); /* Linearize if it's not GSO */ - if (skb_is_nonlinear(chunk->skb)) { + if ((skb_shinfo(chunk->skb)->gso_type & SKB_GSO_SCTP) != SKB_GSO_SCTP && + skb_is_nonlinear(chunk->skb)) { if (skb_linearize(chunk->skb)) { __SCTP_INC_STATS(dev_net(chunk->skb->dev), SCTP_MIB_IN_PKT_DISCARDS); sctp_chunk_free(chunk); @@ -174,15 +185,39 @@ next_chunk: chunk->sctp_hdr = sctp_hdr(chunk->skb); } + if ((skb_shinfo(chunk->skb)->gso_type & SKB_GSO_SCTP) == SKB_GSO_SCTP) { + /* GSO-marked skbs but without frags, handle + * them normally + */ + if (skb_shinfo(chunk->skb)->frag_list) + chunk->head_skb = chunk->skb; + + /* skbs with "cover letter" */ + if (chunk->head_skb && chunk->skb->data_len == chunk->skb->len) + chunk->skb = skb_shinfo(chunk->skb)->frag_list; + + if (WARN_ON(!chunk->skb)) { + __SCTP_INC_STATS(dev_net(chunk->skb->dev), SCTP_MIB_IN_PKT_DISCARDS); + sctp_chunk_free(chunk); + goto next_chunk; + } + } + + if (chunk->asoc) + sock_rps_save_rxhash(chunk->asoc->base.sk, chunk->skb); + queue->in_progress = chunk; +new_skb: /* This is the first chunk in the packet. */ - chunk->singleton = 1; ch = (sctp_chunkhdr_t *) chunk->skb->data; + chunk->singleton = 1; chunk->data_accepted = 0; - - if (chunk->asoc) - sock_rps_save_rxhash(chunk->asoc->base.sk, chunk->skb); + chunk->pdiscard = 0; + chunk->auth = 0; + chunk->has_asconf = 0; + chunk->end_of_packet = 0; + chunk->ecn_ce_done = 0; } chunk->chunk_hdr = ch; diff --git a/net/sctp/offload.c b/net/sctp/offload.c new file mode 100644 index 000000000000..a37887b373a7 --- /dev/null +++ b/net/sctp/offload.c @@ -0,0 +1,98 @@ +/* + * sctp_offload - GRO/GSO Offloading for SCTP + * + * Copyright (C) 2015, Marcelo Ricardo Leitner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static __le32 sctp_gso_make_checksum(struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + return sctp_compute_cksum(skb, skb_transport_offset(skb)); +} + +static struct sk_buff *sctp_gso_segment(struct sk_buff *skb, + netdev_features_t features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + struct sctphdr *sh; + + sh = sctp_hdr(skb); + if (!pskb_may_pull(skb, sizeof(*sh))) + goto out; + + __skb_pull(skb, sizeof(*sh)); + + if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { + /* Packet is from an untrusted source, reset gso_segs. */ + struct skb_shared_info *pinfo = skb_shinfo(skb); + struct sk_buff *frag_iter; + + pinfo->gso_segs = 0; + if (skb->len != skb->data_len) { + /* Means we have chunks in here too */ + pinfo->gso_segs++; + } + + skb_walk_frags(skb, frag_iter) + pinfo->gso_segs++; + + segs = NULL; + goto out; + } + + segs = skb_segment(skb, features | NETIF_F_HW_CSUM); + if (IS_ERR(segs)) + goto out; + + /* All that is left is update SCTP CRC if necessary */ + if (!(features & NETIF_F_SCTP_CRC)) { + for (skb = segs; skb; skb = skb->next) { + if (skb->ip_summed == CHECKSUM_PARTIAL) { + sh = sctp_hdr(skb); + sh->checksum = sctp_gso_make_checksum(skb); + } + } + } + +out: + return segs; +} + +static const struct net_offload sctp_offload = { + .callbacks = { + .gso_segment = sctp_gso_segment, + }, +}; + +int __init sctp_offload_init(void) +{ + return inet_add_offload(&sctp_offload, IPPROTO_SCTP); +} diff --git a/net/sctp/output.c b/net/sctp/output.c index 9844fe573029..60499a69179d 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -84,18 +84,42 @@ static void sctp_packet_reset(struct sctp_packet *packet) struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, __u32 vtag, int ecn_capable) { - struct sctp_chunk *chunk = NULL; + struct sctp_transport *tp = packet->transport; + struct sctp_association *asoc = tp->asoc; pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); packet->vtag = vtag; + if (asoc && tp->dst) { + struct sock *sk = asoc->base.sk; + + rcu_read_lock(); + if (__sk_dst_get(sk) != tp->dst) { + dst_hold(tp->dst); + sk_setup_caps(sk, tp->dst); + } + + if (sk_can_gso(sk)) { + struct net_device *dev = tp->dst->dev; + + packet->max_size = dev->gso_max_size; + } else { + packet->max_size = asoc->pathmtu; + } + rcu_read_unlock(); + + } else { + packet->max_size = tp->pathmtu; + } + if (ecn_capable && sctp_packet_empty(packet)) { - chunk = sctp_get_ecne_prepend(packet->transport->asoc); + struct sctp_chunk *chunk; /* If there a is a prepend chunk stick it on the list before * any other chunks get appended. */ + chunk = sctp_get_ecne_prepend(asoc); if (chunk) sctp_packet_append_chunk(packet, chunk); } @@ -381,12 +405,15 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) struct sctp_transport *tp = packet->transport; struct sctp_association *asoc = tp->asoc; struct sctphdr *sh; - struct sk_buff *nskb; + struct sk_buff *nskb = NULL, *head = NULL; struct sctp_chunk *chunk, *tmp; struct sock *sk; int err = 0; int padding; /* How much padding do we need? */ + int pkt_size; __u8 has_data = 0; + int gso = 0; + int pktcount = 0; struct dst_entry *dst; unsigned char *auth = NULL; /* pointer to auth in skb data */ @@ -400,18 +427,37 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) chunk = list_entry(packet->chunk_list.next, struct sctp_chunk, list); sk = chunk->skb->sk; - /* Allocate the new skb. */ - nskb = alloc_skb(packet->size + MAX_HEADER, gfp); - if (!nskb) + /* Allocate the head skb, or main one if not in GSO */ + if (packet->size > tp->pathmtu && !packet->ipfragok) { + if (sk_can_gso(sk)) { + gso = 1; + pkt_size = packet->overhead; + } else { + /* If this happens, we trash this packet and try + * to build a new one, hopefully correct this + * time. Application may notice this error. + */ + pr_err_once("Trying to GSO but underlying device doesn't support it."); + goto nomem; + } + } else { + pkt_size = packet->size; + } + head = alloc_skb(pkt_size + MAX_HEADER, gfp); + if (!head) goto nomem; + if (gso) { + NAPI_GRO_CB(head)->last = head; + skb_shinfo(head)->gso_type = sk->sk_gso_type; + } /* Make sure the outbound skb has enough header room reserved. */ - skb_reserve(nskb, packet->overhead + MAX_HEADER); + skb_reserve(head, packet->overhead + MAX_HEADER); /* Set the owning socket so that we know where to get the * destination IP address. */ - sctp_packet_set_owner_w(nskb, sk); + sctp_packet_set_owner_w(head, sk); if (!sctp_transport_dst_check(tp)) { sctp_transport_route(tp, NULL, sctp_sk(sk)); @@ -422,11 +468,11 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) dst = dst_clone(tp->dst); if (!dst) goto no_route; - skb_dst_set(nskb, dst); + skb_dst_set(head, dst); /* Build the SCTP header. */ - sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); - skb_reset_transport_header(nskb); + sh = (struct sctphdr *)skb_push(head, sizeof(struct sctphdr)); + skb_reset_transport_header(head); sh->source = htons(packet->source_port); sh->dest = htons(packet->destination_port); @@ -441,90 +487,133 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) sh->vtag = htonl(packet->vtag); sh->checksum = 0; - /** - * 6.10 Bundling - * - * An endpoint bundles chunks by simply including multiple - * chunks in one outbound SCTP packet. ... - */ - - /** - * 3.2 Chunk Field Descriptions - * - * The total length of a chunk (including Type, Length and - * Value fields) MUST be a multiple of 4 bytes. If the length - * of the chunk is not a multiple of 4 bytes, the sender MUST - * pad the chunk with all zero bytes and this padding is not - * included in the chunk length field. The sender should - * never pad with more than 3 bytes. - * - * [This whole comment explains WORD_ROUND() below.] - */ - pr_debug("***sctp_transmit_packet***\n"); - list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) { - list_del_init(&chunk->list); - if (sctp_chunk_is_data(chunk)) { - /* 6.3.1 C4) When data is in flight and when allowed - * by rule C5, a new RTT measurement MUST be made each - * round trip. Furthermore, new RTT measurements - * SHOULD be made no more than once per round-trip - * for a given destination transport address. - */ + do { + /* Set up convenience variables... */ + chunk = list_entry(packet->chunk_list.next, struct sctp_chunk, list); + pktcount++; - if (!chunk->resent && !tp->rto_pending) { - chunk->rtt_in_progress = 1; - tp->rto_pending = 1; + /* Calculate packet size, so it fits in PMTU. Leave + * other chunks for the next packets. + */ + if (gso) { + pkt_size = packet->overhead; + list_for_each_entry(chunk, &packet->chunk_list, list) { + int padded = WORD_ROUND(chunk->skb->len); + + if (pkt_size + padded > tp->pathmtu) + break; + pkt_size += padded; } - has_data = 1; - } + /* Allocate a new skb. */ + nskb = alloc_skb(pkt_size + MAX_HEADER, gfp); + if (!nskb) + goto nomem; - padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; - if (padding) - memset(skb_put(chunk->skb, padding), 0, padding); + /* Make sure the outbound skb has enough header + * room reserved. + */ + skb_reserve(nskb, packet->overhead + MAX_HEADER); + } else { + nskb = head; + } - /* if this is the auth chunk that we are adding, - * store pointer where it will be added and put - * the auth into the packet. + /** + * 3.2 Chunk Field Descriptions + * + * The total length of a chunk (including Type, Length and + * Value fields) MUST be a multiple of 4 bytes. If the length + * of the chunk is not a multiple of 4 bytes, the sender MUST + * pad the chunk with all zero bytes and this padding is not + * included in the chunk length field. The sender should + * never pad with more than 3 bytes. + * + * [This whole comment explains WORD_ROUND() below.] */ - if (chunk == packet->auth) - auth = skb_tail_pointer(nskb); - memcpy(skb_put(nskb, chunk->skb->len), + pkt_size -= packet->overhead; + list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) { + list_del_init(&chunk->list); + if (sctp_chunk_is_data(chunk)) { + /* 6.3.1 C4) When data is in flight and when allowed + * by rule C5, a new RTT measurement MUST be made each + * round trip. Furthermore, new RTT measurements + * SHOULD be made no more than once per round-trip + * for a given destination transport address. + */ + + if (!chunk->resent && !tp->rto_pending) { + chunk->rtt_in_progress = 1; + tp->rto_pending = 1; + } + + has_data = 1; + } + + padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; + if (padding) + memset(skb_put(chunk->skb, padding), 0, padding); + + /* if this is the auth chunk that we are adding, + * store pointer where it will be added and put + * the auth into the packet. + */ + if (chunk == packet->auth) + auth = skb_tail_pointer(nskb); + + memcpy(skb_put(nskb, chunk->skb->len), chunk->skb->data, chunk->skb->len); - pr_debug("*** Chunk:%p[%s] %s 0x%x, length:%d, chunk->skb->len:%d, " - "rtt_in_progress:%d\n", chunk, - sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)), - chunk->has_tsn ? "TSN" : "No TSN", - chunk->has_tsn ? ntohl(chunk->subh.data_hdr->tsn) : 0, - ntohs(chunk->chunk_hdr->length), chunk->skb->len, - chunk->rtt_in_progress); - - /* - * If this is a control chunk, this is our last - * reference. Free data chunks after they've been - * acknowledged or have failed. - */ - if (!sctp_chunk_is_data(chunk)) - sctp_chunk_free(chunk); - } + pr_debug("*** Chunk:%p[%s] %s 0x%x, length:%d, chunk->skb->len:%d, rtt_in_progress:%d\n", + chunk, + sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)), + chunk->has_tsn ? "TSN" : "No TSN", + chunk->has_tsn ? ntohl(chunk->subh.data_hdr->tsn) : 0, + ntohs(chunk->chunk_hdr->length), chunk->skb->len, + chunk->rtt_in_progress); + + /* If this is a control chunk, this is our last + * reference. Free data chunks after they've been + * acknowledged or have failed. + * Re-queue auth chunks if needed. + */ + pkt_size -= WORD_ROUND(chunk->skb->len); - /* SCTP-AUTH, Section 6.2 - * The sender MUST calculate the MAC as described in RFC2104 [2] - * using the hash function H as described by the MAC Identifier and - * the shared association key K based on the endpoint pair shared key - * described by the shared key identifier. The 'data' used for the - * computation of the AUTH-chunk is given by the AUTH chunk with its - * HMAC field set to zero (as shown in Figure 6) followed by all - * chunks that are placed after the AUTH chunk in the SCTP packet. - */ - if (auth) - sctp_auth_calculate_hmac(asoc, nskb, - (struct sctp_auth_chunk *)auth, - gfp); + if (chunk == packet->auth && !list_empty(&packet->chunk_list)) + list_add(&chunk->list, &packet->chunk_list); + else if (!sctp_chunk_is_data(chunk)) + sctp_chunk_free(chunk); + + if (!pkt_size) + break; + } + + /* SCTP-AUTH, Section 6.2 + * The sender MUST calculate the MAC as described in RFC2104 [2] + * using the hash function H as described by the MAC Identifier and + * the shared association key K based on the endpoint pair shared key + * described by the shared key identifier. The 'data' used for the + * computation of the AUTH-chunk is given by the AUTH chunk with its + * HMAC field set to zero (as shown in Figure 6) followed by all + * chunks that are placed after the AUTH chunk in the SCTP packet. + */ + if (auth) + sctp_auth_calculate_hmac(asoc, nskb, + (struct sctp_auth_chunk *)auth, + gfp); + + if (!gso) + break; + + if (skb_gro_receive(&head, nskb)) + goto nomem; + nskb = NULL; + if (WARN_ON_ONCE(skb_shinfo(head)->gso_segs >= + sk->sk_gso_max_segs)) + goto nomem; + } while (!list_empty(&packet->chunk_list)); /* 2) Calculate the Adler-32 checksum of the whole packet, * including the SCTP common header and all the @@ -532,16 +621,18 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) * * Note: Adler-32 is no longer applicable, as has been replaced * by CRC32-C as described in . + * + * If it's a GSO packet, it's postponed to sctp_skb_segment. */ - if (!sctp_checksum_disable) { - if (!(dst->dev->features & NETIF_F_SCTP_CRC) || - (dst_xfrm(dst) != NULL) || packet->ipfragok) { - sh->checksum = sctp_compute_cksum(nskb, 0); + if (!sctp_checksum_disable || gso) { + if (!gso && (!(dst->dev->features & NETIF_F_SCTP_CRC) || + dst_xfrm(dst) || packet->ipfragok)) { + sh->checksum = sctp_compute_cksum(head, 0); } else { /* no need to seed pseudo checksum for SCTP */ - nskb->ip_summed = CHECKSUM_PARTIAL; - nskb->csum_start = skb_transport_header(nskb) - nskb->head; - nskb->csum_offset = offsetof(struct sctphdr, checksum); + head->ip_summed = CHECKSUM_PARTIAL; + head->csum_start = skb_transport_header(head) - head->head; + head->csum_offset = offsetof(struct sctphdr, checksum); } } @@ -557,7 +648,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) * Note: The works for IPv6 layer checks this bit too later * in transmission. See IP6_ECN_flow_xmit(). */ - tp->af_specific->ecn_capable(nskb->sk); + tp->af_specific->ecn_capable(sk); /* Set up the IP options. */ /* BUG: not implemented @@ -566,7 +657,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) /* Dump that on IP! */ if (asoc) { - asoc->stats.opackets++; + asoc->stats.opackets += pktcount; if (asoc->peer.last_sent_to != tp) /* Considering the multiple CPU scenario, this is a * "correcter" place for last_sent_to. --xguo @@ -589,16 +680,36 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) } } - pr_debug("***sctp_transmit_packet*** skb->len:%d\n", nskb->len); + pr_debug("***sctp_transmit_packet*** skb->len:%d\n", head->len); + + if (gso) { + /* Cleanup our debris for IP stacks */ + memset(head->cb, 0, max(sizeof(struct inet_skb_parm), + sizeof(struct inet6_skb_parm))); - nskb->ignore_df = packet->ipfragok; - tp->af_specific->sctp_xmit(nskb, tp); + skb_shinfo(head)->gso_segs = pktcount; + skb_shinfo(head)->gso_size = GSO_BY_FRAGS; + + /* We have to refresh this in case we are xmiting to + * more than one transport at a time + */ + rcu_read_lock(); + if (__sk_dst_get(sk) != tp->dst) { + dst_hold(tp->dst); + sk_setup_caps(sk, tp->dst); + } + rcu_read_unlock(); + } + head->ignore_df = packet->ipfragok; + tp->af_specific->sctp_xmit(head, tp); out: sctp_packet_reset(packet); return err; no_route: - kfree_skb(nskb); + kfree_skb(head); + if (nskb != head) + kfree_skb(nskb); if (asoc) IP_INC_STATS(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); @@ -751,39 +862,63 @@ static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, struct sctp_chunk *chunk, u16 chunk_len) { - size_t psize; - size_t pmtu; - int too_big; + size_t psize, pmtu; sctp_xmit_t retval = SCTP_XMIT_OK; psize = packet->size; - pmtu = ((packet->transport->asoc) ? - (packet->transport->asoc->pathmtu) : - (packet->transport->pathmtu)); - - too_big = (psize + chunk_len > pmtu); + if (packet->transport->asoc) + pmtu = packet->transport->asoc->pathmtu; + else + pmtu = packet->transport->pathmtu; /* Decide if we need to fragment or resubmit later. */ - if (too_big) { - /* It's OK to fragmet at IP level if any one of the following + if (psize + chunk_len > pmtu) { + /* It's OK to fragment at IP level if any one of the following * is true: - * 1. The packet is empty (meaning this chunk is greater - * the MTU) - * 2. The chunk we are adding is a control chunk - * 3. The packet doesn't have any data in it yet and data - * requires authentication. + * 1. The packet is empty (meaning this chunk is greater + * the MTU) + * 2. The packet doesn't have any data in it yet and data + * requires authentication. */ - if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) || + if (sctp_packet_empty(packet) || (!packet->has_data && chunk->auth)) { /* We no longer do re-fragmentation. * Just fragment at the IP layer, if we * actually hit this condition */ packet->ipfragok = 1; - } else { - retval = SCTP_XMIT_PMTU_FULL; + goto out; } + + /* It is also okay to fragment if the chunk we are + * adding is a control chunk, but only if current packet + * is not a GSO one otherwise it causes fragmentation of + * a large frame. So in this case we allow the + * fragmentation by forcing it to be in a new packet. + */ + if (!sctp_chunk_is_data(chunk) && packet->has_data) + retval = SCTP_XMIT_PMTU_FULL; + + if (psize + chunk_len > packet->max_size) + /* Hit GSO/PMTU limit, gotta flush */ + retval = SCTP_XMIT_PMTU_FULL; + + if (!packet->transport->burst_limited && + psize + chunk_len > (packet->transport->cwnd >> 1)) + /* Do not allow a single GSO packet to use more + * than half of cwnd. + */ + retval = SCTP_XMIT_PMTU_FULL; + + if (packet->transport->burst_limited && + psize + chunk_len > (packet->transport->burst_limited >> 1)) + /* Do not allow a single GSO packet to use more + * than half of original cwnd. + */ + retval = SCTP_XMIT_PMTU_FULL; + /* Otherwise it will fit in the GSO packet */ } +out: return retval; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d3d50daa248b..40022ee885d7 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1516,6 +1516,9 @@ static __init int sctp_init(void) if (status) goto err_v6_add_protocol; + if (sctp_offload_init() < 0) + pr_crit("%s: Cannot add SCTP protocol offload\n", __func__); + out: return status; err_v6_add_protocol: diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 67154b848aa9..712fb2339baa 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4003,6 +4003,8 @@ static int sctp_init_sock(struct sock *sk) return -ESOCKTNOSUPPORT; } + sk->sk_gso_type = SKB_GSO_SCTP; + /* Initialize default send parameters. These parameters can be * modified with the SCTP_DEFAULT_SEND_PARAM socket option. */ -- cgit v1.2.3 From a91eb52abb504a1dd3248a5d07b54e7f95d5fcf1 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Fri, 3 Jun 2016 14:35:32 +0300 Subject: qed: Revisit chain implementation RoCE driver is going to need a 32-bit chain [current chain implementation for qed* currently supports only 16-bit producer/consumer chains]. This patch adds said support, as well as doing other slight tweaks and modifications to qed's chain API. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 314 +++++++++--- drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 8 +- drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 5 +- drivers/net/ethernet/qlogic/qed/qed_spq.c | 40 +- drivers/net/ethernet/qlogic/qede/qede_main.c | 6 +- include/linux/qed/qed_chain.h | 553 +++++++++++++--------- include/linux/qed/qed_if.h | 3 +- 7 files changed, 623 insertions(+), 306 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index e9ce6a7bc63b..151173d4a926 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1779,92 +1780,285 @@ void qed_hw_remove(struct qed_dev *cdev) qed_iov_free_hw_info(cdev); } -int qed_chain_alloc(struct qed_dev *cdev, - enum qed_chain_use_mode intended_use, - enum qed_chain_mode mode, - u16 num_elems, - size_t elem_size, - struct qed_chain *p_chain) +static void qed_chain_free_next_ptr(struct qed_dev *cdev, + struct qed_chain *p_chain) +{ + void *p_virt = p_chain->p_virt_addr, *p_virt_next = NULL; + dma_addr_t p_phys = p_chain->p_phys_addr, p_phys_next = 0; + struct qed_chain_next *p_next; + u32 size, i; + + if (!p_virt) + return; + + size = p_chain->elem_size * p_chain->usable_per_page; + + for (i = 0; i < p_chain->page_cnt; i++) { + if (!p_virt) + break; + + p_next = (struct qed_chain_next *)((u8 *)p_virt + size); + p_virt_next = p_next->next_virt; + p_phys_next = HILO_DMA_REGPAIR(p_next->next_phys); + + dma_free_coherent(&cdev->pdev->dev, + QED_CHAIN_PAGE_SIZE, p_virt, p_phys); + + p_virt = p_virt_next; + p_phys = p_phys_next; + } +} + +static void qed_chain_free_single(struct qed_dev *cdev, + struct qed_chain *p_chain) +{ + if (!p_chain->p_virt_addr) + return; + + dma_free_coherent(&cdev->pdev->dev, + QED_CHAIN_PAGE_SIZE, + p_chain->p_virt_addr, p_chain->p_phys_addr); +} + +static void qed_chain_free_pbl(struct qed_dev *cdev, struct qed_chain *p_chain) +{ + void **pp_virt_addr_tbl = p_chain->pbl.pp_virt_addr_tbl; + u32 page_cnt = p_chain->page_cnt, i, pbl_size; + u8 *p_pbl_virt = p_chain->pbl.p_virt_table; + + if (!pp_virt_addr_tbl) + return; + + if (!p_chain->pbl.p_virt_table) + goto out; + + for (i = 0; i < page_cnt; i++) { + if (!pp_virt_addr_tbl[i]) + break; + + dma_free_coherent(&cdev->pdev->dev, + QED_CHAIN_PAGE_SIZE, + pp_virt_addr_tbl[i], + *(dma_addr_t *)p_pbl_virt); + + p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE; + } + + pbl_size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; + dma_free_coherent(&cdev->pdev->dev, + pbl_size, + p_chain->pbl.p_virt_table, p_chain->pbl.p_phys_table); +out: + vfree(p_chain->pbl.pp_virt_addr_tbl); +} + +void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain) +{ + switch (p_chain->mode) { + case QED_CHAIN_MODE_NEXT_PTR: + qed_chain_free_next_ptr(cdev, p_chain); + break; + case QED_CHAIN_MODE_SINGLE: + qed_chain_free_single(cdev, p_chain); + break; + case QED_CHAIN_MODE_PBL: + qed_chain_free_pbl(cdev, p_chain); + break; + } +} + +static int +qed_chain_alloc_sanity_check(struct qed_dev *cdev, + enum qed_chain_cnt_type cnt_type, + size_t elem_size, u32 page_cnt) +{ + u64 chain_size = ELEMS_PER_PAGE(elem_size) * page_cnt; + + /* The actual chain size can be larger than the maximal possible value + * after rounding up the requested elements number to pages, and after + * taking into acount the unusuable elements (next-ptr elements). + * The size of a "u16" chain can be (U16_MAX + 1) since the chain + * size/capacity fields are of a u32 type. + */ + if ((cnt_type == QED_CHAIN_CNT_TYPE_U16 && + chain_size > 0x10000) || + (cnt_type == QED_CHAIN_CNT_TYPE_U32 && + chain_size > 0x100000000ULL)) { + DP_NOTICE(cdev, + "The actual chain size (0x%llx) is larger than the maximal possible value\n", + chain_size); + return -EINVAL; + } + + return 0; +} + +static int +qed_chain_alloc_next_ptr(struct qed_dev *cdev, struct qed_chain *p_chain) { - dma_addr_t p_pbl_phys = 0; - void *p_pbl_virt = NULL; + void *p_virt = NULL, *p_virt_prev = NULL; dma_addr_t p_phys = 0; - void *p_virt = NULL; - u16 page_cnt = 0; - size_t size; + u32 i; - if (mode == QED_CHAIN_MODE_SINGLE) - page_cnt = 1; - else - page_cnt = QED_CHAIN_PAGE_CNT(num_elems, elem_size, mode); + for (i = 0; i < p_chain->page_cnt; i++) { + p_virt = dma_alloc_coherent(&cdev->pdev->dev, + QED_CHAIN_PAGE_SIZE, + &p_phys, GFP_KERNEL); + if (!p_virt) { + DP_NOTICE(cdev, "Failed to allocate chain memory\n"); + return -ENOMEM; + } + + if (i == 0) { + qed_chain_init_mem(p_chain, p_virt, p_phys); + qed_chain_reset(p_chain); + } else { + qed_chain_init_next_ptr_elem(p_chain, p_virt_prev, + p_virt, p_phys); + } + + p_virt_prev = p_virt; + } + /* Last page's next element should point to the beginning of the + * chain. + */ + qed_chain_init_next_ptr_elem(p_chain, p_virt_prev, + p_chain->p_virt_addr, + p_chain->p_phys_addr); + + return 0; +} + +static int +qed_chain_alloc_single(struct qed_dev *cdev, struct qed_chain *p_chain) +{ + dma_addr_t p_phys = 0; + void *p_virt = NULL; - size = page_cnt * QED_CHAIN_PAGE_SIZE; p_virt = dma_alloc_coherent(&cdev->pdev->dev, - size, &p_phys, GFP_KERNEL); + QED_CHAIN_PAGE_SIZE, &p_phys, GFP_KERNEL); if (!p_virt) { - DP_NOTICE(cdev, "Failed to allocate chain mem\n"); - goto nomem; + DP_NOTICE(cdev, "Failed to allocate chain memory\n"); + return -ENOMEM; } - if (mode == QED_CHAIN_MODE_PBL) { - size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; - p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev, - size, &p_pbl_phys, - GFP_KERNEL); - if (!p_pbl_virt) { - DP_NOTICE(cdev, "Failed to allocate chain pbl mem\n"); - goto nomem; - } + qed_chain_init_mem(p_chain, p_virt, p_phys); + qed_chain_reset(p_chain); - qed_chain_pbl_init(p_chain, p_virt, p_phys, page_cnt, - (u8)elem_size, intended_use, - p_pbl_phys, p_pbl_virt); - } else { - qed_chain_init(p_chain, p_virt, p_phys, page_cnt, - (u8)elem_size, intended_use, mode); + return 0; +} + +static int qed_chain_alloc_pbl(struct qed_dev *cdev, struct qed_chain *p_chain) +{ + u32 page_cnt = p_chain->page_cnt, size, i; + dma_addr_t p_phys = 0, p_pbl_phys = 0; + void **pp_virt_addr_tbl = NULL; + u8 *p_pbl_virt = NULL; + void *p_virt = NULL; + + size = page_cnt * sizeof(*pp_virt_addr_tbl); + pp_virt_addr_tbl = vmalloc(size); + if (!pp_virt_addr_tbl) { + DP_NOTICE(cdev, + "Failed to allocate memory for the chain virtual addresses table\n"); + return -ENOMEM; } + memset(pp_virt_addr_tbl, 0, size); - return 0; + /* The allocation of the PBL table is done with its full size, since it + * is expected to be successive. + * qed_chain_init_pbl_mem() is called even in a case of an allocation + * failure, since pp_virt_addr_tbl was previously allocated, and it + * should be saved to allow its freeing during the error flow. + */ + size = page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; + p_pbl_virt = dma_alloc_coherent(&cdev->pdev->dev, + size, &p_pbl_phys, GFP_KERNEL); + qed_chain_init_pbl_mem(p_chain, p_pbl_virt, p_pbl_phys, + pp_virt_addr_tbl); + if (!p_pbl_virt) { + DP_NOTICE(cdev, "Failed to allocate chain pbl memory\n"); + return -ENOMEM; + } -nomem: - dma_free_coherent(&cdev->pdev->dev, - page_cnt * QED_CHAIN_PAGE_SIZE, - p_virt, p_phys); - dma_free_coherent(&cdev->pdev->dev, - page_cnt * QED_CHAIN_PBL_ENTRY_SIZE, - p_pbl_virt, p_pbl_phys); + for (i = 0; i < page_cnt; i++) { + p_virt = dma_alloc_coherent(&cdev->pdev->dev, + QED_CHAIN_PAGE_SIZE, + &p_phys, GFP_KERNEL); + if (!p_virt) { + DP_NOTICE(cdev, "Failed to allocate chain memory\n"); + return -ENOMEM; + } - return -ENOMEM; + if (i == 0) { + qed_chain_init_mem(p_chain, p_virt, p_phys); + qed_chain_reset(p_chain); + } + + /* Fill the PBL table with the physical address of the page */ + *(dma_addr_t *)p_pbl_virt = p_phys; + /* Keep the virtual address of the page */ + p_chain->pbl.pp_virt_addr_tbl[i] = p_virt; + + p_pbl_virt += QED_CHAIN_PBL_ENTRY_SIZE; + } + + return 0; } -void qed_chain_free(struct qed_dev *cdev, - struct qed_chain *p_chain) +int qed_chain_alloc(struct qed_dev *cdev, + enum qed_chain_use_mode intended_use, + enum qed_chain_mode mode, + enum qed_chain_cnt_type cnt_type, + u32 num_elems, size_t elem_size, struct qed_chain *p_chain) { - size_t size; + u32 page_cnt; + int rc = 0; - if (!p_chain->p_virt_addr) - return; + if (mode == QED_CHAIN_MODE_SINGLE) + page_cnt = 1; + else + page_cnt = QED_CHAIN_PAGE_CNT(num_elems, elem_size, mode); - if (p_chain->mode == QED_CHAIN_MODE_PBL) { - size = p_chain->page_cnt * QED_CHAIN_PBL_ENTRY_SIZE; - dma_free_coherent(&cdev->pdev->dev, size, - p_chain->pbl.p_virt_table, - p_chain->pbl.p_phys_table); + rc = qed_chain_alloc_sanity_check(cdev, cnt_type, elem_size, page_cnt); + if (rc) { + DP_NOTICE(cdev, + "Cannot allocate a chain with the given arguments:\n" + "[use_mode %d, mode %d, cnt_type %d, num_elems %d, elem_size %zu]\n", + intended_use, mode, cnt_type, num_elems, elem_size); + return rc; } - size = p_chain->page_cnt * QED_CHAIN_PAGE_SIZE; - dma_free_coherent(&cdev->pdev->dev, size, - p_chain->p_virt_addr, - p_chain->p_phys_addr); + qed_chain_init_params(p_chain, page_cnt, (u8) elem_size, intended_use, + mode, cnt_type); + + switch (mode) { + case QED_CHAIN_MODE_NEXT_PTR: + rc = qed_chain_alloc_next_ptr(cdev, p_chain); + break; + case QED_CHAIN_MODE_SINGLE: + rc = qed_chain_alloc_single(cdev, p_chain); + break; + case QED_CHAIN_MODE_PBL: + rc = qed_chain_alloc_pbl(cdev, p_chain); + break; + } + if (rc) + goto nomem; + + return 0; + +nomem: + qed_chain_free(cdev, p_chain); + return rc; } -int qed_fw_l2_queue(struct qed_hwfn *p_hwfn, - u16 src_id, u16 *dst_id) +int qed_fw_l2_queue(struct qed_hwfn *p_hwfn, u16 src_id, u16 *dst_id) { if (src_id >= RESC_NUM(p_hwfn, QED_L2_QUEUE)) { u16 min, max; - min = (u16)RESC_START(p_hwfn, QED_L2_QUEUE); + min = (u16) RESC_START(p_hwfn, QED_L2_QUEUE); max = min + RESC_NUM(p_hwfn, QED_L2_QUEUE); DP_NOTICE(p_hwfn, "l2_queue id [%d] is not valid, available indices [%d - %d]\n", diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h index dde364d6f502..f810ce45d463 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h @@ -245,9 +245,8 @@ int qed_chain_alloc(struct qed_dev *cdev, enum qed_chain_use_mode intended_use, enum qed_chain_mode mode, - u16 num_elems, - size_t elem_size, - struct qed_chain *p_chain); + enum qed_chain_cnt_type cnt_type, + u32 num_elems, size_t elem_size, struct qed_chain *p_chain); /** * @brief qed_chain_free - Free chain DMA memory @@ -255,8 +254,7 @@ qed_chain_alloc(struct qed_dev *cdev, * @param p_hwfn * @param p_chain */ -void qed_chain_free(struct qed_dev *cdev, - struct qed_chain *p_chain); +void qed_chain_free(struct qed_dev *cdev, struct qed_chain *p_chain); /** * @@brief qed_fw_l2_queue - Get absolute L2 queue ID diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c index 122506416478..63b93fbdc66a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -308,6 +308,7 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, struct qed_spq_entry *p_ent = NULL; struct qed_sp_init_data init_data; int rc = -EINVAL; + u8 page_cnt; /* update initial eq producer */ qed_eq_prod_update(p_hwfn, @@ -350,8 +351,8 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, /* Place EQ address in RAMROD */ DMA_REGPAIR_LE(p_ramrod->event_ring_pbl_addr, p_hwfn->p_eq->chain.pbl.p_phys_table); - p_ramrod->event_ring_num_pages = (u8)p_hwfn->p_eq->chain.page_cnt; - + page_cnt = (u8)qed_chain_get_page_cnt(&p_hwfn->p_eq->chain); + p_ramrod->event_ring_num_pages = page_cnt; DMA_REGPAIR_LE(p_ramrod->consolid_q_pbl_addr, p_hwfn->p_consq->chain.pbl.p_phys_table); diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index acac6626a1b2..ad9bf5c85c3f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -343,6 +343,7 @@ struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn, if (qed_chain_alloc(p_hwfn->cdev, QED_CHAIN_USE_TO_PRODUCE, QED_CHAIN_MODE_PBL, + QED_CHAIN_CNT_TYPE_U16, num_elem, sizeof(union event_ring_element), &p_eq->chain)) { @@ -416,10 +417,10 @@ int qed_eth_cqe_completion(struct qed_hwfn *p_hwfn, ***************************************************************************/ void qed_spq_setup(struct qed_hwfn *p_hwfn) { - struct qed_spq *p_spq = p_hwfn->p_spq; - struct qed_spq_entry *p_virt = NULL; - dma_addr_t p_phys = 0; - unsigned int i = 0; + struct qed_spq *p_spq = p_hwfn->p_spq; + struct qed_spq_entry *p_virt = NULL; + dma_addr_t p_phys = 0; + u32 i, capacity; INIT_LIST_HEAD(&p_spq->pending); INIT_LIST_HEAD(&p_spq->completion_pending); @@ -431,7 +432,8 @@ void qed_spq_setup(struct qed_hwfn *p_hwfn) p_phys = p_spq->p_phys + offsetof(struct qed_spq_entry, ramrod); p_virt = p_spq->p_virt; - for (i = 0; i < p_spq->chain.capacity; i++) { + capacity = qed_chain_get_capacity(&p_spq->chain); + for (i = 0; i < capacity; i++) { DMA_REGPAIR_LE(p_virt->elem.data_ptr, p_phys); list_add_tail(&p_virt->list, &p_spq->free_pool); @@ -459,9 +461,10 @@ void qed_spq_setup(struct qed_hwfn *p_hwfn) int qed_spq_alloc(struct qed_hwfn *p_hwfn) { - struct qed_spq *p_spq = NULL; - dma_addr_t p_phys = 0; - struct qed_spq_entry *p_virt = NULL; + struct qed_spq_entry *p_virt = NULL; + struct qed_spq *p_spq = NULL; + dma_addr_t p_phys = 0; + u32 capacity; /* SPQ struct */ p_spq = @@ -475,6 +478,7 @@ int qed_spq_alloc(struct qed_hwfn *p_hwfn) if (qed_chain_alloc(p_hwfn->cdev, QED_CHAIN_USE_TO_PRODUCE, QED_CHAIN_MODE_SINGLE, + QED_CHAIN_CNT_TYPE_U16, 0, /* N/A when the mode is SINGLE */ sizeof(struct slow_path_element), &p_spq->chain)) { @@ -483,11 +487,11 @@ int qed_spq_alloc(struct qed_hwfn *p_hwfn) } /* allocate and fill the SPQ elements (incl. ramrod data list) */ + capacity = qed_chain_get_capacity(&p_spq->chain); p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, - p_spq->chain.capacity * + capacity * sizeof(struct qed_spq_entry), - &p_phys, - GFP_KERNEL); + &p_phys, GFP_KERNEL); if (!p_virt) goto spq_allocate_fail; @@ -507,16 +511,18 @@ spq_allocate_fail: void qed_spq_free(struct qed_hwfn *p_hwfn) { struct qed_spq *p_spq = p_hwfn->p_spq; + u32 capacity; if (!p_spq) return; - if (p_spq->p_virt) + if (p_spq->p_virt) { + capacity = qed_chain_get_capacity(&p_spq->chain); dma_free_coherent(&p_hwfn->cdev->pdev->dev, - p_spq->chain.capacity * + capacity * sizeof(struct qed_spq_entry), - p_spq->p_virt, - p_spq->p_phys); + p_spq->p_virt, p_spq->p_phys); + } qed_chain_free(p_hwfn->cdev, &p_spq->chain); ; @@ -871,9 +877,9 @@ struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn) if (qed_chain_alloc(p_hwfn->cdev, QED_CHAIN_USE_TO_PRODUCE, QED_CHAIN_MODE_PBL, + QED_CHAIN_CNT_TYPE_U16, QED_CHAIN_PAGE_SIZE / 0x80, - 0x80, - &p_consq->chain)) { + 0x80, &p_consq->chain)) { DP_NOTICE(p_hwfn, "Failed to allocate consq chain"); goto consq_allocate_fail; } diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 4f352476db31..edd2d908c52e 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -2817,6 +2817,7 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, rc = edev->ops->common->chain_alloc(edev->cdev, QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_NEXT_PTR, + QED_CHAIN_CNT_TYPE_U16, RX_RING_SIZE, sizeof(struct eth_rx_bd), &rxq->rx_bd_ring); @@ -2828,6 +2829,7 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, rc = edev->ops->common->chain_alloc(edev->cdev, QED_CHAIN_USE_TO_CONSUME, QED_CHAIN_MODE_PBL, + QED_CHAIN_CNT_TYPE_U16, RX_RING_SIZE, sizeof(union eth_rx_cqe), &rxq->rx_comp_ring); @@ -2879,9 +2881,9 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, rc = edev->ops->common->chain_alloc(edev->cdev, QED_CHAIN_USE_TO_CONSUME_PRODUCE, QED_CHAIN_MODE_PBL, + QED_CHAIN_CNT_TYPE_U16, NUM_TX_BDS_MAX, - sizeof(*p_virt), - &txq->tx_pbl); + sizeof(*p_virt), &txq->tx_pbl); if (rc) goto err; diff --git a/include/linux/qed/qed_chain.h b/include/linux/qed/qed_chain.h index 5f8fcaaa6504..eceaa9ed2ae9 100644 --- a/include/linux/qed/qed_chain.h +++ b/include/linux/qed/qed_chain.h @@ -47,16 +47,56 @@ enum qed_chain_use_mode { QED_CHAIN_USE_TO_CONSUME_PRODUCE, /* Chain starts empty */ }; +enum qed_chain_cnt_type { + /* The chain's size/prod/cons are kept in 16-bit variables */ + QED_CHAIN_CNT_TYPE_U16, + + /* The chain's size/prod/cons are kept in 32-bit variables */ + QED_CHAIN_CNT_TYPE_U32, +}; + struct qed_chain_next { struct regpair next_phys; void *next_virt; }; +struct qed_chain_pbl_u16 { + u16 prod_page_idx; + u16 cons_page_idx; +}; + +struct qed_chain_pbl_u32 { + u32 prod_page_idx; + u32 cons_page_idx; +}; + struct qed_chain_pbl { + /* Base address of a pre-allocated buffer for pbl */ dma_addr_t p_phys_table; void *p_virt_table; - u16 prod_page_idx; - u16 cons_page_idx; + + /* Table for keeping the virtual addresses of the chain pages, + * respectively to the physical addresses in the pbl table. + */ + void **pp_virt_addr_tbl; + + /* Index to current used page by producer/consumer */ + union { + struct qed_chain_pbl_u16 pbl16; + struct qed_chain_pbl_u32 pbl32; + } u; +}; + +struct qed_chain_u16 { + /* Cyclic index of next element to produce/consme */ + u16 prod_idx; + u16 cons_idx; +}; + +struct qed_chain_u32 { + /* Cyclic index of next element to produce/consme */ + u32 prod_idx; + u32 cons_idx; }; struct qed_chain { @@ -64,13 +104,25 @@ struct qed_chain { dma_addr_t p_phys_addr; void *p_prod_elem; void *p_cons_elem; - u16 page_cnt; + enum qed_chain_mode mode; enum qed_chain_use_mode intended_use; /* used to produce/consume */ - u16 capacity; /*< number of _usable_ elements */ - u16 size; /* number of elements */ - u16 prod_idx; - u16 cons_idx; + enum qed_chain_cnt_type cnt_type; + + union { + struct qed_chain_u16 chain16; + struct qed_chain_u32 chain32; + } u; + + u32 page_cnt; + + /* Number of elements - capacity is for usable elements only, + * while size will contain total number of elements [for entire chain]. + */ + u32 capacity; + u32 size; + + /* Elements information for fast calculations */ u16 elem_per_page; u16 elem_per_page_mask; u16 elem_unusable; @@ -96,66 +148,69 @@ struct qed_chain { #define QED_CHAIN_PAGE_CNT(elem_cnt, elem_size, mode) \ DIV_ROUND_UP(elem_cnt, USABLE_ELEMS_PER_PAGE(elem_size, mode)) +#define is_chain_u16(p) ((p)->cnt_type == QED_CHAIN_CNT_TYPE_U16) +#define is_chain_u32(p) ((p)->cnt_type == QED_CHAIN_CNT_TYPE_U32) + /* Accessors */ static inline u16 qed_chain_get_prod_idx(struct qed_chain *p_chain) { - return p_chain->prod_idx; + return p_chain->u.chain16.prod_idx; } static inline u16 qed_chain_get_cons_idx(struct qed_chain *p_chain) { - return p_chain->cons_idx; + return p_chain->u.chain16.cons_idx; +} + +static inline u32 qed_chain_get_cons_idx_u32(struct qed_chain *p_chain) +{ + return p_chain->u.chain32.cons_idx; } static inline u16 qed_chain_get_elem_left(struct qed_chain *p_chain) { u16 used; - /* we don't need to trancate upon assignmet, as we assign u32->u16 */ - used = ((u32)0x10000u + (u32)(p_chain->prod_idx)) - - (u32)p_chain->cons_idx; + used = (u16) (((u32)0x10000 + + (u32)p_chain->u.chain16.prod_idx) - + (u32)p_chain->u.chain16.cons_idx); if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR) - used -= p_chain->prod_idx / p_chain->elem_per_page - - p_chain->cons_idx / p_chain->elem_per_page; + used -= p_chain->u.chain16.prod_idx / p_chain->elem_per_page - + p_chain->u.chain16.cons_idx / p_chain->elem_per_page; - return p_chain->capacity - used; + return (u16)(p_chain->capacity - used); } -static inline u8 qed_chain_is_full(struct qed_chain *p_chain) +static inline u32 qed_chain_get_elem_left_u32(struct qed_chain *p_chain) { - return qed_chain_get_elem_left(p_chain) == p_chain->capacity; -} + u32 used; -static inline u8 qed_chain_is_empty(struct qed_chain *p_chain) -{ - return qed_chain_get_elem_left(p_chain) == 0; -} + used = (u32) (((u64)0x100000000ULL + + (u64)p_chain->u.chain32.prod_idx) - + (u64)p_chain->u.chain32.cons_idx); + if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR) + used -= p_chain->u.chain32.prod_idx / p_chain->elem_per_page - + p_chain->u.chain32.cons_idx / p_chain->elem_per_page; -static inline u16 qed_chain_get_elem_per_page( - struct qed_chain *p_chain) -{ - return p_chain->elem_per_page; + return p_chain->capacity - used; } -static inline u16 qed_chain_get_usable_per_page( - struct qed_chain *p_chain) +static inline u16 qed_chain_get_usable_per_page(struct qed_chain *p_chain) { return p_chain->usable_per_page; } -static inline u16 qed_chain_get_unusable_per_page( - struct qed_chain *p_chain) +static inline u16 qed_chain_get_unusable_per_page(struct qed_chain *p_chain) { return p_chain->elem_unusable; } -static inline u16 qed_chain_get_size(struct qed_chain *p_chain) +static inline u32 qed_chain_get_page_cnt(struct qed_chain *p_chain) { - return p_chain->size; + return p_chain->page_cnt; } -static inline dma_addr_t -qed_chain_get_pbl_phys(struct qed_chain *p_chain) +static inline dma_addr_t qed_chain_get_pbl_phys(struct qed_chain *p_chain) { return p_chain->pbl.p_phys_table; } @@ -172,64 +227,62 @@ qed_chain_get_pbl_phys(struct qed_chain *p_chain) */ static inline void qed_chain_advance_page(struct qed_chain *p_chain, - void **p_next_elem, - u16 *idx_to_inc, - u16 *page_to_inc) + void **p_next_elem, void *idx_to_inc, void *page_to_inc) { + struct qed_chain_next *p_next = NULL; + u32 page_index = 0; switch (p_chain->mode) { case QED_CHAIN_MODE_NEXT_PTR: - { - struct qed_chain_next *p_next = *p_next_elem; + p_next = *p_next_elem; *p_next_elem = p_next->next_virt; - *idx_to_inc += p_chain->elem_unusable; + if (is_chain_u16(p_chain)) + *(u16 *)idx_to_inc += p_chain->elem_unusable; + else + *(u32 *)idx_to_inc += p_chain->elem_unusable; break; - } case QED_CHAIN_MODE_SINGLE: *p_next_elem = p_chain->p_virt_addr; break; case QED_CHAIN_MODE_PBL: - /* It is assumed pages are sequential, next element needs - * to change only when passing going back to first from last. - */ - if (++(*page_to_inc) == p_chain->page_cnt) { - *page_to_inc = 0; - *p_next_elem = p_chain->p_virt_addr; + if (is_chain_u16(p_chain)) { + if (++(*(u16 *)page_to_inc) == p_chain->page_cnt) + *(u16 *)page_to_inc = 0; + page_index = *(u16 *)page_to_inc; + } else { + if (++(*(u32 *)page_to_inc) == p_chain->page_cnt) + *(u32 *)page_to_inc = 0; + page_index = *(u32 *)page_to_inc; } + *p_next_elem = p_chain->pbl.pp_virt_addr_tbl[page_index]; } } #define is_unusable_idx(p, idx) \ - (((p)->idx & (p)->elem_per_page_mask) == (p)->usable_per_page) + (((p)->u.chain16.idx & (p)->elem_per_page_mask) == (p)->usable_per_page) + +#define is_unusable_idx_u32(p, idx) \ + (((p)->u.chain32.idx & (p)->elem_per_page_mask) == (p)->usable_per_page) +#define is_unusable_next_idx(p, idx) \ + ((((p)->u.chain16.idx + 1) & (p)->elem_per_page_mask) == \ + (p)->usable_per_page) -#define is_unusable_next_idx(p, idx) \ - ((((p)->idx + 1) & (p)->elem_per_page_mask) == (p)->usable_per_page) +#define is_unusable_next_idx_u32(p, idx) \ + ((((p)->u.chain32.idx + 1) & (p)->elem_per_page_mask) == \ + (p)->usable_per_page) -#define test_ans_skip(p, idx) \ +#define test_and_skip(p, idx) \ do { \ - if (is_unusable_idx(p, idx)) { \ - (p)->idx += (p)->elem_unusable; \ + if (is_chain_u16(p)) { \ + if (is_unusable_idx(p, idx)) \ + (p)->u.chain16.idx += (p)->elem_unusable; \ + } else { \ + if (is_unusable_idx_u32(p, idx)) \ + (p)->u.chain32.idx += (p)->elem_unusable; \ } \ } while (0) -/** - * @brief qed_chain_return_multi_produced - - * - * A chain in which the driver "Produces" elements should use this API - * to indicate previous produced elements are now consumed. - * - * @param p_chain - * @param num - */ -static inline void -qed_chain_return_multi_produced(struct qed_chain *p_chain, - u16 num) -{ - p_chain->cons_idx += num; - test_ans_skip(p_chain, cons_idx); -} - /** * @brief qed_chain_return_produced - * @@ -240,8 +293,11 @@ qed_chain_return_multi_produced(struct qed_chain *p_chain, */ static inline void qed_chain_return_produced(struct qed_chain *p_chain) { - p_chain->cons_idx++; - test_ans_skip(p_chain, cons_idx); + if (is_chain_u16(p_chain)) + p_chain->u.chain16.cons_idx++; + else + p_chain->u.chain32.cons_idx++; + test_and_skip(p_chain, cons_idx); } /** @@ -257,21 +313,33 @@ static inline void qed_chain_return_produced(struct qed_chain *p_chain) */ static inline void *qed_chain_produce(struct qed_chain *p_chain) { - void *ret = NULL; - - if ((p_chain->prod_idx & p_chain->elem_per_page_mask) == - p_chain->next_page_mask) { - qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, - &p_chain->prod_idx, - &p_chain->pbl.prod_page_idx); + void *p_ret = NULL, *p_prod_idx, *p_prod_page_idx; + + if (is_chain_u16(p_chain)) { + if ((p_chain->u.chain16.prod_idx & + p_chain->elem_per_page_mask) == p_chain->next_page_mask) { + p_prod_idx = &p_chain->u.chain16.prod_idx; + p_prod_page_idx = &p_chain->pbl.u.pbl16.prod_page_idx; + qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, + p_prod_idx, p_prod_page_idx); + } + p_chain->u.chain16.prod_idx++; + } else { + if ((p_chain->u.chain32.prod_idx & + p_chain->elem_per_page_mask) == p_chain->next_page_mask) { + p_prod_idx = &p_chain->u.chain32.prod_idx; + p_prod_page_idx = &p_chain->pbl.u.pbl32.prod_page_idx; + qed_chain_advance_page(p_chain, &p_chain->p_prod_elem, + p_prod_idx, p_prod_page_idx); + } + p_chain->u.chain32.prod_idx++; } - ret = p_chain->p_prod_elem; - p_chain->prod_idx++; + p_ret = p_chain->p_prod_elem; p_chain->p_prod_elem = (void *)(((u8 *)p_chain->p_prod_elem) + p_chain->elem_size); - return ret; + return p_ret; } /** @@ -282,9 +350,9 @@ static inline void *qed_chain_produce(struct qed_chain *p_chain) * @param p_chain * @param num * - * @return u16, number of unusable BDs + * @return number of unusable BDs */ -static inline u16 qed_chain_get_capacity(struct qed_chain *p_chain) +static inline u32 qed_chain_get_capacity(struct qed_chain *p_chain) { return p_chain->capacity; } @@ -297,11 +365,13 @@ static inline u16 qed_chain_get_capacity(struct qed_chain *p_chain) * * @param p_chain */ -static inline void -qed_chain_recycle_consumed(struct qed_chain *p_chain) +static inline void qed_chain_recycle_consumed(struct qed_chain *p_chain) { - test_ans_skip(p_chain, prod_idx); - p_chain->prod_idx++; + test_and_skip(p_chain, prod_idx); + if (is_chain_u16(p_chain)) + p_chain->u.chain16.prod_idx++; + else + p_chain->u.chain32.prod_idx++; } /** @@ -316,21 +386,33 @@ qed_chain_recycle_consumed(struct qed_chain *p_chain) */ static inline void *qed_chain_consume(struct qed_chain *p_chain) { - void *ret = NULL; - - if ((p_chain->cons_idx & p_chain->elem_per_page_mask) == - p_chain->next_page_mask) { + void *p_ret = NULL, *p_cons_idx, *p_cons_page_idx; + + if (is_chain_u16(p_chain)) { + if ((p_chain->u.chain16.cons_idx & + p_chain->elem_per_page_mask) == p_chain->next_page_mask) { + p_cons_idx = &p_chain->u.chain16.cons_idx; + p_cons_page_idx = &p_chain->pbl.u.pbl16.cons_page_idx; + qed_chain_advance_page(p_chain, &p_chain->p_cons_elem, + p_cons_idx, p_cons_page_idx); + } + p_chain->u.chain16.cons_idx++; + } else { + if ((p_chain->u.chain32.cons_idx & + p_chain->elem_per_page_mask) == p_chain->next_page_mask) { + p_cons_idx = &p_chain->u.chain32.cons_idx; + p_cons_page_idx = &p_chain->pbl.u.pbl32.cons_page_idx; qed_chain_advance_page(p_chain, &p_chain->p_cons_elem, - &p_chain->cons_idx, - &p_chain->pbl.cons_page_idx); + p_cons_idx, p_cons_page_idx); + } + p_chain->u.chain32.cons_idx++; } - ret = p_chain->p_cons_elem; - p_chain->cons_idx++; + p_ret = p_chain->p_cons_elem; p_chain->p_cons_elem = (void *)(((u8 *)p_chain->p_cons_elem) + p_chain->elem_size); - return ret; + return p_ret; } /** @@ -340,16 +422,33 @@ static inline void *qed_chain_consume(struct qed_chain *p_chain) */ static inline void qed_chain_reset(struct qed_chain *p_chain) { - int i; - - p_chain->prod_idx = 0; - p_chain->cons_idx = 0; - p_chain->p_cons_elem = p_chain->p_virt_addr; - p_chain->p_prod_elem = p_chain->p_virt_addr; + u32 i; + + if (is_chain_u16(p_chain)) { + p_chain->u.chain16.prod_idx = 0; + p_chain->u.chain16.cons_idx = 0; + } else { + p_chain->u.chain32.prod_idx = 0; + p_chain->u.chain32.cons_idx = 0; + } + p_chain->p_cons_elem = p_chain->p_virt_addr; + p_chain->p_prod_elem = p_chain->p_virt_addr; if (p_chain->mode == QED_CHAIN_MODE_PBL) { - p_chain->pbl.prod_page_idx = p_chain->page_cnt - 1; - p_chain->pbl.cons_page_idx = p_chain->page_cnt - 1; + /* Use (page_cnt - 1) as a reset value for the prod/cons page's + * indices, to avoid unnecessary page advancing on the first + * call to qed_chain_produce/consume. Instead, the indices + * will be advanced to page_cnt and then will be wrapped to 0. + */ + u32 reset_val = p_chain->page_cnt - 1; + + if (is_chain_u16(p_chain)) { + p_chain->pbl.u.pbl16.prod_page_idx = (u16)reset_val; + p_chain->pbl.u.pbl16.cons_page_idx = (u16)reset_val; + } else { + p_chain->pbl.u.pbl32.prod_page_idx = reset_val; + p_chain->pbl.u.pbl32.cons_page_idx = reset_val; + } } switch (p_chain->intended_use) { @@ -377,168 +476,184 @@ static inline void qed_chain_reset(struct qed_chain *p_chain) * @param intended_use * @param mode */ -static inline void qed_chain_init(struct qed_chain *p_chain, - void *p_virt_addr, - dma_addr_t p_phys_addr, - u16 page_cnt, - u8 elem_size, - enum qed_chain_use_mode intended_use, - enum qed_chain_mode mode) +static inline void qed_chain_init_params(struct qed_chain *p_chain, + u32 page_cnt, + u8 elem_size, + enum qed_chain_use_mode intended_use, + enum qed_chain_mode mode, + enum qed_chain_cnt_type cnt_type) { /* chain fixed parameters */ - p_chain->p_virt_addr = p_virt_addr; - p_chain->p_phys_addr = p_phys_addr; + p_chain->p_virt_addr = NULL; + p_chain->p_phys_addr = 0; p_chain->elem_size = elem_size; - p_chain->page_cnt = page_cnt; + p_chain->intended_use = intended_use; p_chain->mode = mode; + p_chain->cnt_type = cnt_type; - p_chain->intended_use = intended_use; p_chain->elem_per_page = ELEMS_PER_PAGE(elem_size); - p_chain->usable_per_page = - USABLE_ELEMS_PER_PAGE(elem_size, mode); - p_chain->capacity = p_chain->usable_per_page * page_cnt; - p_chain->size = p_chain->elem_per_page * page_cnt; + p_chain->usable_per_page = USABLE_ELEMS_PER_PAGE(elem_size, mode); p_chain->elem_per_page_mask = p_chain->elem_per_page - 1; - p_chain->elem_unusable = UNUSABLE_ELEMS_PER_PAGE(elem_size, mode); - p_chain->next_page_mask = (p_chain->usable_per_page & p_chain->elem_per_page_mask); - if (mode == QED_CHAIN_MODE_NEXT_PTR) { - struct qed_chain_next *p_next; - u16 i; - - for (i = 0; i < page_cnt - 1; i++) { - /* Increment mem_phy to the next page. */ - p_phys_addr += QED_CHAIN_PAGE_SIZE; - - /* Initialize the physical address of the next page. */ - p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + - elem_size * - p_chain-> - usable_per_page); - - p_next->next_phys.lo = DMA_LO_LE(p_phys_addr); - p_next->next_phys.hi = DMA_HI_LE(p_phys_addr); - - /* Initialize the virtual address of the next page. */ - p_next->next_virt = (void *)((u8 *)p_virt_addr + - QED_CHAIN_PAGE_SIZE); - - /* Move to the next page. */ - p_virt_addr = p_next->next_virt; - } - - /* Last page's next should point to beginning of the chain */ - p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + - elem_size * - p_chain->usable_per_page); + p_chain->page_cnt = page_cnt; + p_chain->capacity = p_chain->usable_per_page * page_cnt; + p_chain->size = p_chain->elem_per_page * page_cnt; - p_next->next_phys.lo = DMA_LO_LE(p_chain->p_phys_addr); - p_next->next_phys.hi = DMA_HI_LE(p_chain->p_phys_addr); - p_next->next_virt = p_chain->p_virt_addr; - } - qed_chain_reset(p_chain); + p_chain->pbl.p_phys_table = 0; + p_chain->pbl.p_virt_table = NULL; + p_chain->pbl.pp_virt_addr_tbl = NULL; } /** - * @brief qed_chain_pbl_init - Initalizes a basic pbl chain - * struct + * @brief qed_chain_init_mem - + * + * Initalizes a basic chain struct with its chain buffers + * * @param p_chain * @param p_virt_addr virtual address of allocated buffer's beginning * @param p_phys_addr physical address of allocated buffer's beginning - * @param page_cnt number of pages in the allocated buffer - * @param elem_size size of each element in the chain - * @param use_mode - * @param p_phys_pbl pointer to a pre-allocated side table - * which will hold physical page addresses. - * @param p_virt_pbl pointer to a pre allocated side table - * which will hold virtual page addresses. + * */ -static inline void -qed_chain_pbl_init(struct qed_chain *p_chain, - void *p_virt_addr, - dma_addr_t p_phys_addr, - u16 page_cnt, - u8 elem_size, - enum qed_chain_use_mode use_mode, - dma_addr_t p_phys_pbl, - dma_addr_t *p_virt_pbl) +static inline void qed_chain_init_mem(struct qed_chain *p_chain, + void *p_virt_addr, dma_addr_t p_phys_addr) { - dma_addr_t *p_pbl_dma = p_virt_pbl; - int i; - - qed_chain_init(p_chain, p_virt_addr, p_phys_addr, page_cnt, - elem_size, use_mode, QED_CHAIN_MODE_PBL); + p_chain->p_virt_addr = p_virt_addr; + p_chain->p_phys_addr = p_phys_addr; +} +/** + * @brief qed_chain_init_pbl_mem - + * + * Initalizes a basic chain struct with its pbl buffers + * + * @param p_chain + * @param p_virt_pbl pointer to a pre allocated side table which will hold + * virtual page addresses. + * @param p_phys_pbl pointer to a pre-allocated side table which will hold + * physical page addresses. + * @param pp_virt_addr_tbl + * pointer to a pre-allocated side table which will hold + * the virtual addresses of the chain pages. + * + */ +static inline void qed_chain_init_pbl_mem(struct qed_chain *p_chain, + void *p_virt_pbl, + dma_addr_t p_phys_pbl, + void **pp_virt_addr_tbl) +{ p_chain->pbl.p_phys_table = p_phys_pbl; p_chain->pbl.p_virt_table = p_virt_pbl; - - /* Fill the PBL with physical addresses*/ - for (i = 0; i < page_cnt; i++) { - *p_pbl_dma = p_phys_addr; - p_phys_addr += QED_CHAIN_PAGE_SIZE; - p_pbl_dma++; - } + p_chain->pbl.pp_virt_addr_tbl = pp_virt_addr_tbl; } /** - * @brief qed_chain_set_prod - sets the prod to the given - * value + * @brief qed_chain_init_next_ptr_elem - + * + * Initalizes a next pointer element + * + * @param p_chain + * @param p_virt_curr virtual address of a chain page of which the next + * pointer element is initialized + * @param p_virt_next virtual address of the next chain page + * @param p_phys_next physical address of the next chain page * - * @param prod_idx - * @param p_prod_elem */ -static inline void qed_chain_set_prod(struct qed_chain *p_chain, - u16 prod_idx, - void *p_prod_elem) +static inline void +qed_chain_init_next_ptr_elem(struct qed_chain *p_chain, + void *p_virt_curr, + void *p_virt_next, dma_addr_t p_phys_next) { - p_chain->prod_idx = prod_idx; - p_chain->p_prod_elem = p_prod_elem; + struct qed_chain_next *p_next; + u32 size; + + size = p_chain->elem_size * p_chain->usable_per_page; + p_next = (struct qed_chain_next *)((u8 *)p_virt_curr + size); + + DMA_REGPAIR_LE(p_next->next_phys, p_phys_next); + + p_next->next_virt = p_virt_next; } /** - * @brief qed_chain_get_elem - + * @brief qed_chain_get_last_elem - * - * get a pointer to an element represented by absolute idx + * Returns a pointer to the last element of the chain * * @param p_chain - * @assumption p_chain->size is a power of 2 * - * @return void*, a pointer to next element + * @return void* */ -static inline void *qed_chain_sge_get_elem(struct qed_chain *p_chain, - u16 idx) +static inline void *qed_chain_get_last_elem(struct qed_chain *p_chain) { - void *ret = NULL; - - if (idx >= p_chain->size) - return NULL; + struct qed_chain_next *p_next = NULL; + void *p_virt_addr = NULL; + u32 size, last_page_idx; - ret = (u8 *)p_chain->p_virt_addr + p_chain->elem_size * idx; + if (!p_chain->p_virt_addr) + goto out; - return ret; + switch (p_chain->mode) { + case QED_CHAIN_MODE_NEXT_PTR: + size = p_chain->elem_size * p_chain->usable_per_page; + p_virt_addr = p_chain->p_virt_addr; + p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + size); + while (p_next->next_virt != p_chain->p_virt_addr) { + p_virt_addr = p_next->next_virt; + p_next = (struct qed_chain_next *)((u8 *)p_virt_addr + + size); + } + break; + case QED_CHAIN_MODE_SINGLE: + p_virt_addr = p_chain->p_virt_addr; + break; + case QED_CHAIN_MODE_PBL: + last_page_idx = p_chain->page_cnt - 1; + p_virt_addr = p_chain->pbl.pp_virt_addr_tbl[last_page_idx]; + break; + } + /* p_virt_addr points at this stage to the last page of the chain */ + size = p_chain->elem_size * (p_chain->usable_per_page - 1); + p_virt_addr = (u8 *)p_virt_addr + size; +out: + return p_virt_addr; } /** - * @brief qed_chain_sge_inc_cons_prod + * @brief qed_chain_set_prod - sets the prod to the given value * - * for sge chains, producer isn't increased serially, the ring - * is expected to be full at all times. Once elements are - * consumed, they are immediately produced. + * @param prod_idx + * @param p_prod_elem + */ +static inline void qed_chain_set_prod(struct qed_chain *p_chain, + u32 prod_idx, void *p_prod_elem) +{ + if (is_chain_u16(p_chain)) + p_chain->u.chain16.prod_idx = (u16) prod_idx; + else + p_chain->u.chain32.prod_idx = prod_idx; + p_chain->p_prod_elem = p_prod_elem; +} + +/** + * @brief qed_chain_pbl_zero_mem - set chain memory to 0 * * @param p_chain - * @param cnt - * - * @return inline void */ -static inline void -qed_chain_sge_inc_cons_prod(struct qed_chain *p_chain, - u16 cnt) +static inline void qed_chain_pbl_zero_mem(struct qed_chain *p_chain) { - p_chain->prod_idx += cnt; - p_chain->cons_idx += cnt; + u32 i, page_cnt; + + if (p_chain->mode != QED_CHAIN_MODE_PBL) + return; + + page_cnt = qed_chain_get_page_cnt(p_chain); + + for (i = 0; i < page_cnt; i++) + memset(p_chain->pbl.pp_virt_addr_tbl[i], 0, + QED_CHAIN_PAGE_SIZE); } #endif diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index 4c29439f54bf..15efccfdc46e 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -325,7 +325,8 @@ struct qed_common_ops { int (*chain_alloc)(struct qed_dev *cdev, enum qed_chain_use_mode intended_use, enum qed_chain_mode mode, - u16 num_elems, + enum qed_chain_cnt_type cnt_type, + u32 num_elems, size_t elem_size, struct qed_chain *p_chain); -- cgit v1.2.3 From 7a9b6b8f6e4c52b31830d32570c2a226e27651f9 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Fri, 3 Jun 2016 14:35:33 +0300 Subject: qed: Add common HSI for new protocols This adds the qed portion of the RoCE & iSCSI firmware HSI, as well as adding several new common HSI files which would be required by both qed and qed* protocols. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 3008 +++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_sp.h | 26 + include/linux/qed/common_hsi.h | 190 +- include/linux/qed/iscsi_common.h | 1439 ++++++++++++++ include/linux/qed/rdma_common.h | 44 + include/linux/qed/roce_common.h | 17 + include/linux/qed/storage_common.h | 91 + include/linux/qed/tcp_common.h | 226 +++ 8 files changed, 5040 insertions(+), 1 deletion(-) create mode 100644 include/linux/qed/iscsi_common.h create mode 100644 include/linux/qed/rdma_common.h create mode 100644 include/linux/qed/roce_common.h create mode 100644 include/linux/qed/storage_common.h create mode 100644 include/linux/qed/tcp_common.h (limited to 'include/linux') diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index d104ca790977..4cd70bfd929f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -17,7 +17,12 @@ #include #include #include +#include +#include #include +#include +#include +#include struct qed_hwfn; struct qed_ptt; @@ -3631,6 +3636,3009 @@ struct vport_update_ramrod_data { struct eth_vport_rss_config rss_config; }; +struct mstorm_rdma_task_st_ctx { + struct regpair temp[4]; +}; + +struct rdma_close_func_ramrod_data { + u8 cnq_start_offset; + u8 num_cnqs; + u8 vf_id; + u8 vf_valid; + u8 reserved[4]; +}; + +struct rdma_cnq_params { + __le16 sb_num; + u8 sb_index; + u8 num_pbl_pages; + __le32 reserved; + struct regpair pbl_base_addr; + __le16 queue_zone_num; + u8 reserved1[6]; +}; + +struct rdma_create_cq_ramrod_data { + struct regpair cq_handle; + struct regpair pbl_addr; + __le32 max_cqes; + __le16 pbl_num_pages; + __le16 dpi; + u8 is_two_level_pbl; + u8 cnq_id; + u8 pbl_log_page_size; + u8 toggle_bit; + __le16 int_timeout; + __le16 reserved1; +}; + +struct rdma_deregister_tid_ramrod_data { + __le32 itid; + __le32 reserved; +}; + +struct rdma_destroy_cq_output_params { + __le16 cnq_num; + __le16 reserved0; + __le32 reserved1; +}; + +struct rdma_destroy_cq_ramrod_data { + struct regpair output_params_addr; +}; + +enum rdma_event_opcode { + RDMA_EVENT_UNUSED, + RDMA_EVENT_FUNC_INIT, + RDMA_EVENT_FUNC_CLOSE, + RDMA_EVENT_REGISTER_MR, + RDMA_EVENT_DEREGISTER_MR, + RDMA_EVENT_CREATE_CQ, + RDMA_EVENT_RESIZE_CQ, + RDMA_EVENT_DESTROY_CQ, + RDMA_EVENT_CREATE_SRQ, + RDMA_EVENT_MODIFY_SRQ, + RDMA_EVENT_DESTROY_SRQ, + MAX_RDMA_EVENT_OPCODE +}; + +enum rdma_fw_return_code { + RDMA_RETURN_OK = 0, + RDMA_RETURN_REGISTER_MR_BAD_STATE_ERR, + RDMA_RETURN_DEREGISTER_MR_BAD_STATE_ERR, + RDMA_RETURN_RESIZE_CQ_ERR, + RDMA_RETURN_NIG_DRAIN_REQ, + MAX_RDMA_FW_RETURN_CODE +}; + +struct rdma_init_func_hdr { + u8 cnq_start_offset; + u8 num_cnqs; + u8 cq_ring_mode; + u8 cnp_vlan_priority; + __le32 cnp_send_timeout; + u8 cnp_dscp; + u8 vf_id; + u8 vf_valid; + u8 reserved[5]; +}; + +struct rdma_init_func_ramrod_data { + struct rdma_init_func_hdr params_header; + struct rdma_cnq_params cnq_params[NUM_OF_GLOBAL_QUEUES]; +}; + +enum rdma_ramrod_cmd_id { + RDMA_RAMROD_UNUSED, + RDMA_RAMROD_FUNC_INIT, + RDMA_RAMROD_FUNC_CLOSE, + RDMA_RAMROD_REGISTER_MR, + RDMA_RAMROD_DEREGISTER_MR, + RDMA_RAMROD_CREATE_CQ, + RDMA_RAMROD_RESIZE_CQ, + RDMA_RAMROD_DESTROY_CQ, + RDMA_RAMROD_CREATE_SRQ, + RDMA_RAMROD_MODIFY_SRQ, + RDMA_RAMROD_DESTROY_SRQ, + MAX_RDMA_RAMROD_CMD_ID +}; + +struct rdma_register_tid_ramrod_data { + __le32 flags; +#define RDMA_REGISTER_TID_RAMROD_DATA_MAX_ID_MASK 0x3FFFF +#define RDMA_REGISTER_TID_RAMROD_DATA_MAX_ID_SHIFT 0 +#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_MASK 0x1F +#define RDMA_REGISTER_TID_RAMROD_DATA_PAGE_SIZE_LOG_SHIFT 18 +#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_TWO_LEVEL_PBL_SHIFT 23 +#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_ZERO_BASED_SHIFT 24 +#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_PHY_MR_SHIFT 25 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_READ_SHIFT 26 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_WRITE_SHIFT 27 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_REMOTE_ATOMIC_SHIFT 28 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_WRITE_SHIFT 29 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_LOCAL_READ_SHIFT 30 +#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_ENABLE_MW_BIND_SHIFT 31 + u8 flags1; +#define RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG_MASK 0x1F +#define RDMA_REGISTER_TID_RAMROD_DATA_PBL_PAGE_SIZE_LOG_SHIFT 0 +#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_MASK 0x7 +#define RDMA_REGISTER_TID_RAMROD_DATA_TID_TYPE_SHIFT 5 + u8 flags2; +#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_DMA_MR_SHIFT 0 +#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_MASK 0x1 +#define RDMA_REGISTER_TID_RAMROD_DATA_DIF_ON_HOST_FLG_SHIFT 1 +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_MASK 0x3F +#define RDMA_REGISTER_TID_RAMROD_DATA_RESERVED1_SHIFT 2 + u8 key; + u8 length_hi; + u8 vf_id; + u8 vf_valid; + __le16 pd; + __le32 length_lo; + __le32 itid; + __le32 reserved2; + struct regpair va; + struct regpair pbl_base; + struct regpair dif_error_addr; + struct regpair dif_runt_addr; + __le32 reserved3[2]; +}; + +struct rdma_resize_cq_output_params { + __le32 old_cq_cons; + __le32 old_cq_prod; +}; + +struct rdma_resize_cq_ramrod_data { + u8 flags; +#define RDMA_RESIZE_CQ_RAMROD_DATA_TOGGLE_BIT_MASK 0x1 +#define RDMA_RESIZE_CQ_RAMROD_DATA_TOGGLE_BIT_SHIFT 0 +#define RDMA_RESIZE_CQ_RAMROD_DATA_IS_TWO_LEVEL_PBL_MASK 0x1 +#define RDMA_RESIZE_CQ_RAMROD_DATA_IS_TWO_LEVEL_PBL_SHIFT 1 +#define RDMA_RESIZE_CQ_RAMROD_DATA_RESERVED_MASK 0x3F +#define RDMA_RESIZE_CQ_RAMROD_DATA_RESERVED_SHIFT 2 + u8 pbl_log_page_size; + __le16 pbl_num_pages; + __le32 max_cqes; + struct regpair pbl_addr; + struct regpair output_params_addr; +}; + +struct rdma_srq_context { + struct regpair temp[8]; +}; + +struct rdma_srq_create_ramrod_data { + struct regpair pbl_base_addr; + __le16 pages_in_srq_pbl; + __le16 pd_id; + struct rdma_srq_id srq_id; + __le16 page_size; + __le16 reserved1; + __le32 reserved2; + struct regpair producers_addr; +}; + +struct rdma_srq_destroy_ramrod_data { + struct rdma_srq_id srq_id; + __le32 reserved; +}; + +struct rdma_srq_modify_ramrod_data { + struct rdma_srq_id srq_id; + __le32 wqe_limit; +}; + +struct ystorm_rdma_task_st_ctx { + struct regpair temp[4]; +}; + +struct ystorm_rdma_task_ag_ctx { + u8 reserved; + u8 byte1; + __le16 msem_ctx_upd_seq; + u8 flags0; +#define YSTORM_RDMA_TASK_AG_CTX_CONNECTION_TYPE_MASK 0xF +#define YSTORM_RDMA_TASK_AG_CTX_CONNECTION_TYPE_SHIFT 0 +#define YSTORM_RDMA_TASK_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_EXIST_IN_QM0_SHIFT 4 +#define YSTORM_RDMA_TASK_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_BIT1_SHIFT 5 +#define YSTORM_RDMA_TASK_AG_CTX_VALID_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_VALID_SHIFT 6 +#define YSTORM_RDMA_TASK_AG_CTX_BIT3_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_BIT3_SHIFT 7 + u8 flags1; +#define YSTORM_RDMA_TASK_AG_CTX_CF0_MASK 0x3 +#define YSTORM_RDMA_TASK_AG_CTX_CF0_SHIFT 0 +#define YSTORM_RDMA_TASK_AG_CTX_CF1_MASK 0x3 +#define YSTORM_RDMA_TASK_AG_CTX_CF1_SHIFT 2 +#define YSTORM_RDMA_TASK_AG_CTX_CF2SPECIAL_MASK 0x3 +#define YSTORM_RDMA_TASK_AG_CTX_CF2SPECIAL_SHIFT 4 +#define YSTORM_RDMA_TASK_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_CF0EN_SHIFT 6 +#define YSTORM_RDMA_TASK_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_CF1EN_SHIFT 7 + u8 flags2; +#define YSTORM_RDMA_TASK_AG_CTX_BIT4_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_BIT4_SHIFT 0 +#define YSTORM_RDMA_TASK_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_RULE0EN_SHIFT 1 +#define YSTORM_RDMA_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_RULE1EN_SHIFT 2 +#define YSTORM_RDMA_TASK_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_RULE2EN_SHIFT 3 +#define YSTORM_RDMA_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_RULE3EN_SHIFT 4 +#define YSTORM_RDMA_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_RULE4EN_SHIFT 5 +#define YSTORM_RDMA_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_RULE5EN_SHIFT 6 +#define YSTORM_RDMA_TASK_AG_CTX_RULE6EN_MASK 0x1 +#define YSTORM_RDMA_TASK_AG_CTX_RULE6EN_SHIFT 7 + u8 key; + __le32 mw_cnt; + u8 ref_cnt_seq; + u8 ctx_upd_seq; + __le16 dif_flags; + __le16 tx_ref_count; + __le16 last_used_ltid; + __le16 parent_mr_lo; + __le16 parent_mr_hi; + __le32 fbo_lo; + __le32 fbo_hi; +}; + +struct mstorm_rdma_task_ag_ctx { + u8 reserved; + u8 byte1; + __le16 icid; + u8 flags0; +#define MSTORM_RDMA_TASK_AG_CTX_CONNECTION_TYPE_MASK 0xF +#define MSTORM_RDMA_TASK_AG_CTX_CONNECTION_TYPE_SHIFT 0 +#define MSTORM_RDMA_TASK_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_EXIST_IN_QM0_SHIFT 4 +#define MSTORM_RDMA_TASK_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_BIT1_SHIFT 5 +#define MSTORM_RDMA_TASK_AG_CTX_BIT2_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_BIT2_SHIFT 6 +#define MSTORM_RDMA_TASK_AG_CTX_BIT3_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_BIT3_SHIFT 7 + u8 flags1; +#define MSTORM_RDMA_TASK_AG_CTX_CF0_MASK 0x3 +#define MSTORM_RDMA_TASK_AG_CTX_CF0_SHIFT 0 +#define MSTORM_RDMA_TASK_AG_CTX_CF1_MASK 0x3 +#define MSTORM_RDMA_TASK_AG_CTX_CF1_SHIFT 2 +#define MSTORM_RDMA_TASK_AG_CTX_CF2_MASK 0x3 +#define MSTORM_RDMA_TASK_AG_CTX_CF2_SHIFT 4 +#define MSTORM_RDMA_TASK_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_CF0EN_SHIFT 6 +#define MSTORM_RDMA_TASK_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_CF1EN_SHIFT 7 + u8 flags2; +#define MSTORM_RDMA_TASK_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_CF2EN_SHIFT 0 +#define MSTORM_RDMA_TASK_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_RULE0EN_SHIFT 1 +#define MSTORM_RDMA_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_RULE1EN_SHIFT 2 +#define MSTORM_RDMA_TASK_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_RULE2EN_SHIFT 3 +#define MSTORM_RDMA_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_RULE3EN_SHIFT 4 +#define MSTORM_RDMA_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_RULE4EN_SHIFT 5 +#define MSTORM_RDMA_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_RULE5EN_SHIFT 6 +#define MSTORM_RDMA_TASK_AG_CTX_RULE6EN_MASK 0x1 +#define MSTORM_RDMA_TASK_AG_CTX_RULE6EN_SHIFT 7 + u8 key; + __le32 mw_cnt; + u8 ref_cnt_seq; + u8 ctx_upd_seq; + __le16 dif_flags; + __le16 tx_ref_count; + __le16 last_used_ltid; + __le16 parent_mr_lo; + __le16 parent_mr_hi; + __le32 fbo_lo; + __le32 fbo_hi; +}; + +struct ustorm_rdma_task_st_ctx { + struct regpair temp[2]; +}; + +struct ustorm_rdma_task_ag_ctx { + u8 reserved; + u8 byte1; + __le16 icid; + u8 flags0; +#define USTORM_RDMA_TASK_AG_CTX_CONNECTION_TYPE_MASK 0xF +#define USTORM_RDMA_TASK_AG_CTX_CONNECTION_TYPE_SHIFT 0 +#define USTORM_RDMA_TASK_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_EXIST_IN_QM0_SHIFT 4 +#define USTORM_RDMA_TASK_AG_CTX_DIF_RUNT_VALID_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_DIF_RUNT_VALID_SHIFT 5 +#define USTORM_RDMA_TASK_AG_CTX_DIF_WRITE_RESULT_CF_MASK 0x3 +#define USTORM_RDMA_TASK_AG_CTX_DIF_WRITE_RESULT_CF_SHIFT 6 + u8 flags1; +#define USTORM_RDMA_TASK_AG_CTX_DIF_RESULT_TOGGLE_BIT_MASK 0x3 +#define USTORM_RDMA_TASK_AG_CTX_DIF_RESULT_TOGGLE_BIT_SHIFT 0 +#define USTORM_RDMA_TASK_AG_CTX_DIF_TX_IO_FLG_MASK 0x3 +#define USTORM_RDMA_TASK_AG_CTX_DIF_TX_IO_FLG_SHIFT 2 +#define USTORM_RDMA_TASK_AG_CTX_CF3_MASK 0x3 +#define USTORM_RDMA_TASK_AG_CTX_CF3_SHIFT 4 +#define USTORM_RDMA_TASK_AG_CTX_DIF_ERROR_CF_MASK 0x3 +#define USTORM_RDMA_TASK_AG_CTX_DIF_ERROR_CF_SHIFT 6 + u8 flags2; +#define USTORM_RDMA_TASK_AG_CTX_DIF_WRITE_RESULT_CF_EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_DIF_WRITE_RESULT_CF_EN_SHIFT 0 +#define USTORM_RDMA_TASK_AG_CTX_RESERVED2_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RESERVED2_SHIFT 1 +#define USTORM_RDMA_TASK_AG_CTX_RESERVED3_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RESERVED3_SHIFT 2 +#define USTORM_RDMA_TASK_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_RDMA_TASK_AG_CTX_DIF_ERROR_CF_EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_DIF_ERROR_CF_EN_SHIFT 4 +#define USTORM_RDMA_TASK_AG_CTX_RULE0EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RULE0EN_SHIFT 5 +#define USTORM_RDMA_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RULE1EN_SHIFT 6 +#define USTORM_RDMA_TASK_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RULE2EN_SHIFT 7 + u8 flags3; +#define USTORM_RDMA_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RULE3EN_SHIFT 0 +#define USTORM_RDMA_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RULE4EN_SHIFT 1 +#define USTORM_RDMA_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RULE5EN_SHIFT 2 +#define USTORM_RDMA_TASK_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_RDMA_TASK_AG_CTX_RULE6EN_SHIFT 3 +#define USTORM_RDMA_TASK_AG_CTX_DIF_ERROR_TYPE_MASK 0xF +#define USTORM_RDMA_TASK_AG_CTX_DIF_ERROR_TYPE_SHIFT 4 + __le32 dif_err_intervals; + __le32 dif_error_1st_interval; + __le32 reg2; + __le32 dif_runt_value; + __le32 reg4; + __le32 reg5; +}; + +struct rdma_task_context { + struct ystorm_rdma_task_st_ctx ystorm_st_context; + struct ystorm_rdma_task_ag_ctx ystorm_ag_context; + struct tdif_task_context tdif_context; + struct mstorm_rdma_task_ag_ctx mstorm_ag_context; + struct mstorm_rdma_task_st_ctx mstorm_st_context; + struct rdif_task_context rdif_context; + struct ustorm_rdma_task_st_ctx ustorm_st_context; + struct regpair ustorm_st_padding[2]; + struct ustorm_rdma_task_ag_ctx ustorm_ag_context; +}; + +enum rdma_tid_type { + RDMA_TID_REGISTERED_MR, + RDMA_TID_FMR, + RDMA_TID_MW_TYPE1, + RDMA_TID_MW_TYPE2A, + MAX_RDMA_TID_TYPE +}; + +struct mstorm_rdma_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_RDMA_CONN_AG_CTX_BIT0_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_RDMA_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_RDMA_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_RDMA_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_RDMA_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_RDMA_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + +struct tstorm_rdma_conn_ag_ctx { + u8 reserved0; + u8 byte1; + u8 flags0; +#define TSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_RDMA_CONN_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_RDMA_CONN_AG_CTX_CF0_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF0_SHIFT 6 + u8 flags1; +#define TSTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 6 + u8 flags2; +#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_CF6_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_CF7_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_CF8_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF8_SHIFT 6 + u8 flags3; +#define TSTORM_RDMA_CONN_AG_CTX_CF9_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_CF10_MASK 0x3 +#define TSTORM_RDMA_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_SHIFT 7 + u8 flags4; +#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_SHIFT 1 +#define TSTORM_RDMA_CONN_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_RDMA_CONN_AG_CTX_CF8EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_CF9EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_RDMA_CONN_AG_CTX_CF10EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_RDMA_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_RDMA_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_RDMA_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_RDMA_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define TSTORM_RDMA_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_RDMA_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_RDMA_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 byte2; + u8 byte3; + __le16 word0; + u8 byte4; + u8 byte5; + __le16 word1; + __le16 word2; + __le16 word3; + __le32 reg9; + __le32 reg10; +}; + +struct tstorm_rdma_task_ag_ctx { + u8 byte0; + u8 byte1; + __le16 word0; + u8 flags0; +#define TSTORM_RDMA_TASK_AG_CTX_NIBBLE0_MASK 0xF +#define TSTORM_RDMA_TASK_AG_CTX_NIBBLE0_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_BIT0_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT0_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT1_SHIFT 5 +#define TSTORM_RDMA_TASK_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT2_SHIFT 6 +#define TSTORM_RDMA_TASK_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT3_SHIFT 7 + u8 flags1; +#define TSTORM_RDMA_TASK_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT4_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_BIT5_SHIFT 1 +#define TSTORM_RDMA_TASK_AG_CTX_CF0_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF0_SHIFT 2 +#define TSTORM_RDMA_TASK_AG_CTX_CF1_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF1_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_CF2_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF2_SHIFT 6 + u8 flags2; +#define TSTORM_RDMA_TASK_AG_CTX_CF3_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF3_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_CF4_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF4_SHIFT 2 +#define TSTORM_RDMA_TASK_AG_CTX_CF5_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF5_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_CF6_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF6_SHIFT 6 + u8 flags3; +#define TSTORM_RDMA_TASK_AG_CTX_CF7_MASK 0x3 +#define TSTORM_RDMA_TASK_AG_CTX_CF7_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF0EN_SHIFT 2 +#define TSTORM_RDMA_TASK_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF1EN_SHIFT 3 +#define TSTORM_RDMA_TASK_AG_CTX_CF2EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF2EN_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_CF3EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF3EN_SHIFT 5 +#define TSTORM_RDMA_TASK_AG_CTX_CF4EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF4EN_SHIFT 6 +#define TSTORM_RDMA_TASK_AG_CTX_CF5EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF5EN_SHIFT 7 + u8 flags4; +#define TSTORM_RDMA_TASK_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF6EN_SHIFT 0 +#define TSTORM_RDMA_TASK_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_CF7EN_SHIFT 1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE0EN_SHIFT 2 +#define TSTORM_RDMA_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE1EN_SHIFT 3 +#define TSTORM_RDMA_TASK_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE2EN_SHIFT 4 +#define TSTORM_RDMA_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE3EN_SHIFT 5 +#define TSTORM_RDMA_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE4EN_SHIFT 6 +#define TSTORM_RDMA_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_RDMA_TASK_AG_CTX_RULE5EN_SHIFT 7 + u8 byte2; + __le16 word1; + __le32 reg0; + u8 byte3; + u8 byte4; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg1; + __le32 reg2; +}; + +struct ustorm_rdma_conn_ag_ctx { + u8 reserved; + u8 byte1; + u8 flags0; +#define USTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define USTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 2 +#define USTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_RDMA_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_SHIFT 2 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_SHIFT 4 +#define USTORM_RDMA_CONN_AG_CTX_CF6_MASK 0x3 +#define USTORM_RDMA_CONN_AG_CTX_CF6_SHIFT 6 + u8 flags2; +#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 0 +#define USTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_RDMA_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_SE_CF_EN_SHIFT 4 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CQ_ARM_CF_EN_SHIFT 5 +#define USTORM_RDMA_CONN_AG_CTX_CF6EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_RDMA_CONN_AG_CTX_CQ_SE_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CQ_SE_EN_SHIFT 7 + u8 flags3; +#define USTORM_RDMA_CONN_AG_CTX_CQ_EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_CQ_EN_SHIFT 0 +#define USTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_RDMA_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_RDMA_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_RDMA_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_RDMA_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_RDMA_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 conn_dpi; + __le16 word1; + __le32 cq_cons; + __le32 cq_se_prod; + __le32 cq_prod; + __le32 reg3; + __le16 int_timeout; + __le16 word3; +}; + +struct xstorm_roce_conn_ag_ctx_dq_ext_ld_part { + u8 reserved0; + u8 state; + u8 flags0; +#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM0_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM0_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT1_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT1_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT2_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT2_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM3_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_EXIST_IN_QM3_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT4_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT4_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT5_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT5_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT6_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT6_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT7_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT7_SHIFT 7 + u8 flags1; +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT8_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT8_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT9_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT9_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT10_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT10_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT11_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT11_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT12_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT12_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT13_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT13_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT14_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT14_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_YSTORM_FLUSH_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_YSTORM_FLUSH_SHIFT 7 + u8 flags2; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3_SHIFT 6 + u8 flags3; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_SHIFT 6 + u8 flags4; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11_SHIFT 6 + u8 flags5; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15_SHIFT 6 + u8 flags6; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19_SHIFT 6 + u8 flags7; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF0EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF2EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF3EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF4EN_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF5EN_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF6EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_FLUSH_Q0_CF_EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF8EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF10EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF11EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF12EN_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF13EN_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF14EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF15EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF16EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF18EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF19EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF20EN_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF21EN_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_SLOW_PATH_EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE0EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE0EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE1EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE1EN_SHIFT 7 + u8 flags11; +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE2EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE2EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE3EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE3EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE4EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE4EN_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE5EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE5EN_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE6EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE6EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE7EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE7EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED1_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED1_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE9EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE10EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE10EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE11EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE11EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED2_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED2_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED3_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED3_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE14EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE14EN_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE15EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE15EN_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE16EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE16EN_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE17EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE18EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE18EN_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE19EN_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RULE19EN_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED4_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED4_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED5_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED5_SHIFT 3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED6_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED6_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED7_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED7_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED8_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED8_SHIFT 6 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED9_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORMROCECONNAGCTXDQEXTLDPART_MIGRATION_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_MIGRATION_SHIFT 0 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT17_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_BIT17_SHIFT 1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_DPM_PORT_NUM_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_DPM_PORT_NUM_SHIFT 2 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RESERVED_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_RESERVED_SHIFT 4 +#define XSTORMROCECONNAGCTXDQEXTLDPART_ROCE_EDPM_ENABLE_MASK 0x1 +#define XSTORMROCECONNAGCTXDQEXTLDPART_ROCE_EDPM_ENABLE_SHIFT 5 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23_MASK 0x3 +#define XSTORMROCECONNAGCTXDQEXTLDPART_CF23_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le16 word5; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 snd_nxt_psn; + __le32 reg4; +}; + +struct xstorm_rdma_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define XSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT2_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT2_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_RDMA_CONN_AG_CTX_BIT4_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT4_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_BIT5_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT5_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_BIT6_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT6_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_BIT7_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT7_SHIFT 7 + u8 flags1; +#define XSTORM_RDMA_CONN_AG_CTX_BIT8_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT8_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_BIT9_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT9_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT10_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT10_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_RDMA_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_BIT14_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT14_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_YSTORM_FLUSH_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_YSTORM_FLUSH_SHIFT 7 + u8 flags2; +#define XSTORM_RDMA_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_CF3_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF3_SHIFT 6 + u8 flags3; +#define XSTORM_RDMA_CONN_AG_CTX_CF4_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF5_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_CF6_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 6 + u8 flags4; +#define XSTORM_RDMA_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_RDMA_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_CF14_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF14_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_CF15_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF15_SHIFT 6 + u8 flags6; +#define XSTORM_RDMA_CONN_AG_CTX_CF16_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF16_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF17_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF17_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_CF18_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF18_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_CF19_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF19_SHIFT 6 + u8 flags7; +#define XSTORM_RDMA_CONN_AG_CTX_CF20_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF20_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF21_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF21_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF3EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF3EN_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_CF4EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_CF5EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_RDMA_CONN_AG_CTX_CF6EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_RDMA_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_RDMA_CONN_AG_CTX_CF14EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF14EN_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_CF15EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_CF16EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF16EN_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_CF17EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORM_RDMA_CONN_AG_CTX_CF18EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF18EN_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_CF19EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF19EN_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_CF20EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF20EN_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_CF21EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF21EN_SHIFT 3 +#define XSTORM_RDMA_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_CF23EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_CF23EN_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE0EN_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE1EN_SHIFT 7 + u8 flags11; +#define XSTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_RDMA_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_RDMA_CONN_AG_CTX_RULE10EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE10EN_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_RULE11EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_RDMA_CONN_AG_CTX_RULE14EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE14EN_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_RULE16EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_RULE17EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORM_RDMA_CONN_AG_CTX_RULE18EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE18EN_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_RULE19EN_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RULE19EN_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_RDMA_CONN_AG_CTX_MIGRATION_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_MIGRATION_SHIFT 0 +#define XSTORM_RDMA_CONN_AG_CTX_BIT17_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_BIT17_SHIFT 1 +#define XSTORM_RDMA_CONN_AG_CTX_DPM_PORT_NUM_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_DPM_PORT_NUM_SHIFT 2 +#define XSTORM_RDMA_CONN_AG_CTX_RESERVED_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_RESERVED_SHIFT 4 +#define XSTORM_RDMA_CONN_AG_CTX_ROCE_EDPM_ENABLE_MASK 0x1 +#define XSTORM_RDMA_CONN_AG_CTX_ROCE_EDPM_ENABLE_SHIFT 5 +#define XSTORM_RDMA_CONN_AG_CTX_CF23_MASK 0x3 +#define XSTORM_RDMA_CONN_AG_CTX_CF23_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le16 word5; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 snd_nxt_psn; + __le32 reg4; + __le32 reg5; + __le32 reg6; +}; + +struct ystorm_rdma_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_RDMA_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_RDMA_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_RDMA_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_RDMA_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_RDMA_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_RDMA_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_RDMA_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_RDMA_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_RDMA_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_RDMA_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_RDMA_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_RDMA_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_RDMA_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_RDMA_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_RDMA_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_RDMA_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_RDMA_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; + +struct mstorm_roce_conn_st_ctx { + struct regpair temp[6]; +}; + +struct pstorm_roce_conn_st_ctx { + struct regpair temp[16]; +}; + +struct ystorm_roce_conn_st_ctx { + struct regpair temp[2]; +}; + +struct xstorm_roce_conn_st_ctx { + struct regpair temp[22]; +}; + +struct tstorm_roce_conn_st_ctx { + struct regpair temp[30]; +}; + +struct ustorm_roce_conn_st_ctx { + struct regpair temp[12]; +}; + +struct roce_conn_context { + struct ystorm_roce_conn_st_ctx ystorm_st_context; + struct regpair ystorm_st_padding[2]; + struct pstorm_roce_conn_st_ctx pstorm_st_context; + struct xstorm_roce_conn_st_ctx xstorm_st_context; + struct regpair xstorm_st_padding[2]; + struct xstorm_rdma_conn_ag_ctx xstorm_ag_context; + struct tstorm_rdma_conn_ag_ctx tstorm_ag_context; + struct timers_context timer_context; + struct ustorm_rdma_conn_ag_ctx ustorm_ag_context; + struct tstorm_roce_conn_st_ctx tstorm_st_context; + struct mstorm_roce_conn_st_ctx mstorm_st_context; + struct ustorm_roce_conn_st_ctx ustorm_st_context; + struct regpair ustorm_st_padding[2]; +}; + +struct roce_create_qp_req_ramrod_data { + __le16 flags; +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_ROCE_FLAVOR_MASK 0x3 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_ROCE_FLAVOR_SHIFT 0 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_FMR_AND_RESERVED_EN_MASK 0x1 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_FMR_AND_RESERVED_EN_SHIFT 2 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_SIGNALED_COMP_MASK 0x1 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_SIGNALED_COMP_SHIFT 3 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_PRI_MASK 0x7 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_PRI_SHIFT 4 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_RESERVED_MASK 0x1 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_RESERVED_SHIFT 7 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT_MASK 0xF +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT_SHIFT 8 +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_RNR_NAK_CNT_MASK 0xF +#define ROCE_CREATE_QP_REQ_RAMROD_DATA_RNR_NAK_CNT_SHIFT 12 + u8 max_ord; + u8 traffic_class; + u8 hop_limit; + u8 orq_num_pages; + __le16 p_key; + __le32 flow_label; + __le32 dst_qp_id; + __le32 ack_timeout_val; + __le32 initial_psn; + __le16 mtu; + __le16 pd; + __le16 sq_num_pages; + __le16 reseved2; + struct regpair sq_pbl_addr; + struct regpair orq_pbl_addr; + __le16 local_mac_addr[3]; + __le16 remote_mac_addr[3]; + __le16 vlan_id; + __le16 udp_src_port; + __le32 src_gid[4]; + __le32 dst_gid[4]; + struct regpair qp_handle_for_cqe; + struct regpair qp_handle_for_async; + u8 stats_counter_id; + u8 reserved3[7]; + __le32 cq_cid; + __le16 physical_queue0; + __le16 dpi; +}; + +struct roce_create_qp_resp_ramrod_data { + __le16 flags; +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_ROCE_FLAVOR_MASK 0x3 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_ROCE_FLAVOR_SHIFT 0 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_RDMA_RD_EN_MASK 0x1 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_RDMA_RD_EN_SHIFT 2 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_RDMA_WR_EN_MASK 0x1 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_RDMA_WR_EN_SHIFT 3 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_ATOMIC_EN_MASK 0x1 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_ATOMIC_EN_SHIFT 4 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_SRQ_FLG_MASK 0x1 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_SRQ_FLG_SHIFT 5 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_E2E_FLOW_CONTROL_EN_MASK 0x1 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_E2E_FLOW_CONTROL_EN_SHIFT 6 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_RESERVED0_MASK 0x1 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_RESERVED0_SHIFT 7 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_PRI_MASK 0x7 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_PRI_SHIFT 8 +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER_MASK 0x1F +#define ROCE_CREATE_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER_SHIFT 11 + u8 max_ird; + u8 traffic_class; + u8 hop_limit; + u8 irq_num_pages; + __le16 p_key; + __le32 flow_label; + __le32 dst_qp_id; + u8 stats_counter_id; + u8 reserved1; + __le16 mtu; + __le32 initial_psn; + __le16 pd; + __le16 rq_num_pages; + struct rdma_srq_id srq_id; + struct regpair rq_pbl_addr; + struct regpair irq_pbl_addr; + __le16 local_mac_addr[3]; + __le16 remote_mac_addr[3]; + __le16 vlan_id; + __le16 udp_src_port; + __le32 src_gid[4]; + __le32 dst_gid[4]; + struct regpair qp_handle_for_cqe; + struct regpair qp_handle_for_async; + __le32 reserved2[2]; + __le32 cq_cid; + __le16 physical_queue0; + __le16 dpi; +}; + +struct roce_destroy_qp_req_output_params { + __le32 num_bound_mw; + __le32 reserved; +}; + +struct roce_destroy_qp_req_ramrod_data { + struct regpair output_params_addr; +}; + +struct roce_destroy_qp_resp_output_params { + __le32 num_invalidated_mw; + __le32 reserved; +}; + +struct roce_destroy_qp_resp_ramrod_data { + struct regpair output_params_addr; +}; + +enum roce_event_opcode { + ROCE_EVENT_CREATE_QP = 11, + ROCE_EVENT_MODIFY_QP, + ROCE_EVENT_QUERY_QP, + ROCE_EVENT_DESTROY_QP, + MAX_ROCE_EVENT_OPCODE +}; + +struct roce_modify_qp_req_ramrod_data { + __le16 flags; +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_MOVE_TO_ERR_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_MOVE_TO_ERR_FLG_SHIFT 0 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_MOVE_TO_SQD_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_MOVE_TO_SQD_FLG_SHIFT 1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_EN_SQD_ASYNC_NOTIFY_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_EN_SQD_ASYNC_NOTIFY_SHIFT 2 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_P_KEY_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_P_KEY_FLG_SHIFT 3 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_ADDRESS_VECTOR_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_ADDRESS_VECTOR_FLG_SHIFT 4 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_MAX_ORD_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_MAX_ORD_FLG_SHIFT 5 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_RNR_NAK_CNT_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_RNR_NAK_CNT_FLG_SHIFT 6 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT_FLG_SHIFT 7 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_ACK_TIMEOUT_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_ACK_TIMEOUT_FLG_SHIFT 8 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_PRI_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_PRI_FLG_SHIFT 9 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_PRI_MASK 0x7 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_PRI_SHIFT 10 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_RESERVED1_MASK 0x7 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_RESERVED1_SHIFT 13 + u8 fields; +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT_MASK 0xF +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_ERR_RETRY_CNT_SHIFT 0 +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_RNR_NAK_CNT_MASK 0xF +#define ROCE_MODIFY_QP_REQ_RAMROD_DATA_RNR_NAK_CNT_SHIFT 4 + u8 max_ord; + u8 traffic_class; + u8 hop_limit; + __le16 p_key; + __le32 flow_label; + __le32 ack_timeout_val; + __le16 mtu; + __le16 reserved2; + __le32 reserved3[3]; + __le32 src_gid[4]; + __le32 dst_gid[4]; +}; + +struct roce_modify_qp_resp_ramrod_data { + __le16 flags; +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_MOVE_TO_ERR_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_MOVE_TO_ERR_FLG_SHIFT 0 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_RD_EN_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_RD_EN_SHIFT 1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_WR_EN_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_WR_EN_SHIFT 2 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_ATOMIC_EN_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_ATOMIC_EN_SHIFT 3 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_P_KEY_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_P_KEY_FLG_SHIFT 4 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_ADDRESS_VECTOR_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_ADDRESS_VECTOR_FLG_SHIFT 5 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_MAX_IRD_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_MAX_IRD_FLG_SHIFT 6 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_PRI_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_PRI_FLG_SHIFT 7 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER_FLG_SHIFT 8 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_OPS_EN_FLG_MASK 0x1 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_RDMA_OPS_EN_FLG_SHIFT 9 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_RESERVED1_MASK 0x3F +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_RESERVED1_SHIFT 10 + u8 fields; +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_PRI_MASK 0x7 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_PRI_SHIFT 0 +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER_MASK 0x1F +#define ROCE_MODIFY_QP_RESP_RAMROD_DATA_MIN_RNR_NAK_TIMER_SHIFT 3 + u8 max_ird; + u8 traffic_class; + u8 hop_limit; + __le16 p_key; + __le32 flow_label; + __le16 mtu; + __le16 reserved2; + __le32 src_gid[4]; + __le32 dst_gid[4]; +}; + +struct roce_query_qp_req_output_params { + __le32 psn; + __le32 flags; +#define ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_ERR_FLG_MASK 0x1 +#define ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_ERR_FLG_SHIFT 0 +#define ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_SQ_DRAINING_FLG_MASK 0x1 +#define ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_SQ_DRAINING_FLG_SHIFT 1 +#define ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_RESERVED0_MASK 0x3FFFFFFF +#define ROCE_QUERY_QP_REQ_OUTPUT_PARAMS_RESERVED0_SHIFT 2 +}; + +struct roce_query_qp_req_ramrod_data { + struct regpair output_params_addr; +}; + +struct roce_query_qp_resp_output_params { + __le32 psn; + __le32 err_flag; +#define ROCE_QUERY_QP_RESP_OUTPUT_PARAMS_ERROR_FLG_MASK 0x1 +#define ROCE_QUERY_QP_RESP_OUTPUT_PARAMS_ERROR_FLG_SHIFT 0 +#define ROCE_QUERY_QP_RESP_OUTPUT_PARAMS_RESERVED0_MASK 0x7FFFFFFF +#define ROCE_QUERY_QP_RESP_OUTPUT_PARAMS_RESERVED0_SHIFT 1 +}; + +struct roce_query_qp_resp_ramrod_data { + struct regpair output_params_addr; +}; + +enum roce_ramrod_cmd_id { + ROCE_RAMROD_CREATE_QP = 11, + ROCE_RAMROD_MODIFY_QP, + ROCE_RAMROD_QUERY_QP, + ROCE_RAMROD_DESTROY_QP, + MAX_ROCE_RAMROD_CMD_ID +}; + +struct mstorm_roce_req_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_ROCE_REQ_CONN_AG_CTX_BIT0_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + +struct mstorm_roce_resp_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define MSTORM_ROCE_RESP_CONN_AG_CTX_BIT0_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + +enum roce_flavor { + PLAIN_ROCE /* RoCE v1 */ , + RROCE_IPV4 /* RoCE v2 (Routable RoCE) over ipv4 */ , + RROCE_IPV6 /* RoCE v2 (Routable RoCE) over ipv6 */ , + MAX_ROCE_FLAVOR +}; + +struct tstorm_roce_req_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define TSTORM_ROCE_REQ_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RX_ERROR_OCCURED_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RX_ERROR_OCCURED_SHIFT 1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TX_CQE_ERROR_OCCURED_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TX_CQE_ERROR_OCCURED_SHIFT 2 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_MSTORM_FLUSH_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_MSTORM_FLUSH_SHIFT 4 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_CACHED_ORQ_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_CACHED_ORQ_SHIFT 5 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TIMER_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TIMER_CF_SHIFT 6 + u8 flags1; +#define TSTORM_ROCE_REQ_CONN_AG_CTX_CF1_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_SQ_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_SQ_CF_SHIFT 2 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TIMER_STOP_ALL_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TIMER_STOP_ALL_CF_SHIFT 4 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 6 + u8 flags2; +#define TSTORM_ROCE_REQ_CONN_AG_CTX_MSTORM_FLUSH_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_MSTORM_FLUSH_CF_SHIFT 0 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SET_TIMER_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SET_TIMER_CF_SHIFT 2 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TX_ASYNC_ERROR_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TX_ASYNC_ERROR_CF_SHIFT 4 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RXMIT_DONE_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RXMIT_DONE_CF_SHIFT 6 + u8 flags3; +#define TSTORM_ROCE_REQ_CONN_AG_CTX_ERROR_SCAN_COMPLETED_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_ERROR_SCAN_COMPLETED_CF_SHIFT 0 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SQ_DRAIN_COMPLETED_CF_MASK 0x3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SQ_DRAIN_COMPLETED_CF_SHIFT 2 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TIMER_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TIMER_CF_EN_SHIFT 4 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_SQ_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_SQ_CF_EN_SHIFT 6 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_SHIFT 7 + u8 flags4; +#define TSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 0 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_SHIFT 1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SET_TIMER_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SET_TIMER_CF_EN_SHIFT 2 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TX_ASYNC_ERROR_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_TX_ASYNC_ERROR_CF_EN_SHIFT 3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RXMIT_DONE_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RXMIT_DONE_CF_EN_SHIFT 4 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_ERROR_SCAN_COMPLETED_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_ERROR_SCAN_COMPLETED_CF_EN_SHIFT 5 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SQ_DRAIN_COMPLETED_CF_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SQ_DRAIN_COMPLETED_CF_EN_SHIFT 6 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SND_SQ_CONS_EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_SND_SQ_CONS_EN_SHIFT 5 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_ROCE_REQ_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0; + __le32 snd_nxt_psn; + __le32 snd_max_psn; + __le32 orq_prod; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 tx_cqe_error_type; + u8 orq_cache_idx; + __le16 snd_sq_cons_th; + u8 byte4; + u8 byte5; + __le16 snd_sq_cons; + __le16 word2; + __le16 word3; + __le32 reg9; + __le32 reg10; +}; + +struct tstorm_roce_resp_conn_ag_ctx { + u8 byte0; + u8 state; + u8 flags0; +#define TSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_MSTORM_FLUSH_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_MSTORM_FLUSH_SHIFT 4 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF0_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF0_SHIFT 6 + u8 flags1; +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_CF_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_CF_SHIFT 0 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_TX_ERROR_CF_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_TX_ERROR_CF_SHIFT 2 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF3_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF3_SHIFT 4 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 6 + u8 flags2; +#define TSTORM_ROCE_RESP_CONN_AG_CTX_MSTORM_FLUSH_CF_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_MSTORM_FLUSH_CF_SHIFT 0 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF6_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF7_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF8_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF8_SHIFT 6 + u8 flags3; +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF9_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF9_SHIFT 0 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF10_MASK 0x3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_CF_EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_CF_EN_SHIFT 5 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_TX_ERROR_CF_EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_TX_ERROR_CF_EN_SHIFT 6 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF3EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF3EN_SHIFT 7 + u8 flags4; +#define TSTORM_ROCE_RESP_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 0 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_MSTORM_FLUSH_CF_EN_SHIFT 1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF8EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF9EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF9EN_SHIFT 5 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF10EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RQ_RULE_EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RQ_RULE_EN_SHIFT 5 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_ROCE_RESP_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 psn_and_rxmit_id_echo; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 tx_async_error_type; + u8 byte3; + __le16 rq_cons; + u8 byte4; + u8 byte5; + __le16 rq_prod; + __le16 conn_dpi; + __le16 irq_cons; + __le32 num_invlidated_mw; + __le32 reg10; +}; + +struct ustorm_roce_req_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define USTORM_ROCE_REQ_CONN_AG_CTX_BIT0_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_BIT0_SHIFT 0 +#define USTORM_ROCE_REQ_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF0_MASK 0x3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF0_SHIFT 2 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF1_MASK 0x3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF4_MASK 0x3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF4_SHIFT 2 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF5_MASK 0x3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF5_SHIFT 4 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF6_MASK 0x3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF6_SHIFT 6 + u8 flags2; +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF0EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF0EN_SHIFT 0 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF4EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF4EN_SHIFT 4 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF5EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF5EN_SHIFT 5 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF6EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags3; +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_ROCE_REQ_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le16 word2; + __le16 word3; +}; + +struct ustorm_roce_resp_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define USTORM_ROCE_RESP_CONN_AG_CTX_BIT0_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_BIT0_SHIFT 0 +#define USTORM_ROCE_RESP_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF0_MASK 0x3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF0_SHIFT 2 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF1_MASK 0x3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF4_MASK 0x3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF4_SHIFT 2 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF5_MASK 0x3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF5_SHIFT 4 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF6_MASK 0x3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF6_SHIFT 6 + u8 flags2; +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_SHIFT 0 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF4EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF4EN_SHIFT 4 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF5EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF5EN_SHIFT 5 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF6EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags3; +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_ROCE_RESP_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le16 word2; + __le16 word3; +}; + +struct xstorm_roce_req_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED1_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED1_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED2_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED3_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED4_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED4_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED5_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED5_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED6_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED6_SHIFT 7 + u8 flags1; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED7_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED7_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED8_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED8_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT10_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT10_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_ERROR_STATE_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_ERROR_STATE_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_YSTORM_FLUSH_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_YSTORM_FLUSH_SHIFT 7 + u8 flags2; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF3_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF3_SHIFT 6 + u8 flags3; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SQ_FLUSH_CF_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SQ_FLUSH_CF_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RX_ERROR_CF_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RX_ERROR_CF_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SND_RXMIT_CF_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SND_RXMIT_CF_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 6 + u8 flags4; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_FMR_ENDED_CF_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_FMR_ENDED_CF_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF15_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF15_SHIFT 6 + u8 flags6; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF16_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF16_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF17_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF17_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF18_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF18_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF19_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF19_SHIFT 6 + u8 flags7; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF20_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF20_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF21_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF21_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF3EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF3EN_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SQ_FLUSH_CF_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SQ_FLUSH_CF_EN_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RX_ERROR_CF_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RX_ERROR_CF_EN_SHIFT 3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SND_RXMIT_CF_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SND_RXMIT_CF_EN_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_FME_ENDED_CF_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_FME_ENDED_CF_EN_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF15EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF16EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF16EN_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF17EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF18EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF18EN_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF19EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF19EN_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF20EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF20EN_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF21EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF21EN_SHIFT 3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF23EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF23EN_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_SHIFT 7 + u8 flags11; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_E2E_CREDIT_RULE_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_E2E_CREDIT_RULE_EN_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SQ_PROD_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_SQ_PROD_EN_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE11EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_INV_FENCE_RULE_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_INV_FENCE_RULE_EN_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_ORQ_FENCE_RULE_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_ORQ_FENCE_RULE_EN_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_MAX_ORD_RULE_EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_MAX_ORD_RULE_EN_SHIFT 7 + u8 flags13; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE18EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE18EN_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE19EN_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RULE19EN_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_ROCE_REQ_CONN_AG_CTX_MIGRATION_FLAG_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_MIGRATION_FLAG_SHIFT 0 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT17_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_BIT17_SHIFT 1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_DPM_PORT_NUM_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_DPM_PORT_NUM_SHIFT 2 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_RESERVED_SHIFT 4 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_ROCE_EDPM_ENABLE_MASK 0x1 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_ROCE_EDPM_ENABLE_SHIFT 5 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF23_MASK 0x3 +#define XSTORM_ROCE_REQ_CONN_AG_CTX_CF23_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 word1; + __le16 sq_cmp_cons; + __le16 sq_cons; + __le16 sq_prod; + __le16 word5; + __le16 conn_dpi; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 lsn; + __le32 ssn; + __le32 snd_una_psn; + __le32 snd_nxt_psn; + __le32 reg4; + __le32 orq_cons_th; + __le32 orq_cons; +}; + +struct xstorm_roce_resp_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED1_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED1_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED2_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED3_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED4_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED4_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED5_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED5_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED6_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED6_SHIFT 7 + u8 flags1; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED7_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED7_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED8_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RESERVED8_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT10_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT10_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_ERROR_STATE_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_ERROR_STATE_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_YSTORM_FLUSH_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_YSTORM_FLUSH_SHIFT 7 + u8 flags2; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF3_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF3_SHIFT 6 + u8 flags3; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RXMIT_CF_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RXMIT_CF_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_CF_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_CF_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_FORCE_ACK_CF_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_FORCE_ACK_CF_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 6 + u8 flags4; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF14_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF14_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF15_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF15_SHIFT 6 + u8 flags6; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF16_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF16_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF17_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF17_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF18_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF18_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF19_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF19_SHIFT 6 + u8 flags7; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF20_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF20_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF21_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF21_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF3EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF3EN_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RXMIT_CF_EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RXMIT_CF_EN_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_CF_EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RX_ERROR_CF_EN_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_FORCE_ACK_CF_EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_FORCE_ACK_CF_EN_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF14EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF14EN_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF15EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF15EN_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF16EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF16EN_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF17EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF18EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF18EN_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF19EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF19EN_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF20EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF20EN_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF21EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF21EN_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF23EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF23EN_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_SHIFT 7 + u8 flags11; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE10EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE10EN_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_IRQ_PROD_RULE_EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_IRQ_PROD_RULE_EN_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE14EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE14EN_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE16EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE17EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE18EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE18EN_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE19EN_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_RULE19EN_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT16_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT16_SHIFT 0 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT17_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT17_SHIFT 1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT18_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT18_SHIFT 2 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT19_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT19_SHIFT 3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT20_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT20_SHIFT 4 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT21_MASK 0x1 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_BIT21_SHIFT 5 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF23_MASK 0x3 +#define XSTORM_ROCE_RESP_CONN_AG_CTX_CF23_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 word1; + __le16 irq_prod; + __le16 word3; + __le16 word4; + __le16 word5; + __le16 irq_cons; + u8 rxmit_opcode; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 rxmit_psn_and_id; + __le32 rxmit_bytes_length; + __le32 psn; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 msn_and_syndrome; +}; + +struct ystorm_roce_req_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_ROCE_REQ_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_ROCE_REQ_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; + +struct ystorm_roce_resp_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_ROCE_RESP_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_ROCE_RESP_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; + +struct ystorm_iscsi_conn_st_ctx { + __le32 reserved[4]; +}; + +struct pstorm_iscsi_tcp_conn_st_ctx { + __le32 tcp[32]; + __le32 iscsi[4]; +}; + +struct xstorm_iscsi_tcp_conn_st_ctx { + __le32 reserved_iscsi[40]; + __le32 reserved_tcp[4]; +}; + +struct xstorm_iscsi_conn_ag_ctx { + u8 cdu_validation; + u8 state; + u8 flags0; +#define XSTORM_ISCSI_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_EXIST_IN_QM1_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_EXIST_IN_QM1_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_RESERVED1_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RESERVED1_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT4_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT4_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_RESERVED2_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RESERVED2_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT6_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT6_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT7_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT7_SHIFT 7 + u8 flags1; +#define XSTORM_ISCSI_CONN_AG_CTX_BIT8_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT8_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT9_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT9_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT10_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT10_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT11_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT11_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT12_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT12_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT13_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT13_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT14_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT14_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_TX_TRUNCATE_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_TX_TRUNCATE_SHIFT 7 + u8 flags2; +#define XSTORM_ISCSI_CONN_AG_CTX_CF0_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF0_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_CF1_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF1_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_CF2_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF2_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_TIMER_STOP_ALL_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_TIMER_STOP_ALL_SHIFT 6 + u8 flags3; +#define XSTORM_ISCSI_CONN_AG_CTX_CF4_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF4_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_CF5_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF5_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_CF6_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF6_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_CF7_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF7_SHIFT 6 + u8 flags4; +#define XSTORM_ISCSI_CONN_AG_CTX_CF8_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF8_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_CF9_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF9_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_CF10_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF10_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_CF11_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF11_SHIFT 6 + u8 flags5; +#define XSTORM_ISCSI_CONN_AG_CTX_CF12_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF12_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_CF13_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF13_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_CF14_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF14_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_UPDATE_STATE_TO_BASE_CF_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_UPDATE_STATE_TO_BASE_CF_SHIFT 6 + u8 flags6; +#define XSTORM_ISCSI_CONN_AG_CTX_CF16_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF16_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_CF17_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF17_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_CF18_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF18_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_DQ_FLUSH_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_DQ_FLUSH_SHIFT 6 + u8 flags7; +#define XSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q1_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q1_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_SLOW_PATH_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_SLOW_PATH_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_CF0EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF0EN_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_CF1EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF1EN_SHIFT 7 + u8 flags8; +#define XSTORM_ISCSI_CONN_AG_CTX_CF2EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF2EN_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_TIMER_STOP_ALL_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_TIMER_STOP_ALL_EN_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF4EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF4EN_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_CF5EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF5EN_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF6EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF6EN_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_CF7EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF7EN_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_CF8EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF8EN_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_CF9EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF9EN_SHIFT 7 + u8 flags9; +#define XSTORM_ISCSI_CONN_AG_CTX_CF10EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF10EN_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_CF11EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF11EN_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF12EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF12EN_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_CF13EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF13EN_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_CF14EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF14EN_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_UPDATE_STATE_TO_BASE_CF_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_UPDATE_STATE_TO_BASE_CF_EN_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_CF16EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF16EN_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_CF17EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF17EN_SHIFT 7 + u8 flags10; +#define XSTORM_ISCSI_CONN_AG_CTX_CF18EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_CF18EN_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_DQ_FLUSH_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_DQ_FLUSH_EN_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q1_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q1_EN_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_PROC_ONLY_CLEANUP_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_PROC_ONLY_CLEANUP_EN_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE0EN_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_MORE_TO_SEND_DEC_RULE_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_MORE_TO_SEND_DEC_RULE_EN_SHIFT 7 + u8 flags11; +#define XSTORM_ISCSI_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE2EN_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE3EN_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_RESERVED3_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RESERVED3_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE5EN_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE6EN_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE7EN_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED1_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED1_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE9EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE9EN_SHIFT 7 + u8 flags12; +#define XSTORM_ISCSI_CONN_AG_CTX_SQ_DEC_RULE_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_SQ_DEC_RULE_EN_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE11EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE11EN_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED2_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED2_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED3_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED3_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE14EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE14EN_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE15EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE15EN_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE16EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE16EN_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE17EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_RULE17EN_SHIFT 7 + u8 flags13; +#define XSTORM_ISCSI_CONN_AG_CTX_R2TQ_DEC_RULE_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_R2TQ_DEC_RULE_EN_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_HQ_DEC_RULE_EN_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_HQ_DEC_RULE_EN_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED4_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED4_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED5_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED5_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED6_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED6_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED7_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED7_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED8_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED8_SHIFT 6 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED9_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_A0_RESERVED9_SHIFT 7 + u8 flags14; +#define XSTORM_ISCSI_CONN_AG_CTX_BIT16_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT16_SHIFT 0 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT17_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT17_SHIFT 1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT18_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT18_SHIFT 2 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT19_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT19_SHIFT 3 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT20_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_BIT20_SHIFT 4 +#define XSTORM_ISCSI_CONN_AG_CTX_DUMMY_READ_DONE_MASK 0x1 +#define XSTORM_ISCSI_CONN_AG_CTX_DUMMY_READ_DONE_SHIFT 5 +#define XSTORM_ISCSI_CONN_AG_CTX_PROC_ONLY_CLEANUP_MASK 0x3 +#define XSTORM_ISCSI_CONN_AG_CTX_PROC_ONLY_CLEANUP_SHIFT 6 + u8 byte2; + __le16 physical_q0; + __le16 physical_q1; + __le16 dummy_dorq_var; + __le16 sq_cons; + __le16 sq_prod; + __le16 word5; + __le16 slow_io_total_data_tx_update; + u8 byte3; + u8 byte4; + u8 byte5; + u8 byte6; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 more_to_send_seq; + __le32 reg4; + __le32 reg5; + __le32 hq_scan_next_relevant_ack; + __le16 r2tq_prod; + __le16 r2tq_cons; + __le16 hq_prod; + __le16 hq_cons; + __le32 remain_seq; + __le32 bytes_to_next_pdu; + __le32 hq_tcp_seq; + u8 byte7; + u8 byte8; + u8 byte9; + u8 byte10; + u8 byte11; + u8 byte12; + u8 byte13; + u8 byte14; + u8 byte15; + u8 byte16; + __le16 word11; + __le32 reg10; + __le32 reg11; + __le32 exp_stat_sn; + __le32 reg13; + __le32 reg14; + __le32 reg15; + __le32 reg16; + __le32 reg17; +}; + +struct tstorm_iscsi_conn_ag_ctx { + u8 reserved0; + u8 state; + u8 flags0; +#define TSTORM_ISCSI_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT1_SHIFT 1 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT2_SHIFT 2 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT3_SHIFT 3 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT4_SHIFT 4 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_BIT5_SHIFT 5 +#define TSTORM_ISCSI_CONN_AG_CTX_CF0_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF0_SHIFT 6 + u8 flags1; +#define TSTORM_ISCSI_CONN_AG_CTX_CF1_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF1_SHIFT 0 +#define TSTORM_ISCSI_CONN_AG_CTX_CF2_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF2_SHIFT 2 +#define TSTORM_ISCSI_CONN_AG_CTX_TIMER_STOP_ALL_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_TIMER_STOP_ALL_SHIFT 4 +#define TSTORM_ISCSI_CONN_AG_CTX_CF4_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF4_SHIFT 6 + u8 flags2; +#define TSTORM_ISCSI_CONN_AG_CTX_CF5_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF5_SHIFT 0 +#define TSTORM_ISCSI_CONN_AG_CTX_CF6_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF6_SHIFT 2 +#define TSTORM_ISCSI_CONN_AG_CTX_CF7_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF7_SHIFT 4 +#define TSTORM_ISCSI_CONN_AG_CTX_CF8_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF8_SHIFT 6 + u8 flags3; +#define TSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q0_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q0_SHIFT 0 +#define TSTORM_ISCSI_CONN_AG_CTX_CF10_MASK 0x3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF10_SHIFT 2 +#define TSTORM_ISCSI_CONN_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF0EN_SHIFT 4 +#define TSTORM_ISCSI_CONN_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF1EN_SHIFT 5 +#define TSTORM_ISCSI_CONN_AG_CTX_CF2EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF2EN_SHIFT 6 +#define TSTORM_ISCSI_CONN_AG_CTX_TIMER_STOP_ALL_EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_TIMER_STOP_ALL_EN_SHIFT 7 + u8 flags4; +#define TSTORM_ISCSI_CONN_AG_CTX_CF4EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF4EN_SHIFT 0 +#define TSTORM_ISCSI_CONN_AG_CTX_CF5EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF5EN_SHIFT 1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF6EN_SHIFT 2 +#define TSTORM_ISCSI_CONN_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF7EN_SHIFT 3 +#define TSTORM_ISCSI_CONN_AG_CTX_CF8EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF8EN_SHIFT 4 +#define TSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 5 +#define TSTORM_ISCSI_CONN_AG_CTX_CF10EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_CF10EN_SHIFT 6 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags5; +#define TSTORM_ISCSI_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define TSTORM_ISCSI_CONN_AG_CTX_RULE8EN_SHIFT 7 + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le32 reg4; + __le32 reg5; + __le32 reg6; + __le32 reg7; + __le32 reg8; + u8 byte2; + u8 byte3; + __le16 word0; +}; + +struct ustorm_iscsi_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define USTORM_ISCSI_CONN_AG_CTX_BIT0_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_BIT0_SHIFT 0 +#define USTORM_ISCSI_CONN_AG_CTX_BIT1_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_BIT1_SHIFT 1 +#define USTORM_ISCSI_CONN_AG_CTX_CF0_MASK 0x3 +#define USTORM_ISCSI_CONN_AG_CTX_CF0_SHIFT 2 +#define USTORM_ISCSI_CONN_AG_CTX_CF1_MASK 0x3 +#define USTORM_ISCSI_CONN_AG_CTX_CF1_SHIFT 4 +#define USTORM_ISCSI_CONN_AG_CTX_CF2_MASK 0x3 +#define USTORM_ISCSI_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define USTORM_ISCSI_CONN_AG_CTX_CF3_MASK 0x3 +#define USTORM_ISCSI_CONN_AG_CTX_CF3_SHIFT 0 +#define USTORM_ISCSI_CONN_AG_CTX_CF4_MASK 0x3 +#define USTORM_ISCSI_CONN_AG_CTX_CF4_SHIFT 2 +#define USTORM_ISCSI_CONN_AG_CTX_CF5_MASK 0x3 +#define USTORM_ISCSI_CONN_AG_CTX_CF5_SHIFT 4 +#define USTORM_ISCSI_CONN_AG_CTX_CF6_MASK 0x3 +#define USTORM_ISCSI_CONN_AG_CTX_CF6_SHIFT 6 + u8 flags2; +#define USTORM_ISCSI_CONN_AG_CTX_CF0EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_CF0EN_SHIFT 0 +#define USTORM_ISCSI_CONN_AG_CTX_CF1EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_CF1EN_SHIFT 1 +#define USTORM_ISCSI_CONN_AG_CTX_CF2EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_CF2EN_SHIFT 2 +#define USTORM_ISCSI_CONN_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_ISCSI_CONN_AG_CTX_CF4EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_CF4EN_SHIFT 4 +#define USTORM_ISCSI_CONN_AG_CTX_CF5EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_CF5EN_SHIFT 5 +#define USTORM_ISCSI_CONN_AG_CTX_CF6EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_CF6EN_SHIFT 6 +#define USTORM_ISCSI_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE0EN_SHIFT 7 + u8 flags3; +#define USTORM_ISCSI_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE1EN_SHIFT 0 +#define USTORM_ISCSI_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE2EN_SHIFT 1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE3EN_SHIFT 2 +#define USTORM_ISCSI_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE4EN_SHIFT 3 +#define USTORM_ISCSI_CONN_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE5EN_SHIFT 4 +#define USTORM_ISCSI_CONN_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE6EN_SHIFT 5 +#define USTORM_ISCSI_CONN_AG_CTX_RULE7EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE7EN_SHIFT 6 +#define USTORM_ISCSI_CONN_AG_CTX_RULE8EN_MASK 0x1 +#define USTORM_ISCSI_CONN_AG_CTX_RULE8EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; + __le32 reg2; + __le32 reg3; + __le16 word2; + __le16 word3; +}; + +struct tstorm_iscsi_conn_st_ctx { + __le32 reserved[40]; +}; + +struct mstorm_iscsi_conn_ag_ctx { + u8 reserved; + u8 state; + u8 flags0; +#define MSTORM_ISCSI_CONN_AG_CTX_BIT0_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_BIT0_SHIFT 0 +#define MSTORM_ISCSI_CONN_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_BIT1_SHIFT 1 +#define MSTORM_ISCSI_CONN_AG_CTX_CF0_MASK 0x3 +#define MSTORM_ISCSI_CONN_AG_CTX_CF0_SHIFT 2 +#define MSTORM_ISCSI_CONN_AG_CTX_CF1_MASK 0x3 +#define MSTORM_ISCSI_CONN_AG_CTX_CF1_SHIFT 4 +#define MSTORM_ISCSI_CONN_AG_CTX_CF2_MASK 0x3 +#define MSTORM_ISCSI_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define MSTORM_ISCSI_CONN_AG_CTX_CF0EN_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_CF0EN_SHIFT 0 +#define MSTORM_ISCSI_CONN_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_CF1EN_SHIFT 1 +#define MSTORM_ISCSI_CONN_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_CF2EN_SHIFT 2 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_ISCSI_CONN_AG_CTX_RULE4EN_SHIFT 7 + __le16 word0; + __le16 word1; + __le32 reg0; + __le32 reg1; +}; + +struct mstorm_iscsi_tcp_conn_st_ctx { + __le32 reserved_tcp[20]; + __le32 reserved_iscsi[8]; +}; + +struct ustorm_iscsi_conn_st_ctx { + __le32 reserved[52]; +}; + +struct iscsi_conn_context { + struct ystorm_iscsi_conn_st_ctx ystorm_st_context; + struct regpair ystorm_st_padding[2]; + struct pstorm_iscsi_tcp_conn_st_ctx pstorm_st_context; + struct regpair pstorm_st_padding[2]; + struct pb_context xpb2_context; + struct xstorm_iscsi_tcp_conn_st_ctx xstorm_st_context; + struct regpair xstorm_st_padding[2]; + struct xstorm_iscsi_conn_ag_ctx xstorm_ag_context; + struct tstorm_iscsi_conn_ag_ctx tstorm_ag_context; + struct regpair tstorm_ag_padding[2]; + struct timers_context timer_context; + struct ustorm_iscsi_conn_ag_ctx ustorm_ag_context; + struct pb_context upb_context; + struct tstorm_iscsi_conn_st_ctx tstorm_st_context; + struct regpair tstorm_st_padding[2]; + struct mstorm_iscsi_conn_ag_ctx mstorm_ag_context; + struct mstorm_iscsi_tcp_conn_st_ctx mstorm_st_context; + struct ustorm_iscsi_conn_st_ctx ustorm_st_context; +}; + +struct iscsi_init_ramrod_params { + struct iscsi_spe_func_init iscsi_init_spe; + struct tcp_init_params tcp_init; +}; + +struct ystorm_iscsi_conn_ag_ctx { + u8 byte0; + u8 byte1; + u8 flags0; +#define YSTORM_ISCSI_CONN_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_BIT0_SHIFT 0 +#define YSTORM_ISCSI_CONN_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_BIT1_SHIFT 1 +#define YSTORM_ISCSI_CONN_AG_CTX_CF0_MASK 0x3 +#define YSTORM_ISCSI_CONN_AG_CTX_CF0_SHIFT 2 +#define YSTORM_ISCSI_CONN_AG_CTX_CF1_MASK 0x3 +#define YSTORM_ISCSI_CONN_AG_CTX_CF1_SHIFT 4 +#define YSTORM_ISCSI_CONN_AG_CTX_CF2_MASK 0x3 +#define YSTORM_ISCSI_CONN_AG_CTX_CF2_SHIFT 6 + u8 flags1; +#define YSTORM_ISCSI_CONN_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_CF0EN_SHIFT 0 +#define YSTORM_ISCSI_CONN_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_CF1EN_SHIFT 1 +#define YSTORM_ISCSI_CONN_AG_CTX_CF2EN_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_CF2EN_SHIFT 2 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE0EN_SHIFT 3 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE1EN_SHIFT 4 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE2EN_SHIFT 5 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE3EN_SHIFT 6 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_ISCSI_CONN_AG_CTX_RULE4EN_SHIFT 7 + u8 byte2; + u8 byte3; + __le16 word0; + __le32 reg0; + __le32 reg1; + __le16 word1; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg2; + __le32 reg3; +}; #define VF_MAX_STATIC 192 #define MCP_GLOB_PATH_MAX 2 diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h index ea4e9ce53e0a..a548504c3420 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h @@ -63,6 +63,32 @@ union ramrod_data { struct vport_update_ramrod_data vport_update; struct vport_filter_update_ramrod_data vport_filter_update; + struct rdma_init_func_ramrod_data rdma_init_func; + struct rdma_close_func_ramrod_data rdma_close_func; + struct rdma_register_tid_ramrod_data rdma_register_tid; + struct rdma_deregister_tid_ramrod_data rdma_deregister_tid; + struct roce_create_qp_resp_ramrod_data roce_create_qp_resp; + struct roce_create_qp_req_ramrod_data roce_create_qp_req; + struct roce_modify_qp_resp_ramrod_data roce_modify_qp_resp; + struct roce_modify_qp_req_ramrod_data roce_modify_qp_req; + struct roce_query_qp_resp_ramrod_data roce_query_qp_resp; + struct roce_query_qp_req_ramrod_data roce_query_qp_req; + struct roce_destroy_qp_resp_ramrod_data roce_destroy_qp_resp; + struct roce_destroy_qp_req_ramrod_data roce_destroy_qp_req; + struct rdma_create_cq_ramrod_data rdma_create_cq; + struct rdma_resize_cq_ramrod_data rdma_resize_cq; + struct rdma_destroy_cq_ramrod_data rdma_destroy_cq; + struct rdma_srq_create_ramrod_data rdma_create_srq; + struct rdma_srq_destroy_ramrod_data rdma_destroy_srq; + struct rdma_srq_modify_ramrod_data rdma_modify_srq; + + struct iscsi_slow_path_hdr iscsi_empty; + struct iscsi_init_ramrod_params iscsi_init; + struct iscsi_spe_func_dstry iscsi_destroy; + struct iscsi_spe_conn_offload iscsi_conn_offload; + struct iscsi_conn_update_ramrod_params iscsi_conn_update; + struct iscsi_spe_conn_termination iscsi_conn_terminate; + struct vf_start_ramrod_data vf_start; struct vf_stop_ramrod_data vf_stop; }; diff --git a/include/linux/qed/common_hsi.h b/include/linux/qed/common_hsi.h index 285189a5ea6d..077a3b6cc80f 100644 --- a/include/linux/qed/common_hsi.h +++ b/include/linux/qed/common_hsi.h @@ -12,6 +12,7 @@ #define CORE_SPQE_PAGE_SIZE_BYTES 4096 #define X_FINAL_CLEANUP_AGG_INT 1 +#define NUM_OF_GLOBAL_QUEUES 128 /* Queue Zone sizes in bytes */ #define TSTORM_QZONE_SIZE 8 @@ -694,7 +695,10 @@ struct parsing_and_err_flags { #define PARSING_AND_ERR_FLAGS_TUNNELL4CHKSMERROR_SHIFT 15 }; -/* Concrete Function ID. */ +struct pb_context { + __le32 crc[4]; +}; + struct pxp_concrete_fid { __le16 fid; #define PXP_CONCRETE_FID_PFID_MASK 0xF @@ -761,6 +765,72 @@ struct pxp_ptt_entry { }; /* RSS hash type */ +struct rdif_task_context { + __le32 initial_ref_tag; + __le16 app_tag_value; + __le16 app_tag_mask; + u8 flags0; +#define RDIF_TASK_CONTEXT_IGNOREAPPTAG_MASK 0x1 +#define RDIF_TASK_CONTEXT_IGNOREAPPTAG_SHIFT 0 +#define RDIF_TASK_CONTEXT_INITIALREFTAGVALID_MASK 0x1 +#define RDIF_TASK_CONTEXT_INITIALREFTAGVALID_SHIFT 1 +#define RDIF_TASK_CONTEXT_HOSTGUARDTYPE_MASK 0x1 +#define RDIF_TASK_CONTEXT_HOSTGUARDTYPE_SHIFT 2 +#define RDIF_TASK_CONTEXT_SETERRORWITHEOP_MASK 0x1 +#define RDIF_TASK_CONTEXT_SETERRORWITHEOP_SHIFT 3 +#define RDIF_TASK_CONTEXT_PROTECTIONTYPE_MASK 0x3 +#define RDIF_TASK_CONTEXT_PROTECTIONTYPE_SHIFT 4 +#define RDIF_TASK_CONTEXT_CRC_SEED_MASK 0x1 +#define RDIF_TASK_CONTEXT_CRC_SEED_SHIFT 6 +#define RDIF_TASK_CONTEXT_KEEPREFTAGCONST_MASK 0x1 +#define RDIF_TASK_CONTEXT_KEEPREFTAGCONST_SHIFT 7 + u8 partial_dif_data[7]; + __le16 partial_crc_value; + __le16 partial_checksum_value; + __le32 offset_in_io; + __le16 flags1; +#define RDIF_TASK_CONTEXT_VALIDATEGUARD_MASK 0x1 +#define RDIF_TASK_CONTEXT_VALIDATEGUARD_SHIFT 0 +#define RDIF_TASK_CONTEXT_VALIDATEAPPTAG_MASK 0x1 +#define RDIF_TASK_CONTEXT_VALIDATEAPPTAG_SHIFT 1 +#define RDIF_TASK_CONTEXT_VALIDATEREFTAG_MASK 0x1 +#define RDIF_TASK_CONTEXT_VALIDATEREFTAG_SHIFT 2 +#define RDIF_TASK_CONTEXT_FORWARDGUARD_MASK 0x1 +#define RDIF_TASK_CONTEXT_FORWARDGUARD_SHIFT 3 +#define RDIF_TASK_CONTEXT_FORWARDAPPTAG_MASK 0x1 +#define RDIF_TASK_CONTEXT_FORWARDAPPTAG_SHIFT 4 +#define RDIF_TASK_CONTEXT_FORWARDREFTAG_MASK 0x1 +#define RDIF_TASK_CONTEXT_FORWARDREFTAG_SHIFT 5 +#define RDIF_TASK_CONTEXT_INTERVALSIZE_MASK 0x7 +#define RDIF_TASK_CONTEXT_INTERVALSIZE_SHIFT 6 +#define RDIF_TASK_CONTEXT_HOSTINTERFACE_MASK 0x3 +#define RDIF_TASK_CONTEXT_HOSTINTERFACE_SHIFT 9 +#define RDIF_TASK_CONTEXT_DIFBEFOREDATA_MASK 0x1 +#define RDIF_TASK_CONTEXT_DIFBEFOREDATA_SHIFT 11 +#define RDIF_TASK_CONTEXT_RESERVED0_MASK 0x1 +#define RDIF_TASK_CONTEXT_RESERVED0_SHIFT 12 +#define RDIF_TASK_CONTEXT_NETWORKINTERFACE_MASK 0x1 +#define RDIF_TASK_CONTEXT_NETWORKINTERFACE_SHIFT 13 +#define RDIF_TASK_CONTEXT_FORWARDAPPTAGWITHMASK_MASK 0x1 +#define RDIF_TASK_CONTEXT_FORWARDAPPTAGWITHMASK_SHIFT 14 +#define RDIF_TASK_CONTEXT_FORWARDREFTAGWITHMASK_MASK 0x1 +#define RDIF_TASK_CONTEXT_FORWARDREFTAGWITHMASK_SHIFT 15 + __le16 state; +#define RDIF_TASK_CONTEXT_RECEIVEDDIFBYTESLEFT_MASK 0xF +#define RDIF_TASK_CONTEXT_RECEIVEDDIFBYTESLEFT_SHIFT 0 +#define RDIF_TASK_CONTEXT_TRANSMITEDDIFBYTESLEFT_MASK 0xF +#define RDIF_TASK_CONTEXT_TRANSMITEDDIFBYTESLEFT_SHIFT 4 +#define RDIF_TASK_CONTEXT_ERRORINIO_MASK 0x1 +#define RDIF_TASK_CONTEXT_ERRORINIO_SHIFT 8 +#define RDIF_TASK_CONTEXT_CHECKSUMOVERFLOW_MASK 0x1 +#define RDIF_TASK_CONTEXT_CHECKSUMOVERFLOW_SHIFT 9 +#define RDIF_TASK_CONTEXT_REFTAGMASK_MASK 0xF +#define RDIF_TASK_CONTEXT_REFTAGMASK_SHIFT 10 +#define RDIF_TASK_CONTEXT_RESERVED1_MASK 0x3 +#define RDIF_TASK_CONTEXT_RESERVED1_SHIFT 14 + __le32 reserved2; +}; + enum rss_hash_type { RSS_HASH_TYPE_DEFAULT = 0, RSS_HASH_TYPE_IPV4 = 1, @@ -789,4 +859,122 @@ struct status_block { #define STATUS_BLOCK_ZERO_PAD3_SHIFT 24 }; +struct tdif_task_context { + __le32 initial_ref_tag; + __le16 app_tag_value; + __le16 app_tag_mask; + __le16 partial_crc_valueB; + __le16 partial_checksum_valueB; + __le16 stateB; +#define TDIF_TASK_CONTEXT_RECEIVEDDIFBYTESLEFTB_MASK 0xF +#define TDIF_TASK_CONTEXT_RECEIVEDDIFBYTESLEFTB_SHIFT 0 +#define TDIF_TASK_CONTEXT_TRANSMITEDDIFBYTESLEFTB_MASK 0xF +#define TDIF_TASK_CONTEXT_TRANSMITEDDIFBYTESLEFTB_SHIFT 4 +#define TDIF_TASK_CONTEXT_ERRORINIOB_MASK 0x1 +#define TDIF_TASK_CONTEXT_ERRORINIOB_SHIFT 8 +#define TDIF_TASK_CONTEXT_CHECKSUMOVERFLOW_MASK 0x1 +#define TDIF_TASK_CONTEXT_CHECKSUMOVERFLOW_SHIFT 9 +#define TDIF_TASK_CONTEXT_RESERVED0_MASK 0x3F +#define TDIF_TASK_CONTEXT_RESERVED0_SHIFT 10 + u8 reserved1; + u8 flags0; +#define TDIF_TASK_CONTEXT_IGNOREAPPTAG_MASK 0x1 +#define TDIF_TASK_CONTEXT_IGNOREAPPTAG_SHIFT 0 +#define TDIF_TASK_CONTEXT_INITIALREFTAGVALID_MASK 0x1 +#define TDIF_TASK_CONTEXT_INITIALREFTAGVALID_SHIFT 1 +#define TDIF_TASK_CONTEXT_HOSTGUARDTYPE_MASK 0x1 +#define TDIF_TASK_CONTEXT_HOSTGUARDTYPE_SHIFT 2 +#define TDIF_TASK_CONTEXT_SETERRORWITHEOP_MASK 0x1 +#define TDIF_TASK_CONTEXT_SETERRORWITHEOP_SHIFT 3 +#define TDIF_TASK_CONTEXT_PROTECTIONTYPE_MASK 0x3 +#define TDIF_TASK_CONTEXT_PROTECTIONTYPE_SHIFT 4 +#define TDIF_TASK_CONTEXT_CRC_SEED_MASK 0x1 +#define TDIF_TASK_CONTEXT_CRC_SEED_SHIFT 6 +#define TDIF_TASK_CONTEXT_RESERVED2_MASK 0x1 +#define TDIF_TASK_CONTEXT_RESERVED2_SHIFT 7 + __le32 flags1; +#define TDIF_TASK_CONTEXT_VALIDATEGUARD_MASK 0x1 +#define TDIF_TASK_CONTEXT_VALIDATEGUARD_SHIFT 0 +#define TDIF_TASK_CONTEXT_VALIDATEAPPTAG_MASK 0x1 +#define TDIF_TASK_CONTEXT_VALIDATEAPPTAG_SHIFT 1 +#define TDIF_TASK_CONTEXT_VALIDATEREFTAG_MASK 0x1 +#define TDIF_TASK_CONTEXT_VALIDATEREFTAG_SHIFT 2 +#define TDIF_TASK_CONTEXT_FORWARDGUARD_MASK 0x1 +#define TDIF_TASK_CONTEXT_FORWARDGUARD_SHIFT 3 +#define TDIF_TASK_CONTEXT_FORWARDAPPTAG_MASK 0x1 +#define TDIF_TASK_CONTEXT_FORWARDAPPTAG_SHIFT 4 +#define TDIF_TASK_CONTEXT_FORWARDREFTAG_MASK 0x1 +#define TDIF_TASK_CONTEXT_FORWARDREFTAG_SHIFT 5 +#define TDIF_TASK_CONTEXT_INTERVALSIZE_MASK 0x7 +#define TDIF_TASK_CONTEXT_INTERVALSIZE_SHIFT 6 +#define TDIF_TASK_CONTEXT_HOSTINTERFACE_MASK 0x3 +#define TDIF_TASK_CONTEXT_HOSTINTERFACE_SHIFT 9 +#define TDIF_TASK_CONTEXT_DIFBEFOREDATA_MASK 0x1 +#define TDIF_TASK_CONTEXT_DIFBEFOREDATA_SHIFT 11 +#define TDIF_TASK_CONTEXT_RESERVED3_MASK 0x1 +#define TDIF_TASK_CONTEXT_RESERVED3_SHIFT 12 +#define TDIF_TASK_CONTEXT_NETWORKINTERFACE_MASK 0x1 +#define TDIF_TASK_CONTEXT_NETWORKINTERFACE_SHIFT 13 +#define TDIF_TASK_CONTEXT_RECEIVEDDIFBYTESLEFTA_MASK 0xF +#define TDIF_TASK_CONTEXT_RECEIVEDDIFBYTESLEFTA_SHIFT 14 +#define TDIF_TASK_CONTEXT_TRANSMITEDDIFBYTESLEFTA_MASK 0xF +#define TDIF_TASK_CONTEXT_TRANSMITEDDIFBYTESLEFTA_SHIFT 18 +#define TDIF_TASK_CONTEXT_ERRORINIOA_MASK 0x1 +#define TDIF_TASK_CONTEXT_ERRORINIOA_SHIFT 22 +#define TDIF_TASK_CONTEXT_CHECKSUMOVERFLOWA_MASK 0x1 +#define TDIF_TASK_CONTEXT_CHECKSUMOVERFLOWA_SHIFT 23 +#define TDIF_TASK_CONTEXT_REFTAGMASK_MASK 0xF +#define TDIF_TASK_CONTEXT_REFTAGMASK_SHIFT 24 +#define TDIF_TASK_CONTEXT_FORWARDAPPTAGWITHMASK_MASK 0x1 +#define TDIF_TASK_CONTEXT_FORWARDAPPTAGWITHMASK_SHIFT 28 +#define TDIF_TASK_CONTEXT_FORWARDREFTAGWITHMASK_MASK 0x1 +#define TDIF_TASK_CONTEXT_FORWARDREFTAGWITHMASK_SHIFT 29 +#define TDIF_TASK_CONTEXT_KEEPREFTAGCONST_MASK 0x1 +#define TDIF_TASK_CONTEXT_KEEPREFTAGCONST_SHIFT 30 +#define TDIF_TASK_CONTEXT_RESERVED4_MASK 0x1 +#define TDIF_TASK_CONTEXT_RESERVED4_SHIFT 31 + __le32 offset_in_iob; + __le16 partial_crc_value_a; + __le16 partial_checksum_valuea_; + __le32 offset_in_ioa; + u8 partial_dif_data_a[8]; + u8 partial_dif_data_b[8]; +}; + +struct timers_context { + __le32 logical_client0; +#define TIMERS_CONTEXT_EXPIRATIONTIMELC0_MASK 0xFFFFFFF +#define TIMERS_CONTEXT_EXPIRATIONTIMELC0_SHIFT 0 +#define TIMERS_CONTEXT_VALIDLC0_MASK 0x1 +#define TIMERS_CONTEXT_VALIDLC0_SHIFT 28 +#define TIMERS_CONTEXT_ACTIVELC0_MASK 0x1 +#define TIMERS_CONTEXT_ACTIVELC0_SHIFT 29 +#define TIMERS_CONTEXT_RESERVED0_MASK 0x3 +#define TIMERS_CONTEXT_RESERVED0_SHIFT 30 + __le32 logical_client1; +#define TIMERS_CONTEXT_EXPIRATIONTIMELC1_MASK 0xFFFFFFF +#define TIMERS_CONTEXT_EXPIRATIONTIMELC1_SHIFT 0 +#define TIMERS_CONTEXT_VALIDLC1_MASK 0x1 +#define TIMERS_CONTEXT_VALIDLC1_SHIFT 28 +#define TIMERS_CONTEXT_ACTIVELC1_MASK 0x1 +#define TIMERS_CONTEXT_ACTIVELC1_SHIFT 29 +#define TIMERS_CONTEXT_RESERVED1_MASK 0x3 +#define TIMERS_CONTEXT_RESERVED1_SHIFT 30 + __le32 logical_client2; +#define TIMERS_CONTEXT_EXPIRATIONTIMELC2_MASK 0xFFFFFFF +#define TIMERS_CONTEXT_EXPIRATIONTIMELC2_SHIFT 0 +#define TIMERS_CONTEXT_VALIDLC2_MASK 0x1 +#define TIMERS_CONTEXT_VALIDLC2_SHIFT 28 +#define TIMERS_CONTEXT_ACTIVELC2_MASK 0x1 +#define TIMERS_CONTEXT_ACTIVELC2_SHIFT 29 +#define TIMERS_CONTEXT_RESERVED2_MASK 0x3 +#define TIMERS_CONTEXT_RESERVED2_SHIFT 30 + __le32 host_expiration_fields; +#define TIMERS_CONTEXT_HOSTEXPRIRATIONVALUE_MASK 0xFFFFFFF +#define TIMERS_CONTEXT_HOSTEXPRIRATIONVALUE_SHIFT 0 +#define TIMERS_CONTEXT_HOSTEXPRIRATIONVALID_MASK 0x1 +#define TIMERS_CONTEXT_HOSTEXPRIRATIONVALID_SHIFT 28 +#define TIMERS_CONTEXT_RESERVED3_MASK 0x7 +#define TIMERS_CONTEXT_RESERVED3_SHIFT 29 +}; #endif /* __COMMON_HSI__ */ diff --git a/include/linux/qed/iscsi_common.h b/include/linux/qed/iscsi_common.h new file mode 100644 index 000000000000..b3c0feb15ae9 --- /dev/null +++ b/include/linux/qed/iscsi_common.h @@ -0,0 +1,1439 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef __ISCSI_COMMON__ +#define __ISCSI_COMMON__ +/**********************/ +/* ISCSI FW CONSTANTS */ +/**********************/ + +/* iSCSI HSI constants */ +#define ISCSI_DEFAULT_MTU (1500) + +/* Current iSCSI HSI version number composed of two fields (16 bit) */ +#define ISCSI_HSI_MAJOR_VERSION (0) +#define ISCSI_HSI_MINOR_VERSION (0) + +/* KWQ (kernel work queue) layer codes */ +#define ISCSI_SLOW_PATH_LAYER_CODE (6) + +/* CQE completion status */ +#define ISCSI_EQE_COMPLETION_SUCCESS (0x0) +#define ISCSI_EQE_RST_CONN_RCVD (0x1) + +/* iSCSI parameter defaults */ +#define ISCSI_DEFAULT_HEADER_DIGEST (0) +#define ISCSI_DEFAULT_DATA_DIGEST (0) +#define ISCSI_DEFAULT_INITIAL_R2T (1) +#define ISCSI_DEFAULT_IMMEDIATE_DATA (1) +#define ISCSI_DEFAULT_MAX_PDU_LENGTH (0x2000) +#define ISCSI_DEFAULT_FIRST_BURST_LENGTH (0x10000) +#define ISCSI_DEFAULT_MAX_BURST_LENGTH (0x40000) +#define ISCSI_DEFAULT_MAX_OUTSTANDING_R2T (1) + +/* iSCSI parameter limits */ +#define ISCSI_MIN_VAL_MAX_PDU_LENGTH (0x200) +#define ISCSI_MAX_VAL_MAX_PDU_LENGTH (0xffffff) +#define ISCSI_MIN_VAL_BURST_LENGTH (0x200) +#define ISCSI_MAX_VAL_BURST_LENGTH (0xffffff) +#define ISCSI_MIN_VAL_MAX_OUTSTANDING_R2T (1) +#define ISCSI_MAX_VAL_MAX_OUTSTANDING_R2T (0xff) + +/* iSCSI reserved params */ +#define ISCSI_ITT_ALL_ONES (0xffffffff) +#define ISCSI_TTT_ALL_ONES (0xffffffff) + +#define ISCSI_OPTION_1_OFF_CHIP_TCP 1 +#define ISCSI_OPTION_2_ON_CHIP_TCP 2 + +#define ISCSI_INITIATOR_MODE 0 +#define ISCSI_TARGET_MODE 1 + +/* iSCSI request op codes */ +#define ISCSI_OPCODE_NOP_OUT_NO_IMM (0) +#define ISCSI_OPCODE_NOP_OUT ( \ + ISCSI_OPCODE_NOP_OUT_NO_IMM | 0x40) +#define ISCSI_OPCODE_SCSI_CMD_NO_IMM (1) +#define ISCSI_OPCODE_SCSI_CMD ( \ + ISCSI_OPCODE_SCSI_CMD_NO_IMM | 0x40) +#define ISCSI_OPCODE_TMF_REQUEST_NO_IMM (2) +#define ISCSI_OPCODE_TMF_REQUEST ( \ + ISCSI_OPCODE_TMF_REQUEST_NO_IMM | 0x40) +#define ISCSI_OPCODE_LOGIN_REQUEST_NO_IMM (3) +#define ISCSI_OPCODE_LOGIN_REQUEST ( \ + ISCSI_OPCODE_LOGIN_REQUEST_NO_IMM | 0x40) +#define ISCSI_OPCODE_TEXT_REQUEST_NO_IMM (4) +#define ISCSI_OPCODE_TEXT_REQUEST ( \ + ISCSI_OPCODE_TEXT_REQUEST_NO_IMM | 0x40) +#define ISCSI_OPCODE_DATA_OUT (5) +#define ISCSI_OPCODE_LOGOUT_REQUEST_NO_IMM (6) +#define ISCSI_OPCODE_LOGOUT_REQUEST ( \ + ISCSI_OPCODE_LOGOUT_REQUEST_NO_IMM | 0x40) + +/* iSCSI response/messages op codes */ +#define ISCSI_OPCODE_NOP_IN (0x20) +#define ISCSI_OPCODE_SCSI_RESPONSE (0x21) +#define ISCSI_OPCODE_TMF_RESPONSE (0x22) +#define ISCSI_OPCODE_LOGIN_RESPONSE (0x23) +#define ISCSI_OPCODE_TEXT_RESPONSE (0x24) +#define ISCSI_OPCODE_DATA_IN (0x25) +#define ISCSI_OPCODE_LOGOUT_RESPONSE (0x26) +#define ISCSI_OPCODE_R2T (0x31) +#define ISCSI_OPCODE_ASYNC_MSG (0x32) +#define ISCSI_OPCODE_REJECT (0x3f) + +/* iSCSI stages */ +#define ISCSI_STAGE_SECURITY_NEGOTIATION (0) +#define ISCSI_STAGE_LOGIN_OPERATIONAL_NEGOTIATION (1) +#define ISCSI_STAGE_FULL_FEATURE_PHASE (3) + +/* iSCSI CQE errors */ +#define CQE_ERROR_BITMAP_DATA_DIGEST (0x08) +#define CQE_ERROR_BITMAP_RCV_ON_INVALID_CONN (0x10) +#define CQE_ERROR_BITMAP_DATA_TRUNCATED (0x20) + +struct cqe_error_bitmap { + u8 cqe_error_status_bits; +#define CQE_ERROR_BITMAP_DIF_ERR_BITS_MASK 0x7 +#define CQE_ERROR_BITMAP_DIF_ERR_BITS_SHIFT 0 +#define CQE_ERROR_BITMAP_DATA_DIGEST_ERR_MASK 0x1 +#define CQE_ERROR_BITMAP_DATA_DIGEST_ERR_SHIFT 3 +#define CQE_ERROR_BITMAP_RCV_ON_INVALID_CONN_MASK 0x1 +#define CQE_ERROR_BITMAP_RCV_ON_INVALID_CONN_SHIFT 4 +#define CQE_ERROR_BITMAP_DATA_TRUNCATED_ERR_MASK 0x1 +#define CQE_ERROR_BITMAP_DATA_TRUNCATED_ERR_SHIFT 5 +#define CQE_ERROR_BITMAP_UNDER_RUN_ERR_MASK 0x1 +#define CQE_ERROR_BITMAP_UNDER_RUN_ERR_SHIFT 6 +#define CQE_ERROR_BITMAP_RESERVED2_MASK 0x1 +#define CQE_ERROR_BITMAP_RESERVED2_SHIFT 7 +}; + +union cqe_error_status { + u8 error_status; + struct cqe_error_bitmap error_bits; +}; + +struct data_hdr { + __le32 data[12]; +}; + +struct iscsi_async_msg_hdr { + __le16 reserved0; + u8 flags_attr; +#define ISCSI_ASYNC_MSG_HDR_RSRV_MASK 0x7F +#define ISCSI_ASYNC_MSG_HDR_RSRV_SHIFT 0 +#define ISCSI_ASYNC_MSG_HDR_CONST1_MASK 0x1 +#define ISCSI_ASYNC_MSG_HDR_CONST1_SHIFT 7 + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_ASYNC_MSG_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_ASYNC_MSG_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_ASYNC_MSG_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_ASYNC_MSG_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair lun; + __le32 all_ones; + __le32 reserved1; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le16 param1_rsrv; + u8 async_vcode; + u8 async_event; + __le16 param3_rsrv; + __le16 param2_rsrv; + __le32 reserved7; +}; + +struct iscsi_sge { + struct regpair sge_addr; + __le16 sge_len; + __le16 reserved0; + __le32 reserved1; +}; + +struct iscsi_cached_sge_ctx { + struct iscsi_sge sge; + struct regpair reserved; + __le32 dsgl_curr_offset[2]; +}; + +struct iscsi_cmd_hdr { + __le16 reserved1; + u8 flags_attr; +#define ISCSI_CMD_HDR_ATTR_MASK 0x7 +#define ISCSI_CMD_HDR_ATTR_SHIFT 0 +#define ISCSI_CMD_HDR_RSRV_MASK 0x3 +#define ISCSI_CMD_HDR_RSRV_SHIFT 3 +#define ISCSI_CMD_HDR_WRITE_MASK 0x1 +#define ISCSI_CMD_HDR_WRITE_SHIFT 5 +#define ISCSI_CMD_HDR_READ_MASK 0x1 +#define ISCSI_CMD_HDR_READ_SHIFT 6 +#define ISCSI_CMD_HDR_FINAL_MASK 0x1 +#define ISCSI_CMD_HDR_FINAL_SHIFT 7 + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_CMD_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_CMD_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_CMD_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_CMD_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair lun; + __le32 itt; + __le32 expected_transfer_length; + __le32 cmd_sn; + __le32 exp_stat_sn; + __le32 cdb[4]; +}; + +struct iscsi_common_hdr { + u8 hdr_status; + u8 hdr_response; + u8 hdr_flags; + u8 hdr_first_byte; +#define ISCSI_COMMON_HDR_OPCODE_MASK 0x3F +#define ISCSI_COMMON_HDR_OPCODE_SHIFT 0 +#define ISCSI_COMMON_HDR_IMM_MASK 0x1 +#define ISCSI_COMMON_HDR_IMM_SHIFT 6 +#define ISCSI_COMMON_HDR_RSRV_MASK 0x1 +#define ISCSI_COMMON_HDR_RSRV_SHIFT 7 + __le32 hdr_second_dword; +#define ISCSI_COMMON_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_COMMON_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_COMMON_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_COMMON_HDR_TOTAL_AHS_LEN_SHIFT 24 + __le32 lun_reserved[4]; + __le32 data[6]; +}; + +struct iscsi_conn_offload_params { + struct regpair sq_pbl_addr; + struct regpair r2tq_pbl_addr; + struct regpair xhq_pbl_addr; + struct regpair uhq_pbl_addr; + __le32 initial_ack; + __le16 physical_q0; + __le16 physical_q1; + u8 flags; +#define ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B_MASK 0x1 +#define ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B_SHIFT 0 +#define ISCSI_CONN_OFFLOAD_PARAMS_TARGET_MODE_MASK 0x1 +#define ISCSI_CONN_OFFLOAD_PARAMS_TARGET_MODE_SHIFT 1 +#define ISCSI_CONN_OFFLOAD_PARAMS_RESERVED1_MASK 0x3F +#define ISCSI_CONN_OFFLOAD_PARAMS_RESERVED1_SHIFT 2 + u8 pbl_page_size_log; + u8 pbe_page_size_log; + u8 default_cq; + __le32 stat_sn; +}; + +struct iscsi_slow_path_hdr { + u8 op_code; + u8 flags; +#define ISCSI_SLOW_PATH_HDR_RESERVED0_MASK 0xF +#define ISCSI_SLOW_PATH_HDR_RESERVED0_SHIFT 0 +#define ISCSI_SLOW_PATH_HDR_LAYER_CODE_MASK 0x7 +#define ISCSI_SLOW_PATH_HDR_LAYER_CODE_SHIFT 4 +#define ISCSI_SLOW_PATH_HDR_RESERVED1_MASK 0x1 +#define ISCSI_SLOW_PATH_HDR_RESERVED1_SHIFT 7 +}; + +struct iscsi_conn_update_ramrod_params { + struct iscsi_slow_path_hdr hdr; + __le16 conn_id; + __le32 fw_cid; + u8 flags; +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_HD_EN_MASK 0x1 +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_HD_EN_SHIFT 0 +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_DD_EN_MASK 0x1 +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_DD_EN_SHIFT 1 +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_INITIAL_R2T_MASK 0x1 +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_INITIAL_R2T_SHIFT 2 +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_IMMEDIATE_DATA_MASK 0x1 +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_IMMEDIATE_DATA_SHIFT 3 +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_RESERVED1_MASK 0xF +#define ISCSI_CONN_UPDATE_RAMROD_PARAMS_RESERVED1_SHIFT 4 + u8 reserved0[3]; + __le32 max_seq_size; + __le32 max_send_pdu_length; + __le32 max_recv_pdu_length; + __le32 first_seq_length; + __le32 exp_stat_sn; +}; + +struct iscsi_ext_cdb_cmd_hdr { + __le16 reserved1; + u8 flags_attr; +#define ISCSI_EXT_CDB_CMD_HDR_ATTR_MASK 0x7 +#define ISCSI_EXT_CDB_CMD_HDR_ATTR_SHIFT 0 +#define ISCSI_EXT_CDB_CMD_HDR_RSRV_MASK 0x3 +#define ISCSI_EXT_CDB_CMD_HDR_RSRV_SHIFT 3 +#define ISCSI_EXT_CDB_CMD_HDR_WRITE_MASK 0x1 +#define ISCSI_EXT_CDB_CMD_HDR_WRITE_SHIFT 5 +#define ISCSI_EXT_CDB_CMD_HDR_READ_MASK 0x1 +#define ISCSI_EXT_CDB_CMD_HDR_READ_SHIFT 6 +#define ISCSI_EXT_CDB_CMD_HDR_FINAL_MASK 0x1 +#define ISCSI_EXT_CDB_CMD_HDR_FINAL_SHIFT 7 + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_EXT_CDB_CMD_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_EXT_CDB_CMD_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_EXT_CDB_CMD_HDR_CDB_SIZE_MASK 0xFF +#define ISCSI_EXT_CDB_CMD_HDR_CDB_SIZE_SHIFT 24 + struct regpair lun; + __le32 itt; + __le32 expected_transfer_length; + __le32 cmd_sn; + __le32 exp_stat_sn; + struct iscsi_sge cdb_sge; +}; + +struct iscsi_login_req_hdr { + u8 version_min; + u8 version_max; + u8 flags_attr; +#define ISCSI_LOGIN_REQ_HDR_NSG_MASK 0x3 +#define ISCSI_LOGIN_REQ_HDR_NSG_SHIFT 0 +#define ISCSI_LOGIN_REQ_HDR_CSG_MASK 0x3 +#define ISCSI_LOGIN_REQ_HDR_CSG_SHIFT 2 +#define ISCSI_LOGIN_REQ_HDR_RSRV_MASK 0x3 +#define ISCSI_LOGIN_REQ_HDR_RSRV_SHIFT 4 +#define ISCSI_LOGIN_REQ_HDR_C_MASK 0x1 +#define ISCSI_LOGIN_REQ_HDR_C_SHIFT 6 +#define ISCSI_LOGIN_REQ_HDR_T_MASK 0x1 +#define ISCSI_LOGIN_REQ_HDR_T_SHIFT 7 + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_LOGIN_REQ_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_LOGIN_REQ_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_LOGIN_REQ_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_LOGIN_REQ_HDR_TOTAL_AHS_LEN_SHIFT 24 + __le32 isid_TABC; + __le16 tsih; + __le16 isid_d; + __le32 itt; + __le16 reserved1; + __le16 cid; + __le32 cmd_sn; + __le32 exp_stat_sn; + __le32 reserved2[4]; +}; + +struct iscsi_logout_req_hdr { + __le16 reserved0; + u8 reason_code; + u8 opcode; + __le32 reserved1; + __le32 reserved2[2]; + __le32 itt; + __le16 reserved3; + __le16 cid; + __le32 cmd_sn; + __le32 exp_stat_sn; + __le32 reserved4[4]; +}; + +struct iscsi_data_out_hdr { + __le16 reserved1; + u8 flags_attr; +#define ISCSI_DATA_OUT_HDR_RSRV_MASK 0x7F +#define ISCSI_DATA_OUT_HDR_RSRV_SHIFT 0 +#define ISCSI_DATA_OUT_HDR_FINAL_MASK 0x1 +#define ISCSI_DATA_OUT_HDR_FINAL_SHIFT 7 + u8 opcode; + __le32 reserved2; + struct regpair lun; + __le32 itt; + __le32 ttt; + __le32 reserved3; + __le32 exp_stat_sn; + __le32 reserved4; + __le32 data_sn; + __le32 buffer_offset; + __le32 reserved5; +}; + +struct iscsi_data_in_hdr { + u8 status_rsvd; + u8 reserved1; + u8 flags; +#define ISCSI_DATA_IN_HDR_STATUS_MASK 0x1 +#define ISCSI_DATA_IN_HDR_STATUS_SHIFT 0 +#define ISCSI_DATA_IN_HDR_UNDERFLOW_MASK 0x1 +#define ISCSI_DATA_IN_HDR_UNDERFLOW_SHIFT 1 +#define ISCSI_DATA_IN_HDR_OVERFLOW_MASK 0x1 +#define ISCSI_DATA_IN_HDR_OVERFLOW_SHIFT 2 +#define ISCSI_DATA_IN_HDR_RSRV_MASK 0x7 +#define ISCSI_DATA_IN_HDR_RSRV_SHIFT 3 +#define ISCSI_DATA_IN_HDR_ACK_MASK 0x1 +#define ISCSI_DATA_IN_HDR_ACK_SHIFT 6 +#define ISCSI_DATA_IN_HDR_FINAL_MASK 0x1 +#define ISCSI_DATA_IN_HDR_FINAL_SHIFT 7 + u8 opcode; + __le32 reserved2; + struct regpair lun; + __le32 itt; + __le32 ttt; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le32 data_sn; + __le32 buffer_offset; + __le32 residual_count; +}; + +struct iscsi_r2t_hdr { + u8 reserved0[3]; + u8 opcode; + __le32 reserved2; + struct regpair lun; + __le32 itt; + __le32 ttt; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le32 r2t_sn; + __le32 buffer_offset; + __le32 desired_data_trns_len; +}; + +struct iscsi_nop_out_hdr { + __le16 reserved1; + u8 flags_attr; +#define ISCSI_NOP_OUT_HDR_RSRV_MASK 0x7F +#define ISCSI_NOP_OUT_HDR_RSRV_SHIFT 0 +#define ISCSI_NOP_OUT_HDR_CONST1_MASK 0x1 +#define ISCSI_NOP_OUT_HDR_CONST1_SHIFT 7 + u8 opcode; + __le32 reserved2; + struct regpair lun; + __le32 itt; + __le32 ttt; + __le32 cmd_sn; + __le32 exp_stat_sn; + __le32 reserved3; + __le32 reserved4; + __le32 reserved5; + __le32 reserved6; +}; + +struct iscsi_nop_in_hdr { + __le16 reserved0; + u8 flags_attr; +#define ISCSI_NOP_IN_HDR_RSRV_MASK 0x7F +#define ISCSI_NOP_IN_HDR_RSRV_SHIFT 0 +#define ISCSI_NOP_IN_HDR_CONST1_MASK 0x1 +#define ISCSI_NOP_IN_HDR_CONST1_SHIFT 7 + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_NOP_IN_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_NOP_IN_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_NOP_IN_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_NOP_IN_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair lun; + __le32 itt; + __le32 ttt; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le32 reserved5; + __le32 reserved6; + __le32 reserved7; +}; + +struct iscsi_login_response_hdr { + u8 version_active; + u8 version_max; + u8 flags_attr; +#define ISCSI_LOGIN_RESPONSE_HDR_NSG_MASK 0x3 +#define ISCSI_LOGIN_RESPONSE_HDR_NSG_SHIFT 0 +#define ISCSI_LOGIN_RESPONSE_HDR_CSG_MASK 0x3 +#define ISCSI_LOGIN_RESPONSE_HDR_CSG_SHIFT 2 +#define ISCSI_LOGIN_RESPONSE_HDR_RSRV_MASK 0x3 +#define ISCSI_LOGIN_RESPONSE_HDR_RSRV_SHIFT 4 +#define ISCSI_LOGIN_RESPONSE_HDR_C_MASK 0x1 +#define ISCSI_LOGIN_RESPONSE_HDR_C_SHIFT 6 +#define ISCSI_LOGIN_RESPONSE_HDR_T_MASK 0x1 +#define ISCSI_LOGIN_RESPONSE_HDR_T_SHIFT 7 + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_LOGIN_RESPONSE_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_LOGIN_RESPONSE_HDR_TOTAL_AHS_LEN_SHIFT 24 + __le32 isid_TABC; + __le16 tsih; + __le16 isid_d; + __le32 itt; + __le32 reserved1; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le16 reserved2; + u8 status_detail; + u8 status_class; + __le32 reserved4[2]; +}; + +struct iscsi_logout_response_hdr { + u8 reserved1; + u8 response; + u8 flags; + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_LOGOUT_RESPONSE_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_LOGOUT_RESPONSE_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_LOGOUT_RESPONSE_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_LOGOUT_RESPONSE_HDR_TOTAL_AHS_LEN_SHIFT 24 + __le32 reserved2[2]; + __le32 itt; + __le32 reserved3; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le32 reserved4; + __le16 time2retain; + __le16 time2wait; + __le32 reserved5[1]; +}; + +struct iscsi_text_request_hdr { + __le16 reserved0; + u8 flags_attr; +#define ISCSI_TEXT_REQUEST_HDR_RSRV_MASK 0x3F +#define ISCSI_TEXT_REQUEST_HDR_RSRV_SHIFT 0 +#define ISCSI_TEXT_REQUEST_HDR_C_MASK 0x1 +#define ISCSI_TEXT_REQUEST_HDR_C_SHIFT 6 +#define ISCSI_TEXT_REQUEST_HDR_F_MASK 0x1 +#define ISCSI_TEXT_REQUEST_HDR_F_SHIFT 7 + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_TEXT_REQUEST_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_TEXT_REQUEST_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_TEXT_REQUEST_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_TEXT_REQUEST_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair lun; + __le32 itt; + __le32 ttt; + __le32 cmd_sn; + __le32 exp_stat_sn; + __le32 reserved4[4]; +}; + +struct iscsi_text_response_hdr { + __le16 reserved1; + u8 flags; +#define ISCSI_TEXT_RESPONSE_HDR_RSRV_MASK 0x3F +#define ISCSI_TEXT_RESPONSE_HDR_RSRV_SHIFT 0 +#define ISCSI_TEXT_RESPONSE_HDR_C_MASK 0x1 +#define ISCSI_TEXT_RESPONSE_HDR_C_SHIFT 6 +#define ISCSI_TEXT_RESPONSE_HDR_F_MASK 0x1 +#define ISCSI_TEXT_RESPONSE_HDR_F_SHIFT 7 + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_TEXT_RESPONSE_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_TEXT_RESPONSE_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair lun; + __le32 itt; + __le32 ttt; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le32 reserved4[3]; +}; + +struct iscsi_tmf_request_hdr { + __le16 reserved0; + u8 function; + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_TMF_REQUEST_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_TMF_REQUEST_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_TMF_REQUEST_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_TMF_REQUEST_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair lun; + __le32 itt; + __le32 rtt; + __le32 cmd_sn; + __le32 exp_stat_sn; + __le32 ref_cmd_sn; + __le32 exp_data_sn; + __le32 reserved4[2]; +}; + +struct iscsi_tmf_response_hdr { + u8 reserved2; + u8 hdr_response; + u8 hdr_flags; + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_TMF_RESPONSE_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_TMF_RESPONSE_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_TMF_RESPONSE_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_TMF_RESPONSE_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair reserved0; + __le32 itt; + __le32 rtt; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le32 reserved4[3]; +}; + +struct iscsi_response_hdr { + u8 hdr_status; + u8 hdr_response; + u8 hdr_flags; + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_RESPONSE_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_RESPONSE_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_RESPONSE_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_RESPONSE_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair lun; + __le32 itt; + __le32 snack_tag; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le32 exp_data_sn; + __le32 bi_residual_count; + __le32 residual_count; +}; + +struct iscsi_reject_hdr { + u8 reserved4; + u8 hdr_reason; + u8 hdr_flags; + u8 opcode; + __le32 hdr_second_dword; +#define ISCSI_REJECT_HDR_DATA_SEG_LEN_MASK 0xFFFFFF +#define ISCSI_REJECT_HDR_DATA_SEG_LEN_SHIFT 0 +#define ISCSI_REJECT_HDR_TOTAL_AHS_LEN_MASK 0xFF +#define ISCSI_REJECT_HDR_TOTAL_AHS_LEN_SHIFT 24 + struct regpair reserved0; + __le32 reserved1; + __le32 reserved2; + __le32 stat_sn; + __le32 exp_cmd_sn; + __le32 max_cmd_sn; + __le32 data_sn; + __le32 reserved3[2]; +}; + +union iscsi_task_hdr { + struct iscsi_common_hdr common; + struct data_hdr data; + struct iscsi_cmd_hdr cmd; + struct iscsi_ext_cdb_cmd_hdr ext_cdb_cmd; + struct iscsi_login_req_hdr login_req; + struct iscsi_logout_req_hdr logout_req; + struct iscsi_data_out_hdr data_out; + struct iscsi_data_in_hdr data_in; + struct iscsi_r2t_hdr r2t; + struct iscsi_nop_out_hdr nop_out; + struct iscsi_nop_in_hdr nop_in; + struct iscsi_login_response_hdr login_response; + struct iscsi_logout_response_hdr logout_response; + struct iscsi_text_request_hdr text_request; + struct iscsi_text_response_hdr text_response; + struct iscsi_tmf_request_hdr tmf_request; + struct iscsi_tmf_response_hdr tmf_response; + struct iscsi_response_hdr response; + struct iscsi_reject_hdr reject; + struct iscsi_async_msg_hdr async_msg; +}; + +struct iscsi_cqe_common { + __le16 conn_id; + u8 cqe_type; + union cqe_error_status error_bitmap; + __le32 reserved[3]; + union iscsi_task_hdr iscsi_hdr; +}; + +struct iscsi_cqe_solicited { + __le16 conn_id; + u8 cqe_type; + union cqe_error_status error_bitmap; + __le16 itid; + u8 task_type; + u8 fw_dbg_field; + __le32 reserved1[2]; + union iscsi_task_hdr iscsi_hdr; +}; + +struct iscsi_cqe_unsolicited { + __le16 conn_id; + u8 cqe_type; + union cqe_error_status error_bitmap; + __le16 reserved0; + u8 reserved1; + u8 unsol_cqe_type; + struct regpair rqe_opaque; + union iscsi_task_hdr iscsi_hdr; +}; + +union iscsi_cqe { + struct iscsi_cqe_common cqe_common; + struct iscsi_cqe_solicited cqe_solicited; + struct iscsi_cqe_unsolicited cqe_unsolicited; +}; + +enum iscsi_cqes_type { + ISCSI_CQE_TYPE_SOLICITED = 1, + ISCSI_CQE_TYPE_UNSOLICITED, + ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE + , + ISCSI_CQE_TYPE_TASK_CLEANUP, + ISCSI_CQE_TYPE_DUMMY, + MAX_ISCSI_CQES_TYPE +}; + +enum iscsi_cqe_unsolicited_type { + ISCSI_CQE_UNSOLICITED_NONE, + ISCSI_CQE_UNSOLICITED_SINGLE, + ISCSI_CQE_UNSOLICITED_FIRST, + ISCSI_CQE_UNSOLICITED_MIDDLE, + ISCSI_CQE_UNSOLICITED_LAST, + MAX_ISCSI_CQE_UNSOLICITED_TYPE +}; + +struct iscsi_virt_sgl_ctx { + struct regpair sgl_base; + struct regpair dsgl_base; + __le32 sgl_initial_offset; + __le32 dsgl_initial_offset; + __le32 dsgl_curr_offset[2]; +}; + +struct iscsi_sgl_var_params { + u8 sgl_ptr; + u8 dsgl_ptr; + __le16 sge_offset; + __le16 dsge_offset; +}; + +struct iscsi_phys_sgl_ctx { + struct regpair sgl_base; + struct regpair dsgl_base; + u8 sgl_size; + u8 dsgl_size; + __le16 reserved; + struct iscsi_sgl_var_params var_params[2]; +}; + +union iscsi_data_desc_ctx { + struct iscsi_virt_sgl_ctx virt_sgl; + struct iscsi_phys_sgl_ctx phys_sgl; + struct iscsi_cached_sge_ctx cached_sge; +}; + +struct iscsi_debug_modes { + u8 flags; +#define ISCSI_DEBUG_MODES_ASSERT_IF_RX_CONN_ERROR_MASK 0x1 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RX_CONN_ERROR_SHIFT 0 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_RESET_MASK 0x1 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_RESET_SHIFT 1 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_FIN_MASK 0x1 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_FIN_SHIFT 2 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_CLEANUP_MASK 0x1 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_CLEANUP_SHIFT 3 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_REJECT_OR_ASYNC_MASK 0x1 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_REJECT_OR_ASYNC_SHIFT 4 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_NOP_MASK 0x1 +#define ISCSI_DEBUG_MODES_ASSERT_IF_RECV_NOP_SHIFT 5 +#define ISCSI_DEBUG_MODES_RESERVED0_MASK 0x3 +#define ISCSI_DEBUG_MODES_RESERVED0_SHIFT 6 +}; + +struct iscsi_dif_flags { + u8 flags; +#define ISCSI_DIF_FLAGS_PROT_INTERVAL_SIZE_LOG_MASK 0xF +#define ISCSI_DIF_FLAGS_PROT_INTERVAL_SIZE_LOG_SHIFT 0 +#define ISCSI_DIF_FLAGS_DIF_TO_PEER_MASK 0x1 +#define ISCSI_DIF_FLAGS_DIF_TO_PEER_SHIFT 4 +#define ISCSI_DIF_FLAGS_HOST_INTERFACE_MASK 0x7 +#define ISCSI_DIF_FLAGS_HOST_INTERFACE_SHIFT 5 +}; + +enum iscsi_eqe_opcode { + ISCSI_EVENT_TYPE_INIT_FUNC = 0, + ISCSI_EVENT_TYPE_DESTROY_FUNC, + ISCSI_EVENT_TYPE_OFFLOAD_CONN, + ISCSI_EVENT_TYPE_UPDATE_CONN, + ISCSI_EVENT_TYPE_CLEAR_SQ, + ISCSI_EVENT_TYPE_TERMINATE_CONN, + ISCSI_EVENT_TYPE_ASYN_CONNECT_COMPLETE, + ISCSI_EVENT_TYPE_ASYN_TERMINATE_DONE, + RESERVED8, + RESERVED9, + ISCSI_EVENT_TYPE_START_OF_ERROR_TYPES = 10, + ISCSI_EVENT_TYPE_ASYN_ABORT_RCVD, + ISCSI_EVENT_TYPE_ASYN_CLOSE_RCVD, + ISCSI_EVENT_TYPE_ASYN_SYN_RCVD, + ISCSI_EVENT_TYPE_ASYN_MAX_RT_TIME, + ISCSI_EVENT_TYPE_ASYN_MAX_RT_CNT, + ISCSI_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT, + ISCSI_EVENT_TYPE_ASYN_FIN_WAIT2, + ISCSI_EVENT_TYPE_ISCSI_CONN_ERROR, + ISCSI_EVENT_TYPE_TCP_CONN_ERROR, + ISCSI_EVENT_TYPE_ASYN_DELETE_OOO_ISLES, + MAX_ISCSI_EQE_OPCODE +}; + +enum iscsi_error_types { + ISCSI_STATUS_NONE = 0, + ISCSI_CQE_ERROR_UNSOLICITED_RCV_ON_INVALID_CONN = 1, + ISCSI_CONN_ERROR_TASK_CID_MISMATCH, + ISCSI_CONN_ERROR_TASK_NOT_VALID, + ISCSI_CONN_ERROR_RQ_RING_IS_FULL, + ISCSI_CONN_ERROR_CMDQ_RING_IS_FULL, + ISCSI_CONN_ERROR_HQE_CACHING_FAILED, + ISCSI_CONN_ERROR_HEADER_DIGEST_ERROR, + ISCSI_CONN_ERROR_LOCAL_COMPLETION_ERROR, + ISCSI_CONN_ERROR_DATA_OVERRUN, + ISCSI_CONN_ERROR_OUT_OF_SGES_ERROR, + ISCSI_CONN_ERROR_TCP_SEG_PROC_URG_ERROR, + ISCSI_CONN_ERROR_TCP_SEG_PROC_IP_OPTIONS_ERROR, + ISCSI_CONN_ERROR_TCP_SEG_PROC_CONNECT_INVALID_WS_OPTION, + ISCSI_CONN_ERROR_TCP_IP_FRAGMENT_ERROR, + ISCSI_CONN_ERROR_PROTOCOL_ERR_AHS_LEN, + ISCSI_CONN_ERROR_PROTOCOL_ERR_AHS_TYPE, + ISCSI_CONN_ERROR_PROTOCOL_ERR_ITT_OUT_OF_RANGE, + ISCSI_CONN_ERROR_PROTOCOL_ERR_TTT_OUT_OF_RANGE, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_EXCEEDS_PDU_SIZE, + ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE, + ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE_BEFORE_UPDATE, + ISCSI_CONN_ERROR_UNVALID_NOPIN_DSL, + ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_CARRIES_NO_DATA, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SN, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_IN_TTT, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_OUT_ITT, + ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_TTT, + ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_BUFFER_OFFSET, + ISCSI_CONN_ERROR_PROTOCOL_ERR_BUFFER_OFFSET_OOO, + ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_SN, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_2, + ISCSI_CONN_ERROR_PROTOCOL_ERR_LUN, + ISCSI_CONN_ERROR_PROTOCOL_ERR_F_BIT_ZERO, + ISCSI_CONN_ERROR_PROTOCOL_ERR_F_BIT_ZERO_S_BIT_ONE, + ISCSI_CONN_ERROR_PROTOCOL_ERR_EXP_STAT_SN, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DSL_NOT_ZERO, + ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_DSL, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG, + ISCSI_CONN_ERROR_PROTOCOL_ERR_OUTSTANDING_R2T_COUNT, + ISCSI_CONN_ERROR_PROTOCOL_ERR_DIF_TX, + ISCSI_CONN_ERROR_SENSE_DATA_LENGTH, + ISCSI_CONN_ERROR_DATA_PLACEMENT_ERROR, + ISCSI_ERROR_UNKNOWN, + MAX_ISCSI_ERROR_TYPES +}; + +struct iscsi_mflags { + u8 mflags; +#define ISCSI_MFLAGS_SLOW_IO_MASK 0x1 +#define ISCSI_MFLAGS_SLOW_IO_SHIFT 0 +#define ISCSI_MFLAGS_SINGLE_SGE_MASK 0x1 +#define ISCSI_MFLAGS_SINGLE_SGE_SHIFT 1 +#define ISCSI_MFLAGS_RESERVED_MASK 0x3F +#define ISCSI_MFLAGS_RESERVED_SHIFT 2 +}; + +struct iscsi_sgl { + struct regpair sgl_addr; + __le16 updated_sge_size; + __le16 updated_sge_offset; + __le32 byte_offset; +}; + +union iscsi_mstorm_sgl { + struct iscsi_sgl sgl_struct; + struct iscsi_sge single_sge; +}; + +enum iscsi_ramrod_cmd_id { + ISCSI_RAMROD_CMD_ID_UNUSED = 0, + ISCSI_RAMROD_CMD_ID_INIT_FUNC = 1, + ISCSI_RAMROD_CMD_ID_DESTROY_FUNC = 2, + ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN = 3, + ISCSI_RAMROD_CMD_ID_UPDATE_CONN = 4, + ISCSI_RAMROD_CMD_ID_TERMINATION_CONN = 5, + ISCSI_RAMROD_CMD_ID_CLEAR_SQ = 6, + MAX_ISCSI_RAMROD_CMD_ID +}; + +struct iscsi_reg1 { + __le32 reg1_map; +#define ISCSI_REG1_NUM_FAST_SGES_MASK 0x7 +#define ISCSI_REG1_NUM_FAST_SGES_SHIFT 0 +#define ISCSI_REG1_RESERVED1_MASK 0x1FFFFFFF +#define ISCSI_REG1_RESERVED1_SHIFT 3 +}; + +union iscsi_seq_num { + __le16 data_sn; + __le16 r2t_sn; +}; + +struct iscsi_spe_conn_offload { + struct iscsi_slow_path_hdr hdr; + __le16 conn_id; + __le32 fw_cid; + struct iscsi_conn_offload_params iscsi; + struct tcp_offload_params tcp; +}; + +struct iscsi_spe_conn_offload_option2 { + struct iscsi_slow_path_hdr hdr; + __le16 conn_id; + __le32 fw_cid; + struct iscsi_conn_offload_params iscsi; + struct tcp_offload_params_opt2 tcp; +}; + +struct iscsi_spe_conn_termination { + struct iscsi_slow_path_hdr hdr; + __le16 conn_id; + __le32 fw_cid; + u8 abortive; + u8 reserved0[7]; + struct regpair queue_cnts_addr; + struct regpair query_params_addr; +}; + +struct iscsi_spe_func_dstry { + struct iscsi_slow_path_hdr hdr; + __le16 reserved0; + __le32 reserved1; +}; + +struct iscsi_spe_func_init { + struct iscsi_slow_path_hdr hdr; + __le16 half_way_close_timeout; + u8 num_sq_pages_in_ring; + u8 num_r2tq_pages_in_ring; + u8 num_uhq_pages_in_ring; + u8 ll2_rx_queue_id; + u8 ooo_enable; + struct iscsi_debug_modes debug_mode; + __le16 reserved1; + __le32 reserved2; + __le32 reserved3; + __le32 reserved4; + struct scsi_init_func_params func_params; + struct scsi_init_func_queues q_params; +}; + +struct ystorm_iscsi_task_state { + union iscsi_data_desc_ctx sgl_ctx_union; + __le32 buffer_offset[2]; + __le16 bytes_nxt_dif; + __le16 rxmit_bytes_nxt_dif; + union iscsi_seq_num seq_num_union; + u8 dif_bytes_leftover; + u8 rxmit_dif_bytes_leftover; + __le16 reuse_count; + struct iscsi_dif_flags dif_flags; + u8 local_comp; + __le32 exp_r2t_sn; + __le32 sgl_offset[2]; +}; + +struct ystorm_iscsi_task_st_ctx { + struct ystorm_iscsi_task_state state; + union iscsi_task_hdr pdu_hdr; +}; + +struct ystorm_iscsi_task_ag_ctx { + u8 reserved; + u8 byte1; + __le16 word0; + u8 flags0; +#define YSTORM_ISCSI_TASK_AG_CTX_NIBBLE0_MASK 0xF +#define YSTORM_ISCSI_TASK_AG_CTX_NIBBLE0_SHIFT 0 +#define YSTORM_ISCSI_TASK_AG_CTX_BIT0_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_BIT0_SHIFT 4 +#define YSTORM_ISCSI_TASK_AG_CTX_BIT1_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_BIT1_SHIFT 5 +#define YSTORM_ISCSI_TASK_AG_CTX_VALID_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_VALID_SHIFT 6 +#define YSTORM_ISCSI_TASK_AG_CTX_BIT3_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_BIT3_SHIFT 7 + u8 flags1; +#define YSTORM_ISCSI_TASK_AG_CTX_CF0_MASK 0x3 +#define YSTORM_ISCSI_TASK_AG_CTX_CF0_SHIFT 0 +#define YSTORM_ISCSI_TASK_AG_CTX_CF1_MASK 0x3 +#define YSTORM_ISCSI_TASK_AG_CTX_CF1_SHIFT 2 +#define YSTORM_ISCSI_TASK_AG_CTX_CF2SPECIAL_MASK 0x3 +#define YSTORM_ISCSI_TASK_AG_CTX_CF2SPECIAL_SHIFT 4 +#define YSTORM_ISCSI_TASK_AG_CTX_CF0EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_CF0EN_SHIFT 6 +#define YSTORM_ISCSI_TASK_AG_CTX_CF1EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_CF1EN_SHIFT 7 + u8 flags2; +#define YSTORM_ISCSI_TASK_AG_CTX_BIT4_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_BIT4_SHIFT 0 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE0EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE0EN_SHIFT 1 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE1EN_SHIFT 2 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE2EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE2EN_SHIFT 3 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE3EN_SHIFT 4 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE4EN_SHIFT 5 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE5EN_SHIFT 6 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE6EN_MASK 0x1 +#define YSTORM_ISCSI_TASK_AG_CTX_RULE6EN_SHIFT 7 + u8 byte2; + __le32 TTT; + u8 byte3; + u8 byte4; + __le16 word1; +}; + +struct mstorm_iscsi_task_ag_ctx { + u8 cdu_validation; + u8 byte1; + __le16 task_cid; + u8 flags0; +#define MSTORM_ISCSI_TASK_AG_CTX_CONNECTION_TYPE_MASK 0xF +#define MSTORM_ISCSI_TASK_AG_CTX_CONNECTION_TYPE_SHIFT 0 +#define MSTORM_ISCSI_TASK_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_EXIST_IN_QM0_SHIFT 4 +#define MSTORM_ISCSI_TASK_AG_CTX_BIT1_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_BIT1_SHIFT 5 +#define MSTORM_ISCSI_TASK_AG_CTX_VALID_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_VALID_SHIFT 6 +#define MSTORM_ISCSI_TASK_AG_CTX_TASK_CLEANUP_FLAG_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_TASK_CLEANUP_FLAG_SHIFT 7 + u8 flags1; +#define MSTORM_ISCSI_TASK_AG_CTX_TASK_CLEANUP_CF_MASK 0x3 +#define MSTORM_ISCSI_TASK_AG_CTX_TASK_CLEANUP_CF_SHIFT 0 +#define MSTORM_ISCSI_TASK_AG_CTX_CF1_MASK 0x3 +#define MSTORM_ISCSI_TASK_AG_CTX_CF1_SHIFT 2 +#define MSTORM_ISCSI_TASK_AG_CTX_CF2_MASK 0x3 +#define MSTORM_ISCSI_TASK_AG_CTX_CF2_SHIFT 4 +#define MSTORM_ISCSI_TASK_AG_CTX_TASK_CLEANUP_CF_EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_TASK_CLEANUP_CF_EN_SHIFT 6 +#define MSTORM_ISCSI_TASK_AG_CTX_CF1EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_CF1EN_SHIFT 7 + u8 flags2; +#define MSTORM_ISCSI_TASK_AG_CTX_CF2EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_CF2EN_SHIFT 0 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE0EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE0EN_SHIFT 1 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE1EN_SHIFT 2 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE2EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE2EN_SHIFT 3 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE3EN_SHIFT 4 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE4EN_SHIFT 5 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE5EN_SHIFT 6 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE6EN_MASK 0x1 +#define MSTORM_ISCSI_TASK_AG_CTX_RULE6EN_SHIFT 7 + u8 byte2; + __le32 reg0; + u8 byte3; + u8 byte4; + __le16 word1; +}; + +struct ustorm_iscsi_task_ag_ctx { + u8 reserved; + u8 state; + __le16 icid; + u8 flags0; +#define USTORM_ISCSI_TASK_AG_CTX_CONNECTION_TYPE_MASK 0xF +#define USTORM_ISCSI_TASK_AG_CTX_CONNECTION_TYPE_SHIFT 0 +#define USTORM_ISCSI_TASK_AG_CTX_EXIST_IN_QM0_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_EXIST_IN_QM0_SHIFT 4 +#define USTORM_ISCSI_TASK_AG_CTX_BIT1_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_BIT1_SHIFT 5 +#define USTORM_ISCSI_TASK_AG_CTX_HQ_SCANNED_CF_MASK 0x3 +#define USTORM_ISCSI_TASK_AG_CTX_HQ_SCANNED_CF_SHIFT 6 + u8 flags1; +#define USTORM_ISCSI_TASK_AG_CTX_RESERVED1_MASK 0x3 +#define USTORM_ISCSI_TASK_AG_CTX_RESERVED1_SHIFT 0 +#define USTORM_ISCSI_TASK_AG_CTX_R2T2RECV_MASK 0x3 +#define USTORM_ISCSI_TASK_AG_CTX_R2T2RECV_SHIFT 2 +#define USTORM_ISCSI_TASK_AG_CTX_CF3_MASK 0x3 +#define USTORM_ISCSI_TASK_AG_CTX_CF3_SHIFT 4 +#define USTORM_ISCSI_TASK_AG_CTX_DIF_ERROR_CF_MASK 0x3 +#define USTORM_ISCSI_TASK_AG_CTX_DIF_ERROR_CF_SHIFT 6 + u8 flags2; +#define USTORM_ISCSI_TASK_AG_CTX_HQ_SCANNED_CF_EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_HQ_SCANNED_CF_EN_SHIFT 0 +#define USTORM_ISCSI_TASK_AG_CTX_DISABLE_DATA_ACKED_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_DISABLE_DATA_ACKED_SHIFT 1 +#define USTORM_ISCSI_TASK_AG_CTX_R2T2RECV_EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_R2T2RECV_EN_SHIFT 2 +#define USTORM_ISCSI_TASK_AG_CTX_CF3EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_CF3EN_SHIFT 3 +#define USTORM_ISCSI_TASK_AG_CTX_DIF_ERROR_CF_EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_DIF_ERROR_CF_EN_SHIFT 4 +#define USTORM_ISCSI_TASK_AG_CTX_CMP_DATA_TOTAL_EXP_EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_CMP_DATA_TOTAL_EXP_EN_SHIFT 5 +#define USTORM_ISCSI_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_RULE1EN_SHIFT 6 +#define USTORM_ISCSI_TASK_AG_CTX_CMP_CONT_RCV_EXP_EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_CMP_CONT_RCV_EXP_EN_SHIFT 7 + u8 flags3; +#define USTORM_ISCSI_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_RULE3EN_SHIFT 0 +#define USTORM_ISCSI_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_RULE4EN_SHIFT 1 +#define USTORM_ISCSI_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_RULE5EN_SHIFT 2 +#define USTORM_ISCSI_TASK_AG_CTX_RULE6EN_MASK 0x1 +#define USTORM_ISCSI_TASK_AG_CTX_RULE6EN_SHIFT 3 +#define USTORM_ISCSI_TASK_AG_CTX_DIF_ERROR_TYPE_MASK 0xF +#define USTORM_ISCSI_TASK_AG_CTX_DIF_ERROR_TYPE_SHIFT 4 + __le32 dif_err_intervals; + __le32 dif_error_1st_interval; + __le32 rcv_cont_len; + __le32 exp_cont_len; + __le32 total_data_acked; + __le32 exp_data_acked; + u8 next_tid_valid; + u8 byte3; + __le16 word1; + __le16 next_tid; + __le16 word3; + __le32 hdr_residual_count; + __le32 exp_r2t_sn; +}; + +struct mstorm_iscsi_task_st_ctx { + union iscsi_mstorm_sgl sgl_union; + struct iscsi_dif_flags dif_flags; + struct iscsi_mflags flags; + u8 sgl_size; + u8 host_sge_index; + __le16 dix_cur_sge_offset; + __le16 dix_cur_sge_size; + __le32 data_offset_rtid; + u8 dif_offset; + u8 dix_sgl_size; + u8 dix_sge_index; + u8 task_type; + struct regpair sense_db; + struct regpair dix_sgl_cur_sge; + __le32 rem_task_size; + __le16 reuse_count; + __le16 dif_data_residue; + u8 reserved0[4]; + __le32 reserved1[1]; +}; + +struct ustorm_iscsi_task_st_ctx { + __le32 rem_rcv_len; + __le32 exp_data_transfer_len; + __le32 exp_data_sn; + struct regpair lun; + struct iscsi_reg1 reg1; + u8 flags2; +#define USTORM_ISCSI_TASK_ST_CTX_AHS_EXIST_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_AHS_EXIST_SHIFT 0 +#define USTORM_ISCSI_TASK_ST_CTX_RESERVED1_MASK 0x7F +#define USTORM_ISCSI_TASK_ST_CTX_RESERVED1_SHIFT 1 + u8 reserved2; + __le16 reserved3; + __le32 reserved4; + __le32 reserved5; + __le32 reserved6; + __le32 reserved7; + u8 task_type; + u8 error_flags; +#define USTORM_ISCSI_TASK_ST_CTX_DATA_DIGEST_ERROR_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_DATA_DIGEST_ERROR_SHIFT 0 +#define USTORM_ISCSI_TASK_ST_CTX_DATA_TRUNCATED_ERROR_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_DATA_TRUNCATED_ERROR_SHIFT 1 +#define USTORM_ISCSI_TASK_ST_CTX_UNDER_RUN_ERROR_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_UNDER_RUN_ERROR_SHIFT 2 +#define USTORM_ISCSI_TASK_ST_CTX_RESERVED8_MASK 0x1F +#define USTORM_ISCSI_TASK_ST_CTX_RESERVED8_SHIFT 3 + u8 flags; +#define USTORM_ISCSI_TASK_ST_CTX_CQE_WRITE_MASK 0x3 +#define USTORM_ISCSI_TASK_ST_CTX_CQE_WRITE_SHIFT 0 +#define USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP_SHIFT 2 +#define USTORM_ISCSI_TASK_ST_CTX_Q0_R2TQE_WRITE_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_Q0_R2TQE_WRITE_SHIFT 3 +#define USTORM_ISCSI_TASK_ST_CTX_TOTALDATAACKED_DONE_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_TOTALDATAACKED_DONE_SHIFT 4 +#define USTORM_ISCSI_TASK_ST_CTX_HQSCANNED_DONE_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_HQSCANNED_DONE_SHIFT 5 +#define USTORM_ISCSI_TASK_ST_CTX_R2T2RECV_DONE_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_R2T2RECV_DONE_SHIFT 6 +#define USTORM_ISCSI_TASK_ST_CTX_RESERVED0_MASK 0x1 +#define USTORM_ISCSI_TASK_ST_CTX_RESERVED0_SHIFT 7 + u8 cq_rss_number; +}; + +struct iscsi_task_context { + struct ystorm_iscsi_task_st_ctx ystorm_st_context; + struct regpair ystorm_st_padding[2]; + struct ystorm_iscsi_task_ag_ctx ystorm_ag_context; + struct regpair ystorm_ag_padding[2]; + struct tdif_task_context tdif_context; + struct mstorm_iscsi_task_ag_ctx mstorm_ag_context; + struct regpair mstorm_ag_padding[2]; + struct ustorm_iscsi_task_ag_ctx ustorm_ag_context; + struct mstorm_iscsi_task_st_ctx mstorm_st_context; + struct ustorm_iscsi_task_st_ctx ustorm_st_context; + struct rdif_task_context rdif_context; +}; + +enum iscsi_task_type { + ISCSI_TASK_TYPE_INITIATOR_WRITE, + ISCSI_TASK_TYPE_INITIATOR_READ, + ISCSI_TASK_TYPE_MIDPATH, + ISCSI_TASK_TYPE_UNSOLIC, + ISCSI_TASK_TYPE_EXCHCLEANUP, + ISCSI_TASK_TYPE_IRRELEVANT, + ISCSI_TASK_TYPE_TARGET_WRITE, + ISCSI_TASK_TYPE_TARGET_READ, + ISCSI_TASK_TYPE_TARGET_RESPONSE, + ISCSI_TASK_TYPE_LOGIN_RESPONSE, + MAX_ISCSI_TASK_TYPE +}; + +union iscsi_ttt_txlen_union { + __le32 desired_tx_len; + __le32 ttt; +}; + +struct iscsi_uhqe { + __le32 reg1; +#define ISCSI_UHQE_PDU_PAYLOAD_LEN_MASK 0xFFFFF +#define ISCSI_UHQE_PDU_PAYLOAD_LEN_SHIFT 0 +#define ISCSI_UHQE_LOCAL_COMP_MASK 0x1 +#define ISCSI_UHQE_LOCAL_COMP_SHIFT 20 +#define ISCSI_UHQE_TOGGLE_BIT_MASK 0x1 +#define ISCSI_UHQE_TOGGLE_BIT_SHIFT 21 +#define ISCSI_UHQE_PURE_PAYLOAD_MASK 0x1 +#define ISCSI_UHQE_PURE_PAYLOAD_SHIFT 22 +#define ISCSI_UHQE_LOGIN_RESPONSE_PDU_MASK 0x1 +#define ISCSI_UHQE_LOGIN_RESPONSE_PDU_SHIFT 23 +#define ISCSI_UHQE_TASK_ID_HI_MASK 0xFF +#define ISCSI_UHQE_TASK_ID_HI_SHIFT 24 + __le32 reg2; +#define ISCSI_UHQE_BUFFER_OFFSET_MASK 0xFFFFFF +#define ISCSI_UHQE_BUFFER_OFFSET_SHIFT 0 +#define ISCSI_UHQE_TASK_ID_LO_MASK 0xFF +#define ISCSI_UHQE_TASK_ID_LO_SHIFT 24 +}; + +struct iscsi_wqe_field { + __le32 contlen_cdbsize_field; +#define ISCSI_WQE_FIELD_CONT_LEN_MASK 0xFFFFFF +#define ISCSI_WQE_FIELD_CONT_LEN_SHIFT 0 +#define ISCSI_WQE_FIELD_CDB_SIZE_MASK 0xFF +#define ISCSI_WQE_FIELD_CDB_SIZE_SHIFT 24 +}; + +union iscsi_wqe_field_union { + struct iscsi_wqe_field cont_field; + __le32 prev_tid; +}; + +struct iscsi_wqe { + __le16 task_id; + u8 flags; +#define ISCSI_WQE_WQE_TYPE_MASK 0x7 +#define ISCSI_WQE_WQE_TYPE_SHIFT 0 +#define ISCSI_WQE_NUM_FAST_SGES_MASK 0x7 +#define ISCSI_WQE_NUM_FAST_SGES_SHIFT 3 +#define ISCSI_WQE_PTU_INVALIDATE_MASK 0x1 +#define ISCSI_WQE_PTU_INVALIDATE_SHIFT 6 +#define ISCSI_WQE_RESPONSE_MASK 0x1 +#define ISCSI_WQE_RESPONSE_SHIFT 7 + struct iscsi_dif_flags prot_flags; + union iscsi_wqe_field_union cont_prevtid_union; +}; + +enum iscsi_wqe_type { + ISCSI_WQE_TYPE_NORMAL, + ISCSI_WQE_TYPE_TASK_CLEANUP, + ISCSI_WQE_TYPE_MIDDLE_PATH, + ISCSI_WQE_TYPE_LOGIN, + ISCSI_WQE_TYPE_FIRST_R2T_CONT, + ISCSI_WQE_TYPE_NONFIRST_R2T_CONT, + ISCSI_WQE_TYPE_RESPONSE, + MAX_ISCSI_WQE_TYPE +}; + +struct iscsi_xhqe { + union iscsi_ttt_txlen_union ttt_or_txlen; + __le32 exp_stat_sn; + struct iscsi_dif_flags prot_flags; + u8 total_ahs_length; + u8 opcode; + u8 flags; +#define ISCSI_XHQE_NUM_FAST_SGES_MASK 0x7 +#define ISCSI_XHQE_NUM_FAST_SGES_SHIFT 0 +#define ISCSI_XHQE_FINAL_MASK 0x1 +#define ISCSI_XHQE_FINAL_SHIFT 3 +#define ISCSI_XHQE_SUPER_IO_MASK 0x1 +#define ISCSI_XHQE_SUPER_IO_SHIFT 4 +#define ISCSI_XHQE_STATUS_BIT_MASK 0x1 +#define ISCSI_XHQE_STATUS_BIT_SHIFT 5 +#define ISCSI_XHQE_RESERVED_MASK 0x3 +#define ISCSI_XHQE_RESERVED_SHIFT 6 + union iscsi_seq_num seq_num_union; + __le16 reserved1; +}; + +struct mstorm_iscsi_stats_drv { + struct regpair iscsi_rx_dropped_pdus_task_not_valid; +}; + +struct ooo_opaque { + __le32 cid; + u8 drop_isle; + u8 drop_size; + u8 ooo_opcode; + u8 ooo_isle; +}; + +struct pstorm_iscsi_stats_drv { + struct regpair iscsi_tx_bytes_cnt; + struct regpair iscsi_tx_packet_cnt; +}; + +struct tstorm_iscsi_stats_drv { + struct regpair iscsi_rx_bytes_cnt; + struct regpair iscsi_rx_packet_cnt; + struct regpair iscsi_rx_new_ooo_isle_events_cnt; + __le32 iscsi_cmdq_threshold_cnt; + __le32 iscsi_rq_threshold_cnt; + __le32 iscsi_immq_threshold_cnt; +}; + +struct ustorm_iscsi_stats_drv { + struct regpair iscsi_rx_data_pdu_cnt; + struct regpair iscsi_rx_r2t_pdu_cnt; + struct regpair iscsi_rx_total_pdu_cnt; +}; + +struct xstorm_iscsi_stats_drv { + struct regpair iscsi_tx_go_to_slow_start_event_cnt; + struct regpair iscsi_tx_fast_retransmit_event_cnt; +}; + +struct ystorm_iscsi_stats_drv { + struct regpair iscsi_tx_data_pdu_cnt; + struct regpair iscsi_tx_r2t_pdu_cnt; + struct regpair iscsi_tx_total_pdu_cnt; +}; + +struct iscsi_db_data { + u8 params; +#define ISCSI_DB_DATA_DEST_MASK 0x3 +#define ISCSI_DB_DATA_DEST_SHIFT 0 +#define ISCSI_DB_DATA_AGG_CMD_MASK 0x3 +#define ISCSI_DB_DATA_AGG_CMD_SHIFT 2 +#define ISCSI_DB_DATA_BYPASS_EN_MASK 0x1 +#define ISCSI_DB_DATA_BYPASS_EN_SHIFT 4 +#define ISCSI_DB_DATA_RESERVED_MASK 0x1 +#define ISCSI_DB_DATA_RESERVED_SHIFT 5 +#define ISCSI_DB_DATA_AGG_VAL_SEL_MASK 0x3 +#define ISCSI_DB_DATA_AGG_VAL_SEL_SHIFT 6 + u8 agg_flags; + __le16 sq_prod; +}; + +struct tstorm_iscsi_task_ag_ctx { + u8 byte0; + u8 byte1; + __le16 word0; + u8 flags0; +#define TSTORM_ISCSI_TASK_AG_CTX_NIBBLE0_MASK 0xF +#define TSTORM_ISCSI_TASK_AG_CTX_NIBBLE0_SHIFT 0 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT0_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT0_SHIFT 4 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT1_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT1_SHIFT 5 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT2_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT2_SHIFT 6 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT3_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT3_SHIFT 7 + u8 flags1; +#define TSTORM_ISCSI_TASK_AG_CTX_BIT4_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT4_SHIFT 0 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT5_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_BIT5_SHIFT 1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF0_MASK 0x3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF0_SHIFT 2 +#define TSTORM_ISCSI_TASK_AG_CTX_CF1_MASK 0x3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF1_SHIFT 4 +#define TSTORM_ISCSI_TASK_AG_CTX_CF2_MASK 0x3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF2_SHIFT 6 + u8 flags2; +#define TSTORM_ISCSI_TASK_AG_CTX_CF3_MASK 0x3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF3_SHIFT 0 +#define TSTORM_ISCSI_TASK_AG_CTX_CF4_MASK 0x3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF4_SHIFT 2 +#define TSTORM_ISCSI_TASK_AG_CTX_CF5_MASK 0x3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF5_SHIFT 4 +#define TSTORM_ISCSI_TASK_AG_CTX_CF6_MASK 0x3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF6_SHIFT 6 + u8 flags3; +#define TSTORM_ISCSI_TASK_AG_CTX_CF7_MASK 0x3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF7_SHIFT 0 +#define TSTORM_ISCSI_TASK_AG_CTX_CF0EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF0EN_SHIFT 2 +#define TSTORM_ISCSI_TASK_AG_CTX_CF1EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF1EN_SHIFT 3 +#define TSTORM_ISCSI_TASK_AG_CTX_CF2EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF2EN_SHIFT 4 +#define TSTORM_ISCSI_TASK_AG_CTX_CF3EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF3EN_SHIFT 5 +#define TSTORM_ISCSI_TASK_AG_CTX_CF4EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF4EN_SHIFT 6 +#define TSTORM_ISCSI_TASK_AG_CTX_CF5EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF5EN_SHIFT 7 + u8 flags4; +#define TSTORM_ISCSI_TASK_AG_CTX_CF6EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF6EN_SHIFT 0 +#define TSTORM_ISCSI_TASK_AG_CTX_CF7EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_CF7EN_SHIFT 1 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE0EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE0EN_SHIFT 2 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE1EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE1EN_SHIFT 3 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE2EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE2EN_SHIFT 4 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE3EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE3EN_SHIFT 5 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE4EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE4EN_SHIFT 6 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE5EN_MASK 0x1 +#define TSTORM_ISCSI_TASK_AG_CTX_RULE5EN_SHIFT 7 + u8 byte2; + __le16 word1; + __le32 reg0; + u8 byte3; + u8 byte4; + __le16 word2; + __le16 word3; + __le16 word4; + __le32 reg1; + __le32 reg2; +}; + +#endif /* __ISCSI_COMMON__ */ diff --git a/include/linux/qed/rdma_common.h b/include/linux/qed/rdma_common.h new file mode 100644 index 000000000000..187991c1f439 --- /dev/null +++ b/include/linux/qed/rdma_common.h @@ -0,0 +1,44 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef __RDMA_COMMON__ +#define __RDMA_COMMON__ +/************************/ +/* RDMA FW CONSTANTS */ +/************************/ + +#define RDMA_RESERVED_LKEY (0) +#define RDMA_RING_PAGE_SIZE (0x1000) + +#define RDMA_MAX_SGE_PER_SQ_WQE (4) +#define RDMA_MAX_SGE_PER_RQ_WQE (4) + +#define RDMA_MAX_DATA_SIZE_IN_WQE (0x7FFFFFFF) + +#define RDMA_REQ_RD_ATOMIC_ELM_SIZE (0x50) +#define RDMA_RESP_RD_ATOMIC_ELM_SIZE (0x20) + +#define RDMA_MAX_CQS (64 * 1024) +#define RDMA_MAX_TIDS (128 * 1024 - 1) +#define RDMA_MAX_PDS (64 * 1024) + +#define RDMA_NUM_STATISTIC_COUNTERS MAX_NUM_VPORTS + +#define RDMA_TASK_TYPE (PROTOCOLID_ROCE) + +struct rdma_srq_id { + __le16 srq_idx; + __le16 opaque_fid; +}; + +struct rdma_srq_producers { + __le32 sge_prod; + __le32 wqe_prod; +}; + +#endif /* __RDMA_COMMON__ */ diff --git a/include/linux/qed/roce_common.h b/include/linux/qed/roce_common.h new file mode 100644 index 000000000000..2eeaf3dc6646 --- /dev/null +++ b/include/linux/qed/roce_common.h @@ -0,0 +1,17 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef __ROCE_COMMON__ +#define __ROCE_COMMON__ + +#define ROCE_REQ_MAX_INLINE_DATA_SIZE (256) +#define ROCE_REQ_MAX_SINGLE_SQ_WQE_SIZE (288) + +#define ROCE_MAX_QPS (32 * 1024) + +#endif /* __ROCE_COMMON__ */ diff --git a/include/linux/qed/storage_common.h b/include/linux/qed/storage_common.h new file mode 100644 index 000000000000..3b8e1efd9bc2 --- /dev/null +++ b/include/linux/qed/storage_common.h @@ -0,0 +1,91 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef __STORAGE_COMMON__ +#define __STORAGE_COMMON__ + +#define NUM_OF_CMDQS_CQS (NUM_OF_GLOBAL_QUEUES / 2) +#define BDQ_NUM_RESOURCES (4) + +#define BDQ_ID_RQ (0) +#define BDQ_ID_IMM_DATA (1) +#define BDQ_NUM_IDS (2) + +#define BDQ_MAX_EXTERNAL_RING_SIZE (1 << 15) + +struct scsi_bd { + struct regpair address; + struct regpair opaque; +}; + +struct scsi_bdq_ram_drv_data { + __le16 external_producer; + __le16 reserved0[3]; +}; + +struct scsi_drv_cmdq { + __le16 cmdq_cons; + __le16 reserved0; + __le32 reserved1; +}; + +struct scsi_init_func_params { + __le16 num_tasks; + u8 log_page_size; + u8 debug_mode; + u8 reserved2[12]; +}; + +struct scsi_init_func_queues { + struct regpair glbl_q_params_addr; + __le16 rq_buffer_size; + __le16 cq_num_entries; + __le16 cmdq_num_entries; + u8 bdq_resource_id; + u8 q_validity; +#define SCSI_INIT_FUNC_QUEUES_RQ_VALID_MASK 0x1 +#define SCSI_INIT_FUNC_QUEUES_RQ_VALID_SHIFT 0 +#define SCSI_INIT_FUNC_QUEUES_IMM_DATA_VALID_MASK 0x1 +#define SCSI_INIT_FUNC_QUEUES_IMM_DATA_VALID_SHIFT 1 +#define SCSI_INIT_FUNC_QUEUES_CMD_VALID_MASK 0x1 +#define SCSI_INIT_FUNC_QUEUES_CMD_VALID_SHIFT 2 +#define SCSI_INIT_FUNC_QUEUES_RESERVED_VALID_MASK 0x1F +#define SCSI_INIT_FUNC_QUEUES_RESERVED_VALID_SHIFT 3 + u8 num_queues; + u8 queue_relative_offset; + u8 cq_sb_pi; + u8 cmdq_sb_pi; + __le16 cq_cmdq_sb_num_arr[NUM_OF_CMDQS_CQS]; + __le16 reserved0; + u8 bdq_pbl_num_entries[BDQ_NUM_IDS]; + struct regpair bdq_pbl_base_address[BDQ_NUM_IDS]; + __le16 bdq_xoff_threshold[BDQ_NUM_IDS]; + __le16 bdq_xon_threshold[BDQ_NUM_IDS]; + __le16 cmdq_xoff_threshold; + __le16 cmdq_xon_threshold; + __le32 reserved1; +}; + +struct scsi_ram_per_bdq_resource_drv_data { + struct scsi_bdq_ram_drv_data drv_data_per_bdq_id[BDQ_NUM_IDS]; +}; + +struct scsi_sge { + struct regpair sge_addr; + __le16 sge_len; + __le16 reserved0; + __le32 reserved1; +}; + +struct scsi_terminate_extra_params { + __le16 unsolicited_cq_count; + __le16 cmdq_count; + u8 reserved[4]; +}; + +#endif /* __STORAGE_COMMON__ */ diff --git a/include/linux/qed/tcp_common.h b/include/linux/qed/tcp_common.h new file mode 100644 index 000000000000..accba0e6b704 --- /dev/null +++ b/include/linux/qed/tcp_common.h @@ -0,0 +1,226 @@ +/* QLogic qed NIC Driver + * Copyright (c) 2015 QLogic Corporation + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef __TCP_COMMON__ +#define __TCP_COMMON__ + +#define TCP_INVALID_TIMEOUT_VAL -1 + +enum tcp_connect_mode { + TCP_CONNECT_ACTIVE, + TCP_CONNECT_PASSIVE, + MAX_TCP_CONNECT_MODE +}; + +struct tcp_init_params { + __le32 max_cwnd; + __le16 dup_ack_threshold; + __le16 tx_sws_timer; + __le16 min_rto; + __le16 min_rto_rt; + __le16 max_rto; + u8 maxfinrt; + u8 reserved[1]; +}; + +enum tcp_ip_version { + TCP_IPV4, + TCP_IPV6, + MAX_TCP_IP_VERSION +}; + +struct tcp_offload_params { + __le16 local_mac_addr_lo; + __le16 local_mac_addr_mid; + __le16 local_mac_addr_hi; + __le16 remote_mac_addr_lo; + __le16 remote_mac_addr_mid; + __le16 remote_mac_addr_hi; + __le16 vlan_id; + u8 flags; +#define TCP_OFFLOAD_PARAMS_TS_EN_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_TS_EN_SHIFT 0 +#define TCP_OFFLOAD_PARAMS_DA_EN_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_DA_EN_SHIFT 1 +#define TCP_OFFLOAD_PARAMS_KA_EN_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_KA_EN_SHIFT 2 +#define TCP_OFFLOAD_PARAMS_NAGLE_EN_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_NAGLE_EN_SHIFT 3 +#define TCP_OFFLOAD_PARAMS_DA_CNT_EN_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_DA_CNT_EN_SHIFT 4 +#define TCP_OFFLOAD_PARAMS_FIN_SENT_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_FIN_SENT_SHIFT 5 +#define TCP_OFFLOAD_PARAMS_FIN_RECEIVED_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_FIN_RECEIVED_SHIFT 6 +#define TCP_OFFLOAD_PARAMS_RESERVED0_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_RESERVED0_SHIFT 7 + u8 ip_version; + __le32 remote_ip[4]; + __le32 local_ip[4]; + __le32 flow_label; + u8 ttl; + u8 tos_or_tc; + __le16 remote_port; + __le16 local_port; + __le16 mss; + u8 rcv_wnd_scale; + u8 connect_mode; + __le16 srtt; + __le32 cwnd; + __le32 ss_thresh; + __le16 reserved1; + u8 ka_max_probe_cnt; + u8 dup_ack_theshold; + __le32 rcv_next; + __le32 snd_una; + __le32 snd_next; + __le32 snd_max; + __le32 snd_wnd; + __le32 rcv_wnd; + __le32 snd_wl1; + __le32 ts_time; + __le32 ts_recent; + __le32 ts_recent_age; + __le32 total_rt; + __le32 ka_timeout_delta; + __le32 rt_timeout_delta; + u8 dup_ack_cnt; + u8 snd_wnd_probe_cnt; + u8 ka_probe_cnt; + u8 rt_cnt; + __le16 rtt_var; + __le16 reserved2; + __le32 ka_timeout; + __le32 ka_interval; + __le32 max_rt_time; + __le32 initial_rcv_wnd; + u8 snd_wnd_scale; + u8 ack_frequency; + __le16 da_timeout_value; + __le32 ts_ticks_per_second; +}; + +struct tcp_offload_params_opt2 { + __le16 local_mac_addr_lo; + __le16 local_mac_addr_mid; + __le16 local_mac_addr_hi; + __le16 remote_mac_addr_lo; + __le16 remote_mac_addr_mid; + __le16 remote_mac_addr_hi; + __le16 vlan_id; + u8 flags; +#define TCP_OFFLOAD_PARAMS_OPT2_TS_EN_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_OPT2_TS_EN_SHIFT 0 +#define TCP_OFFLOAD_PARAMS_OPT2_DA_EN_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_OPT2_DA_EN_SHIFT 1 +#define TCP_OFFLOAD_PARAMS_OPT2_KA_EN_MASK 0x1 +#define TCP_OFFLOAD_PARAMS_OPT2_KA_EN_SHIFT 2 +#define TCP_OFFLOAD_PARAMS_OPT2_RESERVED0_MASK 0x1F +#define TCP_OFFLOAD_PARAMS_OPT2_RESERVED0_SHIFT 3 + u8 ip_version; + __le32 remote_ip[4]; + __le32 local_ip[4]; + __le32 flow_label; + u8 ttl; + u8 tos_or_tc; + __le16 remote_port; + __le16 local_port; + __le16 mss; + u8 rcv_wnd_scale; + u8 connect_mode; + __le16 syn_ip_payload_length; + __le32 syn_phy_addr_lo; + __le32 syn_phy_addr_hi; + __le32 reserved1[22]; +}; + +enum tcp_seg_placement_event { + TCP_EVENT_ADD_PEN, + TCP_EVENT_ADD_NEW_ISLE, + TCP_EVENT_ADD_ISLE_RIGHT, + TCP_EVENT_ADD_ISLE_LEFT, + TCP_EVENT_JOIN, + TCP_EVENT_NOP, + MAX_TCP_SEG_PLACEMENT_EVENT +}; + +struct tcp_update_params { + __le16 flags; +#define TCP_UPDATE_PARAMS_REMOTE_MAC_ADDR_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_REMOTE_MAC_ADDR_CHANGED_SHIFT 0 +#define TCP_UPDATE_PARAMS_MSS_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_MSS_CHANGED_SHIFT 1 +#define TCP_UPDATE_PARAMS_TTL_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_TTL_CHANGED_SHIFT 2 +#define TCP_UPDATE_PARAMS_TOS_OR_TC_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_TOS_OR_TC_CHANGED_SHIFT 3 +#define TCP_UPDATE_PARAMS_KA_TIMEOUT_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_KA_TIMEOUT_CHANGED_SHIFT 4 +#define TCP_UPDATE_PARAMS_KA_INTERVAL_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_KA_INTERVAL_CHANGED_SHIFT 5 +#define TCP_UPDATE_PARAMS_MAX_RT_TIME_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_MAX_RT_TIME_CHANGED_SHIFT 6 +#define TCP_UPDATE_PARAMS_FLOW_LABEL_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_FLOW_LABEL_CHANGED_SHIFT 7 +#define TCP_UPDATE_PARAMS_INITIAL_RCV_WND_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_INITIAL_RCV_WND_CHANGED_SHIFT 8 +#define TCP_UPDATE_PARAMS_KA_MAX_PROBE_CNT_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_KA_MAX_PROBE_CNT_CHANGED_SHIFT 9 +#define TCP_UPDATE_PARAMS_KA_EN_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_KA_EN_CHANGED_SHIFT 10 +#define TCP_UPDATE_PARAMS_NAGLE_EN_CHANGED_MASK 0x1 +#define TCP_UPDATE_PARAMS_NAGLE_EN_CHANGED_SHIFT 11 +#define TCP_UPDATE_PARAMS_KA_EN_MASK 0x1 +#define TCP_UPDATE_PARAMS_KA_EN_SHIFT 12 +#define TCP_UPDATE_PARAMS_NAGLE_EN_MASK 0x1 +#define TCP_UPDATE_PARAMS_NAGLE_EN_SHIFT 13 +#define TCP_UPDATE_PARAMS_KA_RESTART_MASK 0x1 +#define TCP_UPDATE_PARAMS_KA_RESTART_SHIFT 14 +#define TCP_UPDATE_PARAMS_RETRANSMIT_RESTART_MASK 0x1 +#define TCP_UPDATE_PARAMS_RETRANSMIT_RESTART_SHIFT 15 + __le16 remote_mac_addr_lo; + __le16 remote_mac_addr_mid; + __le16 remote_mac_addr_hi; + __le16 mss; + u8 ttl; + u8 tos_or_tc; + __le32 ka_timeout; + __le32 ka_interval; + __le32 max_rt_time; + __le32 flow_label; + __le32 initial_rcv_wnd; + u8 ka_max_probe_cnt; + u8 reserved1[7]; +}; + +struct tcp_upload_params { + __le32 rcv_next; + __le32 snd_una; + __le32 snd_next; + __le32 snd_max; + __le32 snd_wnd; + __le32 rcv_wnd; + __le32 snd_wl1; + __le32 cwnd; + __le32 ss_thresh; + __le16 srtt; + __le16 rtt_var; + __le32 ts_time; + __le32 ts_recent; + __le32 ts_recent_age; + __le32 total_rt; + __le32 ka_timeout_delta; + __le32 rt_timeout_delta; + u8 dup_ack_cnt; + u8 snd_wnd_probe_cnt; + u8 ka_probe_cnt; + u8 rt_cnt; + __le32 reserved; +}; + +#endif /* __TCP_COMMON__ */ -- cgit v1.2.3 From c5ac93191d7e6977c5c3465ac94c73ebb8a8ecba Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Fri, 3 Jun 2016 14:35:34 +0300 Subject: qed: Add iscsi/rdma personalities This patch adds in the ecore 2 new personalities in addition to QED_PCI_ETH - QED_PCI_ISCSI and QED_PCI_ETH_ROCE. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 4 ++ drivers/net/ethernet/qlogic/qed/qed_dev.c | 6 +++ drivers/net/ethernet/qlogic/qed/qed_hsi.h | 6 ++- drivers/net/ethernet/qlogic/qed/qed_main.c | 5 +- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 13 ++++- drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 17 +++++- include/linux/qed/common_hsi.h | 4 +- include/linux/qed/qed_if.h | 65 +++++++++++++++++++++++ 8 files changed, 114 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 1042f2af854a..4417f127f766 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -127,6 +127,8 @@ struct qed_tunn_update_params { */ enum qed_pci_personality { QED_PCI_ETH, + QED_PCI_ISCSI, + QED_PCI_ETH_ROCE, QED_PCI_DEFAULT /* default in shmem */ }; @@ -170,6 +172,8 @@ enum QED_PORT_MODE { enum qed_dev_cap { QED_DEV_CAP_ETH, + QED_DEV_CAP_ISCSI, + QED_DEV_CAP_ROCE, }; struct qed_hw_info { diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 151173d4a926..30c6d2eb6e4c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1472,6 +1472,12 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET) __set_bit(QED_DEV_CAP_ETH, &p_hwfn->hw_info.device_capabilities); + if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI) + __set_bit(QED_DEV_CAP_ISCSI, + &p_hwfn->hw_info.device_capabilities); + if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ROCE) + __set_bit(QED_DEV_CAP_ROCE, + &p_hwfn->hw_info.device_capabilities); return qed_mcp_fill_shmem_func_info(p_hwfn, p_ptt); } diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 4cd70bfd929f..72e0ad6d16c6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -650,7 +650,7 @@ struct mstorm_vf_zone { /* personality per PF */ enum personality_type { BAD_PERSONALITY_TYP, - PERSONALITY_RESERVED, + PERSONALITY_ISCSI, PERSONALITY_RESERVED2, PERSONALITY_RDMA_AND_ETH, PERSONALITY_RESERVED3, @@ -7072,6 +7072,8 @@ struct public_func { #define FUNC_MF_CFG_PROTOCOL_MASK 0x000000f0 #define FUNC_MF_CFG_PROTOCOL_SHIFT 4 #define FUNC_MF_CFG_PROTOCOL_ETHERNET 0x00000000 +#define FUNC_MF_CFG_PROTOCOL_ISCSI 0x00000010 +#define FUNC_MF_CFG_PROTOCOL_ROCE 0x00000030 #define FUNC_MF_CFG_PROTOCOL_MAX 0x00000030 #define FUNC_MF_CFG_MIN_BW_MASK 0x0000ff00 @@ -7405,6 +7407,8 @@ struct nvm_cfg1_glob { u32 misc_sig; u32 device_capabilities; #define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET 0x1 +#define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI 0x4 +#define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ROCE 0x8 u32 power_dissipated; u32 power_consumed; u32 efi_version; diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index c807f67a02c5..f41f78d6a3f9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -207,6 +207,8 @@ int qed_fill_dev_info(struct qed_dev *cdev, dev_info->pci_mem_start = cdev->pci_params.mem_start; dev_info->pci_mem_end = cdev->pci_params.mem_end; dev_info->pci_irq = cdev->pci_params.irq; + dev_info->rdma_supported = + (cdev->hwfns[0].hw_info.personality == QED_PCI_ETH_ROCE); dev_info->is_mf_default = IS_MF_DEFAULT(&cdev->hwfns[0]); ether_addr_copy(dev_info->hw_mac, cdev->hwfns[0].hw_info.hw_mac_addr); @@ -901,7 +903,8 @@ static int qed_slowpath_stop(struct qed_dev *cdev) if (IS_PF(cdev)) { qed_free_stream_mem(cdev); - qed_sriov_disable(cdev, true); + if (IS_QED_ETH_IF(cdev)) + qed_sriov_disable(cdev, true); qed_nic_stop(cdev); qed_slowpath_irq_free(cdev); diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 2c143b33c002..a240f26344a4 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -977,7 +977,18 @@ qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { case FUNC_MF_CFG_PROTOCOL_ETHERNET: - *p_proto = QED_PCI_ETH; + if (test_bit(QED_DEV_CAP_ROCE, + &p_hwfn->hw_info.device_capabilities)) + *p_proto = QED_PCI_ETH_ROCE; + else + *p_proto = QED_PCI_ETH; + break; + case FUNC_MF_CFG_PROTOCOL_ISCSI: + *p_proto = QED_PCI_ISCSI; + break; + case FUNC_MF_CFG_PROTOCOL_ROCE: + DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); + rc = -EINVAL; break; default: rc = -EINVAL; diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c index 63b93fbdc66a..a52f3fc051f5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -358,11 +358,26 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, qed_tunn_set_pf_start_params(p_hwfn, p_tunn, &p_ramrod->tunnel_config); - p_hwfn->hw_info.personality = PERSONALITY_ETH; if (IS_MF_SI(p_hwfn)) p_ramrod->allow_npar_tx_switching = allow_npar_tx_switch; + switch (p_hwfn->hw_info.personality) { + case QED_PCI_ETH: + p_ramrod->personality = PERSONALITY_ETH; + break; + case QED_PCI_ISCSI: + p_ramrod->personality = PERSONALITY_ISCSI; + break; + case QED_PCI_ETH_ROCE: + p_ramrod->personality = PERSONALITY_RDMA_AND_ETH; + break; + default: + DP_NOTICE(p_hwfn, "Unkown personality %d\n", + p_hwfn->hw_info.personality); + p_ramrod->personality = PERSONALITY_ETH; + } + if (p_hwfn->cdev->p_iov_info) { struct qed_hw_sriov_info *p_iov = p_hwfn->cdev->p_iov_info; diff --git a/include/linux/qed/common_hsi.h b/include/linux/qed/common_hsi.h index 077a3b6cc80f..40c0ada01806 100644 --- a/include/linux/qed/common_hsi.h +++ b/include/linux/qed/common_hsi.h @@ -517,9 +517,9 @@ enum mf_mode { /* Per-protocol connection types */ enum protocol_type { - PROTOCOLID_RESERVED1, + PROTOCOLID_ISCSI, PROTOCOLID_RESERVED2, - PROTOCOLID_RESERVED3, + PROTOCOLID_ROCE, PROTOCOLID_CORE, PROTOCOLID_ETH, PROTOCOLID_RESERVED4, diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index 15efccfdc46e..e8cc49f9688a 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -58,8 +58,70 @@ struct qed_eth_pf_params { u16 num_cons; }; +/* Most of the the parameters below are described in the FW iSCSI / TCP HSI */ +struct qed_iscsi_pf_params { + u64 glbl_q_params_addr; + u64 bdq_pbl_base_addr[2]; + u32 max_cwnd; + u16 cq_num_entries; + u16 cmdq_num_entries; + u16 dup_ack_threshold; + u16 tx_sws_timer; + u16 min_rto; + u16 min_rto_rt; + u16 max_rto; + + /* The following parameters are used during HW-init + * and these parameters need to be passed as arguments + * to update_pf_params routine invoked before slowpath start + */ + u16 num_cons; + u16 num_tasks; + + /* The following parameters are used during protocol-init */ + u16 half_way_close_timeout; + u16 bdq_xoff_threshold[2]; + u16 bdq_xon_threshold[2]; + u16 cmdq_xoff_threshold; + u16 cmdq_xon_threshold; + u16 rq_buffer_size; + + u8 num_sq_pages_in_ring; + u8 num_r2tq_pages_in_ring; + u8 num_uhq_pages_in_ring; + u8 num_queues; + u8 log_page_size; + u8 rqe_log_size; + u8 max_fin_rt; + u8 gl_rq_pi; + u8 gl_cmd_pi; + u8 debug_mode; + u8 ll2_ooo_queue_id; + u8 ooo_enable; + + u8 is_target; + u8 bdq_pbl_num_entries[2]; +}; + +struct qed_rdma_pf_params { + /* Supplied to QED during resource allocation (may affect the ILT and + * the doorbell BAR). + */ + u32 min_dpis; /* number of requested DPIs */ + u32 num_mrs; /* number of requested memory regions */ + u32 num_qps; /* number of requested Queue Pairs */ + u32 num_srqs; /* number of requested SRQ */ + u8 roce_edpm_mode; /* see QED_ROCE_EDPM_MODE_ENABLE */ + u8 gl_pi; /* protocol index */ + + /* Will allocate rate limiters to be used with QPs */ + u8 enable_dcqcn; +}; + struct qed_pf_params { struct qed_eth_pf_params eth_pf_params; + struct qed_iscsi_pf_params iscsi_pf_params; + struct qed_rdma_pf_params rdma_pf_params; }; enum qed_int_mode { @@ -100,6 +162,8 @@ struct qed_dev_info { /* MFW version */ u32 mfw_rev; + bool rdma_supported; + u32 flash_size; u8 mf_mode; bool tx_switching; @@ -111,6 +175,7 @@ enum qed_sb_type { enum qed_protocol { QED_PROTOCOL_ETH, + QED_PROTOCOL_ISCSI, }; struct qed_link_params { -- cgit v1.2.3 From 81b1251d3b761b303955408dd6a49618b5683c2b Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Sat, 4 Jun 2016 08:20:16 +0300 Subject: qed: Fix next-ptr chains for BE / 32-bit Commit a91eb52abb50 ("qed: Revisit chain implementation") contains an incorrect implementation for BE platforms, as device's regpairs containing addresses are LE and they're not converted correctly when read back. In addition, it raises a compilation warning for 32-bit platforms where dma_addr_t is a 32-bit variable. Reported-by: kbuild test robot Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- include/linux/qed/qed_chain.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/qed/qed_chain.h b/include/linux/qed/qed_chain.h index eceaa9ed2ae9..7e441bdeabdc 100644 --- a/include/linux/qed/qed_chain.h +++ b/include/linux/qed/qed_chain.h @@ -25,10 +25,9 @@ } while (0) #define HILO_GEN(hi, lo, type) ((((type)(hi)) << 32) + (lo)) -#define HILO_DMA(hi, lo) HILO_GEN(hi, lo, dma_addr_t) #define HILO_64(hi, lo) HILO_GEN((le32_to_cpu(hi)), (le32_to_cpu(lo)), u64) -#define HILO_DMA_REGPAIR(regpair) (HILO_DMA(regpair.hi, regpair.lo)) #define HILO_64_REGPAIR(regpair) (HILO_64(regpair.hi, regpair.lo)) +#define HILO_DMA_REGPAIR(regpair) ((dma_addr_t)HILO_64_REGPAIR(regpair)) enum qed_chain_mode { /* Each Page contains a next pointer at its end */ -- cgit v1.2.3 From 6eb17e0df74c036eba7548915b37f009403fe09e Mon Sep 17 00:00:00 2001 From: Kejian Yan Date: Fri, 3 Jun 2016 10:55:09 +0800 Subject: ACPI: bus: add stub acpi_dev_found() to linux/acpi.h acpi_dev_found() will be used to detect if a given ACPI device is in the system. It will be compiled in non-ACPI case, but the function is in acpi_bus.h and acpi_bus.h can only be used in ACPI case, so this patch add the stub function to linux/acpi.h to make compiled successfully in non-ACPI cases. Cc: Rafael J. Wysocki Signed-off-by: Kejian Yan Signed-off-by: Yisen Zhuang Signed-off-by: David S. Miller --- include/linux/acpi.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 288fac5294f5..3025d1930f6e 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -543,6 +543,11 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *); struct fwnode_handle; +static inline bool acpi_dev_found(const char *hid) +{ + return false; +} + static inline bool is_acpi_node(struct fwnode_handle *fwnode) { return false; -- cgit v1.2.3 From 4ae399241adba66ad72e5973a1004f37ffbe67cd Mon Sep 17 00:00:00 2001 From: Kejian Yan Date: Fri, 3 Jun 2016 10:55:10 +0800 Subject: ACPI: bus: add stub acpi_evaluate_dsm() to linux/acpi.h acpi_evaluate_dsm() will be used to handle the _DSM method in ACPI case. It will be compiled in non-ACPI case, but the function is in acpi_bus.h and acpi_bus.h can only be used in ACPI case, so this patch add the stub function to linux/acpi.h to make compiled successfully in non-ACPI cases. Cc: Rafael J. Wysocki Signed-off-by: Kejian Yan Signed-off-by: Yisen Zhuang Signed-off-by: David S. Miller --- include/linux/acpi.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux') diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3025d1930f6e..4d4bb4955682 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -659,6 +659,14 @@ static inline bool acpi_driver_match_device(struct device *dev, return false; } +static inline union acpi_object *acpi_evaluate_dsm(acpi_handle handle, + const u8 *uuid, + int rev, int func, + union acpi_object *argv4) +{ + return NULL; +} + static inline int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) { -- cgit v1.2.3 From 98f368e9e2630a3ce3e80fb10fb2e02038cf9578 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 2 Jun 2016 23:43:21 -0500 Subject: kernel: Add noaudit variant of ns_capable() When checking the current cred for a capability in a specific user namespace, it isn't always desirable to have the LSMs audit the check. This patch adds a noaudit variant of ns_capable() for when those situations arise. The common logic between ns_capable() and the new ns_capable_noaudit() is moved into a single, shared function to keep duplicated code to a minimum and ease maintainability. Signed-off-by: Tyler Hicks Acked-by: Serge E. Hallyn Signed-off-by: James Morris --- include/linux/capability.h | 5 +++++ kernel/capability.c | 46 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 41 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/capability.h b/include/linux/capability.h index 00690ff92edf..5f3c63dde2d5 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -206,6 +206,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, struct user_namespace *ns, int cap); extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); +extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); #else static inline bool has_capability(struct task_struct *t, int cap) { @@ -233,6 +234,10 @@ static inline bool ns_capable(struct user_namespace *ns, int cap) { return true; } +static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap) +{ + return true; +} #endif /* CONFIG_MULTIUSER */ extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); diff --git a/kernel/capability.c b/kernel/capability.c index 45432b54d5c6..00411c82dac5 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -361,6 +361,24 @@ bool has_capability_noaudit(struct task_struct *t, int cap) return has_ns_capability_noaudit(t, &init_user_ns, cap); } +static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) +{ + int capable; + + if (unlikely(!cap_valid(cap))) { + pr_crit("capable() called with invalid cap=%u\n", cap); + BUG(); + } + + capable = audit ? security_capable(current_cred(), ns, cap) : + security_capable_noaudit(current_cred(), ns, cap); + if (capable == 0) { + current->flags |= PF_SUPERPRIV; + return true; + } + return false; +} + /** * ns_capable - Determine if the current task has a superior capability in effect * @ns: The usernamespace we want the capability in @@ -374,19 +392,27 @@ bool has_capability_noaudit(struct task_struct *t, int cap) */ bool ns_capable(struct user_namespace *ns, int cap) { - if (unlikely(!cap_valid(cap))) { - pr_crit("capable() called with invalid cap=%u\n", cap); - BUG(); - } - - if (security_capable(current_cred(), ns, cap) == 0) { - current->flags |= PF_SUPERPRIV; - return true; - } - return false; + return ns_capable_common(ns, cap, true); } EXPORT_SYMBOL(ns_capable); +/** + * ns_capable_noaudit - Determine if the current task has a superior capability + * (unaudited) in effect + * @ns: The usernamespace we want the capability in + * @cap: The capability to be tested for + * + * Return true if the current task has the given superior capability currently + * available for use, false if not. + * + * This sets PF_SUPERPRIV on the task if the capability is available on the + * assumption that it's about to be used. + */ +bool ns_capable_noaudit(struct user_namespace *ns, int cap) +{ + return ns_capable_common(ns, cap, false); +} +EXPORT_SYMBOL(ns_capable_noaudit); /** * capable - Determine if the current task has a superior capability in effect -- cgit v1.2.3 From 950334bcf17a6ab55ce13d3bdf050f7b429320d5 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sat, 28 May 2016 18:09:16 -0500 Subject: PCI: Add devm_request_pci_bus_resources() Several host bridge drivers iterate through the list of bridge windows to request resources. Several others don't request the window resources at all. Add a devm_request_pci_bus_resources() interface to make it easier for drivers to request all the window resources. Export to GPL modules (from Arnd Bergmann ). Signed-off-by: Bjorn Helgaas --- drivers/pci/bus.c | 30 +++++++++++++++++++++++++++++- include/linux/pci.h | 5 ++++- 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index dd7cdbee8029..6293ce0f3532 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -91,6 +91,35 @@ void pci_bus_remove_resources(struct pci_bus *bus) } } +int devm_request_pci_bus_resources(struct device *dev, + struct list_head *resources) +{ + struct resource_entry *win; + struct resource *parent, *res; + int err; + + resource_list_for_each_entry(win, resources) { + res = win->res; + switch (resource_type(res)) { + case IORESOURCE_IO: + parent = &ioport_resource; + break; + case IORESOURCE_MEM: + parent = &iomem_resource; + break; + default: + continue; + } + + err = devm_request_resource(dev, parent, res); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(devm_request_pci_bus_resources); + static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL}; #ifdef CONFIG_PCI_BUS_ADDR_T_64BIT static struct pci_bus_region pci_64_bit = {0, @@ -397,4 +426,3 @@ void pci_bus_put(struct pci_bus *bus) put_device(&bus->dev); } EXPORT_SYMBOL(pci_bus_put); - diff --git a/include/linux/pci.h b/include/linux/pci.h index b67e4df20801..6ac83606cb0d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1143,9 +1143,12 @@ void pci_add_resource(struct list_head *resources, struct resource *res); void pci_add_resource_offset(struct list_head *resources, struct resource *res, resource_size_t offset); void pci_free_resource_list(struct list_head *resources); -void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags); +void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, + unsigned int flags); struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n); void pci_bus_remove_resources(struct pci_bus *bus); +int devm_request_pci_bus_resources(struct device *dev, + struct list_head *resources); #define pci_bus_for_each_resource(bus, res, i) \ for (i = 0; \ -- cgit v1.2.3 From 63044c4fd49f9e2ce8ee9c5ca24afe6ebbb9fb46 Mon Sep 17 00:00:00 2001 From: Giovanni Cabiddu Date: Thu, 2 Jun 2016 13:28:55 +0100 Subject: crypto: hash - shrink hash down to two types Move hash to 0xe to free up the space for acomp/scomp Signed-off-by: Giovanni Cabiddu Signed-off-by: Herbert Xu --- include/linux/crypto.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 6e28c895c376..d844cbc365f7 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -48,15 +48,15 @@ #define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 #define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005 #define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006 -#define CRYPTO_ALG_TYPE_DIGEST 0x00000008 -#define CRYPTO_ALG_TYPE_HASH 0x00000008 -#define CRYPTO_ALG_TYPE_SHASH 0x00000009 -#define CRYPTO_ALG_TYPE_AHASH 0x0000000a #define CRYPTO_ALG_TYPE_RNG 0x0000000c #define CRYPTO_ALG_TYPE_AKCIPHER 0x0000000d +#define CRYPTO_ALG_TYPE_DIGEST 0x0000000e +#define CRYPTO_ALG_TYPE_HASH 0x0000000e +#define CRYPTO_ALG_TYPE_SHASH 0x0000000e +#define CRYPTO_ALG_TYPE_AHASH 0x0000000f #define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e -#define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000c +#define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e #define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c #define CRYPTO_ALG_LARVAL 0x00000010 -- cgit v1.2.3 From 4e49ea4a3d276365bf7396c9b77b4d1d5923835a Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:31:41 -0500 Subject: block/fs/drivers: remove rw argument from submit_bio This has callers of submit_bio/submit_bio_wait set the bio->bi_rw instead of passing it in. This makes that use the same as generic_make_request and how we set the other bio fields. Signed-off-by: Mike Christie Fixed up fs/ext4/crypto.c Signed-off-by: Jens Axboe --- block/bio.c | 7 +++---- block/blk-core.c | 11 ++++------- block/blk-flush.c | 3 ++- block/blk-lib.c | 20 +++++++++++--------- drivers/block/drbd/drbd_actlog.c | 2 +- drivers/block/drbd/drbd_bitmap.c | 4 ++-- drivers/block/floppy.c | 3 ++- drivers/block/xen-blkback/blkback.c | 4 +++- drivers/block/xen-blkfront.c | 4 ++-- drivers/md/bcache/debug.c | 6 ++++-- drivers/md/bcache/journal.c | 2 +- drivers/md/bcache/super.c | 4 ++-- drivers/md/dm-bufio.c | 3 ++- drivers/md/dm-io.c | 3 ++- drivers/md/dm-log-writes.c | 9 ++++++--- drivers/md/dm-thin.c | 3 ++- drivers/md/md.c | 10 +++++++--- drivers/md/raid1.c | 3 ++- drivers/md/raid10.c | 4 +++- drivers/md/raid5-cache.c | 7 ++++--- drivers/target/target_core_iblock.c | 24 +++++++++++++----------- fs/btrfs/check-integrity.c | 18 ++++++++++-------- fs/btrfs/check-integrity.h | 4 ++-- fs/btrfs/disk-io.c | 3 ++- fs/btrfs/extent_io.c | 7 ++++--- fs/btrfs/raid56.c | 17 ++++++++++++----- fs/btrfs/scrub.c | 15 ++++++++++----- fs/btrfs/volumes.c | 14 +++++++------- fs/buffer.c | 3 ++- fs/crypto/crypto.c | 3 ++- fs/direct-io.c | 3 ++- fs/ext4/crypto.c | 3 ++- fs/ext4/page-io.c | 3 ++- fs/ext4/readpage.c | 9 +++++---- fs/f2fs/data.c | 4 +++- fs/f2fs/segment.c | 6 ++++-- fs/gfs2/lops.c | 3 ++- fs/gfs2/meta_io.c | 3 ++- fs/gfs2/ops_fstype.c | 3 ++- fs/hfsplus/wrapper.c | 3 ++- fs/jfs/jfs_logmgr.c | 6 ++++-- fs/jfs/jfs_metapage.c | 10 ++++++---- fs/logfs/dev_bdev.c | 15 ++++++++++----- fs/mpage.c | 3 ++- fs/nfs/blocklayout/blocklayout.c | 22 ++++++++++++---------- fs/nilfs2/segbuf.c | 3 ++- fs/ocfs2/cluster/heartbeat.c | 12 +++++++----- fs/xfs/xfs_aops.c | 15 ++++++++++----- fs/xfs/xfs_buf.c | 4 ++-- include/linux/bio.h | 2 +- include/linux/fs.h | 2 +- kernel/power/swap.c | 5 +++-- mm/page_io.c | 10 ++++++---- 53 files changed, 221 insertions(+), 148 deletions(-) (limited to 'include/linux') diff --git a/block/bio.c b/block/bio.c index 0e4aa42bc30d..fc779eba0b95 100644 --- a/block/bio.c +++ b/block/bio.c @@ -854,21 +854,20 @@ static void submit_bio_wait_endio(struct bio *bio) /** * submit_bio_wait - submit a bio, and wait until it completes - * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) * @bio: The &struct bio which describes the I/O * * Simple wrapper around submit_bio(). Returns 0 on success, or the error from * bio_endio() on failure. */ -int submit_bio_wait(int rw, struct bio *bio) +int submit_bio_wait(struct bio *bio) { struct submit_bio_ret ret; - rw |= REQ_SYNC; init_completion(&ret.event); bio->bi_private = &ret; bio->bi_end_io = submit_bio_wait_endio; - submit_bio(rw, bio); + bio->bi_rw |= REQ_SYNC; + submit_bio(bio); wait_for_completion_io(&ret.event); return ret.error; diff --git a/block/blk-core.c b/block/blk-core.c index 2475b1c72773..e95340789592 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2094,7 +2094,6 @@ EXPORT_SYMBOL(generic_make_request); /** * submit_bio - submit a bio to the block device layer for I/O - * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) * @bio: The &struct bio which describes the I/O * * submit_bio() is very similar in purpose to generic_make_request(), and @@ -2102,10 +2101,8 @@ EXPORT_SYMBOL(generic_make_request); * interfaces; @bio must be presetup and ready for I/O. * */ -blk_qc_t submit_bio(int rw, struct bio *bio) +blk_qc_t submit_bio(struct bio *bio) { - bio->bi_rw |= rw; - /* * If it's a regular read/write or a barrier with data attached, * go through the normal accounting stuff before submission. @@ -2113,12 +2110,12 @@ blk_qc_t submit_bio(int rw, struct bio *bio) if (bio_has_data(bio)) { unsigned int count; - if (unlikely(rw & REQ_WRITE_SAME)) + if (unlikely(bio->bi_rw & REQ_WRITE_SAME)) count = bdev_logical_block_size(bio->bi_bdev) >> 9; else count = bio_sectors(bio); - if (rw & WRITE) { + if (bio->bi_rw & WRITE) { count_vm_events(PGPGOUT, count); } else { task_io_account_read(bio->bi_iter.bi_size); @@ -2129,7 +2126,7 @@ blk_qc_t submit_bio(int rw, struct bio *bio) char b[BDEVNAME_SIZE]; printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n", current->comm, task_pid_nr(current), - (rw & WRITE) ? "WRITE" : "READ", + (bio->bi_rw & WRITE) ? "WRITE" : "READ", (unsigned long long)bio->bi_iter.bi_sector, bdevname(bio->bi_bdev, b), count); diff --git a/block/blk-flush.c b/block/blk-flush.c index b1c91d229e5e..3af4a5ad46f5 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -485,8 +485,9 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, bio = bio_alloc(gfp_mask, 0); bio->bi_bdev = bdev; + bio->bi_rw = WRITE_FLUSH; - ret = submit_bio_wait(WRITE_FLUSH, bio); + ret = submit_bio_wait(bio); /* * The driver must store the error location in ->bi_sector, if diff --git a/block/blk-lib.c b/block/blk-lib.c index 23d7f301a196..1f6dec5e0975 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -9,14 +9,14 @@ #include "blk.h" -static struct bio *next_bio(struct bio *bio, int rw, unsigned int nr_pages, +static struct bio *next_bio(struct bio *bio, unsigned int nr_pages, gfp_t gfp) { struct bio *new = bio_alloc(gfp, nr_pages); if (bio) { bio_chain(bio, new); - submit_bio(rw, bio); + submit_bio(bio); } return new; @@ -62,9 +62,10 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, req_sects = end_sect - sector; } - bio = next_bio(bio, type, 1, gfp_mask); + bio = next_bio(bio, 1, gfp_mask); bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; + bio->bi_rw = type; bio->bi_iter.bi_size = req_sects << 9; nr_sects -= req_sects; @@ -110,7 +111,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, type, &bio); if (!ret && bio) { - ret = submit_bio_wait(type, bio); + ret = submit_bio_wait(bio); if (ret == -EOPNOTSUPP) ret = 0; } @@ -147,13 +148,14 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, max_write_same_sectors = UINT_MAX >> 9; while (nr_sects) { - bio = next_bio(bio, REQ_WRITE | REQ_WRITE_SAME, 1, gfp_mask); + bio = next_bio(bio, 1, gfp_mask); bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; bio->bi_vcnt = 1; bio->bi_io_vec->bv_page = page; bio->bi_io_vec->bv_offset = 0; bio->bi_io_vec->bv_len = bdev_logical_block_size(bdev); + bio->bi_rw = REQ_WRITE | REQ_WRITE_SAME; if (nr_sects > max_write_same_sectors) { bio->bi_iter.bi_size = max_write_same_sectors << 9; @@ -166,7 +168,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, } if (bio) - ret = submit_bio_wait(REQ_WRITE | REQ_WRITE_SAME, bio); + ret = submit_bio_wait(bio); return ret != -EOPNOTSUPP ? ret : 0; } EXPORT_SYMBOL(blkdev_issue_write_same); @@ -190,11 +192,11 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, unsigned int sz; while (nr_sects != 0) { - bio = next_bio(bio, WRITE, - min(nr_sects, (sector_t)BIO_MAX_PAGES), + bio = next_bio(bio, min(nr_sects, (sector_t)BIO_MAX_PAGES), gfp_mask); bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; + bio->bi_rw = REQ_WRITE; while (nr_sects != 0) { sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects); @@ -207,7 +209,7 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, } if (bio) - return submit_bio_wait(WRITE, bio); + return submit_bio_wait(bio); return 0; } diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 10459a145062..6069e152c32f 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -177,7 +177,7 @@ static int _drbd_md_sync_page_io(struct drbd_device *device, if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) bio_io_error(bio); else - submit_bio(rw, bio); + submit_bio(bio); wait_until_done_or_force_detached(device, bdev, &device->md_io.done); if (!bio->bi_error) err = device->md_io.error; diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 92d6fc020a65..e8959fee1fa3 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -1011,12 +1011,12 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho bio_add_page(bio, page, len, 0); bio->bi_private = ctx; bio->bi_end_io = drbd_bm_endio; + bio->bi_rw = rw; if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) { - bio->bi_rw |= rw; bio_io_error(bio); } else { - submit_bio(rw, bio); + submit_bio(bio); /* this should not count as user activity and cause the * resync to throttle -- see drbd_rs_should_slow_down(). */ atomic_add(len >> 9, &device->rs_sect_ev); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 84708a5f8c52..73ded25b82c4 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3822,8 +3822,9 @@ static int __floppy_read_block_0(struct block_device *bdev, int drive) bio.bi_flags |= (1 << BIO_QUIET); bio.bi_private = &cbdata; bio.bi_end_io = floppy_rb0_cb; + bio.bi_rw = READ; - submit_bio(READ, &bio); + submit_bio(&bio); process_fd_request(); init_completion(&cbdata.complete); diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 4809c1501d7e..79fe4934f18b 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -1369,6 +1369,7 @@ static int dispatch_rw_block_io(struct xen_blkif_ring *ring, bio->bi_private = pending_req; bio->bi_end_io = end_block_io_op; bio->bi_iter.bi_sector = preq.sector_number; + bio->bi_rw = operation; } preq.sector_number += seg[i].nsec; @@ -1386,13 +1387,14 @@ static int dispatch_rw_block_io(struct xen_blkif_ring *ring, bio->bi_bdev = preq.bdev; bio->bi_private = pending_req; bio->bi_end_io = end_block_io_op; + bio->bi_rw = operation; } atomic_set(&pending_req->pendcnt, nbio); blk_start_plug(&plug); for (i = 0; i < nbio; i++) - submit_bio(operation, biolist[i]); + submit_bio(biolist[i]); /* Let the I/Os go.. */ blk_finish_plug(&plug); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index ca13df854639..52963a26660a 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -2114,7 +2114,7 @@ static int blkif_recover(struct blkfront_info *info) bio_trim(cloned_bio, offset, size); cloned_bio->bi_private = split_bio; cloned_bio->bi_end_io = split_bio_end; - submit_bio(cloned_bio->bi_rw, cloned_bio); + submit_bio(cloned_bio); } /* * Now we have to wait for all those smaller bios to @@ -2123,7 +2123,7 @@ static int blkif_recover(struct blkfront_info *info) continue; } /* We don't need to split this bio */ - submit_bio(bio->bi_rw, bio); + submit_bio(bio); } return 0; diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 8b1f1d5c1819..52b6bcf6b6c8 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -52,9 +52,10 @@ void bch_btree_verify(struct btree *b) bio->bi_bdev = PTR_CACHE(b->c, &b->key, 0)->bdev; bio->bi_iter.bi_sector = PTR_OFFSET(&b->key, 0); bio->bi_iter.bi_size = KEY_SIZE(&v->key) << 9; + bio->bi_rw = REQ_META|READ_SYNC; bch_bio_map(bio, sorted); - submit_bio_wait(REQ_META|READ_SYNC, bio); + submit_bio_wait(bio); bch_bbio_free(bio, b->c); memcpy(ondisk, sorted, KEY_SIZE(&v->key) << 9); @@ -113,11 +114,12 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio) check = bio_clone(bio, GFP_NOIO); if (!check) return; + check->bi_rw |= READ_SYNC; if (bio_alloc_pages(check, GFP_NOIO)) goto out_put; - submit_bio_wait(READ_SYNC, check); + submit_bio_wait(check); bio_for_each_segment(bv, bio, iter) { void *p1 = kmap_atomic(bv.bv_page); diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index 29eba7219b01..af3f9f7f20e2 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -418,7 +418,7 @@ static void journal_discard_work(struct work_struct *work) struct journal_device *ja = container_of(work, struct journal_device, discard_work); - submit_bio(0, &ja->discard_bio); + submit_bio(&ja->discard_bio); } static void do_journal_discard(struct cache *ca) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index f5dbb4e884d8..1eb526a7b8b3 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -212,7 +212,7 @@ static void __write_super(struct cache_sb *sb, struct bio *bio) unsigned i; bio->bi_iter.bi_sector = SB_SECTOR; - bio->bi_rw = REQ_SYNC|REQ_META; + bio->bi_rw = REQ_WRITE|REQ_SYNC|REQ_META; bio->bi_iter.bi_size = SB_SIZE; bch_bio_map(bio, NULL); @@ -238,7 +238,7 @@ static void __write_super(struct cache_sb *sb, struct bio *bio) pr_debug("ver %llu, flags %llu, seq %llu", sb->version, sb->flags, sb->seq); - submit_bio(REQ_WRITE, bio); + submit_bio(bio); } static void bch_write_bdev_super_unlock(struct closure *cl) diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index cd77216beff1..9d3ee7f6c6c7 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -634,6 +634,7 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, * the dm_buffer's inline bio is local to bufio. */ b->bio.bi_private = end_io; + b->bio.bi_rw = rw; /* * We assume that if len >= PAGE_SIZE ptr is page-aligned. @@ -660,7 +661,7 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, ptr += PAGE_SIZE; } while (len > 0); - submit_bio(rw, &b->bio); + submit_bio(&b->bio); } static void submit_io(struct dm_buffer *b, int rw, sector_t block, diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 06d426eb5a30..50f17e32951a 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -322,6 +322,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, bio->bi_iter.bi_sector = where->sector + (where->count - remaining); bio->bi_bdev = where->bdev; bio->bi_end_io = endio; + bio->bi_rw = rw; store_io_and_region_in_bio(bio, io, region); if (rw & REQ_DISCARD) { @@ -355,7 +356,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, } atomic_inc(&io->count); - submit_bio(rw, bio); + submit_bio(bio); } while (remaining); } diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index 608302e222af..addcc4be00b6 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -205,6 +205,7 @@ static int write_metadata(struct log_writes_c *lc, void *entry, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; + bio->bi_rw = WRITE; page = alloc_page(GFP_KERNEL); if (!page) { @@ -226,7 +227,7 @@ static int write_metadata(struct log_writes_c *lc, void *entry, DMERR("Couldn't add page to the log block"); goto error_bio; } - submit_bio(WRITE, bio); + submit_bio(bio); return 0; error_bio: bio_put(bio); @@ -269,6 +270,7 @@ static int log_one_block(struct log_writes_c *lc, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; + bio->bi_rw = WRITE; for (i = 0; i < block->vec_cnt; i++) { /* @@ -279,7 +281,7 @@ static int log_one_block(struct log_writes_c *lc, block->vecs[i].bv_len, 0); if (ret != block->vecs[i].bv_len) { atomic_inc(&lc->io_blocks); - submit_bio(WRITE, bio); + submit_bio(bio); bio = bio_alloc(GFP_KERNEL, block->vec_cnt - i); if (!bio) { DMERR("Couldn't alloc log bio"); @@ -290,6 +292,7 @@ static int log_one_block(struct log_writes_c *lc, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; + bio->bi_rw = WRITE; ret = bio_add_page(bio, block->vecs[i].bv_page, block->vecs[i].bv_len, 0); @@ -301,7 +304,7 @@ static int log_one_block(struct log_writes_c *lc, } sector += block->vecs[i].bv_len >> SECTOR_SHIFT; } - submit_bio(WRITE, bio); + submit_bio(bio); out: kfree(block->data); kfree(block); diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index fc803d50f9f0..8c070eed982c 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -371,7 +371,8 @@ static void end_discard(struct discard_op *op, int r) * need to wait for the chain to complete. */ bio_chain(op->bio, op->parent_bio); - submit_bio(REQ_WRITE | REQ_DISCARD, op->bio); + op->bio->bi_rw = REQ_WRITE | REQ_DISCARD; + submit_bio(op->bio); } blk_finish_plug(&op->plug); diff --git a/drivers/md/md.c b/drivers/md/md.c index 866825f10b4c..fb3950be3070 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -394,8 +394,9 @@ static void submit_flushes(struct work_struct *ws) bi->bi_end_io = md_end_flush; bi->bi_private = rdev; bi->bi_bdev = rdev->bdev; + bi->bi_rw = WRITE_FLUSH; atomic_inc(&mddev->flush_pending); - submit_bio(WRITE_FLUSH, bi); + submit_bio(bi); rcu_read_lock(); rdev_dec_pending(rdev, mddev); } @@ -742,9 +743,10 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev, bio_add_page(bio, page, size, 0); bio->bi_private = rdev; bio->bi_end_io = super_written; + bio->bi_rw = WRITE_FLUSH_FUA; atomic_inc(&mddev->pending_writes); - submit_bio(WRITE_FLUSH_FUA, bio); + submit_bio(bio); } void md_super_wait(struct mddev *mddev) @@ -761,6 +763,7 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, bio->bi_bdev = (metadata_op && rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; + bio->bi_rw = rw; if (metadata_op) bio->bi_iter.bi_sector = sector + rdev->sb_start; else if (rdev->mddev->reshape_position != MaxSector && @@ -770,7 +773,8 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, else bio->bi_iter.bi_sector = sector + rdev->data_offset; bio_add_page(bio, page, size, 0); - submit_bio_wait(rw, bio); + + submit_bio_wait(bio); ret = !bio->bi_error; bio_put(bio); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index c7c8cde0ab21..bc95d4dd600b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2208,7 +2208,8 @@ static int narrow_write_error(struct r1bio *r1_bio, int i) bio_trim(wbio, sector - r1_bio->sector, sectors); wbio->bi_iter.bi_sector += rdev->data_offset; wbio->bi_bdev = rdev->bdev; - if (submit_bio_wait(WRITE, wbio) < 0) + + if (submit_bio_wait(wbio) < 0) /* failure! */ ok = rdev_set_badblocks(rdev, sector, sectors, 0) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index c7de2a53e625..0be6497d8e34 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2474,7 +2474,9 @@ static int narrow_write_error(struct r10bio *r10_bio, int i) choose_data_offset(r10_bio, rdev) + (sector - r10_bio->sector)); wbio->bi_bdev = rdev->bdev; - if (submit_bio_wait(WRITE, wbio) < 0) + wbio->bi_rw = WRITE; + + if (submit_bio_wait(wbio) < 0) /* Failure! */ ok = rdev_set_badblocks(rdev, sector, sectors, 0) diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index e889e2deb7b3..0b014535f5dd 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -254,7 +254,7 @@ static void r5l_submit_current_io(struct r5l_log *log) __r5l_set_io_unit_state(io, IO_UNIT_IO_START); spin_unlock_irqrestore(&log->io_list_lock, flags); - submit_bio(WRITE, io->current_bio); + submit_bio(io->current_bio); } static struct bio *r5l_bio_alloc(struct r5l_log *log) @@ -373,7 +373,7 @@ static void r5l_append_payload_page(struct r5l_log *log, struct page *page) io->current_bio = r5l_bio_alloc(log); bio_chain(io->current_bio, prev); - submit_bio(WRITE, prev); + submit_bio(prev); } if (!bio_add_page(io->current_bio, page, PAGE_SIZE, 0)) @@ -686,7 +686,8 @@ void r5l_flush_stripe_to_raid(struct r5l_log *log) bio_reset(&log->flush_bio); log->flush_bio.bi_bdev = log->rdev->bdev; log->flush_bio.bi_end_io = r5l_log_flush_endio; - submit_bio(WRITE_FLUSH, &log->flush_bio); + log->flush_bio.bi_rw = WRITE_FLUSH; + submit_bio(&log->flush_bio); } static void r5l_write_super(struct r5l_log *log, sector_t cp); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 7c4efb4417b0..c25109cc0329 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -312,7 +312,7 @@ static void iblock_bio_done(struct bio *bio) } static struct bio * -iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) +iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num, int rw) { struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); struct bio *bio; @@ -334,18 +334,19 @@ iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) bio->bi_private = cmd; bio->bi_end_io = &iblock_bio_done; bio->bi_iter.bi_sector = lba; + bio->bi_rw = rw; return bio; } -static void iblock_submit_bios(struct bio_list *list, int rw) +static void iblock_submit_bios(struct bio_list *list) { struct blk_plug plug; struct bio *bio; blk_start_plug(&plug); while ((bio = bio_list_pop(list))) - submit_bio(rw, bio); + submit_bio(bio); blk_finish_plug(&plug); } @@ -387,9 +388,10 @@ iblock_execute_sync_cache(struct se_cmd *cmd) bio = bio_alloc(GFP_KERNEL, 0); bio->bi_end_io = iblock_end_io_flush; bio->bi_bdev = ib_dev->ibd_bd; + bio->bi_rw = WRITE_FLUSH; if (!immed) bio->bi_private = cmd; - submit_bio(WRITE_FLUSH, bio); + submit_bio(bio); return 0; } @@ -478,7 +480,7 @@ iblock_execute_write_same(struct se_cmd *cmd) goto fail; cmd->priv = ibr; - bio = iblock_get_bio(cmd, block_lba, 1); + bio = iblock_get_bio(cmd, block_lba, 1, WRITE); if (!bio) goto fail_free_ibr; @@ -491,7 +493,7 @@ iblock_execute_write_same(struct se_cmd *cmd) while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) != sg->length) { - bio = iblock_get_bio(cmd, block_lba, 1); + bio = iblock_get_bio(cmd, block_lba, 1, WRITE); if (!bio) goto fail_put_bios; @@ -504,7 +506,7 @@ iblock_execute_write_same(struct se_cmd *cmd) sectors -= 1; } - iblock_submit_bios(&list, WRITE); + iblock_submit_bios(&list); return 0; fail_put_bios: @@ -712,7 +714,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, return 0; } - bio = iblock_get_bio(cmd, block_lba, sgl_nents); + bio = iblock_get_bio(cmd, block_lba, sgl_nents, rw); if (!bio) goto fail_free_ibr; @@ -732,11 +734,11 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) != sg->length) { if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) { - iblock_submit_bios(&list, rw); + iblock_submit_bios(&list); bio_cnt = 0; } - bio = iblock_get_bio(cmd, block_lba, sg_num); + bio = iblock_get_bio(cmd, block_lba, sg_num, rw); if (!bio) goto fail_put_bios; @@ -756,7 +758,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, goto fail_put_bios; } - iblock_submit_bios(&list, rw); + iblock_submit_bios(&list); iblock_complete_cmd(cmd); return 0; diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index b677a6ea6001..50f81916663b 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1673,6 +1673,7 @@ static int btrfsic_read_block(struct btrfsic_state *state, } bio->bi_bdev = block_ctx->dev->bdev; bio->bi_iter.bi_sector = dev_bytenr >> 9; + bio->bi_rw = READ; for (j = i; j < num_pages; j++) { ret = bio_add_page(bio, block_ctx->pagev[j], @@ -1685,7 +1686,7 @@ static int btrfsic_read_block(struct btrfsic_state *state, "btrfsic: error, failed to add a single page!\n"); return -1; } - if (submit_bio_wait(READ, bio)) { + if (submit_bio_wait(bio)) { printk(KERN_INFO "btrfsic: read error at logical %llu dev %s!\n", block_ctx->start, block_ctx->dev->name); @@ -2918,9 +2919,10 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh) return submit_bh(rw, bh); } -static void __btrfsic_submit_bio(int rw, struct bio *bio) +static void __btrfsic_submit_bio(struct bio *bio) { struct btrfsic_dev_state *dev_state; + int rw = bio->bi_rw; if (!btrfsic_is_initialized) return; @@ -3016,16 +3018,16 @@ leave: mutex_unlock(&btrfsic_mutex); } -void btrfsic_submit_bio(int rw, struct bio *bio) +void btrfsic_submit_bio(struct bio *bio) { - __btrfsic_submit_bio(rw, bio); - submit_bio(rw, bio); + __btrfsic_submit_bio(bio); + submit_bio(bio); } -int btrfsic_submit_bio_wait(int rw, struct bio *bio) +int btrfsic_submit_bio_wait(struct bio *bio) { - __btrfsic_submit_bio(rw, bio); - return submit_bio_wait(rw, bio); + __btrfsic_submit_bio(bio); + return submit_bio_wait(bio); } int btrfsic_mount(struct btrfs_root *root, diff --git a/fs/btrfs/check-integrity.h b/fs/btrfs/check-integrity.h index 13b8566c97ab..c04e249058c3 100644 --- a/fs/btrfs/check-integrity.h +++ b/fs/btrfs/check-integrity.h @@ -21,8 +21,8 @@ #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY int btrfsic_submit_bh(int rw, struct buffer_head *bh); -void btrfsic_submit_bio(int rw, struct bio *bio); -int btrfsic_submit_bio_wait(int rw, struct bio *bio); +void btrfsic_submit_bio(struct bio *bio); +int btrfsic_submit_bio_wait(struct bio *bio); #else #define btrfsic_submit_bh submit_bh #define btrfsic_submit_bio submit_bio diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 6628fca9f4ed..3666558a2375 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3486,12 +3486,13 @@ static int write_dev_flush(struct btrfs_device *device, int wait) bio->bi_end_io = btrfs_end_empty_barrier; bio->bi_bdev = device->bdev; + bio->bi_rw = WRITE_FLUSH; init_completion(&device->flush_wait); bio->bi_private = &device->flush_wait; device->flush_bio = bio; bio_get(bio); - btrfsic_submit_bio(WRITE_FLUSH, bio); + btrfsic_submit_bio(bio); return 0; } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 6e953de83f08..40e8dcc319d4 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2049,9 +2049,10 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical, return -EIO; } bio->bi_bdev = dev->bdev; + bio->bi_rw = WRITE_SYNC; bio_add_page(bio, page, length, pg_offset); - if (btrfsic_submit_bio_wait(WRITE_SYNC, bio)) { + if (btrfsic_submit_bio_wait(bio)) { /* try to remap that extent elsewhere? */ btrfs_bio_counter_dec(fs_info); bio_put(bio); @@ -2735,14 +2736,14 @@ static int __must_check submit_one_bio(int rw, struct bio *bio, start = page_offset(page) + bvec->bv_offset; bio->bi_private = NULL; - + bio->bi_rw = rw; bio_get(bio); if (tree->ops && tree->ops->submit_bio_hook) ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio, mirror_num, bio_flags, start); else - btrfsic_submit_bio(rw, bio); + btrfsic_submit_bio(bio); bio_put(bio); return ret; diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index f8b6d411a034..36d5bf7bbb59 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -1320,7 +1320,9 @@ write_data: bio->bi_private = rbio; bio->bi_end_io = raid_write_end_io; - submit_bio(WRITE, bio); + bio->bi_rw = WRITE; + + submit_bio(bio); } return; @@ -1573,11 +1575,12 @@ static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio) bio->bi_private = rbio; bio->bi_end_io = raid_rmw_end_io; + bio->bi_rw = READ; btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - submit_bio(READ, bio); + submit_bio(bio); } /* the actual write will happen once the reads are done */ return 0; @@ -2097,11 +2100,12 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio) bio->bi_private = rbio; bio->bi_end_io = raid_recover_end_io; + bio->bi_rw = READ; btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - submit_bio(READ, bio); + submit_bio(bio); } out: return 0; @@ -2433,7 +2437,9 @@ submit_write: bio->bi_private = rbio; bio->bi_end_io = raid_write_end_io; - submit_bio(WRITE, bio); + bio->bi_rw = WRITE; + + submit_bio(bio); } return; @@ -2610,11 +2616,12 @@ static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio) bio->bi_private = rbio; bio->bi_end_io = raid56_parity_scrub_end_io; + bio->bi_rw = READ; btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - submit_bio(READ, bio); + submit_bio(bio); } /* the actual write will happen once the reads are done */ return; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 70427ef66b04..9899f3e44a56 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1504,8 +1504,9 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, sblock->no_io_error_seen = 0; } else { bio->bi_iter.bi_sector = page->physical >> 9; + bio->bi_rw = READ; - if (btrfsic_submit_bio_wait(READ, bio)) + if (btrfsic_submit_bio_wait(bio)) sblock->no_io_error_seen = 0; } @@ -1583,6 +1584,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, return -EIO; bio->bi_bdev = page_bad->dev->bdev; bio->bi_iter.bi_sector = page_bad->physical >> 9; + bio->bi_rw = WRITE; ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0); if (PAGE_SIZE != ret) { @@ -1590,7 +1592,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, return -EIO; } - if (btrfsic_submit_bio_wait(WRITE, bio)) { + if (btrfsic_submit_bio_wait(bio)) { btrfs_dev_stat_inc_and_print(page_bad->dev, BTRFS_DEV_STAT_WRITE_ERRS); btrfs_dev_replace_stats_inc( @@ -1684,6 +1686,7 @@ again: bio->bi_end_io = scrub_wr_bio_end_io; bio->bi_bdev = sbio->dev->bdev; bio->bi_iter.bi_sector = sbio->physical >> 9; + bio->bi_rw = WRITE; sbio->err = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical_for_dev_replace || @@ -1731,7 +1734,7 @@ static void scrub_wr_submit(struct scrub_ctx *sctx) * orders the requests before sending them to the driver which * doubled the write performance on spinning disks when measured * with Linux 3.5 */ - btrfsic_submit_bio(WRITE, sbio->bio); + btrfsic_submit_bio(sbio->bio); } static void scrub_wr_bio_end_io(struct bio *bio) @@ -2041,7 +2044,7 @@ static void scrub_submit(struct scrub_ctx *sctx) sbio = sctx->bios[sctx->curr]; sctx->curr = -1; scrub_pending_bio_inc(sctx); - btrfsic_submit_bio(READ, sbio->bio); + btrfsic_submit_bio(sbio->bio); } static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx, @@ -2088,6 +2091,7 @@ again: bio->bi_end_io = scrub_bio_end_io; bio->bi_bdev = sbio->dev->bdev; bio->bi_iter.bi_sector = sbio->physical >> 9; + bio->bi_rw = READ; sbio->err = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical || @@ -4436,6 +4440,7 @@ static int write_page_nocow(struct scrub_ctx *sctx, bio->bi_iter.bi_size = 0; bio->bi_iter.bi_sector = physical_for_dev_replace >> 9; bio->bi_bdev = dev->bdev; + bio->bi_rw = WRITE_SYNC; ret = bio_add_page(bio, page, PAGE_SIZE, 0); if (ret != PAGE_SIZE) { leave_with_eio: @@ -4444,7 +4449,7 @@ leave_with_eio: return -EIO; } - if (btrfsic_submit_bio_wait(WRITE_SYNC, bio)) + if (btrfsic_submit_bio_wait(bio)) goto leave_with_eio; bio_put(bio); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index da9e0036a864..037f3ab841d8 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -462,7 +462,7 @@ loop_lock: sync_pending = 0; } - btrfsic_submit_bio(cur->bi_rw, cur); + btrfsic_submit_bio(cur); num_run++; batch_run++; @@ -5996,7 +5996,7 @@ static void btrfs_end_bio(struct bio *bio) */ static noinline void btrfs_schedule_bio(struct btrfs_root *root, struct btrfs_device *device, - int rw, struct bio *bio) + struct bio *bio) { int should_queue = 1; struct btrfs_pending_bios *pending_bios; @@ -6007,9 +6007,9 @@ static noinline void btrfs_schedule_bio(struct btrfs_root *root, } /* don't bother with additional async steps for reads, right now */ - if (!(rw & REQ_WRITE)) { + if (!(bio->bi_rw & REQ_WRITE)) { bio_get(bio); - btrfsic_submit_bio(rw, bio); + btrfsic_submit_bio(bio); bio_put(bio); return; } @@ -6023,7 +6023,6 @@ static noinline void btrfs_schedule_bio(struct btrfs_root *root, atomic_inc(&root->fs_info->nr_async_bios); WARN_ON(bio->bi_next); bio->bi_next = NULL; - bio->bi_rw |= rw; spin_lock(&device->io_lock); if (bio->bi_rw & REQ_SYNC) @@ -6057,6 +6056,7 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, btrfs_io_bio(bio)->stripe_index = dev_nr; bio->bi_end_io = btrfs_end_bio; bio->bi_iter.bi_sector = physical >> 9; + bio->bi_rw |= rw; #ifdef DEBUG { struct rcu_string *name; @@ -6075,9 +6075,9 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, btrfs_bio_counter_inc_noblocked(root->fs_info); if (async) - btrfs_schedule_bio(root, dev, rw, bio); + btrfs_schedule_bio(root, dev, bio); else - btrfsic_submit_bio(rw, bio); + btrfsic_submit_bio(bio); } static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) diff --git a/fs/buffer.c b/fs/buffer.c index 754813a6962b..9a55e7f8b25c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -3030,8 +3030,9 @@ static int submit_bh_wbc(int rw, struct buffer_head *bh, rw |= REQ_META; if (buffer_prio(bh)) rw |= REQ_PRIO; + bio->bi_rw = rw; - submit_bio(rw, bio); + submit_bio(bio); return 0; } diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 2fc8c43ce531..5b758566199e 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -318,6 +318,7 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, bio->bi_bdev = inode->i_sb->s_bdev; bio->bi_iter.bi_sector = pblk << (inode->i_sb->s_blocksize_bits - 9); + bio->bi_rw = WRITE; ret = bio_add_page(bio, ciphertext_page, inode->i_sb->s_blocksize, 0); if (ret != inode->i_sb->s_blocksize) { @@ -327,7 +328,7 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, err = -EIO; goto errout; } - err = submit_bio_wait(WRITE, bio); + err = submit_bio_wait(bio); if ((err == 0) && bio->bi_error) err = -EIO; bio_put(bio); diff --git a/fs/direct-io.c b/fs/direct-io.c index f3b4408be590..1bcdd5dde00d 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -375,6 +375,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, bio->bi_bdev = bdev; bio->bi_iter.bi_sector = first_sector; + bio->bi_rw = dio->rw; if (dio->is_async) bio->bi_end_io = dio_bio_end_aio; else @@ -412,7 +413,7 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) sdio->logical_offset_in_bio); dio->bio_cookie = BLK_QC_T_NONE; } else - dio->bio_cookie = submit_bio(dio->rw, bio); + dio->bio_cookie = submit_bio(bio); sdio->bio = NULL; sdio->boundary = 0; diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index 6a6c27373b54..811bd5de8099 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c @@ -428,6 +428,7 @@ int ext4_encrypted_zeroout(struct inode *inode, ext4_lblk_t lblk, bio->bi_bdev = inode->i_sb->s_bdev; bio->bi_iter.bi_sector = pblk << (inode->i_sb->s_blocksize_bits - 9); + bio->bi_rw = WRITE; ret = bio_add_page(bio, ciphertext_page, inode->i_sb->s_blocksize, 0); if (ret != inode->i_sb->s_blocksize) { @@ -439,7 +440,7 @@ int ext4_encrypted_zeroout(struct inode *inode, ext4_lblk_t lblk, err = -EIO; goto errout; } - err = submit_bio_wait(WRITE, bio); + err = submit_bio_wait(bio); if ((err == 0) && bio->bi_error) err = -EIO; bio_put(bio); diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 2a01df9cc1c3..a72dbcc7a43e 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -342,7 +342,8 @@ void ext4_io_submit(struct ext4_io_submit *io) if (bio) { int io_op = io->io_wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE; - submit_bio(io_op, io->io_bio); + io->io_bio->bi_rw = io_op; + submit_bio(io->io_bio); } io->io_bio = NULL; } diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index dc54a4b60eba..130bd45f4a99 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -271,7 +271,7 @@ int ext4_mpage_readpages(struct address_space *mapping, */ if (bio && (last_block_in_bio != blocks[0] - 1)) { submit_and_realloc: - submit_bio(READ, bio); + submit_bio(bio); bio = NULL; } if (bio == NULL) { @@ -294,6 +294,7 @@ int ext4_mpage_readpages(struct address_space *mapping, bio->bi_iter.bi_sector = blocks[0] << (blkbits - 9); bio->bi_end_io = mpage_end_io; bio->bi_private = ctx; + bio->bi_rw = READ; } length = first_hole << blkbits; @@ -303,14 +304,14 @@ int ext4_mpage_readpages(struct address_space *mapping, if (((map.m_flags & EXT4_MAP_BOUNDARY) && (relative_block == map.m_len)) || (first_hole != blocks_per_page)) { - submit_bio(READ, bio); + submit_bio(bio); bio = NULL; } else last_block_in_bio = blocks[blocks_per_page - 1]; goto next_page; confused: if (bio) { - submit_bio(READ, bio); + submit_bio(bio); bio = NULL; } if (!PageUptodate(page)) @@ -323,6 +324,6 @@ int ext4_mpage_readpages(struct address_space *mapping, } BUG_ON(pages && !list_empty(pages)); if (bio) - submit_bio(READ, bio); + submit_bio(bio); return 0; } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 9a8bbc1fb1fa..c595c8f84c48 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -102,7 +102,8 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi, int rw, { if (!is_read_io(rw)) atomic_inc(&sbi->nr_wb_bios); - submit_bio(rw, bio); + bio->bi_rw = rw; + submit_bio(bio); } static void __submit_merged_bio(struct f2fs_bio_info *io) @@ -1080,6 +1081,7 @@ submit_and_realloc: bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(block_nr); bio->bi_end_io = f2fs_read_end_io; bio->bi_private = ctx; + bio->bi_rw = READ; } if (bio_add_page(bio, page, blocksize, 0) < blocksize) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 2e6f537a0e7d..3fe2faba842a 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -406,7 +406,8 @@ repeat: fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list); bio->bi_bdev = sbi->sb->s_bdev; - ret = submit_bio_wait(WRITE_FLUSH, bio); + bio->bi_rw = WRITE_FLUSH; + ret = submit_bio_wait(bio); llist_for_each_entry_safe(cmd, next, fcc->dispatch_list, llnode) { @@ -438,7 +439,8 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi) int ret; bio->bi_bdev = sbi->sb->s_bdev; - ret = submit_bio_wait(WRITE_FLUSH, bio); + bio->bi_rw = WRITE_FLUSH; + ret = submit_bio_wait(bio); bio_put(bio); return ret; } diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index d5369a109781..ce282423a853 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -240,7 +240,8 @@ void gfs2_log_flush_bio(struct gfs2_sbd *sdp, int rw) { if (sdp->sd_log_bio) { atomic_inc(&sdp->sd_log_in_flight); - submit_bio(rw, sdp->sd_log_bio); + sdp->sd_log_bio->bi_rw = rw; + submit_bio(sdp->sd_log_bio); sdp->sd_log_bio = NULL; } } diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 8eaadabbc771..66670e14f654 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -230,7 +230,8 @@ static void gfs2_submit_bhs(int rw, struct buffer_head *bhs[], int num) bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh)); } bio->bi_end_io = gfs2_meta_read_endio; - submit_bio(rw, bio); + bio->bi_rw = rw; + submit_bio(bio); } /** diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 45463600fb81..d9e19f61077b 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -246,7 +246,8 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent) bio->bi_end_io = end_bio_io_page; bio->bi_private = page; - submit_bio(READ_SYNC | REQ_META, bio); + bio->bi_rw = READ_SYNC | REQ_META; + submit_bio(bio); wait_on_page_locked(page); bio_put(bio); if (!PageUptodate(page)) { diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index cc6235671437..d026bb3fb36f 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c @@ -65,6 +65,7 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, bio = bio_alloc(GFP_NOIO, 1); bio->bi_iter.bi_sector = sector; bio->bi_bdev = sb->s_bdev; + bio->bi_rw = rw; if (!(rw & WRITE) && data) *data = (u8 *)buf + offset; @@ -83,7 +84,7 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, buf = (u8 *)buf + len; } - ret = submit_bio_wait(rw, bio); + ret = submit_bio_wait(bio); out: bio_put(bio); return ret < 0 ? ret : 0; diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 63759d723920..3ee3f32562f9 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2002,12 +2002,13 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) bio->bi_end_io = lbmIODone; bio->bi_private = bp; + bio->bi_rw = READ_SYNC; /*check if journaling to disk has been disabled*/ if (log->no_integrity) { bio->bi_iter.bi_size = 0; lbmIODone(bio); } else { - submit_bio(READ_SYNC, bio); + submit_bio(bio); } wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD)); @@ -2145,13 +2146,14 @@ static void lbmStartIO(struct lbuf * bp) bio->bi_end_io = lbmIODone; bio->bi_private = bp; + bio->bi_rw = WRITE_SYNC; /* check if journaling to disk has been disabled */ if (log->no_integrity) { bio->bi_iter.bi_size = 0; lbmIODone(bio); } else { - submit_bio(WRITE_SYNC, bio); + submit_bio(bio); INCREMENT(lmStat.submitted); } } diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index b60e015cc757..97254436a4ed 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -411,7 +411,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) inc_io(page); if (!bio->bi_iter.bi_size) goto dump_bio; - submit_bio(WRITE, bio); + submit_bio(bio); nr_underway++; bio = NULL; } else @@ -434,6 +434,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) bio->bi_iter.bi_sector = pblock << (inode->i_blkbits - 9); bio->bi_end_io = metapage_write_end_io; bio->bi_private = page; + bio->bi_rw = WRITE; /* Don't call bio_add_page yet, we may add to this vec */ bio_offset = offset; @@ -448,7 +449,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) if (!bio->bi_iter.bi_size) goto dump_bio; - submit_bio(WRITE, bio); + submit_bio(bio); nr_underway++; } if (redirty) @@ -506,7 +507,7 @@ static int metapage_readpage(struct file *fp, struct page *page) insert_metapage(page, NULL); inc_io(page); if (bio) - submit_bio(READ, bio); + submit_bio(bio); bio = bio_alloc(GFP_NOFS, 1); bio->bi_bdev = inode->i_sb->s_bdev; @@ -514,6 +515,7 @@ static int metapage_readpage(struct file *fp, struct page *page) pblock << (inode->i_blkbits - 9); bio->bi_end_io = metapage_read_end_io; bio->bi_private = page; + bio->bi_rw = READ; len = xlen << inode->i_blkbits; offset = block_offset << inode->i_blkbits; if (bio_add_page(bio, page, len, offset) < len) @@ -523,7 +525,7 @@ static int metapage_readpage(struct file *fp, struct page *page) block_offset++; } if (bio) - submit_bio(READ, bio); + submit_bio(bio); else unlock_page(page); diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index cc26f8f215f5..29704bda6394 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -29,8 +29,9 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw) bio.bi_bdev = bdev; bio.bi_iter.bi_sector = page->index * (PAGE_SIZE >> 9); bio.bi_iter.bi_size = PAGE_SIZE; + bio.bi_rw = rw; - return submit_bio_wait(rw, &bio); + return submit_bio_wait(&bio); } static int bdev_readpage(void *_sb, struct page *page) @@ -95,8 +96,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; + bio->bi_rw = WRITE; atomic_inc(&super->s_pending_writes); - submit_bio(WRITE, bio); + submit_bio(bio); ofs += i * PAGE_SIZE; index += i; @@ -122,8 +124,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; + bio->bi_rw = WRITE; atomic_inc(&super->s_pending_writes); - submit_bio(WRITE, bio); + submit_bio(bio); return 0; } @@ -185,8 +188,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; + bio->bi_rw = WRITE; atomic_inc(&super->s_pending_writes); - submit_bio(WRITE, bio); + submit_bio(bio); ofs += i * PAGE_SIZE; index += i; @@ -206,8 +210,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; + bio->bi_rw = WRITE; atomic_inc(&super->s_pending_writes); - submit_bio(WRITE, bio); + submit_bio(bio); return 0; } diff --git a/fs/mpage.c b/fs/mpage.c index eedc644b78d7..2c251ecfeeea 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -59,8 +59,9 @@ static void mpage_end_io(struct bio *bio) static struct bio *mpage_bio_submit(int rw, struct bio *bio) { bio->bi_end_io = mpage_end_io; + bio->bi_rw = rw; guard_bio_eod(rw, bio); - submit_bio(rw, bio); + submit_bio(bio); return NULL; } diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 17a42e4eb872..4c79f4ddb052 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -102,14 +102,15 @@ static inline void put_parallel(struct parallel_io *p) } static struct bio * -bl_submit_bio(int rw, struct bio *bio) +bl_submit_bio(struct bio *bio) { if (bio) { get_parallel(bio->bi_private); dprintk("%s submitting %s bio %u@%llu\n", __func__, - rw == READ ? "read" : "write", bio->bi_iter.bi_size, + bio->bi_rw == READ ? "read" : "write", + bio->bi_iter.bi_size, (unsigned long long)bio->bi_iter.bi_sector); - submit_bio(rw, bio); + submit_bio(bio); } return NULL; } @@ -158,7 +159,7 @@ do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect, if (disk_addr < map->start || disk_addr >= map->start + map->len) { if (!dev->map(dev, disk_addr, map)) return ERR_PTR(-EIO); - bio = bl_submit_bio(rw, bio); + bio = bl_submit_bio(bio); } disk_addr += map->disk_offset; disk_addr -= map->start; @@ -174,9 +175,10 @@ retry: disk_addr >> SECTOR_SHIFT, end_io, par); if (!bio) return ERR_PTR(-ENOMEM); + bio->bi_rw = rw; } if (bio_add_page(bio, page, *len, offset) < *len) { - bio = bl_submit_bio(rw, bio); + bio = bl_submit_bio(bio); goto retry; } return bio; @@ -252,7 +254,7 @@ bl_read_pagelist(struct nfs_pgio_header *header) for (i = pg_index; i < header->page_array.npages; i++) { if (extent_length <= 0) { /* We've used up the previous extent */ - bio = bl_submit_bio(READ, bio); + bio = bl_submit_bio(bio); /* Get the next one */ if (!ext_tree_lookup(bl, isect, &be, false)) { @@ -273,7 +275,7 @@ bl_read_pagelist(struct nfs_pgio_header *header) } if (is_hole(&be)) { - bio = bl_submit_bio(READ, bio); + bio = bl_submit_bio(bio); /* Fill hole w/ zeroes w/o accessing device */ dprintk("%s Zeroing page for hole\n", __func__); zero_user_segment(pages[i], pg_offset, pg_len); @@ -306,7 +308,7 @@ bl_read_pagelist(struct nfs_pgio_header *header) header->res.count = (isect << SECTOR_SHIFT) - header->args.offset; } out: - bl_submit_bio(READ, bio); + bl_submit_bio(bio); blk_finish_plug(&plug); put_parallel(par); return PNFS_ATTEMPTED; @@ -398,7 +400,7 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) for (i = pg_index; i < header->page_array.npages; i++) { if (extent_length <= 0) { /* We've used up the previous extent */ - bio = bl_submit_bio(WRITE, bio); + bio = bl_submit_bio(bio); /* Get the next one */ if (!ext_tree_lookup(bl, isect, &be, true)) { header->pnfs_error = -EINVAL; @@ -427,7 +429,7 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) header->res.count = header->args.count; out: - bl_submit_bio(WRITE, bio); + bl_submit_bio(bio); blk_finish_plug(&plug); put_parallel(par); return PNFS_ATTEMPTED; diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index bf36df10540b..0f62909557e7 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -364,7 +364,8 @@ static int nilfs_segbuf_submit_bio(struct nilfs_segment_buffer *segbuf, bio->bi_end_io = nilfs_end_bio_write; bio->bi_private = segbuf; - submit_bio(mode, bio); + bio->bi_rw = mode; + submit_bio(bio); segbuf->sb_nbio++; wi->bio = NULL; diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 6aaf3e351391..8b1d86ebd8d1 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -530,7 +530,7 @@ static void o2hb_bio_end_io(struct bio *bio) static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg, struct o2hb_bio_wait_ctxt *wc, unsigned int *current_slot, - unsigned int max_slots) + unsigned int max_slots, int rw) { int len, current_page; unsigned int vec_len, vec_start; @@ -556,6 +556,7 @@ static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg, bio->bi_bdev = reg->hr_bdev; bio->bi_private = wc; bio->bi_end_io = o2hb_bio_end_io; + bio->bi_rw = rw; vec_start = (cs << bits) % PAGE_SIZE; while(cs < max_slots) { @@ -591,7 +592,8 @@ static int o2hb_read_slots(struct o2hb_region *reg, o2hb_bio_wait_init(&wc); while(current_slot < max_slots) { - bio = o2hb_setup_one_bio(reg, &wc, ¤t_slot, max_slots); + bio = o2hb_setup_one_bio(reg, &wc, ¤t_slot, max_slots, + READ); if (IS_ERR(bio)) { status = PTR_ERR(bio); mlog_errno(status); @@ -599,7 +601,7 @@ static int o2hb_read_slots(struct o2hb_region *reg, } atomic_inc(&wc.wc_num_reqs); - submit_bio(READ, bio); + submit_bio(bio); } status = 0; @@ -623,7 +625,7 @@ static int o2hb_issue_node_write(struct o2hb_region *reg, slot = o2nm_this_node(); - bio = o2hb_setup_one_bio(reg, write_wc, &slot, slot+1); + bio = o2hb_setup_one_bio(reg, write_wc, &slot, slot+1, WRITE_SYNC); if (IS_ERR(bio)) { status = PTR_ERR(bio); mlog_errno(status); @@ -631,7 +633,7 @@ static int o2hb_issue_node_write(struct o2hb_region *reg, } atomic_inc(&write_wc->wc_num_reqs); - submit_bio(WRITE_SYNC, bio); + submit_bio(bio); status = 0; bail: diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 4c463b99fe57..0cd1603856b4 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -438,7 +438,10 @@ xfs_submit_ioend( ioend->io_bio->bi_private = ioend; ioend->io_bio->bi_end_io = xfs_end_bio; - + if (wbc->sync_mode == WB_SYNC_ALL) + ioend->io_bio->bi_rw = WRITE_SYNC; + else + ioend->io_bio->bi_rw = WRITE; /* * If we are failing the IO now, just mark the ioend with an * error and finish it. This will run IO completion immediately @@ -451,8 +454,7 @@ xfs_submit_ioend( return status; } - submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, - ioend->io_bio); + submit_bio(ioend->io_bio); return 0; } @@ -510,8 +512,11 @@ xfs_chain_bio( bio_chain(ioend->io_bio, new); bio_get(ioend->io_bio); /* for xfs_destroy_ioend */ - submit_bio(wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE, - ioend->io_bio); + if (wbc->sync_mode == WB_SYNC_ALL) + ioend->io_bio->bi_rw = WRITE_SYNC; + else + ioend->io_bio->bi_rw = WRITE; + submit_bio(ioend->io_bio); ioend->io_bio = new; } diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index e71cfbd5acb3..0777c67f169b 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1166,7 +1166,7 @@ next_chunk: bio->bi_iter.bi_sector = sector; bio->bi_end_io = xfs_buf_bio_end_io; bio->bi_private = bp; - + bio->bi_rw = rw; for (; size && nr_pages; nr_pages--, page_index++) { int rbytes, nbytes = PAGE_SIZE - offset; @@ -1190,7 +1190,7 @@ next_chunk: flush_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); } - submit_bio(rw, bio); + submit_bio(bio); if (size) goto next_chunk; } else { diff --git a/include/linux/bio.h b/include/linux/bio.h index 9faebf7f9a33..3bde94234eea 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -473,7 +473,7 @@ static inline void bio_io_error(struct bio *bio) struct request_queue; extern int bio_phys_segments(struct request_queue *, struct bio *); -extern int submit_bio_wait(int rw, struct bio *bio); +extern int submit_bio_wait(struct bio *bio); extern void bio_advance(struct bio *, unsigned); extern void bio_init(struct bio *); diff --git a/include/linux/fs.h b/include/linux/fs.h index dd288148a6b1..65e4c51ecb3d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2747,7 +2747,7 @@ static inline void remove_inode_hash(struct inode *inode) extern void inode_sb_list_add(struct inode *inode); #ifdef CONFIG_BLOCK -extern blk_qc_t submit_bio(int, struct bio *); +extern blk_qc_t submit_bio(struct bio *); extern int bdev_read_only(struct block_device *); #endif extern int set_blocksize(struct block_device *, int); diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 160e1006640d..be227f5aa9dc 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -271,6 +271,7 @@ static int hib_submit_io(int rw, pgoff_t page_off, void *addr, bio = bio_alloc(__GFP_RECLAIM | __GFP_HIGH, 1); bio->bi_iter.bi_sector = page_off * (PAGE_SIZE >> 9); bio->bi_bdev = hib_resume_bdev; + bio->bi_rw = rw; if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { printk(KERN_ERR "PM: Adding page to bio failed at %llu\n", @@ -283,9 +284,9 @@ static int hib_submit_io(int rw, pgoff_t page_off, void *addr, bio->bi_end_io = hib_end_io; bio->bi_private = hb; atomic_inc(&hb->count); - submit_bio(rw, bio); + submit_bio(bio); } else { - error = submit_bio_wait(rw, bio); + error = submit_bio_wait(bio); bio_put(bio); } diff --git a/mm/page_io.c b/mm/page_io.c index 242dba07545b..5a5fd66d7bd5 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -259,7 +259,7 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc, bio_end_io_t end_write_func) { struct bio *bio; - int ret, rw = WRITE; + int ret; struct swap_info_struct *sis = page_swap_info(page); if (sis->flags & SWP_FILE) { @@ -317,12 +317,13 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc, ret = -ENOMEM; goto out; } + bio->bi_rw = WRITE; if (wbc->sync_mode == WB_SYNC_ALL) - rw |= REQ_SYNC; + bio->bi_rw |= REQ_SYNC; count_vm_event(PSWPOUT); set_page_writeback(page); unlock_page(page); - submit_bio(rw, bio); + submit_bio(bio); out: return ret; } @@ -369,8 +370,9 @@ int swap_readpage(struct page *page) ret = -ENOMEM; goto out; } + bio->bi_rw = READ; count_vm_event(PSWPIN); - submit_bio(READ, bio); + submit_bio(bio); out: return ret; } -- cgit v1.2.3 From f21508211d2b16e65821abd171378fa6ece126fe Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:31:42 -0500 Subject: block: add REQ_OP definitions and helpers The following patches separate the operation (WRITE, READ, DISCARD, etc) from the rq_flag_bits flags. This patch adds definitions for request/bio operations (REQ_OPs) and adds request/bio accessors to get/set the op. In this patch the REQ_OPs match the REQ rq_flag_bits ones for compat reasons while all the code is converted to use the op accessors in the set. In the last patches the op will become a number and the accessors and helpers in this patch will be dropped or updated. Signed-off-by: Mike Christie Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- include/linux/bio.h | 3 +++ include/linux/blk_types.h | 24 ++++++++++++++++++++++++ include/linux/blkdev.h | 10 +++++++++- include/linux/fs.h | 26 ++++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bio.h b/include/linux/bio.h index 3bde94234eea..09c5308494a6 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -44,6 +44,9 @@ #define BIO_MAX_SIZE (BIO_MAX_PAGES << PAGE_SHIFT) #define BIO_MAX_SECTORS (BIO_MAX_SIZE >> 9) +#define bio_op(bio) (op_from_rq_bits((bio)->bi_rw)) +#define bio_set_op_attrs(bio, op, flags) ((bio)->bi_rw |= (op | flags)) + /* * upper 16 bits of bi_rw define the io priority of this bio */ diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 77e5d81f07aa..6e60baa583da 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -242,6 +242,30 @@ enum rq_flag_bits { #define REQ_HASHED (1ULL << __REQ_HASHED) #define REQ_MQ_INFLIGHT (1ULL << __REQ_MQ_INFLIGHT) +enum req_op { + REQ_OP_READ, + REQ_OP_WRITE = REQ_WRITE, + REQ_OP_DISCARD = REQ_DISCARD, + REQ_OP_WRITE_SAME = REQ_WRITE_SAME, +}; + +/* + * tmp cpmpat. Users used to set the write bit for all non reads, but + * we will be dropping the bitmap use for ops. Support both until + * the end of the patchset. + */ +static inline int op_from_rq_bits(u64 flags) +{ + if (flags & REQ_OP_DISCARD) + return REQ_OP_DISCARD; + else if (flags & REQ_OP_WRITE_SAME) + return REQ_OP_WRITE_SAME; + else if (flags & REQ_OP_WRITE) + return REQ_OP_WRITE; + else + return REQ_OP_READ; +} + typedef unsigned int blk_qc_t; #define BLK_QC_T_NONE -1U #define BLK_QC_T_SHIFT 16 diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 3d9cf326574f..49c2dbcad583 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -200,6 +200,13 @@ struct request { struct request *next_rq; }; +#define req_op(req) (op_from_rq_bits((req)->cmd_flags)) +#define req_set_op(req, op) ((req)->cmd_flags |= op) +#define req_set_op_attrs(req, op, flags) do { \ + req_set_op(req, op); \ + (req)->cmd_flags |= flags; \ +} while (0) + static inline unsigned short req_get_ioprio(struct request *req) { return req->ioprio; @@ -597,7 +604,8 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) -#define rq_data_dir(rq) ((int)((rq)->cmd_flags & 1)) +#define rq_data_dir(rq) \ + (op_is_write(op_from_rq_bits(rq->cmd_flags)) ? WRITE : READ) /* * Driver can handle struct request, if it either has an old style diff --git a/include/linux/fs.h b/include/linux/fs.h index 65e4c51ecb3d..62ca2f9cad95 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2464,15 +2464,37 @@ extern void make_bad_inode(struct inode *); extern bool is_bad_inode(struct inode *); #ifdef CONFIG_BLOCK +/* + * tmp cpmpat. Users used to set the write bit for all non reads, but + * we will be dropping the bitmap use for ops. Support both until + * the end of the patchset. + */ +static inline bool op_is_write(unsigned long flags) +{ + if (flags & (REQ_OP_WRITE | REQ_OP_WRITE_SAME | REQ_OP_DISCARD)) + return true; + else + return false; +} + /* * return READ, READA, or WRITE */ -#define bio_rw(bio) ((bio)->bi_rw & (RW_MASK | RWA_MASK)) +static inline int bio_rw(struct bio *bio) +{ + if (op_is_write(op_from_rq_bits(bio->bi_rw))) + return WRITE; + + return bio->bi_rw & RWA_MASK; +} /* * return data direction, READ or WRITE */ -#define bio_data_dir(bio) ((bio)->bi_rw & 1) +static inline int bio_data_dir(struct bio *bio) +{ + return op_is_write(op_from_rq_bits(bio->bi_rw)) ? WRITE : READ; +} extern void check_disk_size_change(struct gendisk *disk, struct block_device *bdev); -- cgit v1.2.3 From 2a222ca992c35aee1e83af428f3dd26a3f5d5d94 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:31:43 -0500 Subject: fs: have submit_bh users pass in op and flags separately This has submit_bh users pass in the operation and flags separately, so submit_bh_wbc can setup the bio op and bi_rw flags on the bio that is submitted. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- drivers/md/bitmap.c | 4 ++-- fs/btrfs/check-integrity.c | 24 ++++++++++---------- fs/btrfs/check-integrity.h | 2 +- fs/btrfs/disk-io.c | 4 ++-- fs/buffer.c | 53 +++++++++++++++++++++++---------------------- fs/ext4/balloc.c | 2 +- fs/ext4/ialloc.c | 2 +- fs/ext4/inode.c | 2 +- fs/ext4/mmp.c | 4 ++-- fs/fat/misc.c | 2 +- fs/gfs2/bmap.c | 2 +- fs/gfs2/dir.c | 2 +- fs/gfs2/meta_io.c | 6 ++--- fs/jbd2/commit.c | 6 ++--- fs/jbd2/journal.c | 8 +++---- fs/nilfs2/btnode.c | 6 ++--- fs/nilfs2/btnode.h | 2 +- fs/nilfs2/btree.c | 6 +++-- fs/nilfs2/gcinode.c | 5 +++-- fs/nilfs2/mdt.c | 11 +++++----- fs/ntfs/aops.c | 6 ++--- fs/ntfs/compress.c | 2 +- fs/ntfs/file.c | 2 +- fs/ntfs/logfile.c | 2 +- fs/ntfs/mft.c | 4 ++-- fs/ocfs2/buffer_head_io.c | 8 +++---- fs/reiserfs/inode.c | 4 ++-- fs/reiserfs/journal.c | 6 ++--- fs/ufs/util.c | 2 +- include/linux/buffer_head.h | 9 ++++---- 30 files changed, 102 insertions(+), 96 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index d8129ec93ebd..bc6dced4094c 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -297,7 +297,7 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait) atomic_inc(&bitmap->pending_writes); set_buffer_locked(bh); set_buffer_mapped(bh); - submit_bh(WRITE | REQ_SYNC, bh); + submit_bh(REQ_OP_WRITE, REQ_SYNC, bh); bh = bh->b_this_page; } @@ -392,7 +392,7 @@ static int read_page(struct file *file, unsigned long index, atomic_inc(&bitmap->pending_writes); set_buffer_locked(bh); set_buffer_mapped(bh); - submit_bh(READ, bh); + submit_bh(REQ_OP_READ, 0, bh); } block++; bh = bh->b_this_page; diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 50f81916663b..0d3748b07aba 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -2856,12 +2856,12 @@ static struct btrfsic_dev_state *btrfsic_dev_state_lookup( return ds; } -int btrfsic_submit_bh(int rw, struct buffer_head *bh) +int btrfsic_submit_bh(int op, int op_flags, struct buffer_head *bh) { struct btrfsic_dev_state *dev_state; if (!btrfsic_is_initialized) - return submit_bh(rw, bh); + return submit_bh(op, op_flags, bh); mutex_lock(&btrfsic_mutex); /* since btrfsic_submit_bh() might also be called before @@ -2870,26 +2870,26 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh) /* Only called to write the superblock (incl. FLUSH/FUA) */ if (NULL != dev_state && - (rw & WRITE) && bh->b_size > 0) { + (op == REQ_OP_WRITE) && bh->b_size > 0) { u64 dev_bytenr; dev_bytenr = 4096 * bh->b_blocknr; if (dev_state->state->print_mask & BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) printk(KERN_INFO - "submit_bh(rw=0x%x, blocknr=%llu (bytenr %llu)," - " size=%zu, data=%p, bdev=%p)\n", - rw, (unsigned long long)bh->b_blocknr, + "submit_bh(op=0x%x,0x%x, blocknr=%llu " + "(bytenr %llu), size=%zu, data=%p, bdev=%p)\n", + op, op_flags, (unsigned long long)bh->b_blocknr, dev_bytenr, bh->b_size, bh->b_data, bh->b_bdev); btrfsic_process_written_block(dev_state, dev_bytenr, &bh->b_data, 1, NULL, - NULL, bh, rw); - } else if (NULL != dev_state && (rw & REQ_FLUSH)) { + NULL, bh, op_flags); + } else if (NULL != dev_state && (op_flags & REQ_FLUSH)) { if (dev_state->state->print_mask & BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) printk(KERN_INFO - "submit_bh(rw=0x%x FLUSH, bdev=%p)\n", - rw, bh->b_bdev); + "submit_bh(op=0x%x,0x%x FLUSH, bdev=%p)\n", + op, op_flags, bh->b_bdev); if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) { if ((dev_state->state->print_mask & (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | @@ -2907,7 +2907,7 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh) block->never_written = 0; block->iodone_w_error = 0; block->flush_gen = dev_state->last_flush_gen + 1; - block->submit_bio_bh_rw = rw; + block->submit_bio_bh_rw = op_flags; block->orig_bio_bh_private = bh->b_private; block->orig_bio_bh_end_io.bh = bh->b_end_io; block->next_in_same_bio = NULL; @@ -2916,7 +2916,7 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh) } } mutex_unlock(&btrfsic_mutex); - return submit_bh(rw, bh); + return submit_bh(op, op_flags, bh); } static void __btrfsic_submit_bio(struct bio *bio) diff --git a/fs/btrfs/check-integrity.h b/fs/btrfs/check-integrity.h index c04e249058c3..f78dff1c7e86 100644 --- a/fs/btrfs/check-integrity.h +++ b/fs/btrfs/check-integrity.h @@ -20,7 +20,7 @@ #define __BTRFS_CHECK_INTEGRITY__ #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY -int btrfsic_submit_bh(int rw, struct buffer_head *bh); +int btrfsic_submit_bh(int op, int op_flags, struct buffer_head *bh); void btrfsic_submit_bio(struct bio *bio); int btrfsic_submit_bio_wait(struct bio *bio); #else diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3666558a2375..11033ce82f8a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3420,9 +3420,9 @@ static int write_dev_supers(struct btrfs_device *device, * to go down lazy. */ if (i == 0) - ret = btrfsic_submit_bh(WRITE_FUA, bh); + ret = btrfsic_submit_bh(REQ_OP_WRITE, WRITE_FUA, bh); else - ret = btrfsic_submit_bh(WRITE_SYNC, bh); + ret = btrfsic_submit_bh(REQ_OP_WRITE, WRITE_SYNC, bh); if (ret) errors++; } diff --git a/fs/buffer.c b/fs/buffer.c index 9a55e7f8b25c..881d33606830 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -45,7 +45,7 @@ #include static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); -static int submit_bh_wbc(int rw, struct buffer_head *bh, +static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, unsigned long bio_flags, struct writeback_control *wbc); @@ -1225,7 +1225,7 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh) } else { get_bh(bh); bh->b_end_io = end_buffer_read_sync; - submit_bh(READ, bh); + submit_bh(REQ_OP_READ, 0, bh); wait_on_buffer(bh); if (buffer_uptodate(bh)) return bh; @@ -1697,7 +1697,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, struct buffer_head *bh, *head; unsigned int blocksize, bbits; int nr_underway = 0; - int write_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE); + int write_flags = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : 0); head = create_page_buffers(page, inode, (1 << BH_Dirty)|(1 << BH_Uptodate)); @@ -1786,7 +1786,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, do { struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { - submit_bh_wbc(write_op, bh, 0, wbc); + submit_bh_wbc(REQ_OP_WRITE, write_flags, bh, 0, wbc); nr_underway++; } bh = next; @@ -1840,7 +1840,7 @@ recover: struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { clear_buffer_dirty(bh); - submit_bh_wbc(write_op, bh, 0, wbc); + submit_bh_wbc(REQ_OP_WRITE, write_flags, bh, 0, wbc); nr_underway++; } bh = next; @@ -2248,7 +2248,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block) if (buffer_uptodate(bh)) end_buffer_async_read(bh, 1); else - submit_bh(READ, bh); + submit_bh(REQ_OP_READ, 0, bh); } return 0; } @@ -2582,7 +2582,7 @@ int nobh_write_begin(struct address_space *mapping, if (block_start < from || block_end > to) { lock_buffer(bh); bh->b_end_io = end_buffer_read_nobh; - submit_bh(READ, bh); + submit_bh(REQ_OP_READ, 0, bh); nr_reads++; } } @@ -2949,7 +2949,7 @@ static void end_bio_bh_io_sync(struct bio *bio) * errors, this only handles the "we need to be able to * do IO at the final sector" case. */ -void guard_bio_eod(int rw, struct bio *bio) +void guard_bio_eod(int op, struct bio *bio) { sector_t maxsector; struct bio_vec *bvec = &bio->bi_io_vec[bio->bi_vcnt - 1]; @@ -2979,13 +2979,13 @@ void guard_bio_eod(int rw, struct bio *bio) bvec->bv_len -= truncated_bytes; /* ..and clear the end of the buffer for reads */ - if ((rw & RW_MASK) == READ) { + if (op == REQ_OP_READ) { zero_user(bvec->bv_page, bvec->bv_offset + bvec->bv_len, truncated_bytes); } } -static int submit_bh_wbc(int rw, struct buffer_head *bh, +static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, unsigned long bio_flags, struct writeback_control *wbc) { struct bio *bio; @@ -2999,7 +2999,7 @@ static int submit_bh_wbc(int rw, struct buffer_head *bh, /* * Only clear out a write error when rewriting */ - if (test_set_buffer_req(bh) && (rw & WRITE)) + if (test_set_buffer_req(bh) && (op == REQ_OP_WRITE)) clear_buffer_write_io_error(bh); /* @@ -3024,27 +3024,28 @@ static int submit_bh_wbc(int rw, struct buffer_head *bh, bio->bi_flags |= bio_flags; /* Take care of bh's that straddle the end of the device */ - guard_bio_eod(rw, bio); + guard_bio_eod(op, bio); if (buffer_meta(bh)) - rw |= REQ_META; + op_flags |= REQ_META; if (buffer_prio(bh)) - rw |= REQ_PRIO; - bio->bi_rw = rw; + op_flags |= REQ_PRIO; + bio_set_op_attrs(bio, op, op_flags); submit_bio(bio); return 0; } -int _submit_bh(int rw, struct buffer_head *bh, unsigned long bio_flags) +int _submit_bh(int op, int op_flags, struct buffer_head *bh, + unsigned long bio_flags) { - return submit_bh_wbc(rw, bh, bio_flags, NULL); + return submit_bh_wbc(op, op_flags, bh, bio_flags, NULL); } EXPORT_SYMBOL_GPL(_submit_bh); -int submit_bh(int rw, struct buffer_head *bh) +int submit_bh(int op, int op_flags, struct buffer_head *bh) { - return submit_bh_wbc(rw, bh, 0, NULL); + return submit_bh_wbc(op, op_flags, bh, 0, NULL); } EXPORT_SYMBOL(submit_bh); @@ -3086,14 +3087,14 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) if (test_clear_buffer_dirty(bh)) { bh->b_end_io = end_buffer_write_sync; get_bh(bh); - submit_bh(WRITE, bh); + submit_bh(rw, 0, bh); continue; } } else { if (!buffer_uptodate(bh)) { bh->b_end_io = end_buffer_read_sync; get_bh(bh); - submit_bh(rw, bh); + submit_bh(rw, 0, bh); continue; } } @@ -3102,7 +3103,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) } EXPORT_SYMBOL(ll_rw_block); -void write_dirty_buffer(struct buffer_head *bh, int rw) +void write_dirty_buffer(struct buffer_head *bh, int op_flags) { lock_buffer(bh); if (!test_clear_buffer_dirty(bh)) { @@ -3111,7 +3112,7 @@ void write_dirty_buffer(struct buffer_head *bh, int rw) } bh->b_end_io = end_buffer_write_sync; get_bh(bh); - submit_bh(rw, bh); + submit_bh(REQ_OP_WRITE, op_flags, bh); } EXPORT_SYMBOL(write_dirty_buffer); @@ -3120,7 +3121,7 @@ EXPORT_SYMBOL(write_dirty_buffer); * and then start new I/O and then wait upon it. The caller must have a ref on * the buffer_head. */ -int __sync_dirty_buffer(struct buffer_head *bh, int rw) +int __sync_dirty_buffer(struct buffer_head *bh, int op_flags) { int ret = 0; @@ -3129,7 +3130,7 @@ int __sync_dirty_buffer(struct buffer_head *bh, int rw) if (test_clear_buffer_dirty(bh)) { get_bh(bh); bh->b_end_io = end_buffer_write_sync; - ret = submit_bh(rw, bh); + ret = submit_bh(REQ_OP_WRITE, op_flags, bh); wait_on_buffer(bh); if (!ret && !buffer_uptodate(bh)) ret = -EIO; @@ -3392,7 +3393,7 @@ int bh_submit_read(struct buffer_head *bh) get_bh(bh); bh->b_end_io = end_buffer_read_sync; - submit_bh(READ, bh); + submit_bh(REQ_OP_READ, 0, bh); wait_on_buffer(bh); if (buffer_uptodate(bh)) return 0; diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 3020fd70c392..a806b58e4646 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -470,7 +470,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) trace_ext4_read_block_bitmap_load(sb, block_group); bh->b_end_io = ext4_end_bitmap_read; get_bh(bh); - submit_bh(READ | REQ_META | REQ_PRIO, bh); + submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); return bh; verify: err = ext4_validate_block_bitmap(sb, desc, block_group, bh); diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 3da4cf8d18b6..1e4b0b7425e5 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -214,7 +214,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) trace_ext4_load_inode_bitmap(sb, block_group); bh->b_end_io = ext4_end_bitmap_read; get_bh(bh); - submit_bh(READ | REQ_META | REQ_PRIO, bh); + submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { put_bh(bh); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index f7140ca66e3b..ee3c7d84ef9d 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4281,7 +4281,7 @@ make_io: trace_ext4_load_inode(inode); get_bh(bh); bh->b_end_io = end_buffer_read_sync; - submit_bh(READ | REQ_META | REQ_PRIO, bh); + submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { EXT4_ERROR_INODE_BLOCK(inode, block, diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c index 23d436d6f8b8..d89754ef1aab 100644 --- a/fs/ext4/mmp.c +++ b/fs/ext4/mmp.c @@ -52,7 +52,7 @@ static int write_mmp_block(struct super_block *sb, struct buffer_head *bh) lock_buffer(bh); bh->b_end_io = end_buffer_write_sync; get_bh(bh); - submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh); + submit_bh(REQ_OP_WRITE, WRITE_SYNC | REQ_META | REQ_PRIO, bh); wait_on_buffer(bh); sb_end_write(sb); if (unlikely(!buffer_uptodate(bh))) @@ -88,7 +88,7 @@ static int read_mmp_block(struct super_block *sb, struct buffer_head **bh, get_bh(*bh); lock_buffer(*bh); (*bh)->b_end_io = end_buffer_read_sync; - submit_bh(READ_SYNC | REQ_META | REQ_PRIO, *bh); + submit_bh(REQ_OP_READ, READ_SYNC | REQ_META | REQ_PRIO, *bh); wait_on_buffer(*bh); if (!buffer_uptodate(*bh)) { ret = -EIO; diff --git a/fs/fat/misc.c b/fs/fat/misc.c index c4589e981760..8a8698119ff7 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -267,7 +267,7 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) int i, err = 0; for (i = 0; i < nr_bhs; i++) - write_dirty_buffer(bhs[i], WRITE); + write_dirty_buffer(bhs[i], 0); for (i = 0; i < nr_bhs; i++) { wait_on_buffer(bhs[i]); diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 24ce1cdd434a..06d79aa4fe51 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -285,7 +285,7 @@ static void gfs2_metapath_ra(struct gfs2_glock *gl, if (trylock_buffer(rabh)) { if (!buffer_uptodate(rabh)) { rabh->b_end_io = end_buffer_read_sync; - submit_bh(READA | REQ_META, rabh); + submit_bh(REQ_OP_READ, READA | REQ_META, rabh); continue; } unlock_buffer(rabh); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 271d93905bac..0fbb42679cef 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1513,7 +1513,7 @@ static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index, continue; } bh->b_end_io = end_buffer_read_sync; - submit_bh(READA | REQ_META, bh); + submit_bh(REQ_OP_READ, READA | REQ_META, bh); continue; } brelse(bh); diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 66670e14f654..091483e0ca76 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -37,8 +37,8 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb { struct buffer_head *bh, *head; int nr_underway = 0; - int write_op = REQ_META | REQ_PRIO | - (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE); + int write_flags = REQ_META | REQ_PRIO | + (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : 0); BUG_ON(!PageLocked(page)); BUG_ON(!page_has_buffers(page)); @@ -79,7 +79,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb do { struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { - submit_bh(write_op, bh); + submit_bh(REQ_OP_WRITE, write_flags, bh); nr_underway++; } bh = next; diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 70078096117d..8f7d1339c973 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -155,9 +155,9 @@ static int journal_submit_commit_record(journal_t *journal, if (journal->j_flags & JBD2_BARRIER && !jbd2_has_feature_async_commit(journal)) - ret = submit_bh(WRITE_SYNC | WRITE_FLUSH_FUA, bh); + ret = submit_bh(REQ_OP_WRITE, WRITE_SYNC | WRITE_FLUSH_FUA, bh); else - ret = submit_bh(WRITE_SYNC, bh); + ret = submit_bh(REQ_OP_WRITE, WRITE_SYNC, bh); *cbh = bh; return ret; @@ -718,7 +718,7 @@ start_journal_io: clear_buffer_dirty(bh); set_buffer_uptodate(bh); bh->b_end_io = journal_end_buffer_io_sync; - submit_bh(WRITE_SYNC, bh); + submit_bh(REQ_OP_WRITE, WRITE_SYNC, bh); } cond_resched(); stats.run.rs_blocks_logged += bufs; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index b31852f76f46..2606de4fa661 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1346,15 +1346,15 @@ static int journal_reset(journal_t *journal) return jbd2_journal_start_thread(journal); } -static int jbd2_write_superblock(journal_t *journal, int write_op) +static int jbd2_write_superblock(journal_t *journal, int write_flags) { struct buffer_head *bh = journal->j_sb_buffer; journal_superblock_t *sb = journal->j_superblock; int ret; - trace_jbd2_write_superblock(journal, write_op); + trace_jbd2_write_superblock(journal, write_flags); if (!(journal->j_flags & JBD2_BARRIER)) - write_op &= ~(REQ_FUA | REQ_FLUSH); + write_flags &= ~(REQ_FUA | REQ_FLUSH); lock_buffer(bh); if (buffer_write_io_error(bh)) { /* @@ -1374,7 +1374,7 @@ static int jbd2_write_superblock(journal_t *journal, int write_op) jbd2_superblock_csum_set(journal, sb); get_bh(bh); bh->b_end_io = end_buffer_write_sync; - ret = submit_bh(write_op, bh); + ret = submit_bh(REQ_OP_WRITE, write_flags, bh); wait_on_buffer(bh); if (buffer_write_io_error(bh)) { clear_buffer_write_io_error(bh); diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index 0576033699bc..4cca998ec7a0 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c @@ -62,7 +62,7 @@ nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr) } int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, - sector_t pblocknr, int mode, + sector_t pblocknr, int mode, int mode_flags, struct buffer_head **pbh, sector_t *submit_ptr) { struct buffer_head *bh; @@ -95,7 +95,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, } } - if (mode == READA) { + if (mode_flags & REQ_RAHEAD) { if (pblocknr != *submit_ptr + 1 || !trylock_buffer(bh)) { err = -EBUSY; /* internal code */ brelse(bh); @@ -114,7 +114,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, bh->b_blocknr = pblocknr; /* set block address for read */ bh->b_end_io = end_buffer_read_sync; get_bh(bh); - submit_bh(mode, bh); + submit_bh(mode, mode_flags, bh); bh->b_blocknr = blocknr; /* set back to the given block address */ *submit_ptr = pblocknr; err = 0; diff --git a/fs/nilfs2/btnode.h b/fs/nilfs2/btnode.h index 2cc1b80e18f7..4e8aaa1aeb65 100644 --- a/fs/nilfs2/btnode.h +++ b/fs/nilfs2/btnode.h @@ -43,7 +43,7 @@ void nilfs_btnode_cache_clear(struct address_space *); struct buffer_head *nilfs_btnode_create_block(struct address_space *btnc, __u64 blocknr); int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, int, - struct buffer_head **, sector_t *); + int, struct buffer_head **, sector_t *); void nilfs_btnode_delete(struct buffer_head *); int nilfs_btnode_prepare_change_key(struct address_space *, struct nilfs_btnode_chkey_ctxt *); diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index eccb1c89ccbb..982d1e3df3a5 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c @@ -476,7 +476,8 @@ static int __nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr, sector_t submit_ptr = 0; int ret; - ret = nilfs_btnode_submit_block(btnc, ptr, 0, READ, &bh, &submit_ptr); + ret = nilfs_btnode_submit_block(btnc, ptr, 0, REQ_OP_READ, 0, &bh, + &submit_ptr); if (ret) { if (ret != -EEXIST) return ret; @@ -492,7 +493,8 @@ static int __nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr, n > 0 && i < ra->ncmax; n--, i++) { ptr2 = nilfs_btree_node_get_ptr(ra->node, i, ra->ncmax); - ret = nilfs_btnode_submit_block(btnc, ptr2, 0, READA, + ret = nilfs_btnode_submit_block(btnc, ptr2, 0, + REQ_OP_READ, REQ_RAHEAD, &ra_bh, &submit_ptr); if (likely(!ret || ret == -EEXIST)) brelse(ra_bh); diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 693aded72498..e9148f94d696 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c @@ -101,7 +101,7 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff, bh->b_blocknr = pbn; bh->b_end_io = end_buffer_read_sync; get_bh(bh); - submit_bh(READ, bh); + submit_bh(REQ_OP_READ, 0, bh); if (vbn) bh->b_blocknr = vbn; out: @@ -138,7 +138,8 @@ int nilfs_gccache_submit_read_node(struct inode *inode, sector_t pbn, int ret; ret = nilfs_btnode_submit_block(&NILFS_I(inode)->i_btnode_cache, - vbn ? : pbn, pbn, READ, out_bh, &pbn); + vbn ? : pbn, pbn, REQ_OP_READ, 0, + out_bh, &pbn); if (ret == -EEXIST) /* internal code (cache hit) */ ret = 0; return ret; diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 3417d859a03c..0d7b71fbeff8 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -121,7 +121,7 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, static int nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, - int mode, struct buffer_head **out_bh) + int mode, int mode_flags, struct buffer_head **out_bh) { struct buffer_head *bh; __u64 blknum = 0; @@ -135,7 +135,7 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, if (buffer_uptodate(bh)) goto out; - if (mode == READA) { + if (mode_flags & REQ_RAHEAD) { if (!trylock_buffer(bh)) { ret = -EBUSY; goto failed_bh; @@ -157,7 +157,7 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, bh->b_end_io = end_buffer_read_sync; get_bh(bh); - submit_bh(mode, bh); + submit_bh(mode, mode_flags, bh); ret = 0; trace_nilfs2_mdt_submit_block(inode, inode->i_ino, blkoff, mode); @@ -181,7 +181,7 @@ static int nilfs_mdt_read_block(struct inode *inode, unsigned long block, int i, nr_ra_blocks = NILFS_MDT_MAX_RA_BLOCKS; int err; - err = nilfs_mdt_submit_block(inode, block, READ, &first_bh); + err = nilfs_mdt_submit_block(inode, block, REQ_OP_READ, 0, &first_bh); if (err == -EEXIST) /* internal code */ goto out; @@ -191,7 +191,8 @@ static int nilfs_mdt_read_block(struct inode *inode, unsigned long block, if (readahead) { blkoff = block + 1; for (i = 0; i < nr_ra_blocks; i++, blkoff++) { - err = nilfs_mdt_submit_block(inode, blkoff, READA, &bh); + err = nilfs_mdt_submit_block(inode, blkoff, REQ_OP_READ, + REQ_RAHEAD, &bh); if (likely(!err || err == -EEXIST)) brelse(bh); else if (err != -EBUSY) diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 97768a1379f2..fe251f187ff8 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -362,7 +362,7 @@ handle_zblock: for (i = 0; i < nr; i++) { tbh = arr[i]; if (likely(!buffer_uptodate(tbh))) - submit_bh(READ, tbh); + submit_bh(REQ_OP_READ, 0, tbh); else ntfs_end_buffer_async_read(tbh, 1); } @@ -877,7 +877,7 @@ lock_retry_remap: do { struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { - submit_bh(WRITE, bh); + submit_bh(REQ_OP_WRITE, 0, bh); need_end_writeback = false; } bh = next; @@ -1202,7 +1202,7 @@ lock_retry_remap: BUG_ON(!buffer_mapped(tbh)); get_bh(tbh); tbh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE, tbh); + submit_bh(REQ_OP_WRITE, 0, tbh); } /* Synchronize the mft mirror now if not @sync. */ if (is_mft && !sync) diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index f2b5e746f49b..f8eb04387ca4 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c @@ -670,7 +670,7 @@ lock_retry_remap: } get_bh(tbh); tbh->b_end_io = end_buffer_read_sync; - submit_bh(READ, tbh); + submit_bh(REQ_OP_READ, 0, tbh); } /* Wait for io completion on all buffer heads. */ diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 5622ed5a201e..f548629dfaac 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -553,7 +553,7 @@ static inline int ntfs_submit_bh_for_read(struct buffer_head *bh) lock_buffer(bh); get_bh(bh); bh->b_end_io = end_buffer_read_sync; - return submit_bh(READ, bh); + return submit_bh(REQ_OP_READ, 0, bh); } /** diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index 9d71213ca81e..761f12f7f3ef 100644 --- a/fs/ntfs/logfile.c +++ b/fs/ntfs/logfile.c @@ -821,7 +821,7 @@ map_vcn: * completed ignore errors afterwards as we can assume * that if one buffer worked all of them will work. */ - submit_bh(WRITE, bh); + submit_bh(REQ_OP_WRITE, 0, bh); if (should_wait) { should_wait = false; wait_on_buffer(bh); diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 37b2501caaa4..d15d492ce47b 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -592,7 +592,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no, clear_buffer_dirty(tbh); get_bh(tbh); tbh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE, tbh); + submit_bh(REQ_OP_WRITE, 0, tbh); } /* Wait on i/o completion of buffers. */ for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { @@ -785,7 +785,7 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) clear_buffer_dirty(tbh); get_bh(tbh); tbh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE, tbh); + submit_bh(REQ_OP_WRITE, 0, tbh); } /* Synchronize the mft mirror now if not @sync. */ if (!sync && ni->mft_no < vol->mftmirr_size) diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c index fe50ded1b4ce..fb775c940d5f 100644 --- a/fs/ocfs2/buffer_head_io.c +++ b/fs/ocfs2/buffer_head_io.c @@ -79,7 +79,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh, get_bh(bh); /* for end_buffer_write_sync() */ bh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE, bh); + submit_bh(REQ_OP_WRITE, 0, bh); wait_on_buffer(bh); @@ -149,7 +149,7 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block, clear_buffer_uptodate(bh); get_bh(bh); /* for end_buffer_read_sync() */ bh->b_end_io = end_buffer_read_sync; - submit_bh(READ, bh); + submit_bh(REQ_OP_READ, 0, bh); } for (i = nr; i > 0; i--) { @@ -305,7 +305,7 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr, if (validate) set_buffer_needs_validate(bh); bh->b_end_io = end_buffer_read_sync; - submit_bh(READ, bh); + submit_bh(REQ_OP_READ, 0, bh); continue; } } @@ -419,7 +419,7 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb, get_bh(bh); /* for end_buffer_write_sync() */ bh->b_end_io = end_buffer_write_sync; ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &di->i_check); - submit_bh(WRITE, bh); + submit_bh(REQ_OP_WRITE, 0, bh); wait_on_buffer(bh); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 825455d3e4ba..c2c59f9ff04b 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -2668,7 +2668,7 @@ static int reiserfs_write_full_page(struct page *page, do { struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { - submit_bh(WRITE, bh); + submit_bh(REQ_OP_WRITE, 0, bh); nr++; } put_bh(bh); @@ -2728,7 +2728,7 @@ fail: struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { clear_buffer_dirty(bh); - submit_bh(WRITE, bh); + submit_bh(REQ_OP_WRITE, 0, bh); nr++; } put_bh(bh); diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 2ace90e981f0..6945e719bdab 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -652,7 +652,7 @@ static void submit_logged_buffer(struct buffer_head *bh) BUG(); if (!buffer_uptodate(bh)) BUG(); - submit_bh(WRITE, bh); + submit_bh(REQ_OP_WRITE, 0, bh); } static void submit_ordered_buffer(struct buffer_head *bh) @@ -662,7 +662,7 @@ static void submit_ordered_buffer(struct buffer_head *bh) clear_buffer_dirty(bh); if (!buffer_uptodate(bh)) BUG(); - submit_bh(WRITE, bh); + submit_bh(REQ_OP_WRITE, 0, bh); } #define CHUNK_SIZE 32 @@ -2269,7 +2269,7 @@ abort_replay: /* flush out the real blocks */ for (i = 0; i < get_desc_trans_len(desc); i++) { set_buffer_dirty(real_blocks[i]); - write_dirty_buffer(real_blocks[i], WRITE); + write_dirty_buffer(real_blocks[i], 0); } for (i = 0; i < get_desc_trans_len(desc); i++) { wait_on_buffer(real_blocks[i]); diff --git a/fs/ufs/util.c b/fs/ufs/util.c index a409e3e7827a..f41ad0a6106f 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c @@ -118,7 +118,7 @@ void ubh_sync_block(struct ufs_buffer_head *ubh) unsigned i; for (i = 0; i < ubh->count; i++) - write_dirty_buffer(ubh->bh[i], WRITE); + write_dirty_buffer(ubh->bh[i], 0); for (i = 0; i < ubh->count; i++) wait_on_buffer(ubh->bh[i]); diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index d48daa3f6f20..bc9a45d1e3af 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -189,10 +189,11 @@ void unlock_buffer(struct buffer_head *bh); void __lock_buffer(struct buffer_head *bh); void ll_rw_block(int, int, struct buffer_head * bh[]); int sync_dirty_buffer(struct buffer_head *bh); -int __sync_dirty_buffer(struct buffer_head *bh, int rw); -void write_dirty_buffer(struct buffer_head *bh, int rw); -int _submit_bh(int rw, struct buffer_head *bh, unsigned long bio_flags); -int submit_bh(int, struct buffer_head *); +int __sync_dirty_buffer(struct buffer_head *bh, int op_flags); +void write_dirty_buffer(struct buffer_head *bh, int op_flags); +int _submit_bh(int op, int op_flags, struct buffer_head *bh, + unsigned long bio_flags); +int submit_bh(int, int, struct buffer_head *); void write_boundary_block(struct block_device *bdev, sector_t bblock, unsigned blocksize); int bh_uptodate_or_lock(struct buffer_head *bh); -- cgit v1.2.3 From dfec8a14fc9043039e3c04807caf39dc71102816 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:31:44 -0500 Subject: fs: have ll_rw_block users pass in op and flags separately This has ll_rw_block users pass in the operation and flags separately, so ll_rw_block can setup the bio op and bi_rw flags on the bio that is submitted. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- fs/buffer.c | 19 ++++++++++--------- fs/ext4/inode.c | 6 +++--- fs/ext4/namei.c | 3 ++- fs/ext4/super.c | 2 +- fs/gfs2/bmap.c | 2 +- fs/gfs2/meta_io.c | 4 ++-- fs/gfs2/quota.c | 2 +- fs/isofs/compress.c | 2 +- fs/jbd2/journal.c | 2 +- fs/jbd2/recovery.c | 4 ++-- fs/ocfs2/aops.c | 2 +- fs/ocfs2/super.c | 2 +- fs/reiserfs/journal.c | 8 ++++---- fs/reiserfs/stree.c | 4 ++-- fs/reiserfs/super.c | 2 +- fs/squashfs/block.c | 4 ++-- fs/udf/dir.c | 2 +- fs/udf/directory.c | 2 +- fs/udf/inode.c | 2 +- fs/ufs/balloc.c | 2 +- include/linux/buffer_head.h | 2 +- 21 files changed, 40 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/fs/buffer.c b/fs/buffer.c index 881d33606830..373aacb4f4c1 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -588,7 +588,7 @@ void write_boundary_block(struct block_device *bdev, struct buffer_head *bh = __find_get_block(bdev, bblock + 1, blocksize); if (bh) { if (buffer_dirty(bh)) - ll_rw_block(WRITE, 1, &bh); + ll_rw_block(REQ_OP_WRITE, 0, 1, &bh); put_bh(bh); } } @@ -1395,7 +1395,7 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size) { struct buffer_head *bh = __getblk(bdev, block, size); if (likely(bh)) { - ll_rw_block(READA, 1, &bh); + ll_rw_block(REQ_OP_READ, READA, 1, &bh); brelse(bh); } } @@ -1955,7 +1955,7 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len, if (!buffer_uptodate(bh) && !buffer_delay(bh) && !buffer_unwritten(bh) && (block_start < from || block_end > to)) { - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); *wait_bh++=bh; } } @@ -2852,7 +2852,7 @@ int block_truncate_page(struct address_space *mapping, if (!buffer_uptodate(bh) && !buffer_delay(bh) && !buffer_unwritten(bh)) { err = -EIO; - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); wait_on_buffer(bh); /* Uhhuh. Read error. Complain and punt. */ if (!buffer_uptodate(bh)) @@ -3051,7 +3051,8 @@ EXPORT_SYMBOL(submit_bh); /** * ll_rw_block: low-level access to block devices (DEPRECATED) - * @rw: whether to %READ or %WRITE or maybe %READA (readahead) + * @op: whether to %READ or %WRITE + * @op_flags: rq_flag_bits or %READA (readahead) * @nr: number of &struct buffer_heads in the array * @bhs: array of pointers to &struct buffer_head * @@ -3074,7 +3075,7 @@ EXPORT_SYMBOL(submit_bh); * All of the buffers must be for the same device, and must also be a * multiple of the current approved size for the device. */ -void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) +void ll_rw_block(int op, int op_flags, int nr, struct buffer_head *bhs[]) { int i; @@ -3083,18 +3084,18 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) if (!trylock_buffer(bh)) continue; - if (rw == WRITE) { + if (op == WRITE) { if (test_clear_buffer_dirty(bh)) { bh->b_end_io = end_buffer_write_sync; get_bh(bh); - submit_bh(rw, 0, bh); + submit_bh(op, op_flags, bh); continue; } } else { if (!buffer_uptodate(bh)) { bh->b_end_io = end_buffer_read_sync; get_bh(bh); - submit_bh(rw, 0, bh); + submit_bh(op, op_flags, bh); continue; } } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ee3c7d84ef9d..ae44916d40e2 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -981,7 +981,7 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, return bh; if (!bh || buffer_uptodate(bh)) return bh; - ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh); + ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &bh); wait_on_buffer(bh); if (buffer_uptodate(bh)) return bh; @@ -1135,7 +1135,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, if (!buffer_uptodate(bh) && !buffer_delay(bh) && !buffer_unwritten(bh) && (block_start < from || block_end > to)) { - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); *wait_bh++ = bh; decrypt = ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode); @@ -3698,7 +3698,7 @@ static int __ext4_block_zero_page_range(handle_t *handle, if (!buffer_uptodate(bh)) { err = -EIO; - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); wait_on_buffer(bh); /* Uhhuh. Read error. Complain and punt. */ if (!buffer_uptodate(bh)) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index ec4c39952e84..6569c6b47da4 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1443,7 +1443,8 @@ restart: } bh_use[ra_max] = bh; if (bh) - ll_rw_block(READ | REQ_META | REQ_PRIO, + ll_rw_block(REQ_OP_READ, + REQ_META | REQ_PRIO, 1, &bh); } } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 3822a5aedc61..b1a347100d54 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4204,7 +4204,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, goto out_bdev; } journal->j_private = sb; - ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &journal->j_sb_buffer); + ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &journal->j_sb_buffer); wait_on_buffer(journal->j_sb_buffer); if (!buffer_uptodate(journal->j_sb_buffer)) { ext4_msg(sb, KERN_ERR, "I/O error on journal device"); diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 06d79aa4fe51..fd6389cf0f14 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -974,7 +974,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from) if (!buffer_uptodate(bh)) { err = -EIO; - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); wait_on_buffer(bh); /* Uhhuh. Read error. Complain and punt. */ if (!buffer_uptodate(bh)) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 091483e0ca76..b718447f7eb6 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -449,7 +449,7 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) if (buffer_uptodate(first_bh)) goto out; if (!buffer_locked(first_bh)) - ll_rw_block(READ_SYNC | REQ_META, 1, &first_bh); + ll_rw_block(REQ_OP_READ, READ_SYNC | REQ_META, 1, &first_bh); dblock++; extlen--; @@ -458,7 +458,7 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) bh = gfs2_getbuf(gl, dblock, CREATE); if (!buffer_uptodate(bh) && !buffer_locked(bh)) - ll_rw_block(READA | REQ_META, 1, &bh); + ll_rw_block(REQ_OP_READ, READA | REQ_META, 1, &bh); brelse(bh); dblock++; extlen--; diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index ce7d69a2fdc0..62a68234dfff 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -730,7 +730,7 @@ static int gfs2_write_buf_to_page(struct gfs2_inode *ip, unsigned long index, if (PageUptodate(page)) set_buffer_uptodate(bh); if (!buffer_uptodate(bh)) { - ll_rw_block(READ | REQ_META, 1, &bh); + ll_rw_block(REQ_OP_READ, REQ_META, 1, &bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) goto unlock_out; diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index 2e4e834d1a98..2ce5b75ee9a5 100644 --- a/fs/isofs/compress.c +++ b/fs/isofs/compress.c @@ -81,7 +81,7 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start, blocknum = block_start >> bufshift; memset(bhs, 0, (needblocks + 1) * sizeof(struct buffer_head *)); haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks); - ll_rw_block(READ, haveblocks, bhs); + ll_rw_block(REQ_OP_READ, 0, haveblocks, bhs); curbh = 0; curpage = 0; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 2606de4fa661..34bc99637d5a 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1498,7 +1498,7 @@ static int journal_get_superblock(journal_t *journal) J_ASSERT(bh != NULL); if (!buffer_uptodate(bh)) { - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { printk(KERN_ERR diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 805bc6bcd8ab..02dd3360cb20 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -104,7 +104,7 @@ static int do_readahead(journal_t *journal, unsigned int start) if (!buffer_uptodate(bh) && !buffer_locked(bh)) { bufs[nbufs++] = bh; if (nbufs == MAXBUF) { - ll_rw_block(READ, nbufs, bufs); + ll_rw_block(REQ_OP_READ, 0, nbufs, bufs); journal_brelse_array(bufs, nbufs); nbufs = 0; } @@ -113,7 +113,7 @@ static int do_readahead(journal_t *journal, unsigned int start) } if (nbufs) - ll_rw_block(READ, nbufs, bufs); + ll_rw_block(REQ_OP_READ, 0, nbufs, bufs); err = 0; failed: diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index c034edf3ef38..e97a37179614 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -640,7 +640,7 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno, !buffer_new(bh) && ocfs2_should_read_blk(inode, page, block_start) && (block_start < from || block_end > to)) { - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); *wait_bh++=bh; } diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index d7cae3327de5..3971146228d3 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1819,7 +1819,7 @@ static int ocfs2_get_sector(struct super_block *sb, if (!buffer_dirty(*bh)) clear_buffer_uptodate(*bh); unlock_buffer(*bh); - ll_rw_block(READ, 1, bh); + ll_rw_block(REQ_OP_READ, 0, 1, bh); wait_on_buffer(*bh); if (!buffer_uptodate(*bh)) { mlog_errno(-EIO); diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 6945e719bdab..bc2dde2423c2 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -870,7 +870,7 @@ loop_next: */ if (buffer_dirty(bh) && unlikely(bh->b_page->mapping == NULL)) { spin_unlock(lock); - ll_rw_block(WRITE, 1, &bh); + ll_rw_block(REQ_OP_WRITE, 0, 1, &bh); spin_lock(lock); } put_bh(bh); @@ -1057,7 +1057,7 @@ static int flush_commit_list(struct super_block *s, if (tbh) { if (buffer_dirty(tbh)) { depth = reiserfs_write_unlock_nested(s); - ll_rw_block(WRITE, 1, &tbh); + ll_rw_block(REQ_OP_WRITE, 0, 1, &tbh); reiserfs_write_lock_nested(s, depth); } put_bh(tbh) ; @@ -2244,7 +2244,7 @@ abort_replay: } } /* read in the log blocks, memcpy to the corresponding real block */ - ll_rw_block(READ, get_desc_trans_len(desc), log_blocks); + ll_rw_block(REQ_OP_READ, 0, get_desc_trans_len(desc), log_blocks); for (i = 0; i < get_desc_trans_len(desc); i++) { wait_on_buffer(log_blocks[i]); @@ -2346,7 +2346,7 @@ static struct buffer_head *reiserfs_breada(struct block_device *dev, } else bhlist[j++] = bh; } - ll_rw_block(READ, j, bhlist); + ll_rw_block(REQ_OP_READ, 0, j, bhlist); for (i = 1; i < j; i++) brelse(bhlist[i]); bh = bhlist[0]; diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 5feacd689241..64b29b592d86 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -551,7 +551,7 @@ static int search_by_key_reada(struct super_block *s, if (!buffer_uptodate(bh[j])) { if (depth == -1) depth = reiserfs_write_unlock_nested(s); - ll_rw_block(READA, 1, bh + j); + ll_rw_block(REQ_OP_READ, READA, 1, bh + j); } brelse(bh[j]); } @@ -660,7 +660,7 @@ int search_by_key(struct super_block *sb, const struct cpu_key *key, if (!buffer_uptodate(bh) && depth == -1) depth = reiserfs_write_unlock_nested(sb); - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); wait_on_buffer(bh); if (depth != -1) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index b8f2d1e8c645..9938a518c5ef 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1661,7 +1661,7 @@ static int read_super_block(struct super_block *s, int offset) /* after journal replay, reread all bitmap and super blocks */ static int reread_meta_blocks(struct super_block *s) { - ll_rw_block(READ, 1, &SB_BUFFER_WITH_SB(s)); + ll_rw_block(REQ_OP_READ, 0, 1, &SB_BUFFER_WITH_SB(s)); wait_on_buffer(SB_BUFFER_WITH_SB(s)); if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) { reiserfs_warning(s, "reiserfs-2504", "error reading the super"); diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index 2c2618410d51..ce62a380314f 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c @@ -124,7 +124,7 @@ int squashfs_read_data(struct super_block *sb, u64 index, int length, goto block_release; bytes += msblk->devblksize; } - ll_rw_block(READ, b, bh); + ll_rw_block(REQ_OP_READ, 0, b, bh); } else { /* * Metadata block. @@ -156,7 +156,7 @@ int squashfs_read_data(struct super_block *sb, u64 index, int length, goto block_release; bytes += msblk->devblksize; } - ll_rw_block(READ, b - 1, bh + 1); + ll_rw_block(REQ_OP_READ, 0, b - 1, bh + 1); } for (i = 0; i < b; i++) { diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 4c5593abc553..80c8a21daed9 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -113,7 +113,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx) brelse(tmp); } if (num) { - ll_rw_block(READA, num, bha); + ll_rw_block(REQ_OP_READ, READA, num, bha); for (i = 0; i < num; i++) brelse(bha[i]); } diff --git a/fs/udf/directory.c b/fs/udf/directory.c index c763fda257bf..71f3e0b5b8ab 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c @@ -87,7 +87,7 @@ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, brelse(tmp); } if (num) { - ll_rw_block(READA, num, bha); + ll_rw_block(REQ_OP_READ, READA, num, bha); for (i = 0; i < num; i++) brelse(bha[i]); } diff --git a/fs/udf/inode.c b/fs/udf/inode.c index f323aff740ef..55aa587bbc38 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1199,7 +1199,7 @@ struct buffer_head *udf_bread(struct inode *inode, int block, if (buffer_uptodate(bh)) return bh; - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); wait_on_buffer(bh); if (buffer_uptodate(bh)) diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 0447b949c7f5..67e085d591d8 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -292,7 +292,7 @@ static void ufs_change_blocknr(struct inode *inode, sector_t beg, if (!buffer_mapped(bh)) map_bh(bh, inode->i_sb, oldb + pos); if (!buffer_uptodate(bh)) { - ll_rw_block(READ, 1, &bh); + ll_rw_block(REQ_OP_READ, 0, 1, &bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { ufs_error(inode->i_sb, __func__, diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index bc9a45d1e3af..d1dd29338ba0 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -187,7 +187,7 @@ struct buffer_head *alloc_buffer_head(gfp_t gfp_flags); void free_buffer_head(struct buffer_head * bh); void unlock_buffer(struct buffer_head *bh); void __lock_buffer(struct buffer_head *bh); -void ll_rw_block(int, int, struct buffer_head * bh[]); +void ll_rw_block(int, int, int, struct buffer_head * bh[]); int sync_dirty_buffer(struct buffer_head *bh); int __sync_dirty_buffer(struct buffer_head *bh, int op_flags); void write_dirty_buffer(struct buffer_head *bh, int op_flags); -- cgit v1.2.3 From a8ebb056a8aeb58aafef0af241a6b3ac34ac86bd Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:31:45 -0500 Subject: block, drivers, cgroup: use op_is_write helper instead of checking for REQ_WRITE We currently set REQ_WRITE/WRITE for all non READ IOs like discard, flush, writesame, etc. In the next patches where we no longer set up the op as a bitmap, we will not be able to detect a operation direction like writesame by testing if REQ_WRITE is set. This patch converts the drivers and cgroup to use the op_is_write helper. This should just cover the simple cases. I did dm, md and bcache in their own patches because they were more involved. Signed-off-by: Mike Christie Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/blk-core.c | 4 ++-- block/blk-merge.c | 2 +- drivers/ata/libata-scsi.c | 2 +- drivers/block/loop.c | 6 +++--- drivers/block/umem.c | 2 +- drivers/scsi/osd/osd_initiator.c | 4 ++-- include/linux/blk-cgroup.h | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/block/blk-core.c b/block/blk-core.c index e95340789592..e8e5865a53e2 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2115,7 +2115,7 @@ blk_qc_t submit_bio(struct bio *bio) else count = bio_sectors(bio); - if (bio->bi_rw & WRITE) { + if (op_is_write(bio_op(bio))) { count_vm_events(PGPGOUT, count); } else { task_io_account_read(bio->bi_iter.bi_size); @@ -2126,7 +2126,7 @@ blk_qc_t submit_bio(struct bio *bio) char b[BDEVNAME_SIZE]; printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n", current->comm, task_pid_nr(current), - (bio->bi_rw & WRITE) ? "WRITE" : "READ", + op_is_write(bio_op(bio)) ? "WRITE" : "READ", (unsigned long long)bio->bi_iter.bi_sector, bdevname(bio->bi_bdev, b), count); diff --git a/block/blk-merge.c b/block/blk-merge.c index 261353166dcf..b198070c5bc4 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -439,7 +439,7 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, } if (q->dma_drain_size && q->dma_drain_needed(rq)) { - if (rq->cmd_flags & REQ_WRITE) + if (op_is_write(req_op(rq))) memset(q->dma_drain_buffer, 0, q->dma_drain_size); sg_unmark_end(sg); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index bfec66fb26e2..4c6eb22cc85d 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1190,7 +1190,7 @@ static int atapi_drain_needed(struct request *rq) if (likely(rq->cmd_type != REQ_TYPE_BLOCK_PC)) return 0; - if (!blk_rq_bytes(rq) || (rq->cmd_flags & REQ_WRITE)) + if (!blk_rq_bytes(rq) || op_is_write(req_op(rq))) return 0; return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 1fa8cc235977..e9f1701af7cb 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -447,7 +447,7 @@ static int lo_req_flush(struct loop_device *lo, struct request *rq) static inline void handle_partial_read(struct loop_cmd *cmd, long bytes) { - if (bytes < 0 || (cmd->rq->cmd_flags & REQ_WRITE)) + if (bytes < 0 || op_is_write(req_op(cmd->rq))) return; if (unlikely(bytes < blk_rq_bytes(cmd->rq))) { @@ -541,7 +541,7 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq) pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset; - if (rq->cmd_flags & REQ_WRITE) { + if (op_is_write(req_op(rq))) { if (rq->cmd_flags & REQ_FLUSH) ret = lo_req_flush(lo, rq); else if (rq->cmd_flags & REQ_DISCARD) @@ -1672,7 +1672,7 @@ static int loop_queue_rq(struct blk_mq_hw_ctx *hctx, static void loop_handle_cmd(struct loop_cmd *cmd) { - const bool write = cmd->rq->cmd_flags & REQ_WRITE; + const bool write = op_is_write(req_op(cmd->rq)); struct loop_device *lo = cmd->rq->q->queuedata; int ret = 0; diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 7939b9f87441..4b3ba74e9d22 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -462,7 +462,7 @@ static void process_page(unsigned long data) le32_to_cpu(desc->local_addr)>>9, le32_to_cpu(desc->transfer_size)); dump_dmastat(card, control); - } else if ((bio->bi_rw & REQ_WRITE) && + } else if (op_is_write(bio_op(bio)) && le32_to_cpu(desc->local_addr) >> 9 == card->init_size) { card->init_size += le32_to_cpu(desc->transfer_size) >> 9; diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 3b11aad03752..14ed39b32bfc 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -824,7 +824,7 @@ void osd_req_write(struct osd_request *or, { _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, len); WARN_ON(or->out.bio || or->out.total_bytes); - WARN_ON(0 == (bio->bi_rw & REQ_WRITE)); + WARN_ON(!op_is_write(bio_op(bio))); or->out.bio = bio; or->out.total_bytes = len; } @@ -875,7 +875,7 @@ void osd_req_read(struct osd_request *or, { _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len); WARN_ON(or->in.bio || or->in.total_bytes); - WARN_ON(bio->bi_rw & REQ_WRITE); + WARN_ON(op_is_write(bio_op(bio))); or->in.bio = bio; or->in.total_bytes = len; } diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index c02e669945e9..04f9c8d64060 100644 --- a/include/linux/blk-cgroup.h +++ b/include/linux/blk-cgroup.h @@ -601,7 +601,7 @@ static inline void blkg_rwstat_add(struct blkg_rwstat *rwstat, { struct percpu_counter *cnt; - if (rw & REQ_WRITE) + if (op_is_write(rw)) cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_WRITE]; else cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_READ]; -- cgit v1.2.3 From 95fe6c1a209ef89d9f94dd04a0ad72be1487d5d5 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:31:48 -0500 Subject: block, fs, mm, drivers: use bio set/get op accessors This patch converts the simple bi_rw use cases in the block, drivers, mm and fs code to set/get the bio operation using bio_set_op_attrs/bio_op These should be simple one or two liner cases, so I just did them in one patch. The next patches handle the more complicated cases in a module per patch. Signed-off-by: Mike Christie Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/bio.c | 13 ++++++------- block/blk-core.c | 6 +++--- block/blk-flush.c | 2 +- block/blk-lib.c | 4 ++-- block/blk-map.c | 2 +- block/blk-merge.c | 12 ++++++------ drivers/block/brd.c | 2 +- drivers/block/floppy.c | 2 +- drivers/block/pktcdvd.c | 4 ++-- drivers/block/rsxx/dma.c | 2 +- drivers/block/zram/zram_drv.c | 2 +- drivers/lightnvm/rrpc.c | 6 +++--- drivers/scsi/osd/osd_initiator.c | 8 ++++---- drivers/staging/lustre/lustre/llite/lloop.c | 6 +++--- fs/crypto/crypto.c | 2 +- fs/exofs/ore.c | 2 +- fs/ext4/page-io.c | 6 +++--- fs/ext4/readpage.c | 2 +- fs/jfs/jfs_logmgr.c | 4 ++-- fs/jfs/jfs_metapage.c | 4 ++-- fs/logfs/dev_bdev.c | 12 ++++++------ fs/nfs/blocklayout/blocklayout.c | 4 ++-- include/linux/bio.h | 15 ++++++++++----- mm/page_io.c | 4 ++-- 24 files changed, 65 insertions(+), 61 deletions(-) (limited to 'include/linux') diff --git a/block/bio.c b/block/bio.c index fc779eba0b95..848cd351513b 100644 --- a/block/bio.c +++ b/block/bio.c @@ -656,16 +656,15 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, bio = bio_alloc_bioset(gfp_mask, bio_segments(bio_src), bs); if (!bio) return NULL; - bio->bi_bdev = bio_src->bi_bdev; bio->bi_rw = bio_src->bi_rw; bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector; bio->bi_iter.bi_size = bio_src->bi_iter.bi_size; - if (bio->bi_rw & REQ_DISCARD) + if (bio_op(bio) == REQ_OP_DISCARD) goto integrity_clone; - if (bio->bi_rw & REQ_WRITE_SAME) { + if (bio_op(bio) == REQ_OP_WRITE_SAME) { bio->bi_io_vec[bio->bi_vcnt++] = bio_src->bi_io_vec[0]; goto integrity_clone; } @@ -1166,7 +1165,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q, goto out_bmd; if (iter->type & WRITE) - bio->bi_rw |= REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); ret = 0; @@ -1336,7 +1335,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, * set data direction, and check if mapped pages need bouncing */ if (iter->type & WRITE) - bio->bi_rw |= REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); bio_set_flag(bio, BIO_USER_MAPPED); @@ -1529,7 +1528,7 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, bio->bi_private = data; } else { bio->bi_end_io = bio_copy_kern_endio; - bio->bi_rw |= REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); } return bio; @@ -1784,7 +1783,7 @@ struct bio *bio_split(struct bio *bio, int sectors, * Discards need a mutable bio_vec to accommodate the payload * required by the DSM TRIM and UNMAP commands. */ - if (bio->bi_rw & REQ_DISCARD) + if (bio_op(bio) == REQ_OP_DISCARD) split = bio_clone_bioset(bio, gfp, bs); else split = bio_clone_fast(bio, gfp, bs); diff --git a/block/blk-core.c b/block/blk-core.c index e8e5865a53e2..7e943dce781c 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1973,14 +1973,14 @@ generic_make_request_checks(struct bio *bio) } } - if ((bio->bi_rw & REQ_DISCARD) && + if ((bio_op(bio) == REQ_OP_DISCARD) && (!blk_queue_discard(q) || ((bio->bi_rw & REQ_SECURE) && !blk_queue_secdiscard(q)))) { err = -EOPNOTSUPP; goto end_io; } - if (bio->bi_rw & REQ_WRITE_SAME && !bdev_write_same(bio->bi_bdev)) { + if (bio_op(bio) == REQ_OP_WRITE_SAME && !bdev_write_same(bio->bi_bdev)) { err = -EOPNOTSUPP; goto end_io; } @@ -2110,7 +2110,7 @@ blk_qc_t submit_bio(struct bio *bio) if (bio_has_data(bio)) { unsigned int count; - if (unlikely(bio->bi_rw & REQ_WRITE_SAME)) + if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) count = bdev_logical_block_size(bio->bi_bdev) >> 9; else count = bio_sectors(bio); diff --git a/block/blk-flush.c b/block/blk-flush.c index 3af4a5ad46f5..9fd1f63a6348 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -485,7 +485,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, bio = bio_alloc(gfp_mask, 0); bio->bi_bdev = bdev; - bio->bi_rw = WRITE_FLUSH; + bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH); ret = submit_bio_wait(bio); diff --git a/block/blk-lib.c b/block/blk-lib.c index 1f6dec5e0975..c614eaa7b853 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -155,7 +155,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, bio->bi_io_vec->bv_page = page; bio->bi_io_vec->bv_offset = 0; bio->bi_io_vec->bv_len = bdev_logical_block_size(bdev); - bio->bi_rw = REQ_WRITE | REQ_WRITE_SAME; + bio_set_op_attrs(bio, REQ_OP_WRITE_SAME, 0); if (nr_sects > max_write_same_sectors) { bio->bi_iter.bi_size = max_write_same_sectors << 9; @@ -196,7 +196,7 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, gfp_mask); bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; - bio->bi_rw = REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); while (nr_sects != 0) { sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects); diff --git a/block/blk-map.c b/block/blk-map.c index b9f88b7751fb..61733a660c3a 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -224,7 +224,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, return PTR_ERR(bio); if (!reading) - bio->bi_rw |= REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); if (do_copy) rq->cmd_flags |= REQ_COPY_USER; diff --git a/block/blk-merge.c b/block/blk-merge.c index b198070c5bc4..5a03f967557a 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -172,9 +172,9 @@ void blk_queue_split(struct request_queue *q, struct bio **bio, struct bio *split, *res; unsigned nsegs; - if ((*bio)->bi_rw & REQ_DISCARD) + if (bio_op(*bio) == REQ_OP_DISCARD) split = blk_bio_discard_split(q, *bio, bs, &nsegs); - else if ((*bio)->bi_rw & REQ_WRITE_SAME) + else if (bio_op(*bio) == REQ_OP_WRITE_SAME) split = blk_bio_write_same_split(q, *bio, bs, &nsegs); else split = blk_bio_segment_split(q, *bio, q->bio_split, &nsegs); @@ -213,10 +213,10 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, * This should probably be returning 0, but blk_add_request_payload() * (Christoph!!!!) */ - if (bio->bi_rw & REQ_DISCARD) + if (bio_op(bio) == REQ_OP_DISCARD) return 1; - if (bio->bi_rw & REQ_WRITE_SAME) + if (bio_op(bio) == REQ_OP_WRITE_SAME) return 1; fbio = bio; @@ -385,7 +385,7 @@ static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio, nsegs = 0; cluster = blk_queue_cluster(q); - if (bio->bi_rw & REQ_DISCARD) { + if (bio_op(bio) == REQ_OP_DISCARD) { /* * This is a hack - drivers should be neither modifying the * biovec, nor relying on bi_vcnt - but because of @@ -400,7 +400,7 @@ static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio, return 0; } - if (bio->bi_rw & REQ_WRITE_SAME) { + if (bio_op(bio) == REQ_OP_WRITE_SAME) { single_segment: *sg = sglist; bvec = bio_iovec(bio); diff --git a/drivers/block/brd.c b/drivers/block/brd.c index c04bd9bc39fd..f5b0d6f4e09f 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -339,7 +339,7 @@ static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio) if (bio_end_sector(bio) > get_capacity(bdev->bd_disk)) goto io_error; - if (unlikely(bio->bi_rw & REQ_DISCARD)) { + if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) { if (sector & ((PAGE_SIZE >> SECTOR_SHIFT) - 1) || bio->bi_iter.bi_size & ~PAGE_MASK) goto io_error; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 73ded25b82c4..f9bfecd733a8 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3822,7 +3822,7 @@ static int __floppy_read_block_0(struct block_device *bdev, int drive) bio.bi_flags |= (1 << BIO_QUIET); bio.bi_private = &cbdata; bio.bi_end_io = floppy_rb0_cb; - bio.bi_rw = READ; + bio_set_op_attrs(&bio, REQ_OP_READ, 0); submit_bio(&bio); process_fd_request(); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index d06c62eccdf0..9393bc730acf 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1074,7 +1074,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) BUG(); atomic_inc(&pkt->io_wait); - bio->bi_rw = READ; + bio_set_op_attrs(bio, REQ_OP_READ, 0); pkt_queue_bio(pd, bio); frames_read++; } @@ -1336,7 +1336,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) /* Start the write request */ atomic_set(&pkt->io_wait, 1); - pkt->w_bio->bi_rw = WRITE; + bio_set_op_attrs(pkt->w_bio, REQ_OP_WRITE, 0); pkt_queue_bio(pd, pkt->w_bio); } diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index cf8cd293abb5..5a20385f87d0 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -705,7 +705,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, dma_cnt[i] = 0; } - if (bio->bi_rw & REQ_DISCARD) { + if (bio_op(bio) == REQ_OP_DISCARD) { bv_len = bio->bi_iter.bi_size; while (bv_len > 0) { diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 8fcad8b761f1..e5e5d19f2172 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -874,7 +874,7 @@ static void __zram_make_request(struct zram *zram, struct bio *bio) offset = (bio->bi_iter.bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; - if (unlikely(bio->bi_rw & REQ_DISCARD)) { + if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) { zram_bio_discard(zram, index, offset, bio); bio_endio(bio); return; diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 2103e97a974f..de86d72dcdf0 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -342,7 +342,7 @@ try: /* Perform read to do GC */ bio->bi_iter.bi_sector = rrpc_get_sector(rev->addr); - bio->bi_rw = READ; + bio_set_op_attrs(bio, REQ_OP_READ, 0); bio->bi_private = &wait; bio->bi_end_io = rrpc_end_sync_bio; @@ -364,7 +364,7 @@ try: reinit_completion(&wait); bio->bi_iter.bi_sector = rrpc_get_sector(rev->addr); - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); bio->bi_private = &wait; bio->bi_end_io = rrpc_end_sync_bio; @@ -908,7 +908,7 @@ static blk_qc_t rrpc_make_rq(struct request_queue *q, struct bio *bio) struct nvm_rq *rqd; int err; - if (bio->bi_rw & REQ_DISCARD) { + if (bio_op(bio) == REQ_OP_DISCARD) { rrpc_discard(rrpc, bio); return BLK_QC_T_NONE; } diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 14ed39b32bfc..daa4dc17f172 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -726,7 +726,7 @@ static int _osd_req_list_objects(struct osd_request *or, return PTR_ERR(bio); } - bio->bi_rw &= ~REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_READ, 0); or->in.bio = bio; or->in.total_bytes = bio->bi_iter.bi_size; return 0; @@ -839,7 +839,7 @@ int osd_req_write_kern(struct osd_request *or, if (IS_ERR(bio)) return PTR_ERR(bio); - bio->bi_rw |= REQ_WRITE; /* FIXME: bio_set_dir() */ + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); osd_req_write(or, obj, offset, bio, len); return 0; } @@ -956,7 +956,7 @@ static int _osd_req_finalize_cdb_cont(struct osd_request *or, const u8 *cap_key) if (IS_ERR(bio)) return PTR_ERR(bio); - bio->bi_rw |= REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); /* integrity check the continuation before the bio is linked * with the other data segments since the continuation @@ -1077,7 +1077,7 @@ int osd_req_write_sg_kern(struct osd_request *or, if (IS_ERR(bio)) return PTR_ERR(bio); - bio->bi_rw |= REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); osd_req_write_sg(or, obj, bio, sglist, numentries); return 0; diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c index 813a9a354e5f..b677930a8a3b 100644 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ b/drivers/staging/lustre/lustre/llite/lloop.c @@ -211,9 +211,9 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head) return io->ci_result; io->ci_lockreq = CILR_NEVER; - rw = head->bi_rw; + rw = bio_data_dir(head); for (bio = head; bio ; bio = bio->bi_next) { - LASSERT(rw == bio->bi_rw); + LASSERT(rw == bio_data_dir(bio)); offset = (pgoff_t)(bio->bi_iter.bi_sector << 9) + lo->lo_offset; bio_for_each_segment(bvec, bio, iter) { @@ -305,7 +305,7 @@ static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req) /* TODO: need to split the bio, too bad. */ LASSERT(first->bi_vcnt <= LLOOP_MAX_SEGMENTS); - rw = first->bi_rw; + rw = bio_data_dir(first); bio = &lo->lo_bio; while (*bio && (*bio)->bi_rw == rw) { CDEBUG(D_INFO, "bio sector %llu size %u count %u vcnt%u\n", diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 5b758566199e..c502c116924c 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -318,7 +318,7 @@ int fscrypt_zeroout_range(struct inode *inode, pgoff_t lblk, bio->bi_bdev = inode->i_sb->s_bdev; bio->bi_iter.bi_sector = pblk << (inode->i_sb->s_blocksize_bits - 9); - bio->bi_rw = WRITE; + 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) { diff --git a/fs/exofs/ore.c b/fs/exofs/ore.c index 7bd8ac8dfb28..8bb72807e70d 100644 --- a/fs/exofs/ore.c +++ b/fs/exofs/ore.c @@ -878,7 +878,7 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp) } else { bio = master_dev->bio; /* FIXME: bio_set_dir() */ - bio->bi_rw |= REQ_WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); } osd_req_write(or, _ios_obj(ios, cur_comp), diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index a72dbcc7a43e..5185fed40fab 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -340,9 +340,9 @@ void ext4_io_submit(struct ext4_io_submit *io) struct bio *bio = io->io_bio; if (bio) { - int io_op = io->io_wbc->sync_mode == WB_SYNC_ALL ? - WRITE_SYNC : WRITE; - io->io_bio->bi_rw = io_op; + int io_op_flags = io->io_wbc->sync_mode == WB_SYNC_ALL ? + WRITE_SYNC : 0; + bio_set_op_attrs(io->io_bio, REQ_OP_WRITE, io_op_flags); submit_bio(io->io_bio); } io->io_bio = NULL; diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index 130bd45f4a99..2ced5a823354 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -294,7 +294,7 @@ int ext4_mpage_readpages(struct address_space *mapping, bio->bi_iter.bi_sector = blocks[0] << (blkbits - 9); bio->bi_end_io = mpage_end_io; bio->bi_private = ctx; - bio->bi_rw = READ; + bio_set_op_attrs(bio, REQ_OP_READ, 0); } length = first_hole << blkbits; diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 3ee3f32562f9..a74752146ec9 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2002,7 +2002,7 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) bio->bi_end_io = lbmIODone; bio->bi_private = bp; - bio->bi_rw = READ_SYNC; + bio_set_op_attrs(bio, REQ_OP_READ, READ_SYNC); /*check if journaling to disk has been disabled*/ if (log->no_integrity) { bio->bi_iter.bi_size = 0; @@ -2146,7 +2146,7 @@ static void lbmStartIO(struct lbuf * bp) bio->bi_end_io = lbmIODone; bio->bi_private = bp; - bio->bi_rw = WRITE_SYNC; + bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_SYNC); /* check if journaling to disk has been disabled */ if (log->no_integrity) { diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 97254436a4ed..e7fa9e513040 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -434,7 +434,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) bio->bi_iter.bi_sector = pblock << (inode->i_blkbits - 9); bio->bi_end_io = metapage_write_end_io; bio->bi_private = page; - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); /* Don't call bio_add_page yet, we may add to this vec */ bio_offset = offset; @@ -515,7 +515,7 @@ static int metapage_readpage(struct file *fp, struct page *page) pblock << (inode->i_blkbits - 9); bio->bi_end_io = metapage_read_end_io; bio->bi_private = page; - bio->bi_rw = READ; + bio_set_op_attrs(bio, REQ_OP_READ, 0); len = xlen << inode->i_blkbits; offset = block_offset << inode->i_blkbits; if (bio_add_page(bio, page, len, offset) < len) diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 29704bda6394..a8329cc47dec 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -14,7 +14,7 @@ #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) -static int sync_request(struct page *page, struct block_device *bdev, int rw) +static int sync_request(struct page *page, struct block_device *bdev, int op) { struct bio bio; struct bio_vec bio_vec; @@ -29,7 +29,7 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw) bio.bi_bdev = bdev; bio.bi_iter.bi_sector = page->index * (PAGE_SIZE >> 9); bio.bi_iter.bi_size = PAGE_SIZE; - bio.bi_rw = rw; + bio_set_op_attrs(&bio, op, 0); return submit_bio_wait(&bio); } @@ -96,7 +96,7 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); atomic_inc(&super->s_pending_writes); submit_bio(bio); @@ -124,7 +124,7 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); atomic_inc(&super->s_pending_writes); submit_bio(bio); return 0; @@ -188,7 +188,7 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); atomic_inc(&super->s_pending_writes); submit_bio(bio); @@ -210,7 +210,7 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); atomic_inc(&super->s_pending_writes); submit_bio(bio); return 0; diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 4c79f4ddb052..f55a4e756047 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -107,7 +107,7 @@ bl_submit_bio(struct bio *bio) if (bio) { get_parallel(bio->bi_private); dprintk("%s submitting %s bio %u@%llu\n", __func__, - bio->bi_rw == READ ? "read" : "write", + bio_op(bio) == READ ? "read" : "write", bio->bi_iter.bi_size, (unsigned long long)bio->bi_iter.bi_sector); submit_bio(bio); @@ -175,7 +175,7 @@ retry: disk_addr >> SECTOR_SHIFT, end_io, par); if (!bio) return ERR_PTR(-ENOMEM); - bio->bi_rw = rw; + bio_set_op_attrs(bio, rw, 0); } if (bio_add_page(bio, page, *len, offset) < *len) { bio = bl_submit_bio(bio); diff --git a/include/linux/bio.h b/include/linux/bio.h index 09c5308494a6..4568647269a7 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -109,18 +109,23 @@ static inline bool bio_has_data(struct bio *bio) { if (bio && bio->bi_iter.bi_size && - !(bio->bi_rw & REQ_DISCARD)) + bio_op(bio) != REQ_OP_DISCARD) return true; return false; } +static inline bool bio_no_advance_iter(struct bio *bio) +{ + return bio_op(bio) == REQ_OP_DISCARD || bio_op(bio) == REQ_OP_WRITE_SAME; +} + static inline bool bio_is_rw(struct bio *bio) { if (!bio_has_data(bio)) return false; - if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) + if (bio_no_advance_iter(bio)) return false; return true; @@ -228,7 +233,7 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, { iter->bi_sector += bytes >> 9; - if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) + if (bio_no_advance_iter(bio)) iter->bi_size -= bytes; else bvec_iter_advance(bio->bi_io_vec, iter, bytes); @@ -256,10 +261,10 @@ static inline unsigned bio_segments(struct bio *bio) * differently: */ - if (bio->bi_rw & REQ_DISCARD) + if (bio_op(bio) == REQ_OP_DISCARD) return 1; - if (bio->bi_rw & REQ_WRITE_SAME) + if (bio_op(bio) == REQ_OP_WRITE_SAME) return 1; bio_for_each_segment(bv, bio, iter) diff --git a/mm/page_io.c b/mm/page_io.c index 5a5fd66d7bd5..dcc5d3769608 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -317,7 +317,7 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc, ret = -ENOMEM; goto out; } - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); if (wbc->sync_mode == WB_SYNC_ALL) bio->bi_rw |= REQ_SYNC; count_vm_event(PSWPOUT); @@ -370,7 +370,7 @@ int swap_readpage(struct page *page) ret = -ENOMEM; goto out; } - bio->bi_rw = READ; + bio_set_op_attrs(bio, REQ_OP_READ, 0); count_vm_event(PSWPIN); submit_bio(bio); out: -- cgit v1.2.3 From 469e3216e20a3946a292ff0414ab86de408d465e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:31:49 -0500 Subject: block discard: use bio set op accessor This converts the block issue discard helper and users to use the bio_set_op_attrs accessor and only pass in the operation flags like REQ_SEQURE. Signed-off-by: Mike Christie Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/blk-lib.c | 13 +++++++------ drivers/md/dm-thin.c | 2 +- include/linux/blkdev.h | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/block/blk-lib.c b/block/blk-lib.c index c614eaa7b853..ff2a7f04af4d 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -23,7 +23,8 @@ static struct bio *next_bio(struct bio *bio, unsigned int nr_pages, } int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, int type, struct bio **biop) + sector_t nr_sects, gfp_t gfp_mask, int op_flags, + struct bio **biop) { struct request_queue *q = bdev_get_queue(bdev); struct bio *bio = *biop; @@ -34,7 +35,7 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, return -ENXIO; if (!blk_queue_discard(q)) return -EOPNOTSUPP; - if ((type & REQ_SECURE) && !blk_queue_secdiscard(q)) + if ((op_flags & REQ_SECURE) && !blk_queue_secdiscard(q)) return -EOPNOTSUPP; /* Zero-sector (unknown) and one-sector granularities are the same. */ @@ -65,7 +66,7 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, bio = next_bio(bio, 1, gfp_mask); bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; - bio->bi_rw = type; + bio_set_op_attrs(bio, REQ_OP_DISCARD, op_flags); bio->bi_iter.bi_size = req_sects << 9; nr_sects -= req_sects; @@ -99,16 +100,16 @@ EXPORT_SYMBOL(__blkdev_issue_discard); int blkdev_issue_discard(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, unsigned long flags) { - int type = REQ_WRITE | REQ_DISCARD; + int op_flags = 0; struct bio *bio = NULL; struct blk_plug plug; int ret; if (flags & BLKDEV_DISCARD_SECURE) - type |= REQ_SECURE; + op_flags |= REQ_SECURE; blk_start_plug(&plug); - ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, type, + ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, op_flags, &bio); if (!ret && bio) { ret = submit_bio_wait(bio); diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 8c070eed982c..e8661c25d3ea 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -360,7 +360,7 @@ static int issue_discard(struct discard_op *op, dm_block_t data_b, dm_block_t da sector_t len = block_to_sectors(tc->pool, data_e - data_b); return __blkdev_issue_discard(tc->pool_dev->bdev, s, len, - GFP_NOWAIT, REQ_WRITE | REQ_DISCARD, &op->bio); + GFP_NOWAIT, 0, &op->bio); } static void end_discard(struct discard_op *op, int r) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 49c2dbcad583..8c78aca080af 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1149,7 +1149,8 @@ extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *); extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, unsigned long flags); extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, int type, struct bio **biop); + sector_t nr_sects, gfp_t gfp_mask, int op_flags, + struct bio **biop); extern int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, struct page *page); extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, -- cgit v1.2.3 From 8a4c1e42e0eb7189296ac140761370e2549cffe7 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:31:50 -0500 Subject: direct-io: use bio set/get op accessors This patch has the dio code use a REQ_OP for the op and rq_flag_bits for bi_rw flags. To set/get the op it uses the bio_set_op_attrs/bio_op accssors. It also begins to convert btrfs's dio_submit_t because of the dio submit_io callout use. The next patches will completely convert this code and the reset of the btrfs code paths. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- fs/btrfs/inode.c | 8 ++++---- fs/direct-io.c | 34 ++++++++++++++++++++-------------- include/linux/fs.h | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8b1212e8f7a8..348ad81903bd 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8433,14 +8433,14 @@ out_err: return 0; } -static void btrfs_submit_direct(int rw, struct bio *dio_bio, - struct inode *inode, loff_t file_offset) +static void btrfs_submit_direct(struct bio *dio_bio, struct inode *inode, + loff_t file_offset) { struct btrfs_dio_private *dip = NULL; struct bio *io_bio = NULL; struct btrfs_io_bio *btrfs_bio; int skip_sum; - int write = rw & REQ_WRITE; + bool write = (bio_op(dio_bio) == REQ_OP_WRITE); int ret = 0; skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; @@ -8491,7 +8491,7 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio, dio_data->unsubmitted_oe_range_end; } - ret = btrfs_submit_direct_hook(rw, dip, skip_sum); + ret = btrfs_submit_direct_hook(dio_bio->bi_rw, dip, skip_sum); if (!ret) return; diff --git a/fs/direct-io.c b/fs/direct-io.c index 1bcdd5dde00d..7c3ce73cb617 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -108,7 +108,8 @@ struct dio_submit { /* dio_state communicated between submission path and end_io */ struct dio { int flags; /* doesn't change */ - int rw; + int op; + int op_flags; blk_qc_t bio_cookie; struct block_device *bio_bdev; struct inode *inode; @@ -163,7 +164,7 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) ret = iov_iter_get_pages(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES, &sdio->from); - if (ret < 0 && sdio->blocks_available && (dio->rw & WRITE)) { + if (ret < 0 && sdio->blocks_available && (dio->op == REQ_OP_WRITE)) { struct page *page = ZERO_PAGE(0); /* * A memory fault, but the filesystem has some outstanding @@ -242,7 +243,8 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, bool is_async) transferred = dio->result; /* Check for short read case */ - if ((dio->rw == READ) && ((offset + transferred) > dio->i_size)) + if ((dio->op == REQ_OP_READ) && + ((offset + transferred) > dio->i_size)) transferred = dio->i_size - offset; } @@ -273,7 +275,7 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, bool is_async) */ dio->iocb->ki_pos += transferred; - if (dio->rw & WRITE) + if (dio->op == REQ_OP_WRITE) ret = generic_write_sync(dio->iocb, transferred); dio->iocb->ki_complete(dio->iocb, ret, 0); } @@ -375,7 +377,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, bio->bi_bdev = bdev; bio->bi_iter.bi_sector = first_sector; - bio->bi_rw = dio->rw; + bio_set_op_attrs(bio, dio->op, dio->op_flags); if (dio->is_async) bio->bi_end_io = dio_bio_end_aio; else @@ -403,14 +405,13 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) dio->refcount++; spin_unlock_irqrestore(&dio->bio_lock, flags); - if (dio->is_async && dio->rw == READ && dio->should_dirty) + if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty) bio_set_pages_dirty(bio); dio->bio_bdev = bio->bi_bdev; if (sdio->submit_io) { - sdio->submit_io(dio->rw, bio, dio->inode, - sdio->logical_offset_in_bio); + sdio->submit_io(bio, dio->inode, sdio->logical_offset_in_bio); dio->bio_cookie = BLK_QC_T_NONE; } else dio->bio_cookie = submit_bio(bio); @@ -479,14 +480,14 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio) if (bio->bi_error) dio->io_error = -EIO; - if (dio->is_async && dio->rw == READ && dio->should_dirty) { + if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty) { err = bio->bi_error; bio_check_pages_dirty(bio); /* transfers ownership */ } else { bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; - if (dio->rw == READ && !PageCompound(page) && + if (dio->op == REQ_OP_READ && !PageCompound(page) && dio->should_dirty) set_page_dirty_lock(page); put_page(page); @@ -639,7 +640,7 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio, * which may decide to handle it or also return an unmapped * buffer head. */ - create = dio->rw & WRITE; + create = dio->op == REQ_OP_WRITE; if (dio->flags & DIO_SKIP_HOLES) { if (fs_startblk <= ((i_size_read(dio->inode) - 1) >> i_blkbits)) @@ -789,7 +790,7 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page, { int ret = 0; - if (dio->rw & WRITE) { + if (dio->op == REQ_OP_WRITE) { /* * Read accounting is performed in submit_bio() */ @@ -989,7 +990,7 @@ do_holes: loff_t i_size_aligned; /* AKPM: eargh, -ENOTBLK is a hack */ - if (dio->rw & WRITE) { + if (dio->op == REQ_OP_WRITE) { put_page(page); return -ENOTBLK; } @@ -1203,7 +1204,12 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, dio->is_async = true; dio->inode = inode; - dio->rw = iov_iter_rw(iter) == WRITE ? WRITE_ODIRECT : READ; + if (iov_iter_rw(iter) == WRITE) { + dio->op = REQ_OP_WRITE; + dio->op_flags = WRITE_ODIRECT; + } else { + dio->op = REQ_OP_READ; + } /* * For AIO O_(D)SYNC writes we need to defer completions to a workqueue diff --git a/include/linux/fs.h b/include/linux/fs.h index 62ca2f9cad95..af6f3c7e4822 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2824,7 +2824,7 @@ extern int generic_file_open(struct inode * inode, struct file * filp); extern int nonseekable_open(struct inode * inode, struct file * filp); #ifdef CONFIG_BLOCK -typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode, +typedef void (dio_submit_t)(struct bio *bio, struct inode *inode, loff_t file_offset); enum { -- cgit v1.2.3 From e6047149db702374f240dc18bab665479e25a8cc Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:04 -0500 Subject: dm: use bio op accessors Separate the op from the rq_flag_bits and have dm set/get the bio using bio_set_op_attrs/bio_op. Signed-off-by: Mike Christie Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- drivers/md/dm-bufio.c | 8 +++--- drivers/md/dm-cache-target.c | 10 +++++--- drivers/md/dm-crypt.c | 8 +++--- drivers/md/dm-io.c | 56 ++++++++++++++++++++++------------------- drivers/md/dm-kcopyd.c | 5 ++-- drivers/md/dm-log-writes.c | 8 +++--- drivers/md/dm-log.c | 5 ++-- drivers/md/dm-raid1.c | 19 ++++++++------ drivers/md/dm-region-hash.c | 4 +-- drivers/md/dm-snap-persistent.c | 24 ++++++++++-------- drivers/md/dm-stripe.c | 4 +-- drivers/md/dm-thin.c | 17 +++++++------ drivers/md/dm.c | 8 +++--- include/linux/dm-io.h | 3 ++- 14 files changed, 99 insertions(+), 80 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 9d3ee7f6c6c7..6571c81465e1 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -574,7 +574,8 @@ static void use_dmio(struct dm_buffer *b, int rw, sector_t block, { int r; struct dm_io_request io_req = { - .bi_rw = rw, + .bi_op = rw, + .bi_op_flags = 0, .notify.fn = dmio_complete, .notify.context = b, .client = b->c->dm_io, @@ -634,7 +635,7 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, * the dm_buffer's inline bio is local to bufio. */ b->bio.bi_private = end_io; - b->bio.bi_rw = rw; + bio_set_op_attrs(&b->bio, rw, 0); /* * We assume that if len >= PAGE_SIZE ptr is page-aligned. @@ -1327,7 +1328,8 @@ EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers); int dm_bufio_issue_flush(struct dm_bufio_client *c) { struct dm_io_request io_req = { - .bi_rw = WRITE_FLUSH, + .bi_op = REQ_OP_WRITE, + .bi_op_flags = WRITE_FLUSH, .mem.type = DM_IO_KMEM, .mem.ptr.addr = NULL, .client = c->dm_io, diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index ee0510f9a85e..540e80eb317d 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -788,7 +788,8 @@ static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio) spin_lock_irqsave(&cache->lock, flags); if (cache->need_tick_bio && - !(bio->bi_rw & (REQ_FUA | REQ_FLUSH | REQ_DISCARD))) { + !(bio->bi_rw & (REQ_FUA | REQ_FLUSH)) && + bio_op(bio) != REQ_OP_DISCARD) { pb->tick = true; cache->need_tick_bio = false; } @@ -851,7 +852,7 @@ static void inc_ds(struct cache *cache, struct bio *bio, static bool accountable_bio(struct cache *cache, struct bio *bio) { return ((bio->bi_bdev == cache->origin_dev->bdev) && - !(bio->bi_rw & REQ_DISCARD)); + bio_op(bio) != REQ_OP_DISCARD); } static void accounted_begin(struct cache *cache, struct bio *bio) @@ -1067,7 +1068,8 @@ static void dec_io_migrations(struct cache *cache) static bool discard_or_flush(struct bio *bio) { - return bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD); + return bio_op(bio) == REQ_OP_DISCARD || + bio->bi_rw & (REQ_FLUSH | REQ_FUA); } static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell) @@ -1980,7 +1982,7 @@ static void process_deferred_bios(struct cache *cache) if (bio->bi_rw & REQ_FLUSH) process_flush_bio(cache, bio); - else if (bio->bi_rw & REQ_DISCARD) + else if (bio_op(bio) == REQ_OP_DISCARD) process_discard_bio(cache, &structs, bio); else process_bio(cache, &structs, bio); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 4f3cb3554944..057d19b5e196 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1136,7 +1136,7 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone) clone->bi_private = io; clone->bi_end_io = crypt_endio; clone->bi_bdev = cc->dev->bdev; - clone->bi_rw = io->base_bio->bi_rw; + bio_set_op_attrs(clone, bio_op(io->base_bio), io->base_bio->bi_rw); } static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp) @@ -1911,11 +1911,11 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) struct crypt_config *cc = ti->private; /* - * If bio is REQ_FLUSH or REQ_DISCARD, just bypass crypt queues. + * If bio is REQ_FLUSH or REQ_OP_DISCARD, just bypass crypt queues. * - for REQ_FLUSH device-mapper core ensures that no IO is in-flight - * - for REQ_DISCARD caller must use flush if IO ordering matters + * - for REQ_OP_DISCARD caller must use flush if IO ordering matters */ - if (unlikely(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) { + if (unlikely(bio->bi_rw & REQ_FLUSH || bio_op(bio) == REQ_OP_DISCARD)) { bio->bi_bdev = cc->dev->bdev; if (bio_sectors(bio)) bio->bi_iter.bi_sector = cc->start + diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 26e9a85e3356..22e0597d631e 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -278,8 +278,9 @@ static void km_dp_init(struct dpages *dp, void *data) /*----------------------------------------------------------------- * IO routines that accept a list of pages. *---------------------------------------------------------------*/ -static void do_region(int rw, unsigned region, struct dm_io_region *where, - struct dpages *dp, struct io *io) +static void do_region(int op, int op_flags, unsigned region, + struct dm_io_region *where, struct dpages *dp, + struct io *io) { struct bio *bio; struct page *page; @@ -295,24 +296,25 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, /* * Reject unsupported discard and write same requests. */ - if (rw & REQ_DISCARD) + if (op == REQ_OP_DISCARD) special_cmd_max_sectors = q->limits.max_discard_sectors; - else if (rw & REQ_WRITE_SAME) + else if (op == REQ_OP_WRITE_SAME) special_cmd_max_sectors = q->limits.max_write_same_sectors; - if ((rw & (REQ_DISCARD | REQ_WRITE_SAME)) && special_cmd_max_sectors == 0) { + if ((op == REQ_OP_DISCARD || op == REQ_OP_WRITE_SAME) && + special_cmd_max_sectors == 0) { dec_count(io, region, -EOPNOTSUPP); return; } /* - * where->count may be zero if rw holds a flush and we need to + * where->count may be zero if op holds a flush and we need to * send a zero-sized flush. */ do { /* * Allocate a suitably sized-bio. */ - if ((rw & REQ_DISCARD) || (rw & REQ_WRITE_SAME)) + if ((op == REQ_OP_DISCARD) || (op == REQ_OP_WRITE_SAME)) num_bvecs = 1; else num_bvecs = min_t(int, BIO_MAX_PAGES, @@ -322,14 +324,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, bio->bi_iter.bi_sector = where->sector + (where->count - remaining); bio->bi_bdev = where->bdev; bio->bi_end_io = endio; - bio->bi_rw = rw; + bio_set_op_attrs(bio, op, op_flags); store_io_and_region_in_bio(bio, io, region); - if (rw & REQ_DISCARD) { + if (op == REQ_OP_DISCARD) { num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining); bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT; remaining -= num_sectors; - } else if (rw & REQ_WRITE_SAME) { + } else if (op == REQ_OP_WRITE_SAME) { /* * WRITE SAME only uses a single page. */ @@ -360,7 +362,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, } while (remaining); } -static void dispatch_io(int rw, unsigned int num_regions, +static void dispatch_io(int op, int op_flags, unsigned int num_regions, struct dm_io_region *where, struct dpages *dp, struct io *io, int sync) { @@ -370,7 +372,7 @@ static void dispatch_io(int rw, unsigned int num_regions, BUG_ON(num_regions > DM_IO_MAX_REGIONS); if (sync) - rw |= REQ_SYNC; + op_flags |= REQ_SYNC; /* * For multiple regions we need to be careful to rewind @@ -378,8 +380,8 @@ static void dispatch_io(int rw, unsigned int num_regions, */ for (i = 0; i < num_regions; i++) { *dp = old_pages; - if (where[i].count || (rw & REQ_FLUSH)) - do_region(rw, i, where + i, dp, io); + if (where[i].count || (op_flags & REQ_FLUSH)) + do_region(op, op_flags, i, where + i, dp, io); } /* @@ -403,13 +405,13 @@ static void sync_io_complete(unsigned long error, void *context) } static int sync_io(struct dm_io_client *client, unsigned int num_regions, - struct dm_io_region *where, int rw, struct dpages *dp, - unsigned long *error_bits) + struct dm_io_region *where, int op, int op_flags, + struct dpages *dp, unsigned long *error_bits) { struct io *io; struct sync_io sio; - if (num_regions > 1 && !op_is_write(rw)) { + if (num_regions > 1 && !op_is_write(op)) { WARN_ON(1); return -EIO; } @@ -426,7 +428,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, io->vma_invalidate_address = dp->vma_invalidate_address; io->vma_invalidate_size = dp->vma_invalidate_size; - dispatch_io(rw, num_regions, where, dp, io, 1); + dispatch_io(op, op_flags, num_regions, where, dp, io, 1); wait_for_completion_io(&sio.wait); @@ -437,12 +439,12 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, } static int async_io(struct dm_io_client *client, unsigned int num_regions, - struct dm_io_region *where, int rw, struct dpages *dp, - io_notify_fn fn, void *context) + struct dm_io_region *where, int op, int op_flags, + struct dpages *dp, io_notify_fn fn, void *context) { struct io *io; - if (num_regions > 1 && !op_is_write(rw)) { + if (num_regions > 1 && !op_is_write(op)) { WARN_ON(1); fn(1, context); return -EIO; @@ -458,7 +460,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, io->vma_invalidate_address = dp->vma_invalidate_address; io->vma_invalidate_size = dp->vma_invalidate_size; - dispatch_io(rw, num_regions, where, dp, io, 0); + dispatch_io(op, op_flags, num_regions, where, dp, io, 0); return 0; } @@ -481,7 +483,7 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp, case DM_IO_VMA: flush_kernel_vmap_range(io_req->mem.ptr.vma, size); - if ((io_req->bi_rw & RW_MASK) == READ) { + if (io_req->bi_op == REQ_OP_READ) { dp->vma_invalidate_address = io_req->mem.ptr.vma; dp->vma_invalidate_size = size; } @@ -519,10 +521,12 @@ int dm_io(struct dm_io_request *io_req, unsigned num_regions, if (!io_req->notify.fn) return sync_io(io_req->client, num_regions, where, - io_req->bi_rw, &dp, sync_error_bits); + io_req->bi_op, io_req->bi_op_flags, &dp, + sync_error_bits); - return async_io(io_req->client, num_regions, where, io_req->bi_rw, - &dp, io_req->notify.fn, io_req->notify.context); + return async_io(io_req->client, num_regions, where, io_req->bi_op, + io_req->bi_op_flags, &dp, io_req->notify.fn, + io_req->notify.context); } EXPORT_SYMBOL(dm_io); diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 9f390e47f2a4..9da1d54ac6cb 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -496,7 +496,8 @@ static int run_io_job(struct kcopyd_job *job) { int r; struct dm_io_request io_req = { - .bi_rw = job->rw, + .bi_op = job->rw, + .bi_op_flags = 0, .mem.type = DM_IO_PAGE_LIST, .mem.ptr.pl = job->pages, .mem.offset = 0, @@ -734,7 +735,7 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, /* * Use WRITE SAME to optimize zeroing if all dests support it. */ - job->rw = WRITE | REQ_WRITE_SAME; + job->rw = REQ_OP_WRITE_SAME; for (i = 0; i < job->num_dests; i++) if (!bdev_write_same(job->dests[i].bdev)) { job->rw = WRITE; diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index addcc4be00b6..0edb8ea51e46 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -205,7 +205,7 @@ static int write_metadata(struct log_writes_c *lc, void *entry, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); page = alloc_page(GFP_KERNEL); if (!page) { @@ -270,7 +270,7 @@ static int log_one_block(struct log_writes_c *lc, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); for (i = 0; i < block->vec_cnt; i++) { /* @@ -292,7 +292,7 @@ static int log_one_block(struct log_writes_c *lc, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - bio->bi_rw = WRITE; + bio_set_op_attrs(bio, REQ_OP_WRITE, 0); ret = bio_add_page(bio, block->vecs[i].bv_page, block->vecs[i].bv_len, 0); @@ -557,7 +557,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio) int i = 0; bool flush_bio = (bio->bi_rw & REQ_FLUSH); bool fua_bio = (bio->bi_rw & REQ_FUA); - bool discard_bio = (bio->bi_rw & REQ_DISCARD); + bool discard_bio = (bio_op(bio) == REQ_OP_DISCARD); pb->block = NULL; diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 627d19186d5a..4ca2d1df5b44 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -293,7 +293,7 @@ static void header_from_disk(struct log_header_core *core, struct log_header_dis static int rw_header(struct log_c *lc, int rw) { - lc->io_req.bi_rw = rw; + lc->io_req.bi_op = rw; return dm_io(&lc->io_req, 1, &lc->header_location, NULL); } @@ -306,7 +306,8 @@ static int flush_header(struct log_c *lc) .count = 0, }; - lc->io_req.bi_rw = WRITE_FLUSH; + lc->io_req.bi_op = REQ_OP_WRITE; + lc->io_req.bi_op_flags = WRITE_FLUSH; return dm_io(&lc->io_req, 1, &null_location, NULL); } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index b3ccf1e0d4f2..907df2ba8fd4 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -260,7 +260,8 @@ static int mirror_flush(struct dm_target *ti) struct dm_io_region io[ms->nr_mirrors]; struct mirror *m; struct dm_io_request io_req = { - .bi_rw = WRITE_FLUSH, + .bi_op = REQ_OP_WRITE, + .bi_op_flags = WRITE_FLUSH, .mem.type = DM_IO_KMEM, .mem.ptr.addr = NULL, .client = ms->io_client, @@ -541,7 +542,8 @@ static void read_async_bio(struct mirror *m, struct bio *bio) { struct dm_io_region io; struct dm_io_request io_req = { - .bi_rw = READ, + .bi_op = REQ_OP_READ, + .bi_op_flags = 0, .mem.type = DM_IO_BIO, .mem.ptr.bio = bio, .notify.fn = read_callback, @@ -624,7 +626,7 @@ static void write_callback(unsigned long error, void *context) * If the bio is discard, return an error, but do not * degrade the array. */ - if (bio->bi_rw & REQ_DISCARD) { + if (bio_op(bio) == REQ_OP_DISCARD) { bio->bi_error = -EOPNOTSUPP; bio_endio(bio); return; @@ -654,7 +656,8 @@ static void do_write(struct mirror_set *ms, struct bio *bio) struct dm_io_region io[ms->nr_mirrors], *dest = io; struct mirror *m; struct dm_io_request io_req = { - .bi_rw = WRITE | (bio->bi_rw & WRITE_FLUSH_FUA), + .bi_op = REQ_OP_WRITE, + .bi_op_flags = bio->bi_rw & WRITE_FLUSH_FUA, .mem.type = DM_IO_BIO, .mem.ptr.bio = bio, .notify.fn = write_callback, @@ -662,8 +665,8 @@ static void do_write(struct mirror_set *ms, struct bio *bio) .client = ms->io_client, }; - if (bio->bi_rw & REQ_DISCARD) { - io_req.bi_rw |= REQ_DISCARD; + if (bio_op(bio) == REQ_OP_DISCARD) { + io_req.bi_op = REQ_OP_DISCARD; io_req.mem.type = DM_IO_KMEM; io_req.mem.ptr.addr = NULL; } @@ -702,7 +705,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) while ((bio = bio_list_pop(writes))) { if ((bio->bi_rw & REQ_FLUSH) || - (bio->bi_rw & REQ_DISCARD)) { + (bio_op(bio) == REQ_OP_DISCARD)) { bio_list_add(&sync, bio); continue; } @@ -1250,7 +1253,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error) * We need to dec pending if this was a write. */ if (rw == WRITE) { - if (!(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) + if (!(bio->bi_rw & REQ_FLUSH) && bio_op(bio) != REQ_OP_DISCARD) dm_rh_dec(ms->rh, bio_record->write_region); return error; } diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 74cb7b991d41..3550ca7c6577 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -403,7 +403,7 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio) return; } - if (bio->bi_rw & REQ_DISCARD) + if (bio_op(bio) == REQ_OP_DISCARD) return; /* We must inform the log that the sync count has changed. */ @@ -526,7 +526,7 @@ void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios) struct bio *bio; for (bio = bios->head; bio; bio = bio->bi_next) { - if (bio->bi_rw & (REQ_FLUSH | REQ_DISCARD)) + if (bio->bi_rw & REQ_FLUSH || bio_op(bio) == REQ_OP_DISCARD) continue; rh_inc(rh, dm_rh_bio_to_region(rh, bio)); } diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 4d3909393f2c..b8cf956b577b 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -226,8 +226,8 @@ static void do_metadata(struct work_struct *work) /* * Read or write a chunk aligned and sized block of data from a device. */ -static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw, - int metadata) +static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int op, + int op_flags, int metadata) { struct dm_io_region where = { .bdev = dm_snap_cow(ps->store->snap)->bdev, @@ -235,7 +235,8 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw, .count = ps->store->chunk_size, }; struct dm_io_request io_req = { - .bi_rw = rw, + .bi_op = op, + .bi_op_flags = op_flags, .mem.type = DM_IO_VMA, .mem.ptr.vma = area, .client = ps->io_client, @@ -281,14 +282,14 @@ static void skip_metadata(struct pstore *ps) * Read or write a metadata area. Remembering to skip the first * chunk which holds the header. */ -static int area_io(struct pstore *ps, int rw) +static int area_io(struct pstore *ps, int op, int op_flags) { int r; chunk_t chunk; chunk = area_location(ps, ps->current_area); - r = chunk_io(ps, ps->area, chunk, rw, 0); + r = chunk_io(ps, ps->area, chunk, op, op_flags, 0); if (r) return r; @@ -302,7 +303,8 @@ static void zero_memory_area(struct pstore *ps) static int zero_disk_area(struct pstore *ps, chunk_t area) { - return chunk_io(ps, ps->zero_area, area_location(ps, area), WRITE, 0); + return chunk_io(ps, ps->zero_area, area_location(ps, area), + REQ_OP_WRITE, 0, 0); } static int read_header(struct pstore *ps, int *new_snapshot) @@ -334,7 +336,7 @@ static int read_header(struct pstore *ps, int *new_snapshot) if (r) return r; - r = chunk_io(ps, ps->header_area, 0, READ, 1); + r = chunk_io(ps, ps->header_area, 0, REQ_OP_READ, 0, 1); if (r) goto bad; @@ -395,7 +397,7 @@ static int write_header(struct pstore *ps) dh->version = cpu_to_le32(ps->version); dh->chunk_size = cpu_to_le32(ps->store->chunk_size); - return chunk_io(ps, ps->header_area, 0, WRITE, 1); + return chunk_io(ps, ps->header_area, 0, REQ_OP_WRITE, 0, 1); } /* @@ -739,7 +741,7 @@ static void persistent_commit_exception(struct dm_exception_store *store, /* * Commit exceptions to disk. */ - if (ps->valid && area_io(ps, WRITE_FLUSH_FUA)) + if (ps->valid && area_io(ps, REQ_OP_WRITE, WRITE_FLUSH_FUA)) ps->valid = 0; /* @@ -779,7 +781,7 @@ static int persistent_prepare_merge(struct dm_exception_store *store, return 0; ps->current_area--; - r = area_io(ps, READ); + r = area_io(ps, REQ_OP_READ, 0); if (r < 0) return r; ps->current_committed = ps->exceptions_per_area; @@ -816,7 +818,7 @@ static int persistent_commit_merge(struct dm_exception_store *store, for (i = 0; i < nr_merged; i++) clear_exception(ps, ps->current_committed - 1 - i); - r = area_io(ps, WRITE_FLUSH_FUA); + r = area_io(ps, REQ_OP_WRITE, WRITE_FLUSH_FUA); if (r < 0) return r; diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 797ddb900b06..b738178ca068 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -292,8 +292,8 @@ static int stripe_map(struct dm_target *ti, struct bio *bio) bio->bi_bdev = sc->stripe[target_bio_nr].dev->bdev; return DM_MAPIO_REMAPPED; } - if (unlikely(bio->bi_rw & REQ_DISCARD) || - unlikely(bio->bi_rw & REQ_WRITE_SAME)) { + if (unlikely(bio_op(bio) == REQ_OP_DISCARD) || + unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) { target_bio_nr = dm_bio_get_target_bio_nr(bio); BUG_ON(target_bio_nr >= sc->stripes); return stripe_map_range(sc, bio, target_bio_nr); diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index e8661c25d3ea..1b684cbb9ba2 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -371,7 +371,7 @@ static void end_discard(struct discard_op *op, int r) * need to wait for the chain to complete. */ bio_chain(op->bio, op->parent_bio); - op->bio->bi_rw = REQ_WRITE | REQ_DISCARD; + bio_set_op_attrs(op->bio, REQ_OP_DISCARD, 0); submit_bio(op->bio); } @@ -705,7 +705,7 @@ static void inc_all_io_entry(struct pool *pool, struct bio *bio) { struct dm_thin_endio_hook *h; - if (bio->bi_rw & REQ_DISCARD) + if (bio_op(bio) == REQ_OP_DISCARD) return; h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook)); @@ -868,7 +868,8 @@ static void __inc_remap_and_issue_cell(void *context, struct bio *bio; while ((bio = bio_list_pop(&cell->bios))) { - if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)) + if (bio->bi_rw & (REQ_FLUSH | REQ_FUA) || + bio_op(bio) == REQ_OP_DISCARD) bio_list_add(&info->defer_bios, bio); else { inc_all_io_entry(info->tc->pool, bio); @@ -1640,7 +1641,8 @@ static void __remap_and_issue_shared_cell(void *context, while ((bio = bio_list_pop(&cell->bios))) { if ((bio_data_dir(bio) == WRITE) || - (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA))) + (bio->bi_rw & (REQ_FLUSH | REQ_FUA) || + bio_op(bio) == REQ_OP_DISCARD)) bio_list_add(&info->defer_bios, bio); else { struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));; @@ -2029,7 +2031,7 @@ static void process_thin_deferred_bios(struct thin_c *tc) break; } - if (bio->bi_rw & REQ_DISCARD) + if (bio_op(bio) == REQ_OP_DISCARD) pool->process_discard(tc, bio); else pool->process_bio(tc, bio); @@ -2116,7 +2118,7 @@ static void process_thin_deferred_cells(struct thin_c *tc) return; } - if (cell->holder->bi_rw & REQ_DISCARD) + if (bio_op(cell->holder) == REQ_OP_DISCARD) pool->process_discard_cell(tc, cell); else pool->process_cell(tc, cell); @@ -2554,7 +2556,8 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio) return DM_MAPIO_SUBMITTED; } - if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)) { + if (bio->bi_rw & (REQ_FLUSH | REQ_FUA) || + bio_op(bio) == REQ_OP_DISCARD) { thin_defer_bio_with_throttle(tc, bio); return DM_MAPIO_SUBMITTED; } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f5ac0a32cb6c..9204a2dfdd64 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1053,7 +1053,7 @@ static void clone_endio(struct bio *bio) } } - if (unlikely(r == -EREMOTEIO && (bio->bi_rw & REQ_WRITE_SAME) && + if (unlikely(r == -EREMOTEIO && (bio_op(bio) == REQ_OP_WRITE_SAME) && !bdev_get_queue(bio->bi_bdev)->limits.max_write_same_sectors)) disable_write_same(md); @@ -1748,9 +1748,9 @@ static int __split_and_process_non_flush(struct clone_info *ci) unsigned len; int r; - if (unlikely(bio->bi_rw & REQ_DISCARD)) + if (unlikely(bio_op(bio) == REQ_OP_DISCARD)) return __send_discard(ci); - else if (unlikely(bio->bi_rw & REQ_WRITE_SAME)) + else if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) return __send_write_same(ci); ti = dm_table_find_target(ci->map, ci->sector); @@ -2415,7 +2415,7 @@ static struct mapped_device *alloc_dev(int minor) bio_init(&md->flush_bio); md->flush_bio.bi_bdev = md->bdev; - md->flush_bio.bi_rw = WRITE_FLUSH; + bio_set_op_attrs(&md->flush_bio, REQ_OP_WRITE, WRITE_FLUSH); dm_stats_init(&md->stats); diff --git a/include/linux/dm-io.h b/include/linux/dm-io.h index a68cbe59e6ad..b91b023deffb 100644 --- a/include/linux/dm-io.h +++ b/include/linux/dm-io.h @@ -57,7 +57,8 @@ struct dm_io_notify { */ struct dm_io_client; struct dm_io_request { - int bi_rw; /* READ|WRITE - not READA */ + int bi_op; /* REQ_OP */ + int bi_op_flags; /* rq_flag_bits */ struct dm_io_memory mem; /* Memory to use for io */ struct dm_io_notify notify; /* Synchronous if notify.fn is NULL */ struct dm_io_client *client; /* Client memory handler */ -- cgit v1.2.3 From ba568ea0a2ef9a193ca24874228474ec7ae2ff98 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:13 -0500 Subject: block: prepare elevator to use REQ_OPs. This patch converts the elevator code to use separate variables for the operation and flags, and to check req_op for the REQ_OP. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/blk-core.c | 2 +- block/cfq-iosched.c | 4 ++-- block/elevator.c | 7 +++---- include/linux/elevator.h | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/block/blk-core.c b/block/blk-core.c index a68dc0709299..090e55d7cad7 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1081,7 +1081,7 @@ static struct request *__get_request(struct request_list *rl, int op, if (unlikely(blk_queue_dying(q))) return ERR_PTR(-ENODEV); - may_queue = elv_may_queue(q, op | op_flags); + may_queue = elv_may_queue(q, op, op_flags); if (may_queue == ELV_MQUEUE_NO) goto rq_starved; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 4a349787bc62..3fcc5986c01d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -4285,7 +4285,7 @@ static inline int __cfq_may_queue(struct cfq_queue *cfqq) return ELV_MQUEUE_MAY; } -static int cfq_may_queue(struct request_queue *q, int rw) +static int cfq_may_queue(struct request_queue *q, int op, int op_flags) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; @@ -4302,7 +4302,7 @@ static int cfq_may_queue(struct request_queue *q, int rw) if (!cic) return ELV_MQUEUE_MAY; - cfqq = cic_to_cfqq(cic, rw_is_sync(rw)); + cfqq = cic_to_cfqq(cic, rw_is_sync(op | op_flags)); if (cfqq) { cfq_init_prio_data(cfqq, cic); diff --git a/block/elevator.c b/block/elevator.c index c3555c9c672f..ea9319db50d7 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -366,8 +366,7 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq) list_for_each_prev(entry, &q->queue_head) { struct request *pos = list_entry_rq(entry); - if ((rq->cmd_flags & REQ_DISCARD) != - (pos->cmd_flags & REQ_DISCARD)) + if ((req_op(rq) == REQ_OP_DISCARD) != (req_op(pos) == REQ_OP_DISCARD)) break; if (rq_data_dir(rq) != rq_data_dir(pos)) break; @@ -717,12 +716,12 @@ void elv_put_request(struct request_queue *q, struct request *rq) e->type->ops.elevator_put_req_fn(rq); } -int elv_may_queue(struct request_queue *q, int rw) +int elv_may_queue(struct request_queue *q, int op, int op_flags) { struct elevator_queue *e = q->elevator; if (e->type->ops.elevator_may_queue_fn) - return e->type->ops.elevator_may_queue_fn(q, rw); + return e->type->ops.elevator_may_queue_fn(q, op, op_flags); return ELV_MQUEUE_MAY; } diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 638b324f0291..953d28647435 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -26,7 +26,7 @@ typedef int (elevator_dispatch_fn) (struct request_queue *, int); typedef void (elevator_add_req_fn) (struct request_queue *, struct request *); typedef struct request *(elevator_request_list_fn) (struct request_queue *, struct request *); typedef void (elevator_completed_req_fn) (struct request_queue *, struct request *); -typedef int (elevator_may_queue_fn) (struct request_queue *, int); +typedef int (elevator_may_queue_fn) (struct request_queue *, int, int); typedef void (elevator_init_icq_fn) (struct io_cq *); typedef void (elevator_exit_icq_fn) (struct io_cq *); @@ -134,7 +134,7 @@ extern struct request *elv_former_request(struct request_queue *, struct request extern struct request *elv_latter_request(struct request_queue *, struct request *); extern int elv_register_queue(struct request_queue *q); extern void elv_unregister_queue(struct request_queue *q); -extern int elv_may_queue(struct request_queue *, int); +extern int elv_may_queue(struct request_queue *, int, int); extern void elv_completed_request(struct request_queue *, struct request *); extern int elv_set_request(struct request_queue *q, struct request *rq, struct bio *bio, gfp_t gfp_mask); -- cgit v1.2.3 From 63a4cc24867de73626e16767ce616c50dc5438d3 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:14 -0500 Subject: blkg_rwstat: separate op from flags The bio and request operation and flags are going to be separate definitions, so we cannot pass them in as a bitmap. This patch converts the blkg_rwstat code and its caller, cfq, to pass in the values separately. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 49 +++++++++++++++++++++++++++------------------- include/linux/blk-cgroup.h | 13 ++++++------ 2 files changed, 36 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3fcc5986c01d..3dafdbad8f9c 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -667,9 +667,10 @@ static inline void cfqg_put(struct cfq_group *cfqg) } while (0) static inline void cfqg_stats_update_io_add(struct cfq_group *cfqg, - struct cfq_group *curr_cfqg, int rw) + struct cfq_group *curr_cfqg, int op, + int op_flags) { - blkg_rwstat_add(&cfqg->stats.queued, rw, 1); + blkg_rwstat_add(&cfqg->stats.queued, op, op_flags, 1); cfqg_stats_end_empty_time(&cfqg->stats); cfqg_stats_set_start_group_wait_time(cfqg, curr_cfqg); } @@ -683,26 +684,30 @@ static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg, #endif } -static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int rw) +static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int op, + int op_flags) { - blkg_rwstat_add(&cfqg->stats.queued, rw, -1); + blkg_rwstat_add(&cfqg->stats.queued, op, op_flags, -1); } -static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int rw) +static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int op, + int op_flags) { - blkg_rwstat_add(&cfqg->stats.merged, rw, 1); + blkg_rwstat_add(&cfqg->stats.merged, op, op_flags, 1); } static inline void cfqg_stats_update_completion(struct cfq_group *cfqg, - uint64_t start_time, uint64_t io_start_time, int rw) + uint64_t start_time, uint64_t io_start_time, int op, + int op_flags) { struct cfqg_stats *stats = &cfqg->stats; unsigned long long now = sched_clock(); if (time_after64(now, io_start_time)) - blkg_rwstat_add(&stats->service_time, rw, now - io_start_time); + blkg_rwstat_add(&stats->service_time, op, op_flags, + now - io_start_time); if (time_after64(io_start_time, start_time)) - blkg_rwstat_add(&stats->wait_time, rw, + blkg_rwstat_add(&stats->wait_time, op, op_flags, io_start_time - start_time); } @@ -781,13 +786,16 @@ static inline void cfqg_put(struct cfq_group *cfqg) { } #define cfq_log_cfqg(cfqd, cfqg, fmt, args...) do {} while (0) static inline void cfqg_stats_update_io_add(struct cfq_group *cfqg, - struct cfq_group *curr_cfqg, int rw) { } + struct cfq_group *curr_cfqg, int op, int op_flags) { } static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg, unsigned long time, unsigned long unaccounted_time) { } -static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int rw) { } -static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int rw) { } +static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int op, + int op_flags) { } +static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int op, + int op_flags) { } static inline void cfqg_stats_update_completion(struct cfq_group *cfqg, - uint64_t start_time, uint64_t io_start_time, int rw) { } + uint64_t start_time, uint64_t io_start_time, int op, + int op_flags) { } #endif /* CONFIG_CFQ_GROUP_IOSCHED */ @@ -2461,10 +2469,10 @@ static void cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq) { elv_rb_del(&cfqq->sort_list, rq); cfqq->queued[rq_is_sync(rq)]--; - cfqg_stats_update_io_remove(RQ_CFQG(rq), rq->cmd_flags); + cfqg_stats_update_io_remove(RQ_CFQG(rq), req_op(rq), rq->cmd_flags); cfq_add_rq_rb(rq); cfqg_stats_update_io_add(RQ_CFQG(rq), cfqq->cfqd->serving_group, - rq->cmd_flags); + req_op(rq), rq->cmd_flags); } static struct request * @@ -2517,7 +2525,7 @@ static void cfq_remove_request(struct request *rq) cfq_del_rq_rb(rq); cfqq->cfqd->rq_queued--; - cfqg_stats_update_io_remove(RQ_CFQG(rq), rq->cmd_flags); + cfqg_stats_update_io_remove(RQ_CFQG(rq), req_op(rq), rq->cmd_flags); if (rq->cmd_flags & REQ_PRIO) { WARN_ON(!cfqq->prio_pending); cfqq->prio_pending--; @@ -2552,7 +2560,7 @@ static void cfq_merged_request(struct request_queue *q, struct request *req, static void cfq_bio_merged(struct request_queue *q, struct request *req, struct bio *bio) { - cfqg_stats_update_io_merged(RQ_CFQG(req), bio->bi_rw); + cfqg_stats_update_io_merged(RQ_CFQG(req), bio_op(bio), bio->bi_rw); } static void @@ -2575,7 +2583,7 @@ cfq_merged_requests(struct request_queue *q, struct request *rq, if (cfqq->next_rq == next) cfqq->next_rq = rq; cfq_remove_request(next); - cfqg_stats_update_io_merged(RQ_CFQG(rq), next->cmd_flags); + cfqg_stats_update_io_merged(RQ_CFQG(rq), req_op(next), next->cmd_flags); cfqq = RQ_CFQQ(next); /* @@ -4108,7 +4116,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq) rq->fifo_time = jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)]; list_add_tail(&rq->queuelist, &cfqq->fifo); cfq_add_rq_rb(rq); - cfqg_stats_update_io_add(RQ_CFQG(rq), cfqd->serving_group, + cfqg_stats_update_io_add(RQ_CFQG(rq), cfqd->serving_group, req_op(rq), rq->cmd_flags); cfq_rq_enqueued(cfqd, cfqq, rq); } @@ -4206,7 +4214,8 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) cfqq->dispatched--; (RQ_CFQG(rq))->dispatched--; cfqg_stats_update_completion(cfqq->cfqg, rq_start_time_ns(rq), - rq_io_start_time_ns(rq), rq->cmd_flags); + rq_io_start_time_ns(rq), req_op(rq), + rq->cmd_flags); cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--; diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index 04f9c8d64060..f77150a4a96a 100644 --- a/include/linux/blk-cgroup.h +++ b/include/linux/blk-cgroup.h @@ -590,25 +590,26 @@ static inline void blkg_rwstat_exit(struct blkg_rwstat *rwstat) /** * blkg_rwstat_add - add a value to a blkg_rwstat * @rwstat: target blkg_rwstat - * @rw: mask of REQ_{WRITE|SYNC} + * @op: REQ_OP + * @op_flags: rq_flag_bits * @val: value to add * * Add @val to @rwstat. The counters are chosen according to @rw. The * caller is responsible for synchronizing calls to this function. */ static inline void blkg_rwstat_add(struct blkg_rwstat *rwstat, - int rw, uint64_t val) + int op, int op_flags, uint64_t val) { struct percpu_counter *cnt; - if (op_is_write(rw)) + if (op_is_write(op)) cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_WRITE]; else cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_READ]; __percpu_counter_add(cnt, val, BLKG_STAT_CPU_BATCH); - if (rw & REQ_SYNC) + if (op_flags & REQ_SYNC) cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_SYNC]; else cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_ASYNC]; @@ -713,9 +714,9 @@ static inline bool blkcg_bio_issue_check(struct request_queue *q, if (!throtl) { blkg = blkg ?: q->root_blkg; - blkg_rwstat_add(&blkg->stat_bytes, bio->bi_rw, + blkg_rwstat_add(&blkg->stat_bytes, bio_op(bio), bio->bi_rw, bio->bi_iter.bi_size); - blkg_rwstat_add(&blkg->stat_ios, bio->bi_rw, 1); + blkg_rwstat_add(&blkg->stat_ios, bio_op(bio), bio->bi_rw, 1); } rcu_read_unlock(); -- cgit v1.2.3 From 8fe0d473f5477e9916d3ac581a226acfe83142be Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:15 -0500 Subject: block: convert merge/insert code to check for REQ_OPs. This patch converts the block layer merging code to use separate variables for the operation and flags, and to check req_op for the REQ_OP. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/blk-core.c | 2 +- block/blk-merge.c | 10 ++++++---- include/linux/blkdev.h | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/block/blk-core.c b/block/blk-core.c index 090e55d7cad7..1333bb764b28 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2161,7 +2161,7 @@ EXPORT_SYMBOL(submit_bio); static int blk_cloned_rq_check_limits(struct request_queue *q, struct request *rq) { - if (blk_rq_sectors(rq) > blk_queue_get_max_sectors(q, rq->cmd_flags)) { + if (blk_rq_sectors(rq) > blk_queue_get_max_sectors(q, req_op(rq))) { printk(KERN_ERR "%s: over max size limit.\n", __func__); return -EIO; } diff --git a/block/blk-merge.c b/block/blk-merge.c index 5a03f967557a..c265348b75d1 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -649,7 +649,8 @@ static int attempt_merge(struct request_queue *q, struct request *req, if (!rq_mergeable(req) || !rq_mergeable(next)) return 0; - if (!blk_check_merge_flags(req->cmd_flags, next->cmd_flags)) + if (!blk_check_merge_flags(req->cmd_flags, req_op(req), next->cmd_flags, + req_op(next))) return 0; /* @@ -663,7 +664,7 @@ static int attempt_merge(struct request_queue *q, struct request *req, || req_no_special_merge(next)) return 0; - if (req->cmd_flags & REQ_WRITE_SAME && + if (req_op(req) == REQ_OP_WRITE_SAME && !blk_write_same_mergeable(req->bio, next->bio)) return 0; @@ -751,7 +752,8 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) if (!rq_mergeable(rq) || !bio_mergeable(bio)) return false; - if (!blk_check_merge_flags(rq->cmd_flags, bio->bi_rw)) + if (!blk_check_merge_flags(rq->cmd_flags, req_op(rq), bio->bi_rw, + bio_op(bio))) return false; /* different data direction or already started, don't merge */ @@ -767,7 +769,7 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) return false; /* must be using the same buffer */ - if (rq->cmd_flags & REQ_WRITE_SAME && + if (req_op(rq) == REQ_OP_WRITE_SAME && !blk_write_same_mergeable(rq->bio, bio)) return false; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 8c78aca080af..25f01ff19780 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -666,16 +666,16 @@ static inline bool rq_mergeable(struct request *rq) return true; } -static inline bool blk_check_merge_flags(unsigned int flags1, - unsigned int flags2) +static inline bool blk_check_merge_flags(unsigned int flags1, unsigned int op1, + unsigned int flags2, unsigned int op2) { - if ((flags1 & REQ_DISCARD) != (flags2 & REQ_DISCARD)) + if ((op1 == REQ_OP_DISCARD) != (op2 == REQ_OP_DISCARD)) return false; if ((flags1 & REQ_SECURE) != (flags2 & REQ_SECURE)) return false; - if ((flags1 & REQ_WRITE_SAME) != (flags2 & REQ_WRITE_SAME)) + if ((op1 == REQ_OP_WRITE_SAME) != (op2 == REQ_OP_WRITE_SAME)) return false; return true; @@ -887,12 +887,12 @@ static inline unsigned int blk_rq_cur_sectors(const struct request *rq) } static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q, - unsigned int cmd_flags) + int op) { - if (unlikely(cmd_flags & REQ_DISCARD)) + if (unlikely(op == REQ_OP_DISCARD)) return min(q->limits.max_discard_sectors, UINT_MAX >> 9); - if (unlikely(cmd_flags & REQ_WRITE_SAME)) + if (unlikely(op == REQ_OP_WRITE_SAME)) return q->limits.max_write_same_sectors; return q->limits.max_sectors; @@ -919,11 +919,11 @@ static inline unsigned int blk_rq_get_max_sectors(struct request *rq) if (unlikely(rq->cmd_type != REQ_TYPE_FS)) return q->limits.max_hw_sectors; - if (!q->limits.chunk_sectors || (rq->cmd_flags & REQ_DISCARD)) - return blk_queue_get_max_sectors(q, rq->cmd_flags); + if (!q->limits.chunk_sectors || (req_op(rq) == REQ_OP_DISCARD)) + return blk_queue_get_max_sectors(q, req_op(rq)); return min(blk_max_size_offset(q, blk_rq_pos(rq)), - blk_queue_get_max_sectors(q, rq->cmd_flags)); + blk_queue_get_max_sectors(q, req_op(rq))); } static inline unsigned int blk_rq_count_bios(struct request *rq) -- cgit v1.2.3 From d9d8c5c489f4969667a05727e9c2c4f78cffef1a Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:16 -0500 Subject: block: convert is_sync helpers to use REQ_OPs. This patch converts the is_sync helpers to use separate variables for the operation and flags. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/blk-core.c | 6 +++--- block/blk-mq.c | 8 ++++---- block/cfq-iosched.c | 2 +- include/linux/blkdev.h | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/block/blk-core.c b/block/blk-core.c index 1333bb764b28..f9f422837cea 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -962,7 +962,7 @@ static void __freed_request(struct request_list *rl, int sync) static void freed_request(struct request_list *rl, int op, unsigned int flags) { struct request_queue *q = rl->q; - int sync = rw_is_sync(op | flags); + int sync = rw_is_sync(op, flags); q->nr_rqs[sync]--; rl->count[sync]--; @@ -1075,7 +1075,7 @@ static struct request *__get_request(struct request_list *rl, int op, struct elevator_type *et = q->elevator->type; struct io_context *ioc = rq_ioc(bio); struct io_cq *icq = NULL; - const bool is_sync = rw_is_sync(op | op_flags) != 0; + const bool is_sync = rw_is_sync(op, op_flags) != 0; int may_queue; if (unlikely(blk_queue_dying(q))) @@ -1244,7 +1244,7 @@ static struct request *get_request(struct request_queue *q, int op, int op_flags, struct bio *bio, gfp_t gfp_mask) { - const bool is_sync = rw_is_sync(op | op_flags) != 0; + const bool is_sync = rw_is_sync(op, op_flags) != 0; DEFINE_WAIT(wait); struct request_list *rl; struct request *rq; diff --git a/block/blk-mq.c b/block/blk-mq.c index 3393f29faa9e..29bcd9c07a34 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -204,7 +204,7 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx, rq->end_io_data = NULL; rq->next_rq = NULL; - ctx->rq_dispatched[rw_is_sync(op | op_flags)]++; + ctx->rq_dispatched[rw_is_sync(op, op_flags)]++; } static struct request * @@ -1178,7 +1178,7 @@ static struct request *blk_mq_map_request(struct request_queue *q, ctx = blk_mq_get_ctx(q); hctx = q->mq_ops->map_queue(q, ctx->cpu); - if (rw_is_sync(bio->bi_rw)) + if (rw_is_sync(bio_op(bio), bio->bi_rw)) op_flags |= REQ_SYNC; trace_block_getrq(q, bio, op); @@ -1246,7 +1246,7 @@ static int blk_mq_direct_issue_request(struct request *rq, blk_qc_t *cookie) */ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio) { - const int is_sync = rw_is_sync(bio->bi_rw); + const int is_sync = rw_is_sync(bio_op(bio), bio->bi_rw); const int is_flush_fua = bio->bi_rw & (REQ_FLUSH | REQ_FUA); struct blk_map_ctx data; struct request *rq; @@ -1343,7 +1343,7 @@ done: */ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio) { - const int is_sync = rw_is_sync(bio->bi_rw); + const int is_sync = rw_is_sync(bio_op(bio), bio->bi_rw); const int is_flush_fua = bio->bi_rw & (REQ_FLUSH | REQ_FUA); struct blk_plug *plug; unsigned int request_count = 0; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3dafdbad8f9c..b1154861f4c9 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -4311,7 +4311,7 @@ static int cfq_may_queue(struct request_queue *q, int op, int op_flags) if (!cic) return ELV_MQUEUE_MAY; - cfqq = cic_to_cfqq(cic, rw_is_sync(op | op_flags)); + cfqq = cic_to_cfqq(cic, rw_is_sync(op, op_flags)); if (cfqq) { cfq_init_prio_data(cfqq, cic); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 25f01ff19780..4937c056fcbd 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -624,14 +624,14 @@ static inline unsigned int blk_queue_cluster(struct request_queue *q) /* * We regard a request as sync, if either a read or a sync write */ -static inline bool rw_is_sync(unsigned int rw_flags) +static inline bool rw_is_sync(int op, unsigned int rw_flags) { - return !(rw_flags & REQ_WRITE) || (rw_flags & REQ_SYNC); + return op == REQ_OP_READ || (rw_flags & REQ_SYNC); } static inline bool rq_is_sync(struct request *rq) { - return rw_is_sync(rq->cmd_flags); + return rw_is_sync(req_op(rq), rq->cmd_flags); } static inline bool blk_rl_full(struct request_list *rl, bool sync) -- cgit v1.2.3 From 1b9a9ab78b0ab79dc1f0ddd5fbed7833ec7de3a4 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:18 -0500 Subject: blktrace: use op accessors Have blktrace use the req/bio op accessor to get the REQ_OP. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- include/linux/blktrace_api.h | 2 +- include/trace/events/bcache.h | 12 ++++++--- include/trace/events/block.h | 31 ++++++++++++++-------- kernel/trace/blktrace.c | 62 +++++++++++++++++++++++++------------------ 4 files changed, 65 insertions(+), 42 deletions(-) (limited to 'include/linux') diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h index 0f3172b8b225..cceb72f9e29f 100644 --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -118,7 +118,7 @@ static inline int blk_cmd_buf_len(struct request *rq) } extern void blk_dump_cmd(char *buf, struct request *rq); -extern void blk_fill_rwbs(char *rwbs, u32 rw, int bytes); +extern void blk_fill_rwbs(char *rwbs, int op, u32 rw, int bytes); #endif /* CONFIG_EVENT_TRACING && CONFIG_BLOCK */ diff --git a/include/trace/events/bcache.h b/include/trace/events/bcache.h index 981acf74b14f..65673d8b81ac 100644 --- a/include/trace/events/bcache.h +++ b/include/trace/events/bcache.h @@ -27,7 +27,8 @@ DECLARE_EVENT_CLASS(bcache_request, __entry->sector = bio->bi_iter.bi_sector; __entry->orig_sector = bio->bi_iter.bi_sector - 16; __entry->nr_sector = bio->bi_iter.bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u (from %d,%d @ %llu)", @@ -101,7 +102,8 @@ DECLARE_EVENT_CLASS(bcache_bio, __entry->dev = bio->bi_bdev->bd_dev; __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio->bi_iter.bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u", @@ -136,7 +138,8 @@ TRACE_EVENT(bcache_read, __entry->dev = bio->bi_bdev->bd_dev; __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio->bi_iter.bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); __entry->cache_hit = hit; __entry->bypass = bypass; ), @@ -167,7 +170,8 @@ TRACE_EVENT(bcache_write, __entry->inode = inode; __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio->bi_iter.bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); __entry->writeback = writeback; __entry->bypass = bypass; ), diff --git a/include/trace/events/block.h b/include/trace/events/block.h index e8a5eca1dbe5..5a2a7592068f 100644 --- a/include/trace/events/block.h +++ b/include/trace/events/block.h @@ -84,7 +84,8 @@ DECLARE_EVENT_CLASS(block_rq_with_error, 0 : blk_rq_sectors(rq); __entry->errors = rq->errors; - blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq)); + blk_fill_rwbs(__entry->rwbs, req_op(rq), rq->cmd_flags, + blk_rq_bytes(rq)); blk_dump_cmd(__get_str(cmd), rq); ), @@ -162,7 +163,7 @@ TRACE_EVENT(block_rq_complete, __entry->nr_sector = nr_bytes >> 9; __entry->errors = rq->errors; - blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, nr_bytes); + blk_fill_rwbs(__entry->rwbs, req_op(rq), rq->cmd_flags, nr_bytes); blk_dump_cmd(__get_str(cmd), rq); ), @@ -198,7 +199,8 @@ DECLARE_EVENT_CLASS(block_rq, __entry->bytes = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ? blk_rq_bytes(rq) : 0; - blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq)); + blk_fill_rwbs(__entry->rwbs, req_op(rq), rq->cmd_flags, + blk_rq_bytes(rq)); blk_dump_cmd(__get_str(cmd), rq); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -272,7 +274,8 @@ TRACE_EVENT(block_bio_bounce, bio->bi_bdev->bd_dev : 0; __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -310,7 +313,8 @@ TRACE_EVENT(block_bio_complete, __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); __entry->error = error; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u [%d]", @@ -337,7 +341,8 @@ DECLARE_EVENT_CLASS(block_bio_merge, __entry->dev = bio->bi_bdev->bd_dev; __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -404,7 +409,8 @@ TRACE_EVENT(block_bio_queue, __entry->dev = bio->bi_bdev->bd_dev; __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -432,7 +438,7 @@ DECLARE_EVENT_CLASS(block_get_rq, __entry->dev = bio ? bio->bi_bdev->bd_dev : 0; __entry->sector = bio ? bio->bi_iter.bi_sector : 0; __entry->nr_sector = bio ? bio_sectors(bio) : 0; - blk_fill_rwbs(__entry->rwbs, + blk_fill_rwbs(__entry->rwbs, bio ? bio_op(bio) : 0, bio ? bio->bi_rw : 0, __entry->nr_sector); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -567,7 +573,8 @@ TRACE_EVENT(block_split, __entry->dev = bio->bi_bdev->bd_dev; __entry->sector = bio->bi_iter.bi_sector; __entry->new_sector = new_sector; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -610,7 +617,8 @@ TRACE_EVENT(block_bio_remap, __entry->nr_sector = bio_sectors(bio); __entry->old_dev = dev; __entry->old_sector = from; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); + blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_rw, + bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu", @@ -656,7 +664,8 @@ TRACE_EVENT(block_rq_remap, __entry->old_dev = dev; __entry->old_sector = from; __entry->nr_bios = blk_rq_count_bios(rq); - blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq)); + blk_fill_rwbs(__entry->rwbs, req_op(rq), rq->cmd_flags, + blk_rq_bytes(rq)); ), TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu %u", diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 9aef8654e90d..2d16fad519b2 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -199,7 +199,8 @@ static const u32 ddir_act[2] = { BLK_TC_ACT(BLK_TC_READ), * blk_io_trace structure and places it in a per-cpu subbuffer. */ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, - int rw, u32 what, int error, int pdu_len, void *pdu_data) + int op, int op_flags, u32 what, int error, int pdu_len, + void *pdu_data) { struct task_struct *tsk = current; struct ring_buffer_event *event = NULL; @@ -214,13 +215,14 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, if (unlikely(bt->trace_state != Blktrace_running && !blk_tracer)) return; - what |= ddir_act[rw & WRITE]; - what |= MASK_TC_BIT(rw, SYNC); - what |= MASK_TC_BIT(rw, RAHEAD); - what |= MASK_TC_BIT(rw, META); - what |= MASK_TC_BIT(rw, DISCARD); - what |= MASK_TC_BIT(rw, FLUSH); - what |= MASK_TC_BIT(rw, FUA); + what |= ddir_act[op_is_write(op) ? WRITE : READ]; + what |= MASK_TC_BIT(op_flags, SYNC); + what |= MASK_TC_BIT(op_flags, RAHEAD); + what |= MASK_TC_BIT(op_flags, META); + what |= MASK_TC_BIT(op_flags, FLUSH); + what |= MASK_TC_BIT(op_flags, FUA); + if (op == REQ_OP_DISCARD) + what |= BLK_TC_ACT(BLK_TC_DISCARD); pid = tsk->pid; if (act_log_check(bt, what, sector, pid)) @@ -708,11 +710,11 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq, if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { what |= BLK_TC_ACT(BLK_TC_PC); - __blk_add_trace(bt, 0, nr_bytes, rq->cmd_flags, + __blk_add_trace(bt, 0, nr_bytes, req_op(rq), rq->cmd_flags, what, rq->errors, rq->cmd_len, rq->cmd); } else { what |= BLK_TC_ACT(BLK_TC_FS); - __blk_add_trace(bt, blk_rq_pos(rq), nr_bytes, + __blk_add_trace(bt, blk_rq_pos(rq), nr_bytes, req_op(rq), rq->cmd_flags, what, rq->errors, 0, NULL); } } @@ -770,7 +772,7 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, return; __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, - bio->bi_rw, what, error, 0, NULL); + bio_op(bio), bio->bi_rw, what, error, 0, NULL); } static void blk_add_trace_bio_bounce(void *ignore, @@ -818,7 +820,8 @@ static void blk_add_trace_getrq(void *ignore, struct blk_trace *bt = q->blk_trace; if (bt) - __blk_add_trace(bt, 0, 0, rw, BLK_TA_GETRQ, 0, 0, NULL); + __blk_add_trace(bt, 0, 0, rw, 0, BLK_TA_GETRQ, 0, 0, + NULL); } } @@ -833,7 +836,7 @@ static void blk_add_trace_sleeprq(void *ignore, struct blk_trace *bt = q->blk_trace; if (bt) - __blk_add_trace(bt, 0, 0, rw, BLK_TA_SLEEPRQ, + __blk_add_trace(bt, 0, 0, rw, 0, BLK_TA_SLEEPRQ, 0, 0, NULL); } } @@ -843,7 +846,7 @@ static void blk_add_trace_plug(void *ignore, struct request_queue *q) struct blk_trace *bt = q->blk_trace; if (bt) - __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL); + __blk_add_trace(bt, 0, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL); } static void blk_add_trace_unplug(void *ignore, struct request_queue *q, @@ -860,7 +863,7 @@ static void blk_add_trace_unplug(void *ignore, struct request_queue *q, else what = BLK_TA_UNPLUG_TIMER; - __blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu); + __blk_add_trace(bt, 0, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu); } } @@ -874,8 +877,9 @@ static void blk_add_trace_split(void *ignore, __be64 rpdu = cpu_to_be64(pdu); __blk_add_trace(bt, bio->bi_iter.bi_sector, - bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT, - bio->bi_error, sizeof(rpdu), &rpdu); + bio->bi_iter.bi_size, bio_op(bio), bio->bi_rw, + BLK_TA_SPLIT, bio->bi_error, sizeof(rpdu), + &rpdu); } } @@ -907,7 +911,7 @@ static void blk_add_trace_bio_remap(void *ignore, r.sector_from = cpu_to_be64(from); __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, - bio->bi_rw, BLK_TA_REMAP, bio->bi_error, + bio_op(bio), bio->bi_rw, BLK_TA_REMAP, bio->bi_error, sizeof(r), &r); } @@ -940,7 +944,7 @@ static void blk_add_trace_rq_remap(void *ignore, r.sector_from = cpu_to_be64(from); __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), - rq_data_dir(rq), BLK_TA_REMAP, !!rq->errors, + rq_data_dir(rq), 0, BLK_TA_REMAP, !!rq->errors, sizeof(r), &r); } @@ -965,10 +969,10 @@ void blk_add_driver_data(struct request_queue *q, return; if (rq->cmd_type == REQ_TYPE_BLOCK_PC) - __blk_add_trace(bt, 0, blk_rq_bytes(rq), 0, + __blk_add_trace(bt, 0, blk_rq_bytes(rq), 0, 0, BLK_TA_DRV_DATA, rq->errors, len, data); else - __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0, + __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0, 0, BLK_TA_DRV_DATA, rq->errors, len, data); } EXPORT_SYMBOL_GPL(blk_add_driver_data); @@ -1769,21 +1773,27 @@ void blk_dump_cmd(char *buf, struct request *rq) } } -void blk_fill_rwbs(char *rwbs, u32 rw, int bytes) +void blk_fill_rwbs(char *rwbs, int op, u32 rw, int bytes) { int i = 0; if (rw & REQ_FLUSH) rwbs[i++] = 'F'; - if (rw & WRITE) + switch (op) { + case REQ_OP_WRITE: + case REQ_OP_WRITE_SAME: rwbs[i++] = 'W'; - else if (rw & REQ_DISCARD) + break; + case REQ_OP_DISCARD: rwbs[i++] = 'D'; - else if (bytes) + break; + case REQ_OP_READ: rwbs[i++] = 'R'; - else + break; + default: rwbs[i++] = 'N'; + } if (rw & REQ_FUA) rwbs[i++] = 'F'; -- cgit v1.2.3 From 43b62ce3ff0ac1f13b732cb1bd130f522af1dba4 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:20 -0500 Subject: block: move bio io prio to a new field In the next patch, we move drop the compat code and make the op a separate value that is hidden in bi_rw. To give the op and rq bits flags room to grow this moves prio to its own field. Signed-off-by: Mike Christie Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- include/linux/bio.h | 14 ++------------ include/linux/blk_types.h | 5 ++--- 2 files changed, 4 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bio.h b/include/linux/bio.h index 4568647269a7..35108c2f8ea9 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -47,18 +47,8 @@ #define bio_op(bio) (op_from_rq_bits((bio)->bi_rw)) #define bio_set_op_attrs(bio, op, flags) ((bio)->bi_rw |= (op | flags)) -/* - * upper 16 bits of bi_rw define the io priority of this bio - */ -#define BIO_PRIO_SHIFT (8 * sizeof(unsigned long) - IOPRIO_BITS) -#define bio_prio(bio) ((bio)->bi_rw >> BIO_PRIO_SHIFT) -#define bio_prio_valid(bio) ioprio_valid(bio_prio(bio)) - -#define bio_set_prio(bio, prio) do { \ - WARN_ON(prio >= (1 << IOPRIO_BITS)); \ - (bio)->bi_rw &= ((1UL << BIO_PRIO_SHIFT) - 1); \ - (bio)->bi_rw |= ((unsigned long) (prio) << BIO_PRIO_SHIFT); \ -} while (0) +#define bio_prio(bio) (bio)->bi_ioprio +#define bio_set_prio(bio, prio) ((bio)->bi_ioprio = prio) /* * various member access, note that bio_data should of course not be used diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 6e60baa583da..27384134f8a0 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -48,9 +48,8 @@ struct bio { struct block_device *bi_bdev; unsigned int bi_flags; /* status, command, etc */ int bi_error; - unsigned long bi_rw; /* bottom bits READ/WRITE, - * top bits priority - */ + unsigned long bi_rw; /* READ/WRITE */ + unsigned short bi_ioprio; struct bvec_iter bi_iter; -- cgit v1.2.3 From 6296b9604fcebc2dd8d6ec396de80b2da84d9700 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:21 -0500 Subject: block, drivers, fs: shrink bi_rw from long to int We don't need bi_rw to be so large on 64 bit archs, so reduce it to unsigned int. Signed-off-by: Mike Christie Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- block/blk-core.c | 2 +- drivers/md/dm-flakey.c | 2 +- drivers/md/raid5.c | 6 +++--- fs/btrfs/check-integrity.c | 4 ++-- fs/btrfs/inode.c | 2 +- include/linux/blk_types.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/block/blk-core.c b/block/blk-core.c index f9f422837cea..c7d66c23a708 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1853,7 +1853,7 @@ static void handle_bad_sector(struct bio *bio) char b[BDEVNAME_SIZE]; printk(KERN_INFO "attempt to access beyond end of device\n"); - printk(KERN_INFO "%s: rw=%ld, want=%Lu, limit=%Lu\n", + printk(KERN_INFO "%s: rw=%d, want=%Lu, limit=%Lu\n", bdevname(bio->bi_bdev, b), bio->bi_rw, (unsigned long long)bio_end_sector(bio), diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index b7341de87015..29b99fb6a16a 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -266,7 +266,7 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) data[fc->corrupt_bio_byte - 1] = fc->corrupt_bio_value; DMDEBUG("Corrupting data bio=%p by writing %u to byte %u " - "(rw=%c bi_rw=%lu bi_sector=%llu cur_bytes=%u)\n", + "(rw=%c bi_rw=%u bi_sector=%llu cur_bytes=%u)\n", bio, fc->corrupt_bio_value, fc->corrupt_bio_byte, (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_rw, (unsigned long long)bio->bi_iter.bi_sector, bio_bytes); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e35c163fb429..b9122e2c6aa1 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1001,7 +1001,7 @@ again: : raid5_end_read_request; bi->bi_private = sh; - pr_debug("%s: for %llu schedule op %ld on disc %d\n", + pr_debug("%s: for %llu schedule op %d on disc %d\n", __func__, (unsigned long long)sh->sector, bi->bi_rw, i); atomic_inc(&sh->count); @@ -1052,7 +1052,7 @@ again: rbi->bi_end_io = raid5_end_write_request; rbi->bi_private = sh; - pr_debug("%s: for %llu schedule op %ld on " + pr_debug("%s: for %llu schedule op %d on " "replacement disc %d\n", __func__, (unsigned long long)sh->sector, rbi->bi_rw, i); @@ -1087,7 +1087,7 @@ again: if (!rdev && !rrdev) { if (op_is_write(op)) set_bit(STRIPE_DEGRADED, &sh->state); - pr_debug("skip op %ld on disc %d for sector %llu\n", + pr_debug("skip op %d on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector); clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 80a43893f492..da944ffddbaf 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -2943,7 +2943,7 @@ static void __btrfsic_submit_bio(struct bio *bio) if (dev_state->state->print_mask & BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) printk(KERN_INFO - "submit_bio(rw=%d,0x%lx, bi_vcnt=%u," + "submit_bio(rw=%d,0x%x, bi_vcnt=%u," " bi_sector=%llu (bytenr %llu), bi_bdev=%p)\n", bio_op(bio), bio->bi_rw, bio->bi_vcnt, (unsigned long long)bio->bi_iter.bi_sector, @@ -2986,7 +2986,7 @@ static void __btrfsic_submit_bio(struct bio *bio) if (dev_state->state->print_mask & BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) printk(KERN_INFO - "submit_bio(rw=%d,0x%lx FLUSH, bdev=%p)\n", + "submit_bio(rw=%d,0x%x FLUSH, bdev=%p)\n", bio_op(bio), bio->bi_rw, bio->bi_bdev); if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) { if ((dev_state->state->print_mask & diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ec61db64c4c9..1323e4faa44c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8184,7 +8184,7 @@ static void btrfs_end_dio_bio(struct bio *bio) if (err) btrfs_warn(BTRFS_I(dip->inode)->root->fs_info, - "direct IO failed ino %llu rw %d,%lu sector %#Lx len %u err no %d", + "direct IO failed ino %llu rw %d,%u sector %#Lx len %u err no %d", btrfs_ino(dip->inode), bio_op(bio), bio->bi_rw, (unsigned long long)bio->bi_iter.bi_sector, bio->bi_iter.bi_size, err); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 27384134f8a0..5efb6f12d2f5 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -48,7 +48,7 @@ struct bio { struct block_device *bi_bdev; unsigned int bi_flags; /* status, command, etc */ int bi_error; - unsigned long bi_rw; /* READ/WRITE */ + unsigned int bi_rw; /* READ/WRITE */ unsigned short bi_ioprio; struct bvec_iter bi_iter; -- cgit v1.2.3 From 4e1b2d52a80d79296a5d899d73249748dea71a53 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:22 -0500 Subject: block, fs, drivers: remove REQ_OP compat defs and related code This patch drops the compat definition of req_op where it matches the rq_flag_bits definitions, and drops the related old and compat code that allowed users to set either the op or flags for the operation. We also then store the operation in the bi_rw/cmd_flags field similar to how we used to store the bio ioprio where it sat in the upper bits of the field. Signed-off-by: Mike Christie Signed-off-by: Jens Axboe --- drivers/scsi/sd.c | 2 +- include/linux/bio.h | 3 --- include/linux/blk_types.h | 52 +++++++++++++++++---------------------------- include/linux/blkdev.h | 14 ++++++++---- include/linux/fs.h | 37 +++++++++++++------------------- include/trace/events/f2fs.h | 1 - 6 files changed, 46 insertions(+), 63 deletions(-) (limited to 'include/linux') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c8dc2217d386..fad86ad89e64 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1012,7 +1012,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt) } else if (rq_data_dir(rq) == READ) { SCpnt->cmnd[0] = READ_6; } else { - scmd_printk(KERN_ERR, SCpnt, "Unknown command %d,%llx\n", + scmd_printk(KERN_ERR, SCpnt, "Unknown command %llu,%llx\n", req_op(rq), (unsigned long long) rq->cmd_flags); goto out; } diff --git a/include/linux/bio.h b/include/linux/bio.h index 35108c2f8ea9..0bbb2e332410 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -44,9 +44,6 @@ #define BIO_MAX_SIZE (BIO_MAX_PAGES << PAGE_SHIFT) #define BIO_MAX_SECTORS (BIO_MAX_SIZE >> 9) -#define bio_op(bio) (op_from_rq_bits((bio)->bi_rw)) -#define bio_set_op_attrs(bio, op, flags) ((bio)->bi_rw |= (op | flags)) - #define bio_prio(bio) (bio)->bi_ioprio #define bio_set_prio(bio, prio) ((bio)->bi_ioprio = prio) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 5efb6f12d2f5..23c1ab2a9475 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -48,7 +48,9 @@ struct bio { struct block_device *bi_bdev; unsigned int bi_flags; /* status, command, etc */ int bi_error; - unsigned int bi_rw; /* READ/WRITE */ + unsigned int bi_rw; /* bottom bits req flags, + * top bits REQ_OP + */ unsigned short bi_ioprio; struct bvec_iter bi_iter; @@ -106,6 +108,16 @@ struct bio { struct bio_vec bi_inline_vecs[0]; }; +#define BIO_OP_SHIFT (8 * sizeof(unsigned int) - REQ_OP_BITS) +#define bio_op(bio) ((bio)->bi_rw >> BIO_OP_SHIFT) + +#define bio_set_op_attrs(bio, op, op_flags) do { \ + WARN_ON(op >= (1 << REQ_OP_BITS)); \ + (bio)->bi_rw &= ((1 << BIO_OP_SHIFT) - 1); \ + (bio)->bi_rw |= ((unsigned int) (op) << BIO_OP_SHIFT); \ + (bio)->bi_rw |= op_flags; \ +} while (0) + #define BIO_RESET_BYTES offsetof(struct bio, bi_max_vecs) /* @@ -144,7 +156,6 @@ struct bio { */ enum rq_flag_bits { /* common flags */ - __REQ_WRITE, /* not set, read. set, write */ __REQ_FAILFAST_DEV, /* no driver retries of device errors */ __REQ_FAILFAST_TRANSPORT, /* no driver retries of transport errors */ __REQ_FAILFAST_DRIVER, /* no driver retries of driver errors */ @@ -152,9 +163,7 @@ enum rq_flag_bits { __REQ_SYNC, /* request is sync (sync write or read) */ __REQ_META, /* metadata io request */ __REQ_PRIO, /* boost priority in cfq */ - __REQ_DISCARD, /* request to discard sectors */ - __REQ_SECURE, /* secure discard (used with __REQ_DISCARD) */ - __REQ_WRITE_SAME, /* write same block many times */ + __REQ_SECURE, /* secure discard (used with REQ_OP_DISCARD) */ __REQ_NOIDLE, /* don't anticipate more IO after this one */ __REQ_INTEGRITY, /* I/O includes block integrity payload */ @@ -190,28 +199,22 @@ enum rq_flag_bits { __REQ_NR_BITS, /* stops here */ }; -#define REQ_WRITE (1ULL << __REQ_WRITE) #define REQ_FAILFAST_DEV (1ULL << __REQ_FAILFAST_DEV) #define REQ_FAILFAST_TRANSPORT (1ULL << __REQ_FAILFAST_TRANSPORT) #define REQ_FAILFAST_DRIVER (1ULL << __REQ_FAILFAST_DRIVER) #define REQ_SYNC (1ULL << __REQ_SYNC) #define REQ_META (1ULL << __REQ_META) #define REQ_PRIO (1ULL << __REQ_PRIO) -#define REQ_DISCARD (1ULL << __REQ_DISCARD) -#define REQ_WRITE_SAME (1ULL << __REQ_WRITE_SAME) #define REQ_NOIDLE (1ULL << __REQ_NOIDLE) #define REQ_INTEGRITY (1ULL << __REQ_INTEGRITY) #define REQ_FAILFAST_MASK \ (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER) #define REQ_COMMON_MASK \ - (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | \ - REQ_DISCARD | REQ_WRITE_SAME | REQ_NOIDLE | REQ_FLUSH | REQ_FUA | \ - REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE) + (REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | REQ_NOIDLE | \ + REQ_FLUSH | REQ_FUA | REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE) #define REQ_CLONE_MASK REQ_COMMON_MASK -#define BIO_NO_ADVANCE_ITER_MASK (REQ_DISCARD|REQ_WRITE_SAME) - /* This mask is used for both bio and request merge checking */ #define REQ_NOMERGE_FLAGS \ (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ) @@ -243,27 +246,12 @@ enum rq_flag_bits { enum req_op { REQ_OP_READ, - REQ_OP_WRITE = REQ_WRITE, - REQ_OP_DISCARD = REQ_DISCARD, - REQ_OP_WRITE_SAME = REQ_WRITE_SAME, + REQ_OP_WRITE, + REQ_OP_DISCARD, /* request to discard sectors */ + REQ_OP_WRITE_SAME, /* write same block many times */ }; -/* - * tmp cpmpat. Users used to set the write bit for all non reads, but - * we will be dropping the bitmap use for ops. Support both until - * the end of the patchset. - */ -static inline int op_from_rq_bits(u64 flags) -{ - if (flags & REQ_OP_DISCARD) - return REQ_OP_DISCARD; - else if (flags & REQ_OP_WRITE_SAME) - return REQ_OP_WRITE_SAME; - else if (flags & REQ_OP_WRITE) - return REQ_OP_WRITE; - else - return REQ_OP_READ; -} +#define REQ_OP_BITS 2 typedef unsigned int blk_qc_t; #define BLK_QC_T_NONE -1U diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 4937c056fcbd..78ae3dbf2de1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -200,8 +200,15 @@ struct request { struct request *next_rq; }; -#define req_op(req) (op_from_rq_bits((req)->cmd_flags)) -#define req_set_op(req, op) ((req)->cmd_flags |= op) +#define REQ_OP_SHIFT (8 * sizeof(u64) - REQ_OP_BITS) +#define req_op(req) ((req)->cmd_flags >> REQ_OP_SHIFT) + +#define req_set_op(req, op) do { \ + WARN_ON(op >= (1 << REQ_OP_BITS)); \ + (req)->cmd_flags &= ((1ULL << REQ_OP_SHIFT) - 1); \ + (req)->cmd_flags |= ((u64) (op) << REQ_OP_SHIFT); \ +} while (0) + #define req_set_op_attrs(req, op, flags) do { \ req_set_op(req, op); \ (req)->cmd_flags |= flags; \ @@ -604,8 +611,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) -#define rq_data_dir(rq) \ - (op_is_write(op_from_rq_bits(rq->cmd_flags)) ? WRITE : READ) +#define rq_data_dir(rq) (op_is_write(req_op(rq)) ? WRITE : READ) /* * Driver can handle struct request, if it either has an old style diff --git a/include/linux/fs.h b/include/linux/fs.h index af6f3c7e4822..ccd166477487 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -152,9 +152,10 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define CHECK_IOVEC_ONLY -1 /* - * The below are the various read and write types that we support. Some of + * The below are the various read and write flags that we support. Some of * them include behavioral modifiers that send information down to the - * block layer and IO scheduler. Terminology: + * block layer and IO scheduler. They should be used along with a req_op. + * Terminology: * * The block layer uses device plugging to defer IO a little bit, in * the hope that we will see more IO very shortly. This increases @@ -193,19 +194,19 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, * non-volatile media on completion. * */ -#define RW_MASK REQ_WRITE +#define RW_MASK REQ_OP_WRITE #define RWA_MASK REQ_RAHEAD -#define READ 0 +#define READ REQ_OP_READ #define WRITE RW_MASK #define READA RWA_MASK -#define READ_SYNC (READ | REQ_SYNC) -#define WRITE_SYNC (WRITE | REQ_SYNC | REQ_NOIDLE) -#define WRITE_ODIRECT (WRITE | REQ_SYNC) -#define WRITE_FLUSH (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH) -#define WRITE_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FUA) -#define WRITE_FLUSH_FUA (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_FLUSH | REQ_FUA) +#define READ_SYNC REQ_SYNC +#define WRITE_SYNC (REQ_SYNC | REQ_NOIDLE) +#define WRITE_ODIRECT REQ_SYNC +#define WRITE_FLUSH (REQ_SYNC | REQ_NOIDLE | REQ_FLUSH) +#define WRITE_FUA (REQ_SYNC | REQ_NOIDLE | REQ_FUA) +#define WRITE_FLUSH_FUA (REQ_SYNC | REQ_NOIDLE | REQ_FLUSH | REQ_FUA) /* * Attribute flags. These should be or-ed together to figure out what @@ -2464,17 +2465,9 @@ extern void make_bad_inode(struct inode *); extern bool is_bad_inode(struct inode *); #ifdef CONFIG_BLOCK -/* - * tmp cpmpat. Users used to set the write bit for all non reads, but - * we will be dropping the bitmap use for ops. Support both until - * the end of the patchset. - */ -static inline bool op_is_write(unsigned long flags) +static inline bool op_is_write(unsigned int op) { - if (flags & (REQ_OP_WRITE | REQ_OP_WRITE_SAME | REQ_OP_DISCARD)) - return true; - else - return false; + return op == REQ_OP_READ ? false : true; } /* @@ -2482,7 +2475,7 @@ static inline bool op_is_write(unsigned long flags) */ static inline int bio_rw(struct bio *bio) { - if (op_is_write(op_from_rq_bits(bio->bi_rw))) + if (op_is_write(bio_op(bio))) return WRITE; return bio->bi_rw & RWA_MASK; @@ -2493,7 +2486,7 @@ static inline int bio_rw(struct bio *bio) */ static inline int bio_data_dir(struct bio *bio) { - return op_is_write(op_from_rq_bits(bio->bi_rw)) ? WRITE : READ; + return op_is_write(bio_op(bio)) ? WRITE : READ; } extern void check_disk_size_change(struct gendisk *disk, diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 733b896fd44f..30efa44a473c 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -31,7 +31,6 @@ TRACE_DEFINE_ENUM(BG_GC); TRACE_DEFINE_ENUM(LFS); TRACE_DEFINE_ENUM(SSR); TRACE_DEFINE_ENUM(__REQ_RAHEAD); -TRACE_DEFINE_ENUM(__REQ_WRITE); TRACE_DEFINE_ENUM(__REQ_SYNC); TRACE_DEFINE_ENUM(__REQ_NOIDLE); TRACE_DEFINE_ENUM(__REQ_FLUSH); -- cgit v1.2.3 From 3a5e02ced11e22ecd9da3d6710afe15bcfee1d10 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:23 -0500 Subject: block, drivers: add REQ_OP_FLUSH operation This adds a REQ_OP_FLUSH operation that is sent to request_fn based drivers by the block layer's flush code, instead of sending requests with the request->cmd_flags REQ_FLUSH bit set. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- Documentation/block/writeback_cache_control.txt | 6 +++--- arch/um/drivers/ubd_kern.c | 2 +- block/blk-flush.c | 4 ++-- drivers/block/loop.c | 4 ++-- drivers/block/nbd.c | 2 +- drivers/block/osdblk.c | 2 +- drivers/block/ps3disk.c | 4 ++-- drivers/block/skd_main.c | 2 +- drivers/block/virtio_blk.c | 2 +- drivers/block/xen-blkfront.c | 8 ++++---- drivers/ide/ide-disk.c | 2 +- drivers/md/dm.c | 2 +- drivers/mmc/card/block.c | 6 +++--- drivers/mmc/card/queue.h | 3 ++- drivers/mtd/mtd_blkdevs.c | 2 +- drivers/nvme/host/core.c | 2 +- drivers/scsi/sd.c | 7 +++---- include/linux/blk_types.h | 3 ++- include/linux/blkdev.h | 3 +++ kernel/trace/blktrace.c | 5 +++++ 20 files changed, 40 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/Documentation/block/writeback_cache_control.txt b/Documentation/block/writeback_cache_control.txt index 59e0516cbf6b..da70bdacd503 100644 --- a/Documentation/block/writeback_cache_control.txt +++ b/Documentation/block/writeback_cache_control.txt @@ -73,9 +73,9 @@ doing: blk_queue_write_cache(sdkp->disk->queue, true, false); -and handle empty REQ_FLUSH requests in its prep_fn/request_fn. Note that +and handle empty REQ_OP_FLUSH requests in its prep_fn/request_fn. Note that REQ_FLUSH requests with a payload are automatically turned into a sequence -of an empty REQ_FLUSH request followed by the actual write by the block +of an empty REQ_OP_FLUSH request followed by the actual write by the block layer. For devices that also support the FUA bit the block layer needs to be told to pass through the REQ_FUA bit using: @@ -83,4 +83,4 @@ to be told to pass through the REQ_FUA bit using: and the driver must handle write requests that have the REQ_FUA bit set in prep_fn/request_fn. If the FUA bit is not natively supported the block -layer turns it into an empty REQ_FLUSH request after the actual write. +layer turns it into an empty REQ_OP_FLUSH request after the actual write. diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 17e96dc29596..ef6b4d960bad 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1286,7 +1286,7 @@ static void do_ubd_request(struct request_queue *q) req = dev->request; - if (req->cmd_flags & REQ_FLUSH) { + if (req_op(req) == REQ_OP_FLUSH) { io_req = kmalloc(sizeof(struct io_thread_req), GFP_ATOMIC); if (io_req == NULL) { diff --git a/block/blk-flush.c b/block/blk-flush.c index 9fd1f63a6348..21f0d5b0d2ca 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -29,7 +29,7 @@ * The actual execution of flush is double buffered. Whenever a request * needs to execute PRE or POSTFLUSH, it queues at * fq->flush_queue[fq->flush_pending_idx]. Once certain criteria are met, a - * flush is issued and the pending_idx is toggled. When the flush + * REQ_OP_FLUSH is issued and the pending_idx is toggled. When the flush * completes, all the requests which were pending are proceeded to the next * step. This allows arbitrary merging of different types of FLUSH/FUA * requests. @@ -330,7 +330,7 @@ static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq) } flush_rq->cmd_type = REQ_TYPE_FS; - flush_rq->cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ; + req_set_op_attrs(flush_rq, REQ_OP_FLUSH, WRITE_FLUSH | REQ_FLUSH_SEQ); flush_rq->rq_disk = first_rq->rq_disk; flush_rq->end_io = flush_end_io; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b9b737cafd5f..364d491d4bdd 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -542,7 +542,7 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq) pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset; if (op_is_write(req_op(rq))) { - if (rq->cmd_flags & REQ_FLUSH) + if (req_op(rq) == REQ_OP_FLUSH) ret = lo_req_flush(lo, rq); else if (req_op(rq) == REQ_OP_DISCARD) ret = lo_discard(lo, rq, pos); @@ -1659,7 +1659,7 @@ static int loop_queue_rq(struct blk_mq_hw_ctx *hctx, if (lo->lo_state != Lo_bound) return -EIO; - if (lo->use_dio && (!(cmd->rq->cmd_flags & REQ_FLUSH) || + if (lo->use_dio && (req_op(cmd->rq) != REQ_OP_FLUSH || req_op(cmd->rq) == REQ_OP_DISCARD)) cmd->use_aio = true; else diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 6c2c28d124d0..d6f3c9336f29 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -284,7 +284,7 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req) type = NBD_CMD_DISC; else if (req_op(req) == REQ_OP_DISCARD) type = NBD_CMD_TRIM; - else if (req->cmd_flags & REQ_FLUSH) + else if (req_op(req) == REQ_OP_FLUSH) type = NBD_CMD_FLUSH; else if (rq_data_dir(req) == WRITE) type = NBD_CMD_WRITE; diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c index c2854a2bfdb0..92900f5f0b47 100644 --- a/drivers/block/osdblk.c +++ b/drivers/block/osdblk.c @@ -321,7 +321,7 @@ static void osdblk_rq_fn(struct request_queue *q) * driver-specific, etc. */ - do_flush = rq->cmd_flags & REQ_FLUSH; + do_flush = (req_op(rq) == REQ_OP_FLUSH); do_write = (rq_data_dir(rq) == WRITE); if (!do_flush) { /* osd_flush does not use a bio */ diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 4b7e405830d7..acb44529c05e 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -196,7 +196,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); while ((req = blk_fetch_request(q))) { - if (req->cmd_flags & REQ_FLUSH) { + if (req_op(req) == REQ_OP_FLUSH) { if (ps3disk_submit_flush_request(dev, req)) break; } else if (req->cmd_type == REQ_TYPE_FS) { @@ -256,7 +256,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) return IRQ_HANDLED; } - if (req->cmd_flags & REQ_FLUSH) { + if (req_op(req) == REQ_OP_FLUSH) { read = 0; op = "flush"; } else { diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 910e065918af..5c07a23e2ada 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -597,7 +597,7 @@ static void skd_request_fn(struct request_queue *q) data_dir = rq_data_dir(req); io_flags = req->cmd_flags; - if (io_flags & REQ_FLUSH) + if (req_op(req) == REQ_OP_FLUSH) flush++; if (io_flags & REQ_FUA) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 42758b52768c..18e4069dd24b 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -172,7 +172,7 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); vbr->req = req; - if (req->cmd_flags & REQ_FLUSH) { + if (req_op(req) == REQ_OP_FLUSH) { vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_FLUSH); vbr->out_hdr.sector = 0; vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 6fd160197b7a..3aeb25bd5057 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -743,7 +743,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri * The indirect operation can only be a BLKIF_OP_READ or * BLKIF_OP_WRITE */ - BUG_ON(req->cmd_flags & (REQ_FLUSH | REQ_FUA)); + BUG_ON(req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA); ring_req->operation = BLKIF_OP_INDIRECT; ring_req->u.indirect.indirect_op = rq_data_dir(req) ? BLKIF_OP_WRITE : BLKIF_OP_READ; @@ -755,7 +755,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri ring_req->u.rw.handle = info->handle; ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE : BLKIF_OP_READ; - if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) { + if (req_op(req) == REQ_OP_FLUSH || req->cmd_flags & REQ_FUA) { /* * Ideally we can do an unordered flush-to-disk. * In case the backend onlysupports barriers, use that. @@ -865,7 +865,7 @@ static inline bool blkif_request_flush_invalid(struct request *req, struct blkfront_info *info) { return ((req->cmd_type != REQ_TYPE_FS) || - ((req->cmd_flags & REQ_FLUSH) && + ((req_op(req) == REQ_OP_FLUSH) && !(info->feature_flush & REQ_FLUSH)) || ((req->cmd_flags & REQ_FUA) && !(info->feature_flush & REQ_FUA))); @@ -2055,7 +2055,7 @@ static int blkif_recover(struct blkfront_info *info) /* * Get the bios in the request so we can re-queue them. */ - if (copy[i].request->cmd_flags & REQ_FLUSH || + if (req_op(copy[i].request) == REQ_OP_FLUSH || req_op(copy[i].request) == REQ_OP_DISCARD || copy[i].request->cmd_flags & (REQ_FUA | REQ_SECURE)) { /* diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 05dbcce70b0e..e378ef70ed63 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -431,7 +431,7 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq) ide_drive_t *drive = q->queuedata; struct ide_cmd *cmd; - if (!(rq->cmd_flags & REQ_FLUSH)) + if (req_op(rq) != REQ_OP_FLUSH) return BLKPREP_OK; if (rq->special) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f6b104c77b6d..fcc68c8edba0 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2171,7 +2171,7 @@ static void dm_request_fn(struct request_queue *q) /* always use block 0 to find the target for flushes for now */ pos = 0; - if (!(rq->cmd_flags & REQ_FLUSH)) + if (req_op(rq) != REQ_OP_FLUSH) pos = blk_rq_pos(rq); if ((dm_request_peeked_before_merge_deadline(md) && diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 201a8719f6c4..bca20f88a8b2 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1722,7 +1722,8 @@ static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req) !IS_ALIGNED(blk_rq_sectors(next), 8)) break; - if (req_op(next) == REQ_OP_DISCARD || next->cmd_flags & REQ_FLUSH) + if (req_op(next) == REQ_OP_DISCARD || + req_op(next) == REQ_OP_FLUSH) break; if (rq_data_dir(cur) != rq_data_dir(next)) @@ -2147,7 +2148,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) struct mmc_card *card = md->queue.card; struct mmc_host *host = card->host; unsigned long flags; - unsigned int cmd_flags = req ? req->cmd_flags : 0; if (req && !mq->mqrq_prev->req) /* claim host only for the first request */ @@ -2171,7 +2171,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ret = mmc_blk_issue_secdiscard_rq(mq, req); else ret = mmc_blk_issue_discard_rq(mq, req); - } else if (cmd_flags & REQ_FLUSH) { + } else if (req && req_op(req) == REQ_OP_FLUSH) { /* complete ongoing async transfer before issuing flush */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 9fb26f20a44d..d62531124d54 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -3,7 +3,8 @@ static inline bool mmc_req_is_special(struct request *req) { - return req && (req->cmd_flags & REQ_FLUSH || req_op(req) == REQ_OP_DISCARD); + return req && + (req_op(req) == REQ_OP_FLUSH || req_op(req) == REQ_OP_DISCARD); } struct request; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 4eb9a5fb151c..78b3eb45faf6 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -87,7 +87,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, if (req->cmd_type != REQ_TYPE_FS) return -EIO; - if (req->cmd_flags & REQ_FLUSH) + if (req_op(req) == REQ_OP_FLUSH) return tr->flush(dev); if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 089b8b8aad4f..abdfdcfb66f4 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -290,7 +290,7 @@ int nvme_setup_cmd(struct nvme_ns *ns, struct request *req, if (req->cmd_type == REQ_TYPE_DRV_PRIV) memcpy(cmd, req->cmd, sizeof(*cmd)); - else if (req->cmd_flags & REQ_FLUSH) + else if (req_op(req) == REQ_OP_FLUSH) nvme_setup_flush(ns, cmd); else if (req_op(req) == REQ_OP_DISCARD) ret = nvme_setup_discard(ns, req, cmd); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index fad86ad89e64..5a9db0fe1ee0 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1143,12 +1143,11 @@ static int sd_init_command(struct scsi_cmnd *cmd) return sd_setup_discard_cmnd(cmd); case REQ_OP_WRITE_SAME: return sd_setup_write_same_cmnd(cmd); + case REQ_OP_FLUSH: + return sd_setup_flush_cmnd(cmd); case REQ_OP_READ: case REQ_OP_WRITE: - if (rq->cmd_flags & REQ_FLUSH) - return sd_setup_flush_cmnd(cmd); - else - return sd_setup_read_write_cmnd(cmd); + return sd_setup_read_write_cmnd(cmd); default: BUG(); } diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 23c1ab2a9475..32d87522f349 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -249,9 +249,10 @@ enum req_op { REQ_OP_WRITE, REQ_OP_DISCARD, /* request to discard sectors */ REQ_OP_WRITE_SAME, /* write same block many times */ + REQ_OP_FLUSH, /* request for cache flush */ }; -#define REQ_OP_BITS 2 +#define REQ_OP_BITS 3 typedef unsigned int blk_qc_t; #define BLK_QC_T_NONE -1U diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 78ae3dbf2de1..0c9f8793c87e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -666,6 +666,9 @@ static inline bool rq_mergeable(struct request *rq) if (rq->cmd_type != REQ_TYPE_FS) return false; + if (req_op(rq) == REQ_OP_FLUSH) + return false; + if (rq->cmd_flags & REQ_NOMERGE_FLAGS) return false; diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 2d16fad519b2..0c70fbb6ea8d 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -223,6 +223,8 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, what |= MASK_TC_BIT(op_flags, FUA); if (op == REQ_OP_DISCARD) what |= BLK_TC_ACT(BLK_TC_DISCARD); + if (op == REQ_OP_FLUSH) + what |= BLK_TC_ACT(BLK_TC_FLUSH); pid = tsk->pid; if (act_log_check(bt, what, sector, pid)) @@ -1788,6 +1790,9 @@ void blk_fill_rwbs(char *rwbs, int op, u32 rw, int bytes) case REQ_OP_DISCARD: rwbs[i++] = 'D'; break; + case REQ_OP_FLUSH: + rwbs[i++] = 'F'; + break; case REQ_OP_READ: rwbs[i++] = 'R'; break; -- cgit v1.2.3 From 28a8f0d317bf225ff15008f5dd66ae16242dd843 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 5 Jun 2016 14:32:25 -0500 Subject: block, drivers, fs: rename REQ_FLUSH to REQ_PREFLUSH To avoid confusion between REQ_OP_FLUSH, which is handled by request_fn drivers, and upper layers requesting the block layer perform a flush sequence along with possibly a WRITE, this patch renames REQ_FLUSH to REQ_PREFLUSH. Signed-off-by: Mike Christie Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Jens Axboe --- Documentation/block/writeback_cache_control.txt | 22 +++++++++++----------- Documentation/device-mapper/log-writes.txt | 10 +++++----- block/blk-core.c | 12 ++++++------ block/blk-flush.c | 16 ++++++++-------- block/blk-mq.c | 4 ++-- drivers/block/drbd/drbd_actlog.c | 4 ++-- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_protocol.h | 2 +- drivers/block/drbd/drbd_receiver.c | 2 +- drivers/block/drbd/drbd_req.c | 2 +- drivers/md/bcache/journal.c | 2 +- drivers/md/bcache/request.c | 8 ++++---- drivers/md/dm-cache-target.c | 12 ++++++------ drivers/md/dm-crypt.c | 7 ++++--- drivers/md/dm-era-target.c | 4 ++-- drivers/md/dm-io.c | 2 +- drivers/md/dm-log-writes.c | 2 +- drivers/md/dm-raid1.c | 5 +++-- drivers/md/dm-region-hash.c | 4 ++-- drivers/md/dm-snap.c | 6 +++--- drivers/md/dm-stripe.c | 2 +- drivers/md/dm-thin.c | 8 ++++---- drivers/md/dm.c | 12 ++++++------ drivers/md/linear.c | 2 +- drivers/md/md.c | 2 +- drivers/md/md.h | 2 +- drivers/md/multipath.c | 2 +- drivers/md/raid0.c | 2 +- drivers/md/raid1.c | 3 ++- drivers/md/raid10.c | 2 +- drivers/md/raid5-cache.c | 2 +- drivers/md/raid5.c | 2 +- fs/btrfs/check-integrity.c | 8 ++++---- fs/jbd2/journal.c | 2 +- fs/xfs/xfs_buf.c | 2 +- include/linux/blk_types.h | 8 ++++---- include/linux/fs.h | 4 ++-- include/trace/events/f2fs.h | 2 +- kernel/trace/blktrace.c | 5 +++-- 39 files changed, 102 insertions(+), 98 deletions(-) (limited to 'include/linux') diff --git a/Documentation/block/writeback_cache_control.txt b/Documentation/block/writeback_cache_control.txt index da70bdacd503..8a6bdada5f6b 100644 --- a/Documentation/block/writeback_cache_control.txt +++ b/Documentation/block/writeback_cache_control.txt @@ -20,11 +20,11 @@ a forced cache flush, and the Force Unit Access (FUA) flag for requests. Explicit cache flushes ---------------------- -The REQ_FLUSH flag can be OR ed into the r/w flags of a bio submitted from +The REQ_PREFLUSH flag can be OR ed into the r/w flags of a bio submitted from the filesystem and will make sure the volatile cache of the storage device has been flushed before the actual I/O operation is started. This explicitly guarantees that previously completed write requests are on non-volatile -storage before the flagged bio starts. In addition the REQ_FLUSH flag can be +storage before the flagged bio starts. In addition the REQ_PREFLUSH flag can be set on an otherwise empty bio structure, which causes only an explicit cache flush without any dependent I/O. It is recommend to use the blkdev_issue_flush() helper for a pure cache flush. @@ -41,21 +41,21 @@ signaled after the data has been committed to non-volatile storage. Implementation details for filesystems -------------------------------------- -Filesystems can simply set the REQ_FLUSH and REQ_FUA bits and do not have to +Filesystems can simply set the REQ_PREFLUSH and REQ_FUA bits and do not have to worry if the underlying devices need any explicit cache flushing and how -the Forced Unit Access is implemented. The REQ_FLUSH and REQ_FUA flags +the Forced Unit Access is implemented. The REQ_PREFLUSH and REQ_FUA flags may both be set on a single bio. Implementation details for make_request_fn based block drivers -------------------------------------------------------------- -These drivers will always see the REQ_FLUSH and REQ_FUA bits as they sit +These drivers will always see the REQ_PREFLUSH and REQ_FUA bits as they sit directly below the submit_bio interface. For remapping drivers the REQ_FUA bits need to be propagated to underlying devices, and a global flush needs -to be implemented for bios with the REQ_FLUSH bit set. For real device -drivers that do not have a volatile cache the REQ_FLUSH and REQ_FUA bits -on non-empty bios can simply be ignored, and REQ_FLUSH requests without +to be implemented for bios with the REQ_PREFLUSH bit set. For real device +drivers that do not have a volatile cache the REQ_PREFLUSH and REQ_FUA bits +on non-empty bios can simply be ignored, and REQ_PREFLUSH requests without data can be completed successfully without doing any work. Drivers for devices with volatile caches need to implement the support for these flags themselves without any help from the block layer. @@ -65,8 +65,8 @@ Implementation details for request_fn based block drivers -------------------------------------------------------------- For devices that do not support volatile write caches there is no driver -support required, the block layer completes empty REQ_FLUSH requests before -entering the driver and strips off the REQ_FLUSH and REQ_FUA bits from +support required, the block layer completes empty REQ_PREFLUSH requests before +entering the driver and strips off the REQ_PREFLUSH and REQ_FUA bits from requests that have a payload. For devices with volatile write caches the driver needs to tell the block layer that it supports flushing caches by doing: @@ -74,7 +74,7 @@ doing: blk_queue_write_cache(sdkp->disk->queue, true, false); and handle empty REQ_OP_FLUSH requests in its prep_fn/request_fn. Note that -REQ_FLUSH requests with a payload are automatically turned into a sequence +REQ_PREFLUSH requests with a payload are automatically turned into a sequence of an empty REQ_OP_FLUSH request followed by the actual write by the block layer. For devices that also support the FUA bit the block layer needs to be told to pass through the REQ_FUA bit using: diff --git a/Documentation/device-mapper/log-writes.txt b/Documentation/device-mapper/log-writes.txt index c10f30c9b534..f4ebcbaf50f3 100644 --- a/Documentation/device-mapper/log-writes.txt +++ b/Documentation/device-mapper/log-writes.txt @@ -14,14 +14,14 @@ Log Ordering We log things in order of completion once we are sure the write is no longer in cache. This means that normal WRITE requests are not actually logged until the -next REQ_FLUSH request. This is to make it easier for userspace to replay the -log in a way that correlates to what is on disk and not what is in cache, to -make it easier to detect improper waiting/flushing. +next REQ_PREFLUSH request. This is to make it easier for userspace to replay +the log in a way that correlates to what is on disk and not what is in cache, +to make it easier to detect improper waiting/flushing. This works by attaching all WRITE requests to a list once the write completes. -Once we see a REQ_FLUSH request we splice this list onto the request and once +Once we see a REQ_PREFLUSH request we splice this list onto the request and once the FLUSH request completes we log all of the WRITEs and then the FLUSH. Only -completed WRITEs, at the time the REQ_FLUSH is issued, are added in order to +completed WRITEs, at the time the REQ_PREFLUSH is issued, are added in order to simulate the worst case scenario with regard to power failures. Consider the following example (W means write, C means complete): diff --git a/block/blk-core.c b/block/blk-core.c index c7d66c23a708..32a283eb7274 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1029,7 +1029,7 @@ static bool blk_rq_should_init_elevator(struct bio *bio) * Flush requests do not use the elevator so skip initialization. * This allows a request to share the flush and elevator data. */ - if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) + if (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA)) return false; return true; @@ -1736,7 +1736,7 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio) return BLK_QC_T_NONE; } - if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) { + if (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA)) { spin_lock_irq(q->queue_lock); where = ELEVATOR_INSERT_FLUSH; goto get_rq; @@ -1968,9 +1968,9 @@ generic_make_request_checks(struct bio *bio) * drivers without flush support don't have to worry * about them. */ - if ((bio->bi_rw & (REQ_FLUSH | REQ_FUA)) && + if ((bio->bi_rw & (REQ_PREFLUSH | REQ_FUA)) && !test_bit(QUEUE_FLAG_WC, &q->queue_flags)) { - bio->bi_rw &= ~(REQ_FLUSH | REQ_FUA); + bio->bi_rw &= ~(REQ_PREFLUSH | REQ_FUA); if (!nr_sectors) { err = 0; goto end_io; @@ -2217,7 +2217,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq) */ BUG_ON(blk_queued_rq(rq)); - if (rq->cmd_flags & (REQ_FLUSH|REQ_FUA)) + if (rq->cmd_flags & (REQ_PREFLUSH | REQ_FUA)) where = ELEVATOR_INSERT_FLUSH; add_acct_request(q, rq, where); @@ -3311,7 +3311,7 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) /* * rq is already accounted, so use raw insert */ - if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) + if (rq->cmd_flags & (REQ_PREFLUSH | REQ_FUA)) __elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH); else __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE); diff --git a/block/blk-flush.c b/block/blk-flush.c index 21f0d5b0d2ca..d308def812db 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -10,8 +10,8 @@ * optional steps - PREFLUSH, DATA and POSTFLUSH - according to the request * properties and hardware capability. * - * If a request doesn't have data, only REQ_FLUSH makes sense, which - * indicates a simple flush request. If there is data, REQ_FLUSH indicates + * If a request doesn't have data, only REQ_PREFLUSH makes sense, which + * indicates a simple flush request. If there is data, REQ_PREFLUSH indicates * that the device cache should be flushed before the data is executed, and * REQ_FUA means that the data must be on non-volatile media on request * completion. @@ -20,11 +20,11 @@ * difference. The requests are either completed immediately if there's no * data or executed as normal requests otherwise. * - * If the device has writeback cache and supports FUA, REQ_FLUSH is + * If the device has writeback cache and supports FUA, REQ_PREFLUSH is * translated to PREFLUSH but REQ_FUA is passed down directly with DATA. * - * If the device has writeback cache and doesn't support FUA, REQ_FLUSH is - * translated to PREFLUSH and REQ_FUA to POSTFLUSH. + * If the device has writeback cache and doesn't support FUA, REQ_PREFLUSH + * is translated to PREFLUSH and REQ_FUA to POSTFLUSH. * * The actual execution of flush is double buffered. Whenever a request * needs to execute PRE or POSTFLUSH, it queues at @@ -103,7 +103,7 @@ static unsigned int blk_flush_policy(unsigned long fflags, struct request *rq) policy |= REQ_FSEQ_DATA; if (fflags & (1UL << QUEUE_FLAG_WC)) { - if (rq->cmd_flags & REQ_FLUSH) + if (rq->cmd_flags & REQ_PREFLUSH) policy |= REQ_FSEQ_PREFLUSH; if (!(fflags & (1UL << QUEUE_FLAG_FUA)) && (rq->cmd_flags & REQ_FUA)) @@ -391,9 +391,9 @@ void blk_insert_flush(struct request *rq) /* * @policy now records what operations need to be done. Adjust - * REQ_FLUSH and FUA for the driver. + * REQ_PREFLUSH and FUA for the driver. */ - rq->cmd_flags &= ~REQ_FLUSH; + rq->cmd_flags &= ~REQ_PREFLUSH; if (!(fflags & (1UL << QUEUE_FLAG_FUA))) rq->cmd_flags &= ~REQ_FUA; diff --git a/block/blk-mq.c b/block/blk-mq.c index 29bcd9c07a34..13f460368759 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1247,7 +1247,7 @@ static int blk_mq_direct_issue_request(struct request *rq, blk_qc_t *cookie) static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio) { const int is_sync = rw_is_sync(bio_op(bio), bio->bi_rw); - const int is_flush_fua = bio->bi_rw & (REQ_FLUSH | REQ_FUA); + const int is_flush_fua = bio->bi_rw & (REQ_PREFLUSH | REQ_FUA); struct blk_map_ctx data; struct request *rq; unsigned int request_count = 0; @@ -1344,7 +1344,7 @@ done: static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio) { const int is_sync = rw_is_sync(bio_op(bio), bio->bi_rw); - const int is_flush_fua = bio->bi_rw & (REQ_FLUSH | REQ_FUA); + const int is_flush_fua = bio->bi_rw & (REQ_PREFLUSH | REQ_FUA); struct blk_plug *plug; unsigned int request_count = 0; struct blk_map_ctx data; diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index f236a31cc095..d524973f94b3 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -148,7 +148,7 @@ static int _drbd_md_sync_page_io(struct drbd_device *device, device->md_io.error = -ENODEV; if ((op == REQ_OP_WRITE) && !test_bit(MD_NO_FUA, &device->flags)) - op_flags |= REQ_FUA | REQ_FLUSH; + op_flags |= REQ_FUA | REQ_PREFLUSH; op_flags |= REQ_SYNC | REQ_NOIDLE; bio = bio_alloc_drbd(GFP_NOIO); @@ -847,7 +847,7 @@ int __drbd_change_sync(struct drbd_device *device, sector_t sector, int size, unsigned long count = 0; sector_t esector, nr_sectors; - /* This would be an empty REQ_FLUSH, be silent. */ + /* This would be an empty REQ_PREFLUSH, be silent. */ if ((mode == SET_OUT_OF_SYNC) && size == 0) return 0; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index d55febcaa414..2b37744db0fa 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1609,7 +1609,7 @@ static u32 bio_flags_to_wire(struct drbd_connection *connection, if (connection->agreed_pro_version >= 95) return (bio->bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) | (bio->bi_rw & REQ_FUA ? DP_FUA : 0) | - (bio->bi_rw & REQ_FLUSH ? DP_FLUSH : 0) | + (bio->bi_rw & REQ_PREFLUSH ? DP_FLUSH : 0) | (bio_op(bio) == REQ_OP_DISCARD ? DP_DISCARD : 0); else return bio->bi_rw & REQ_SYNC ? DP_RW_SYNC : 0; diff --git a/drivers/block/drbd/drbd_protocol.h b/drivers/block/drbd/drbd_protocol.h index ef9245363dcc..129f8c76c9b1 100644 --- a/drivers/block/drbd/drbd_protocol.h +++ b/drivers/block/drbd/drbd_protocol.h @@ -112,7 +112,7 @@ struct p_header100 { #define DP_MAY_SET_IN_SYNC 4 #define DP_UNPLUG 8 /* not used anymore */ #define DP_FUA 16 /* equals REQ_FUA */ -#define DP_FLUSH 32 /* equals REQ_FLUSH */ +#define DP_FLUSH 32 /* equals REQ_PREFLUSH */ #define DP_DISCARD 64 /* equals REQ_DISCARD */ #define DP_SEND_RECEIVE_ACK 128 /* This is a proto B write request */ #define DP_SEND_WRITE_ACK 256 /* This is a proto C write request */ diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6c5997894475..1ee002352ea2 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2158,7 +2158,7 @@ static unsigned long wire_flags_to_bio_flags(u32 dpf) { return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) | (dpf & DP_FUA ? REQ_FUA : 0) | - (dpf & DP_FLUSH ? REQ_FLUSH : 0); + (dpf & DP_FLUSH ? REQ_PREFLUSH : 0); } static unsigned long wire_flags_to_bio_op(u32 dpf) diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 2255dcfebd2b..eef6e9575b4e 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1132,7 +1132,7 @@ static int drbd_process_write_request(struct drbd_request *req) * replicating, in which case there is no point. */ if (unlikely(req->i.size == 0)) { /* The only size==0 bios we expect are empty flushes. */ - D_ASSERT(device, req->master_bio->bi_rw & REQ_FLUSH); + D_ASSERT(device, req->master_bio->bi_rw & REQ_PREFLUSH); if (remote) _req_mod(req, QUEUE_AS_DRBD_BARRIER); return remote; diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index a3c3b309ff4a..6925023e12d4 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -631,7 +631,7 @@ static void journal_write_unlocked(struct closure *cl) bio->bi_end_io = journal_write_endio; bio->bi_private = w; bio_set_op_attrs(bio, REQ_OP_WRITE, - REQ_SYNC|REQ_META|REQ_FLUSH|REQ_FUA); + REQ_SYNC|REQ_META|REQ_PREFLUSH|REQ_FUA); bch_bio_map(bio, w->data); trace_bcache_journal_write(bio); diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 016b0aa7199c..69f16f43f8ab 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -205,10 +205,10 @@ static void bch_data_insert_start(struct closure *cl) return bch_data_invalidate(cl); /* - * Journal writes are marked REQ_FLUSH; if the original write was a + * Journal writes are marked REQ_PREFLUSH; if the original write was a * flush, it'll wait on the journal write. */ - bio->bi_rw &= ~(REQ_FLUSH|REQ_FUA); + bio->bi_rw &= ~(REQ_PREFLUSH|REQ_FUA); do { unsigned i; @@ -668,7 +668,7 @@ static inline struct search *search_alloc(struct bio *bio, s->iop.write_prio = 0; s->iop.error = 0; s->iop.flags = 0; - s->iop.flush_journal = (bio->bi_rw & (REQ_FLUSH|REQ_FUA)) != 0; + s->iop.flush_journal = (bio->bi_rw & (REQ_PREFLUSH|REQ_FUA)) != 0; s->iop.wq = bcache_wq; return s; @@ -920,7 +920,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s) bch_writeback_add(dc); s->iop.bio = bio; - if (bio->bi_rw & REQ_FLUSH) { + if (bio->bi_rw & REQ_PREFLUSH) { /* Also need to send a flush to the backing device */ struct bio *flush = bio_alloc_bioset(GFP_NOIO, 0, dc->disk.bio_split); diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 540e80eb317d..718744db62df 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -788,7 +788,7 @@ static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio) spin_lock_irqsave(&cache->lock, flags); if (cache->need_tick_bio && - !(bio->bi_rw & (REQ_FUA | REQ_FLUSH)) && + !(bio->bi_rw & (REQ_FUA | REQ_PREFLUSH)) && bio_op(bio) != REQ_OP_DISCARD) { pb->tick = true; cache->need_tick_bio = false; @@ -830,7 +830,7 @@ static dm_oblock_t get_bio_block(struct cache *cache, struct bio *bio) static int bio_triggers_commit(struct cache *cache, struct bio *bio) { - return bio->bi_rw & (REQ_FLUSH | REQ_FUA); + return bio->bi_rw & (REQ_PREFLUSH | REQ_FUA); } /* @@ -1069,7 +1069,7 @@ static void dec_io_migrations(struct cache *cache) static bool discard_or_flush(struct bio *bio) { return bio_op(bio) == REQ_OP_DISCARD || - bio->bi_rw & (REQ_FLUSH | REQ_FUA); + bio->bi_rw & (REQ_PREFLUSH | REQ_FUA); } static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell) @@ -1614,8 +1614,8 @@ static void process_flush_bio(struct cache *cache, struct bio *bio) remap_to_cache(cache, bio, 0); /* - * REQ_FLUSH is not directed at any particular block so we don't - * need to inc_ds(). REQ_FUA's are split into a write + REQ_FLUSH + * REQ_PREFLUSH is not directed at any particular block so we don't + * need to inc_ds(). REQ_FUA's are split into a write + REQ_PREFLUSH * by dm-core. */ issue(cache, bio); @@ -1980,7 +1980,7 @@ static void process_deferred_bios(struct cache *cache) bio = bio_list_pop(&bios); - if (bio->bi_rw & REQ_FLUSH) + if (bio->bi_rw & REQ_PREFLUSH) process_flush_bio(cache, bio); else if (bio_op(bio) == REQ_OP_DISCARD) process_discard_bio(cache, &structs, bio); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 057d19b5e196..96dd5d7e454a 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1911,11 +1911,12 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) struct crypt_config *cc = ti->private; /* - * If bio is REQ_FLUSH or REQ_OP_DISCARD, just bypass crypt queues. - * - for REQ_FLUSH device-mapper core ensures that no IO is in-flight + * If bio is REQ_PREFLUSH or REQ_OP_DISCARD, just bypass crypt queues. + * - for REQ_PREFLUSH device-mapper core ensures that no IO is in-flight * - for REQ_OP_DISCARD caller must use flush if IO ordering matters */ - if (unlikely(bio->bi_rw & REQ_FLUSH || bio_op(bio) == REQ_OP_DISCARD)) { + if (unlikely(bio->bi_rw & REQ_PREFLUSH || + bio_op(bio) == REQ_OP_DISCARD)) { bio->bi_bdev = cc->dev->bdev; if (bio_sectors(bio)) bio->bi_iter.bi_sector = cc->start + diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c index 665bf3285618..2faf49d8f4d7 100644 --- a/drivers/md/dm-era-target.c +++ b/drivers/md/dm-era-target.c @@ -1540,9 +1540,9 @@ static int era_map(struct dm_target *ti, struct bio *bio) remap_to_origin(era, bio); /* - * REQ_FLUSH bios carry no data, so we're not interested in them. + * REQ_PREFLUSH bios carry no data, so we're not interested in them. */ - if (!(bio->bi_rw & REQ_FLUSH) && + if (!(bio->bi_rw & REQ_PREFLUSH) && (bio_data_dir(bio) == WRITE) && !metadata_current_marked(era->md, block)) { defer_bio(era, bio); diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 22e0597d631e..0e225fd4a8d1 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -380,7 +380,7 @@ static void dispatch_io(int op, int op_flags, unsigned int num_regions, */ for (i = 0; i < num_regions; i++) { *dp = old_pages; - if (where[i].count || (op_flags & REQ_FLUSH)) + if (where[i].count || (op_flags & REQ_PREFLUSH)) do_region(op, op_flags, i, where + i, dp, io); } diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index 0edb8ea51e46..b5dbf7a0515e 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -555,7 +555,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio) struct bio_vec bv; size_t alloc_size; int i = 0; - bool flush_bio = (bio->bi_rw & REQ_FLUSH); + bool flush_bio = (bio->bi_rw & REQ_PREFLUSH); bool fua_bio = (bio->bi_rw & REQ_FUA); bool discard_bio = (bio_op(bio) == REQ_OP_DISCARD); diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 907df2ba8fd4..9f5f460c0e92 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -704,7 +704,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) bio_list_init(&requeue); while ((bio = bio_list_pop(writes))) { - if ((bio->bi_rw & REQ_FLUSH) || + if ((bio->bi_rw & REQ_PREFLUSH) || (bio_op(bio) == REQ_OP_DISCARD)) { bio_list_add(&sync, bio); continue; @@ -1253,7 +1253,8 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error) * We need to dec pending if this was a write. */ if (rw == WRITE) { - if (!(bio->bi_rw & REQ_FLUSH) && bio_op(bio) != REQ_OP_DISCARD) + if (!(bio->bi_rw & REQ_PREFLUSH) && + bio_op(bio) != REQ_OP_DISCARD) dm_rh_dec(ms->rh, bio_record->write_region); return error; } diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 3550ca7c6577..b11813431f31 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -398,7 +398,7 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio) region_t region = dm_rh_bio_to_region(rh, bio); int recovering = 0; - if (bio->bi_rw & REQ_FLUSH) { + if (bio->bi_rw & REQ_PREFLUSH) { rh->flush_failure = 1; return; } @@ -526,7 +526,7 @@ void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios) struct bio *bio; for (bio = bios->head; bio; bio = bio->bi_next) { - if (bio->bi_rw & REQ_FLUSH || bio_op(bio) == REQ_OP_DISCARD) + if (bio->bi_rw & REQ_PREFLUSH || bio_op(bio) == REQ_OP_DISCARD) continue; rh_inc(rh, dm_rh_bio_to_region(rh, bio)); } diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 70bb0e8b62ce..69ab1ff5f5c9 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1680,7 +1680,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) init_tracked_chunk(bio); - if (bio->bi_rw & REQ_FLUSH) { + if (bio->bi_rw & REQ_PREFLUSH) { bio->bi_bdev = s->cow->bdev; return DM_MAPIO_REMAPPED; } @@ -1799,7 +1799,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio) init_tracked_chunk(bio); - if (bio->bi_rw & REQ_FLUSH) { + if (bio->bi_rw & REQ_PREFLUSH) { if (!dm_bio_get_target_bio_nr(bio)) bio->bi_bdev = s->origin->bdev; else @@ -2285,7 +2285,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio) bio->bi_bdev = o->dev->bdev; - if (unlikely(bio->bi_rw & REQ_FLUSH)) + if (unlikely(bio->bi_rw & REQ_PREFLUSH)) return DM_MAPIO_REMAPPED; if (bio_rw(bio) != WRITE) diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index b738178ca068..48f1c01d7b9f 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -286,7 +286,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio) uint32_t stripe; unsigned target_bio_nr; - if (bio->bi_rw & REQ_FLUSH) { + if (bio->bi_rw & REQ_PREFLUSH) { target_bio_nr = dm_bio_get_target_bio_nr(bio); BUG_ON(target_bio_nr >= sc->stripes); bio->bi_bdev = sc->stripe[target_bio_nr].dev->bdev; diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 1b684cbb9ba2..5f9e3d799d66 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -697,7 +697,7 @@ static void remap_to_origin(struct thin_c *tc, struct bio *bio) static int bio_triggers_commit(struct thin_c *tc, struct bio *bio) { - return (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) && + return (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA)) && dm_thin_changed_this_transaction(tc->td); } @@ -868,7 +868,7 @@ static void __inc_remap_and_issue_cell(void *context, struct bio *bio; while ((bio = bio_list_pop(&cell->bios))) { - if (bio->bi_rw & (REQ_FLUSH | REQ_FUA) || + if (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA) || bio_op(bio) == REQ_OP_DISCARD) bio_list_add(&info->defer_bios, bio); else { @@ -1641,7 +1641,7 @@ static void __remap_and_issue_shared_cell(void *context, while ((bio = bio_list_pop(&cell->bios))) { if ((bio_data_dir(bio) == WRITE) || - (bio->bi_rw & (REQ_FLUSH | REQ_FUA) || + (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA) || bio_op(bio) == REQ_OP_DISCARD)) bio_list_add(&info->defer_bios, bio); else { @@ -2556,7 +2556,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio) return DM_MAPIO_SUBMITTED; } - if (bio->bi_rw & (REQ_FLUSH | REQ_FUA) || + if (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA) || bio_op(bio) == REQ_OP_DISCARD) { thin_defer_bio_with_throttle(tc, bio); return DM_MAPIO_SUBMITTED; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index fcc68c8edba0..aba7ed9abb3a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1003,12 +1003,12 @@ static void dec_pending(struct dm_io *io, int error) if (io_error == DM_ENDIO_REQUEUE) return; - if ((bio->bi_rw & REQ_FLUSH) && bio->bi_iter.bi_size) { + if ((bio->bi_rw & REQ_PREFLUSH) && bio->bi_iter.bi_size) { /* * Preflush done for flush with data, reissue - * without REQ_FLUSH. + * without REQ_PREFLUSH. */ - bio->bi_rw &= ~REQ_FLUSH; + bio->bi_rw &= ~REQ_PREFLUSH; queue_io(md, bio); } else { /* done with normal IO or empty flush */ @@ -1477,7 +1477,7 @@ EXPORT_SYMBOL_GPL(dm_set_target_max_io_len); /* * A target may call dm_accept_partial_bio only from the map routine. It is - * allowed for all bio types except REQ_FLUSH. + * allowed for all bio types except REQ_PREFLUSH. * * dm_accept_partial_bio informs the dm that the target only wants to process * additional n_sectors sectors of the bio and the rest of the data should be @@ -1507,7 +1507,7 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors) { struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone); unsigned bi_size = bio->bi_iter.bi_size >> SECTOR_SHIFT; - BUG_ON(bio->bi_rw & REQ_FLUSH); + BUG_ON(bio->bi_rw & REQ_PREFLUSH); BUG_ON(bi_size > *tio->len_ptr); BUG_ON(n_sectors > bi_size); *tio->len_ptr -= bi_size - n_sectors; @@ -1795,7 +1795,7 @@ static void __split_and_process_bio(struct mapped_device *md, start_io_acct(ci.io); - if (bio->bi_rw & REQ_FLUSH) { + if (bio->bi_rw & REQ_PREFLUSH) { ci.bio = &ci.md->flush_bio; ci.sector_count = 0; error = __send_empty_flush(&ci); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 1ad3f485672c..70ff888d25d0 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -221,7 +221,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) struct bio *split; sector_t start_sector, end_sector, data_offset; - if (unlikely(bio->bi_rw & REQ_FLUSH)) { + if (unlikely(bio->bi_rw & REQ_PREFLUSH)) { md_flush_request(mddev, bio); return; } diff --git a/drivers/md/md.c b/drivers/md/md.c index bd4844fe0e98..1f123f5a29da 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -414,7 +414,7 @@ static void md_submit_flush_data(struct work_struct *ws) /* an empty barrier - all done */ bio_endio(bio); else { - bio->bi_rw &= ~REQ_FLUSH; + bio->bi_rw &= ~REQ_PREFLUSH; mddev->pers->make_request(mddev, bio); } diff --git a/drivers/md/md.h b/drivers/md/md.h index 2e0918fc376d..b4f335245bd6 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -424,7 +424,7 @@ struct mddev { /* Generic flush handling. * The last to finish preflush schedules a worker to submit - * the rest of the request (without the REQ_FLUSH flag). + * the rest of the request (without the REQ_PREFLUSH flag). */ struct bio *flush_bio; atomic_t flush_pending; diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index dd483bb2e111..72ea98e89e57 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -111,7 +111,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio) struct multipath_bh * mp_bh; struct multipath_info *multipath; - if (unlikely(bio->bi_rw & REQ_FLUSH)) { + if (unlikely(bio->bi_rw & REQ_PREFLUSH)) { md_flush_request(mddev, bio); return; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 051a10ca4e09..c3d439083212 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -458,7 +458,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) struct md_rdev *tmp_dev; struct bio *split; - if (unlikely(bio->bi_rw & REQ_FLUSH)) { + if (unlikely(bio->bi_rw & REQ_PREFLUSH)) { md_flush_request(mddev, bio); return; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index a3427230f7cf..10e53cd6a995 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1056,7 +1056,8 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio) const int op = bio_op(bio); const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); - const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); + const unsigned long do_flush_fua = (bio->bi_rw & + (REQ_PREFLUSH | REQ_FUA)); const unsigned long do_sec = (bio->bi_rw & REQ_SECURE); struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 615045a11bac..245640b50153 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1447,7 +1447,7 @@ static void raid10_make_request(struct mddev *mddev, struct bio *bio) struct bio *split; - if (unlikely(bio->bi_rw & REQ_FLUSH)) { + if (unlikely(bio->bi_rw & REQ_PREFLUSH)) { md_flush_request(mddev, bio); return; } diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index 92651381b094..5504ce2bac06 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -536,7 +536,7 @@ int r5l_handle_flush_request(struct r5l_log *log, struct bio *bio) bio_endio(bio); return 0; } - bio->bi_rw &= ~REQ_FLUSH; + bio->bi_rw &= ~REQ_PREFLUSH; return -EAGAIN; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index b9122e2c6aa1..7aacf5b55e15 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5150,7 +5150,7 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi) DEFINE_WAIT(w); bool do_prepare; - if (unlikely(bi->bi_rw & REQ_FLUSH)) { + if (unlikely(bi->bi_rw & REQ_PREFLUSH)) { int ret = r5l_handle_flush_request(conf->log, bi); if (ret == 0) diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index da944ffddbaf..ca70bc78b27d 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -2207,7 +2207,7 @@ static void btrfsic_bio_end_io(struct bio *bp) block->dev_bytenr, block->mirror_num); next_block = block->next_in_same_bio; block->iodone_w_error = iodone_w_error; - if (block->submit_bio_bh_rw & REQ_FLUSH) { + if (block->submit_bio_bh_rw & REQ_PREFLUSH) { dev_state->last_flush_gen++; if ((dev_state->state->print_mask & BTRFSIC_PRINT_MASK_END_IO_BIO_BH)) @@ -2243,7 +2243,7 @@ static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate) block->dev_bytenr, block->mirror_num); block->iodone_w_error = iodone_w_error; - if (block->submit_bio_bh_rw & REQ_FLUSH) { + if (block->submit_bio_bh_rw & REQ_PREFLUSH) { dev_state->last_flush_gen++; if ((dev_state->state->print_mask & BTRFSIC_PRINT_MASK_END_IO_BIO_BH)) @@ -2884,7 +2884,7 @@ int btrfsic_submit_bh(int op, int op_flags, struct buffer_head *bh) btrfsic_process_written_block(dev_state, dev_bytenr, &bh->b_data, 1, NULL, NULL, bh, op_flags); - } else if (NULL != dev_state && (op_flags & REQ_FLUSH)) { + } else if (NULL != dev_state && (op_flags & REQ_PREFLUSH)) { if (dev_state->state->print_mask & BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) printk(KERN_INFO @@ -2982,7 +2982,7 @@ static void __btrfsic_submit_bio(struct bio *bio) kunmap(bio->bi_io_vec[i].bv_page); } kfree(mapped_datav); - } else if (NULL != dev_state && (bio->bi_rw & REQ_FLUSH)) { + } else if (NULL != dev_state && (bio->bi_rw & REQ_PREFLUSH)) { if (dev_state->state->print_mask & BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) printk(KERN_INFO diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 34bc99637d5a..dc68f562f681 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1354,7 +1354,7 @@ static int jbd2_write_superblock(journal_t *journal, int write_flags) trace_jbd2_write_superblock(journal, write_flags); if (!(journal->j_flags & JBD2_BARRIER)) - write_flags &= ~(REQ_FUA | REQ_FLUSH); + write_flags &= ~(REQ_FUA | REQ_PREFLUSH); lock_buffer(bh); if (buffer_write_io_error(bh)) { /* diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index d8acd3716dbd..686d8f160f5c 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1237,7 +1237,7 @@ _xfs_buf_ioapply( if (bp->b_flags & XBF_FUA) op_flags |= REQ_FUA; if (bp->b_flags & XBF_FLUSH) - op_flags |= REQ_FLUSH; + op_flags |= REQ_PREFLUSH; /* * Run the write verifier callback function if it exists. If diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 32d87522f349..562ab8301217 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -168,7 +168,7 @@ enum rq_flag_bits { __REQ_NOIDLE, /* don't anticipate more IO after this one */ __REQ_INTEGRITY, /* I/O includes block integrity payload */ __REQ_FUA, /* forced unit access */ - __REQ_FLUSH, /* request for cache flush */ + __REQ_PREFLUSH, /* request for cache flush */ /* bio only flags */ __REQ_RAHEAD, /* read ahead, can fail anytime */ @@ -212,12 +212,12 @@ enum rq_flag_bits { (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER) #define REQ_COMMON_MASK \ (REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | REQ_NOIDLE | \ - REQ_FLUSH | REQ_FUA | REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE) + REQ_PREFLUSH | REQ_FUA | REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE) #define REQ_CLONE_MASK REQ_COMMON_MASK /* This mask is used for both bio and request merge checking */ #define REQ_NOMERGE_FLAGS \ - (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_FLUSH_SEQ) + (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_PREFLUSH | REQ_FUA | REQ_FLUSH_SEQ) #define REQ_RAHEAD (1ULL << __REQ_RAHEAD) #define REQ_THROTTLED (1ULL << __REQ_THROTTLED) @@ -235,7 +235,7 @@ enum rq_flag_bits { #define REQ_PREEMPT (1ULL << __REQ_PREEMPT) #define REQ_ALLOCED (1ULL << __REQ_ALLOCED) #define REQ_COPY_USER (1ULL << __REQ_COPY_USER) -#define REQ_FLUSH (1ULL << __REQ_FLUSH) +#define REQ_PREFLUSH (1ULL << __REQ_PREFLUSH) #define REQ_FLUSH_SEQ (1ULL << __REQ_FLUSH_SEQ) #define REQ_IO_STAT (1ULL << __REQ_IO_STAT) #define REQ_MIXED_MERGE (1ULL << __REQ_MIXED_MERGE) diff --git a/include/linux/fs.h b/include/linux/fs.h index ccd166477487..183024525d40 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -204,9 +204,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define READ_SYNC REQ_SYNC #define WRITE_SYNC (REQ_SYNC | REQ_NOIDLE) #define WRITE_ODIRECT REQ_SYNC -#define WRITE_FLUSH (REQ_SYNC | REQ_NOIDLE | REQ_FLUSH) +#define WRITE_FLUSH (REQ_SYNC | REQ_NOIDLE | REQ_PREFLUSH) #define WRITE_FUA (REQ_SYNC | REQ_NOIDLE | REQ_FUA) -#define WRITE_FLUSH_FUA (REQ_SYNC | REQ_NOIDLE | REQ_FLUSH | REQ_FUA) +#define WRITE_FLUSH_FUA (REQ_SYNC | REQ_NOIDLE | REQ_PREFLUSH | REQ_FUA) /* * Attribute flags. These should be or-ed together to figure out what diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 30efa44a473c..878963a1f058 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -33,7 +33,7 @@ TRACE_DEFINE_ENUM(SSR); TRACE_DEFINE_ENUM(__REQ_RAHEAD); TRACE_DEFINE_ENUM(__REQ_SYNC); TRACE_DEFINE_ENUM(__REQ_NOIDLE); -TRACE_DEFINE_ENUM(__REQ_FLUSH); +TRACE_DEFINE_ENUM(__REQ_PREFLUSH); TRACE_DEFINE_ENUM(__REQ_FUA); TRACE_DEFINE_ENUM(__REQ_PRIO); TRACE_DEFINE_ENUM(__REQ_META); diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 0c70fbb6ea8d..03b0dd98ff0e 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -189,6 +189,7 @@ static const u32 ddir_act[2] = { BLK_TC_ACT(BLK_TC_READ), BLK_TC_ACT(BLK_TC_WRITE) }; #define BLK_TC_RAHEAD BLK_TC_AHEAD +#define BLK_TC_PREFLUSH BLK_TC_FLUSH /* The ilog2() calls fall out because they're constant */ #define MASK_TC_BIT(rw, __name) ((rw & REQ_ ## __name) << \ @@ -219,7 +220,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, what |= MASK_TC_BIT(op_flags, SYNC); what |= MASK_TC_BIT(op_flags, RAHEAD); what |= MASK_TC_BIT(op_flags, META); - what |= MASK_TC_BIT(op_flags, FLUSH); + what |= MASK_TC_BIT(op_flags, PREFLUSH); what |= MASK_TC_BIT(op_flags, FUA); if (op == REQ_OP_DISCARD) what |= BLK_TC_ACT(BLK_TC_DISCARD); @@ -1779,7 +1780,7 @@ void blk_fill_rwbs(char *rwbs, int op, u32 rw, int bytes) { int i = 0; - if (rw & REQ_FLUSH) + if (rw & REQ_PREFLUSH) rwbs[i++] = 'F'; switch (op) { -- cgit v1.2.3 From f9eb8aea2a1e12fc2f584d1627deeb957435a801 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jun 2016 09:37:15 -0700 Subject: net_sched: transform qdisc running bit into a seqcount Instead of using a single bit (__QDISC___STATE_RUNNING) in sch->__state, use a seqcount. This adds lockdep support, but more importantly it will allow us to sample qdisc/class statistics without having to grab qdisc root lock. Signed-off-by: Eric Dumazet Cc: Cong Wang Cc: Jamal Hadi Salim Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 ++ drivers/net/ppp/ppp_generic.c | 3 +++ drivers/net/team/team.c | 2 ++ include/linux/netdevice.h | 1 + include/net/sch_generic.h | 15 ++++----------- net/bluetooth/6lowpan.c | 2 ++ net/core/dev.c | 2 +- net/ieee802154/6lowpan/core.c | 3 +++ net/l2tp/l2tp_eth.c | 4 ++++ net/sched/sch_generic.c | 14 ++++++++++---- 10 files changed, 32 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 941ec99cd3b6..681af31a60ed 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4610,6 +4610,7 @@ static int bond_check_params(struct bond_params *params) static struct lock_class_key bonding_netdev_xmit_lock_key; static struct lock_class_key bonding_netdev_addr_lock_key; static struct lock_class_key bonding_tx_busylock_key; +static struct lock_class_key bonding_qdisc_running_key; static void bond_set_lockdep_class_one(struct net_device *dev, struct netdev_queue *txq, @@ -4625,6 +4626,7 @@ static void bond_set_lockdep_class(struct net_device *dev) &bonding_netdev_addr_lock_key); netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL); dev->qdisc_tx_busylock = &bonding_tx_busylock_key; + dev->qdisc_running_key = &bonding_qdisc_running_key; } /* Called from registration process */ diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 8dedafa1a95d..aeabaa42317f 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1313,9 +1313,12 @@ ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64) } static struct lock_class_key ppp_tx_busylock; +static struct lock_class_key ppp_qdisc_running_key; + static int ppp_dev_init(struct net_device *dev) { dev->qdisc_tx_busylock = &ppp_tx_busylock; + dev->qdisc_running_key = &ppp_qdisc_running_key; return 0; } diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 2ace126533cd..00eb38956a2c 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1577,6 +1577,7 @@ static const struct team_option team_options[] = { static struct lock_class_key team_netdev_xmit_lock_key; static struct lock_class_key team_netdev_addr_lock_key; static struct lock_class_key team_tx_busylock_key; +static struct lock_class_key team_qdisc_running_key; static void team_set_lockdep_class_one(struct net_device *dev, struct netdev_queue *txq, @@ -1590,6 +1591,7 @@ static void team_set_lockdep_class(struct net_device *dev) lockdep_set_class(&dev->addr_list_lock, &team_netdev_addr_lock_key); netdev_for_each_tx_queue(dev, team_set_lockdep_class_one, NULL); dev->qdisc_tx_busylock = &team_tx_busylock_key; + dev->qdisc_running_key = &team_qdisc_running_key; } static int team_init(struct net_device *dev) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index fa6df2699532..59d7e06d88d5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1862,6 +1862,7 @@ struct net_device { #endif struct phy_device *phydev; struct lock_class_key *qdisc_tx_busylock; + struct lock_class_key *qdisc_running_key; bool proto_down; }; #define to_net_dev(d) container_of(d, struct net_device, dev) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index a1fd76c22a59..bff8d895ef8a 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -29,13 +29,6 @@ enum qdisc_state_t { __QDISC_STATE_THROTTLED, }; -/* - * following bits are only changed while qdisc lock is held - */ -enum qdisc___state_t { - __QDISC___STATE_RUNNING = 1, -}; - struct qdisc_size_table { struct rcu_head rcu; struct list_head list; @@ -93,7 +86,7 @@ struct Qdisc { unsigned long state; struct sk_buff_head q; struct gnet_stats_basic_packed bstats; - unsigned int __state; + seqcount_t running; struct gnet_stats_queue qstats; struct rcu_head rcu_head; int padded; @@ -104,20 +97,20 @@ struct Qdisc { static inline bool qdisc_is_running(const struct Qdisc *qdisc) { - return (qdisc->__state & __QDISC___STATE_RUNNING) ? true : false; + return (raw_read_seqcount(&qdisc->running) & 1) ? true : false; } static inline bool qdisc_run_begin(struct Qdisc *qdisc) { if (qdisc_is_running(qdisc)) return false; - qdisc->__state |= __QDISC___STATE_RUNNING; + write_seqcount_begin(&qdisc->running); return true; } static inline void qdisc_run_end(struct Qdisc *qdisc) { - qdisc->__state &= ~__QDISC___STATE_RUNNING; + write_seqcount_end(&qdisc->running); } static inline bool qdisc_may_bulk(const struct Qdisc *qdisc) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 780089d75915..977a11e418d0 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -629,6 +629,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) static struct lock_class_key bt_tx_busylock; static struct lock_class_key bt_netdev_xmit_lock_key; +static struct lock_class_key bt_qdisc_running_key; static void bt_set_lockdep_class_one(struct net_device *dev, struct netdev_queue *txq, @@ -641,6 +642,7 @@ static int bt_dev_init(struct net_device *dev) { netdev_for_each_tx_queue(dev, bt_set_lockdep_class_one, NULL); dev->qdisc_tx_busylock = &bt_tx_busylock; + dev->qdisc_running_key = &bt_qdisc_running_key; return 0; } diff --git a/net/core/dev.c b/net/core/dev.c index 896b686d1966..e0bcc39f4a7d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3075,7 +3075,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, /* * Heuristic to force contended enqueues to serialize on a * separate lock before trying to get qdisc main lock. - * This permits __QDISC___STATE_RUNNING owner to get the lock more + * This permits qdisc->running owner to get the lock more * often and dequeue packets faster. */ contended = qdisc_is_running(q); diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index dd085db8580e..14aa5effd29a 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -60,6 +60,7 @@ static struct header_ops lowpan_header_ops = { static struct lock_class_key lowpan_tx_busylock; static struct lock_class_key lowpan_netdev_xmit_lock_key; +static struct lock_class_key lowpan_qdisc_running_key; static void lowpan_set_lockdep_class_one(struct net_device *ldev, struct netdev_queue *txq, @@ -73,6 +74,8 @@ static int lowpan_dev_init(struct net_device *ldev) { netdev_for_each_tx_queue(ldev, lowpan_set_lockdep_class_one, NULL); ldev->qdisc_tx_busylock = &lowpan_tx_busylock; + ldev->qdisc_running_key = &lowpan_qdisc_running_key; + return 0; } diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index e253c26f31ac..c00d72d182fa 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -68,6 +68,8 @@ static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net) } static struct lock_class_key l2tp_eth_tx_busylock; +static struct lock_class_key l2tp_qdisc_running_key; + static int l2tp_eth_dev_init(struct net_device *dev) { struct l2tp_eth *priv = netdev_priv(dev); @@ -76,6 +78,8 @@ static int l2tp_eth_dev_init(struct net_device *dev) eth_hw_addr_random(dev); eth_broadcast_addr(dev->broadcast); dev->qdisc_tx_busylock = &l2tp_eth_tx_busylock; + dev->qdisc_running_key = &l2tp_qdisc_running_key; + return 0; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 269dd71b3828..cebea73e70ac 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -110,7 +110,7 @@ static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, /* * Transmit possibly several skbs, and handle the return status as - * required. Holding the __QDISC___STATE_RUNNING bit guarantees that + * required. Owning running seqcount bit guarantees that * only one CPU can execute this function. * * Returns to the caller: @@ -137,10 +137,10 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, HARD_TX_UNLOCK(dev, txq); } else { - spin_lock(root_lock); + spin_lock_nested(root_lock, SINGLE_DEPTH_NESTING); return qdisc_qlen(q); } - spin_lock(root_lock); + spin_lock_nested(root_lock, SINGLE_DEPTH_NESTING); if (dev_xmit_complete(ret)) { /* Driver sent out skb successfully or skb was consumed */ @@ -163,7 +163,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, /* * NOTE: Called under qdisc_lock(q) with locally disabled BH. * - * __QDISC___STATE_RUNNING guarantees only one CPU can process + * running seqcount guarantees only one CPU can process * this qdisc at a time. qdisc_lock(q) serializes queue accesses for * this queue. * @@ -379,6 +379,7 @@ struct Qdisc noop_qdisc = { .list = LIST_HEAD_INIT(noop_qdisc.list), .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), .dev_queue = &noop_netdev_queue, + .running = SEQCNT_ZERO(noop_qdisc.running), .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock), }; EXPORT_SYMBOL(noop_qdisc); @@ -537,6 +538,7 @@ struct Qdisc_ops pfifo_fast_ops __read_mostly = { EXPORT_SYMBOL(pfifo_fast_ops); static struct lock_class_key qdisc_tx_busylock; +static struct lock_class_key qdisc_running_key; struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, const struct Qdisc_ops *ops) @@ -570,6 +572,10 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, lockdep_set_class(&sch->busylock, dev->qdisc_tx_busylock ?: &qdisc_tx_busylock); + seqcount_init(&sch->running); + lockdep_set_class(&sch->running, + dev->qdisc_running_key ?: &qdisc_running_key); + sch->ops = ops; sch->enqueue = ops->enqueue; sch->dequeue = ops->dequeue; -- cgit v1.2.3 From f4502dd1da9b060a49d539eb754ff86cb97b89f0 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Wed, 8 Jun 2016 12:18:31 +0530 Subject: spi: Add DMA support for spi_flash_read() Few SPI devices provide accelerated read interfaces to read from SPI-NOR flash devices. These hardwares also support DMA to transfer data from flash to memory either via mem-to-mem DMA or dedicated slave DMA channels. Hence, add support for DMA in order to improve throughput and reduce CPU load. Use spi_map_buf() to get sg table for the buffer and pass it to SPI driver. Signed-off-by: Vignesh R Signed-off-by: Mark Brown --- drivers/spi/spi.c | 28 ++++++++++++++++++++++++++++ include/linux/spi/spi.h | 4 ++++ 2 files changed, 32 insertions(+) (limited to 'include/linux') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 77e6e45951f4..c9a8d544e467 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -849,6 +849,20 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) return 0; } #else /* !CONFIG_HAS_DMA */ +static inline int spi_map_buf(struct spi_master *master, + struct device *dev, struct sg_table *sgt, + void *buf, size_t len, + enum dma_data_direction dir) +{ + return -EINVAL; +} + +static inline void spi_unmap_buf(struct spi_master *master, + struct device *dev, struct sg_table *sgt, + enum dma_data_direction dir) +{ +} + static inline int __spi_map_msg(struct spi_master *master, struct spi_message *msg) { @@ -2725,6 +2739,7 @@ int spi_flash_read(struct spi_device *spi, { struct spi_master *master = spi->master; + struct device *rx_dev = NULL; int ret; if ((msg->opcode_nbits == SPI_NBITS_DUAL || @@ -2750,9 +2765,22 @@ int spi_flash_read(struct spi_device *spi, return ret; } } + mutex_lock(&master->bus_lock_mutex); + if (master->dma_rx) { + rx_dev = master->dma_rx->device->dev; + ret = spi_map_buf(master, rx_dev, &msg->rx_sg, + msg->buf, msg->len, + DMA_FROM_DEVICE); + if (!ret) + msg->cur_msg_mapped = true; + } ret = master->spi_flash_read(spi, msg); + if (msg->cur_msg_mapped) + spi_unmap_buf(master, rx_dev, &msg->rx_sg, + DMA_FROM_DEVICE); mutex_unlock(&master->bus_lock_mutex); + if (master->auto_runtime_pm) pm_runtime_put(master->dev.parent); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 1f03483f61e5..7b53af4ba5f8 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1143,6 +1143,8 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd) * @opcode_nbits: number of lines to send opcode * @addr_nbits: number of lines to send address * @data_nbits: number of lines for data + * @rx_sg: Scatterlist for receive data read from flash + * @cur_msg_mapped: message has been mapped for DMA */ struct spi_flash_read_message { void *buf; @@ -1155,6 +1157,8 @@ struct spi_flash_read_message { u8 opcode_nbits; u8 addr_nbits; u8 data_nbits; + struct sg_table rx_sg; + bool cur_msg_mapped; }; /* SPI core interface for flash read support */ -- cgit v1.2.3 From 331b6d8c7afc2e5b900b9dcd850c265e1ba8d8e7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Sun, 22 May 2016 12:48:27 +0200 Subject: locking/barriers: Validate lockless_dereference() is used on a pointer type Use the type to validate the argument @p is indeed a pointer type. Signed-off-by: Peter Zijlstra (Intel) Cc: Alexey Dobriyan Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Paul McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20160522104827.GP3193@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- include/linux/compiler.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 793c0829e3a3..06f27fd9d760 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -545,10 +545,14 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s * Similar to rcu_dereference(), but for situations where the pointed-to * object's lifetime is managed by something other than RCU. That * "something other" might be reference counting or simple immortality. + * + * The seemingly unused void * variable is to validate @p is indeed a pointer + * type. All pointer types silently cast to void *. */ #define lockless_dereference(p) \ ({ \ typeof(p) _________p1 = READ_ONCE(p); \ + __maybe_unused const void * const _________p2 = _________p1; \ smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ (_________p1); \ }) -- cgit v1.2.3 From 8ee62b1870be8e630158701632a533d0378e15b8 Mon Sep 17 00:00:00 2001 From: Jason Low Date: Fri, 3 Jun 2016 22:26:02 -0700 Subject: locking/rwsem: Convert sem->count to 'atomic_long_t' Convert the rwsem count variable to an atomic_long_t since we use it as an atomic variable. This also allows us to remove the rwsem_atomic_{add,update}() "abstraction" which would now be an unnecesary level of indirection. In follow up patches, we also remove the rwsem_atomic_{add,update}() definitions across the various architectures. Suggested-by: Peter Zijlstra Signed-off-by: Jason Low [ Build warning fixes on various architectures. ] Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Davidlohr Bueso Cc: Fenghua Yu Cc: Heiko Carstens Cc: Jason Low Cc: Linus Torvalds Cc: Martin Schwidefsky Cc: Paul E. McKenney Cc: Peter Hurley Cc: Terry Rudd Cc: Thomas Gleixner Cc: Tim Chen Cc: Tony Luck Cc: Waiman Long Link: http://lkml.kernel.org/r/1465017963-4839-2-git-send-email-jason.low2@hpe.com Signed-off-by: Ingo Molnar --- arch/alpha/include/asm/rwsem.h | 26 +++++++++++++------------- arch/ia64/include/asm/rwsem.h | 24 ++++++++++++------------ include/asm-generic/rwsem.h | 6 +++--- include/linux/rwsem.h | 8 +++++--- kernel/locking/rwsem-xadd.c | 32 +++++++++++++++++--------------- 5 files changed, 50 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/include/asm/rwsem.h b/arch/alpha/include/asm/rwsem.h index 0131a7058778..b40021aabb9f 100644 --- a/arch/alpha/include/asm/rwsem.h +++ b/arch/alpha/include/asm/rwsem.h @@ -25,8 +25,8 @@ static inline void __down_read(struct rw_semaphore *sem) { long oldcount; #ifndef CONFIG_SMP - oldcount = sem->count; - sem->count += RWSEM_ACTIVE_READ_BIAS; + oldcount = sem->count.counter; + sem->count.counter += RWSEM_ACTIVE_READ_BIAS; #else long temp; __asm__ __volatile__( @@ -52,13 +52,13 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) { long old, new, res; - res = sem->count; + res = atomic_long_read(&sem->count); do { new = res + RWSEM_ACTIVE_READ_BIAS; if (new <= 0) break; old = res; - res = cmpxchg(&sem->count, old, new); + res = atomic_long_cmpxchg(&sem->count, old, new); } while (res != old); return res >= 0 ? 1 : 0; } @@ -67,8 +67,8 @@ static inline long ___down_write(struct rw_semaphore *sem) { long oldcount; #ifndef CONFIG_SMP - oldcount = sem->count; - sem->count += RWSEM_ACTIVE_WRITE_BIAS; + oldcount = sem->count.counter; + sem->count.counter += RWSEM_ACTIVE_WRITE_BIAS; #else long temp; __asm__ __volatile__( @@ -106,7 +106,7 @@ static inline int __down_write_killable(struct rw_semaphore *sem) */ static inline int __down_write_trylock(struct rw_semaphore *sem) { - long ret = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, + long ret = atomic_long_cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); if (ret == RWSEM_UNLOCKED_VALUE) return 1; @@ -117,8 +117,8 @@ static inline void __up_read(struct rw_semaphore *sem) { long oldcount; #ifndef CONFIG_SMP - oldcount = sem->count; - sem->count -= RWSEM_ACTIVE_READ_BIAS; + oldcount = sem->count.counter; + sem->count.counter -= RWSEM_ACTIVE_READ_BIAS; #else long temp; __asm__ __volatile__( @@ -142,8 +142,8 @@ static inline void __up_write(struct rw_semaphore *sem) { long count; #ifndef CONFIG_SMP - sem->count -= RWSEM_ACTIVE_WRITE_BIAS; - count = sem->count; + sem->count.counter -= RWSEM_ACTIVE_WRITE_BIAS; + count = sem->count.counter; #else long temp; __asm__ __volatile__( @@ -171,8 +171,8 @@ static inline void __downgrade_write(struct rw_semaphore *sem) { long oldcount; #ifndef CONFIG_SMP - oldcount = sem->count; - sem->count -= RWSEM_WAITING_BIAS; + oldcount = sem->count.counter; + sem->count.counter -= RWSEM_WAITING_BIAS; #else long temp; __asm__ __volatile__( diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h index 8b23e070b844..c5d544f188ed 100644 --- a/arch/ia64/include/asm/rwsem.h +++ b/arch/ia64/include/asm/rwsem.h @@ -40,7 +40,7 @@ static inline void __down_read (struct rw_semaphore *sem) { - long result = ia64_fetchadd8_acq((unsigned long *)&sem->count, 1); + long result = ia64_fetchadd8_acq((unsigned long *)&sem->count.counter, 1); if (result < 0) rwsem_down_read_failed(sem); @@ -55,9 +55,9 @@ ___down_write (struct rw_semaphore *sem) long old, new; do { - old = sem->count; + old = atomic_long_read(&sem->count); new = old + RWSEM_ACTIVE_WRITE_BIAS; - } while (cmpxchg_acq(&sem->count, old, new) != old); + } while (atomic_long_cmpxchg_acquire(&sem->count, old, new) != old); return old; } @@ -85,7 +85,7 @@ __down_write_killable (struct rw_semaphore *sem) static inline void __up_read (struct rw_semaphore *sem) { - long result = ia64_fetchadd8_rel((unsigned long *)&sem->count, -1); + long result = ia64_fetchadd8_rel((unsigned long *)&sem->count.counter, -1); if (result < 0 && (--result & RWSEM_ACTIVE_MASK) == 0) rwsem_wake(sem); @@ -100,9 +100,9 @@ __up_write (struct rw_semaphore *sem) long old, new; do { - old = sem->count; + old = atomic_long_read(&sem->count); new = old - RWSEM_ACTIVE_WRITE_BIAS; - } while (cmpxchg_rel(&sem->count, old, new) != old); + } while (atomic_long_cmpxchg_release(&sem->count, old, new) != old); if (new < 0 && (new & RWSEM_ACTIVE_MASK) == 0) rwsem_wake(sem); @@ -115,8 +115,8 @@ static inline int __down_read_trylock (struct rw_semaphore *sem) { long tmp; - while ((tmp = sem->count) >= 0) { - if (tmp == cmpxchg_acq(&sem->count, tmp, tmp+1)) { + while ((tmp = atomic_long_read(&sem->count)) >= 0) { + if (tmp == atomic_long_cmpxchg_acquire(&sem->count, tmp, tmp+1)) { return 1; } } @@ -129,8 +129,8 @@ __down_read_trylock (struct rw_semaphore *sem) static inline int __down_write_trylock (struct rw_semaphore *sem) { - long tmp = cmpxchg_acq(&sem->count, RWSEM_UNLOCKED_VALUE, - RWSEM_ACTIVE_WRITE_BIAS); + long tmp = atomic_long_cmpxchg_acquire(&sem->count, + RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); return tmp == RWSEM_UNLOCKED_VALUE; } @@ -143,9 +143,9 @@ __downgrade_write (struct rw_semaphore *sem) long old, new; do { - old = sem->count; + old = atomic_long_read(&sem->count); new = old - RWSEM_WAITING_BIAS; - } while (cmpxchg_rel(&sem->count, old, new) != old); + } while (atomic_long_cmpxchg_release(&sem->count, old, new) != old); if (old < 0) rwsem_downgrade_wake(sem); diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h index 3fc94a046bf5..a3a93eca766c 100644 --- a/include/asm-generic/rwsem.h +++ b/include/asm-generic/rwsem.h @@ -41,8 +41,8 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) { long tmp; - while ((tmp = sem->count) >= 0) { - if (tmp == cmpxchg_acquire(&sem->count, tmp, + while ((tmp = atomic_long_read(&sem->count)) >= 0) { + if (tmp == atomic_long_cmpxchg_acquire(&sem->count, tmp, tmp + RWSEM_ACTIVE_READ_BIAS)) { return 1; } @@ -79,7 +79,7 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) { long tmp; - tmp = cmpxchg_acquire(&sem->count, RWSEM_UNLOCKED_VALUE, + tmp = atomic_long_cmpxchg_acquire(&sem->count, RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); return tmp == RWSEM_UNLOCKED_VALUE; } diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index d37fbb34d06f..dd1d14250340 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h @@ -23,10 +23,11 @@ struct rw_semaphore; #ifdef CONFIG_RWSEM_GENERIC_SPINLOCK #include /* use a generic implementation */ +#define __RWSEM_INIT_COUNT(name) .count = RWSEM_UNLOCKED_VALUE #else /* All arch specific implementations share the same struct */ struct rw_semaphore { - long count; + atomic_long_t count; struct list_head wait_list; raw_spinlock_t wait_lock; #ifdef CONFIG_RWSEM_SPIN_ON_OWNER @@ -54,9 +55,10 @@ extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); /* In all implementations count != 0 means locked */ static inline int rwsem_is_locked(struct rw_semaphore *sem) { - return sem->count != 0; + return atomic_long_read(&sem->count) != 0; } +#define __RWSEM_INIT_COUNT(name) .count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE) #endif /* Common initializer macros and functions */ @@ -74,7 +76,7 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem) #endif #define __RWSEM_INITIALIZER(name) \ - { .count = RWSEM_UNLOCKED_VALUE, \ + { __RWSEM_INIT_COUNT(name), \ .wait_list = LIST_HEAD_INIT((name).wait_list), \ .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \ __RWSEM_OPT_INIT(name) \ diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index b957da7fcb19..63b40a5c62ec 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -80,7 +80,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name, debug_check_no_locks_freed((void *)sem, sizeof(*sem)); lockdep_init_map(&sem->dep_map, name, key, 0); #endif - sem->count = RWSEM_UNLOCKED_VALUE; + atomic_long_set(&sem->count, RWSEM_UNLOCKED_VALUE); raw_spin_lock_init(&sem->wait_lock); INIT_LIST_HEAD(&sem->wait_list); #ifdef CONFIG_RWSEM_SPIN_ON_OWNER @@ -153,10 +153,11 @@ __rwsem_mark_wake(struct rw_semaphore *sem, if (wake_type != RWSEM_WAKE_READ_OWNED) { adjustment = RWSEM_ACTIVE_READ_BIAS; try_reader_grant: - oldcount = rwsem_atomic_update(adjustment, sem) - adjustment; + oldcount = atomic_long_add_return(adjustment, &sem->count) - adjustment; + if (unlikely(oldcount < RWSEM_WAITING_BIAS)) { /* A writer stole the lock. Undo our reader grant. */ - if (rwsem_atomic_update(-adjustment, sem) & + if (atomic_long_sub_return(adjustment, &sem->count) & RWSEM_ACTIVE_MASK) goto out; /* Last active locker left. Retry waking readers. */ @@ -186,7 +187,7 @@ __rwsem_mark_wake(struct rw_semaphore *sem, adjustment -= RWSEM_WAITING_BIAS; if (adjustment) - rwsem_atomic_add(adjustment, sem); + atomic_long_add(adjustment, &sem->count); next = sem->wait_list.next; loop = woken; @@ -233,7 +234,7 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem) list_add_tail(&waiter.list, &sem->wait_list); /* we're now waiting on the lock, but no longer actively locking */ - count = rwsem_atomic_update(adjustment, sem); + count = atomic_long_add_return(adjustment, &sem->count); /* If there are no active locks, wake the front queued process(es). * @@ -282,7 +283,8 @@ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem) RWSEM_ACTIVE_WRITE_BIAS : RWSEM_ACTIVE_WRITE_BIAS + RWSEM_WAITING_BIAS; - if (cmpxchg_acquire(&sem->count, RWSEM_WAITING_BIAS, count) == RWSEM_WAITING_BIAS) { + if (atomic_long_cmpxchg_acquire(&sem->count, RWSEM_WAITING_BIAS, count) + == RWSEM_WAITING_BIAS) { rwsem_set_owner(sem); return true; } @@ -296,13 +298,13 @@ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem) */ static inline bool rwsem_try_write_lock_unqueued(struct rw_semaphore *sem) { - long old, count = READ_ONCE(sem->count); + long old, count = atomic_long_read(&sem->count); while (true) { if (!(count == 0 || count == RWSEM_WAITING_BIAS)) return false; - old = cmpxchg_acquire(&sem->count, count, + old = atomic_long_cmpxchg_acquire(&sem->count, count, count + RWSEM_ACTIVE_WRITE_BIAS); if (old == count) { rwsem_set_owner(sem); @@ -324,7 +326,7 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem) rcu_read_lock(); owner = READ_ONCE(sem->owner); if (!owner) { - long count = READ_ONCE(sem->count); + long count = atomic_long_read(&sem->count); /* * If sem->owner is not set, yet we have just recently entered the * slowpath with the lock being active, then there is a possibility @@ -375,7 +377,7 @@ bool rwsem_spin_on_owner(struct rw_semaphore *sem, struct task_struct *owner) * held by readers. Check the counter to verify the * state. */ - count = READ_ONCE(sem->count); + count = atomic_long_read(&sem->count); return (count == 0 || count == RWSEM_WAITING_BIAS); } @@ -460,7 +462,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) WAKE_Q(wake_q); /* undo write bias from down_write operation, stop active locking */ - count = rwsem_atomic_update(-RWSEM_ACTIVE_WRITE_BIAS, sem); + count = atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, &sem->count); /* do optimistic spinning and steal lock if possible */ if (rwsem_optimistic_spin(sem)) @@ -483,7 +485,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) /* we're now waiting on the lock, but no longer actively locking */ if (waiting) { - count = READ_ONCE(sem->count); + count = atomic_long_read(&sem->count); /* * If there were already threads queued before us and there are @@ -505,7 +507,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) } } else - count = rwsem_atomic_update(RWSEM_WAITING_BIAS, sem); + count = atomic_long_add_return(RWSEM_WAITING_BIAS, &sem->count); /* wait until we successfully acquire the lock */ set_current_state(state); @@ -521,7 +523,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) schedule(); set_current_state(state); - } while ((count = sem->count) & RWSEM_ACTIVE_MASK); + } while ((count = atomic_long_read(&sem->count)) & RWSEM_ACTIVE_MASK); raw_spin_lock_irq(&sem->wait_lock); } @@ -536,7 +538,7 @@ out_nolock: raw_spin_lock_irq(&sem->wait_lock); list_del(&waiter.list); if (list_empty(&sem->wait_list)) - rwsem_atomic_update(-RWSEM_WAITING_BIAS, sem); + atomic_long_add(-RWSEM_WAITING_BIAS, &sem->count); else __rwsem_mark_wake(sem, RWSEM_WAKE_ANY, &wake_q); raw_spin_unlock_irq(&sem->wait_lock); -- cgit v1.2.3 From 6ad8c632ee48ae099aa13704ef18a641220fe211 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Wed, 8 Jun 2016 06:22:10 -0400 Subject: qed: Add support for query/config dcbx. Query API reads the dcbx data from the device shared memory and return it to the caller. The config API configures the user provided dcbx values on the device, and initiates the dcbx negotiation with the peer. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 533 ++++++++++++++++++++++++++++- drivers/net/ethernet/qlogic/qed/qed_dcbx.h | 28 ++ drivers/net/ethernet/qlogic/qed/qed_hsi.h | 3 + include/linux/qed/qed_if.h | 90 +++++ 4 files changed, 653 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index 21ec1c2df2c7..e782484d2d89 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -252,7 +252,7 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, if (p_data->arr[type].update) continue; - enable = (type == DCBX_PROTOCOL_ETH) ? false : dcbx_enabled; + enable = !(type == DCBX_PROTOCOL_ETH); qed_dcbx_update_app_info(p_data, p_hwfn, enable, true, priority, tc, type); } @@ -351,6 +351,293 @@ qed_dcbx_copy_mib(struct qed_hwfn *p_hwfn, return rc; } +#ifdef CONFIG_DCB +static void +qed_dcbx_get_priority_info(struct qed_hwfn *p_hwfn, + struct qed_dcbx_app_prio *p_prio, + struct qed_dcbx_results *p_results) +{ + u8 val; + + p_prio->roce = QED_DCBX_INVALID_PRIORITY; + p_prio->roce_v2 = QED_DCBX_INVALID_PRIORITY; + p_prio->iscsi = QED_DCBX_INVALID_PRIORITY; + p_prio->fcoe = QED_DCBX_INVALID_PRIORITY; + + if (p_results->arr[DCBX_PROTOCOL_ROCE].update && + p_results->arr[DCBX_PROTOCOL_ROCE].enable) + p_prio->roce = p_results->arr[DCBX_PROTOCOL_ROCE].priority; + + if (p_results->arr[DCBX_PROTOCOL_ROCE_V2].update && + p_results->arr[DCBX_PROTOCOL_ROCE_V2].enable) { + val = p_results->arr[DCBX_PROTOCOL_ROCE_V2].priority; + p_prio->roce_v2 = val; + } + + if (p_results->arr[DCBX_PROTOCOL_ISCSI].update && + p_results->arr[DCBX_PROTOCOL_ISCSI].enable) + p_prio->iscsi = p_results->arr[DCBX_PROTOCOL_ISCSI].priority; + + if (p_results->arr[DCBX_PROTOCOL_FCOE].update && + p_results->arr[DCBX_PROTOCOL_FCOE].enable) + p_prio->fcoe = p_results->arr[DCBX_PROTOCOL_FCOE].priority; + + if (p_results->arr[DCBX_PROTOCOL_ETH].update && + p_results->arr[DCBX_PROTOCOL_ETH].enable) + p_prio->eth = p_results->arr[DCBX_PROTOCOL_ETH].priority; + + DP_VERBOSE(p_hwfn, QED_MSG_DCB, + "Priorities: iscsi %d, roce %d, roce v2 %d, fcoe %d, eth %d\n", + p_prio->iscsi, p_prio->roce, p_prio->roce_v2, p_prio->fcoe, + p_prio->eth); +} + +static void +qed_dcbx_get_app_data(struct qed_hwfn *p_hwfn, + struct dcbx_app_priority_feature *p_app, + struct dcbx_app_priority_entry *p_tbl, + struct qed_dcbx_params *p_params) +{ + struct qed_app_entry *entry; + u8 pri_map; + int i; + + p_params->app_willing = QED_MFW_GET_FIELD(p_app->flags, + DCBX_APP_WILLING); + p_params->app_valid = QED_MFW_GET_FIELD(p_app->flags, DCBX_APP_ENABLED); + p_params->app_error = QED_MFW_GET_FIELD(p_app->flags, DCBX_APP_ERROR); + p_params->num_app_entries = QED_MFW_GET_FIELD(p_app->flags, + DCBX_APP_NUM_ENTRIES); + for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { + entry = &p_params->app_entry[i]; + entry->ethtype = !(QED_MFW_GET_FIELD(p_tbl[i].entry, + DCBX_APP_SF)); + pri_map = QED_MFW_GET_FIELD(p_tbl[i].entry, DCBX_APP_PRI_MAP); + entry->prio = ffs(pri_map) - 1; + entry->proto_id = QED_MFW_GET_FIELD(p_tbl[i].entry, + DCBX_APP_PROTOCOL_ID); + qed_dcbx_get_app_protocol_type(p_hwfn, p_tbl[i].entry, + entry->proto_id, + &entry->proto_type); + } + + DP_VERBOSE(p_hwfn, QED_MSG_DCB, + "APP params: willing %d, valid %d error = %d\n", + p_params->app_willing, p_params->app_valid, + p_params->app_error); +} + +static void +qed_dcbx_get_pfc_data(struct qed_hwfn *p_hwfn, + u32 pfc, struct qed_dcbx_params *p_params) +{ + u8 pfc_map; + + p_params->pfc.willing = QED_MFW_GET_FIELD(pfc, DCBX_PFC_WILLING); + p_params->pfc.max_tc = QED_MFW_GET_FIELD(pfc, DCBX_PFC_CAPS); + p_params->pfc.enabled = QED_MFW_GET_FIELD(pfc, DCBX_PFC_ENABLED); + pfc_map = QED_MFW_GET_FIELD(pfc, DCBX_PFC_PRI_EN_BITMAP); + p_params->pfc.prio[0] = !!(pfc_map & DCBX_PFC_PRI_EN_BITMAP_PRI_0); + p_params->pfc.prio[1] = !!(pfc_map & DCBX_PFC_PRI_EN_BITMAP_PRI_1); + p_params->pfc.prio[2] = !!(pfc_map & DCBX_PFC_PRI_EN_BITMAP_PRI_2); + p_params->pfc.prio[3] = !!(pfc_map & DCBX_PFC_PRI_EN_BITMAP_PRI_3); + p_params->pfc.prio[4] = !!(pfc_map & DCBX_PFC_PRI_EN_BITMAP_PRI_4); + p_params->pfc.prio[5] = !!(pfc_map & DCBX_PFC_PRI_EN_BITMAP_PRI_5); + p_params->pfc.prio[6] = !!(pfc_map & DCBX_PFC_PRI_EN_BITMAP_PRI_6); + p_params->pfc.prio[7] = !!(pfc_map & DCBX_PFC_PRI_EN_BITMAP_PRI_7); + + DP_VERBOSE(p_hwfn, QED_MSG_DCB, + "PFC params: willing %d, pfc_bitmap %d\n", + p_params->pfc.willing, pfc_map); +} + +static void +qed_dcbx_get_ets_data(struct qed_hwfn *p_hwfn, + struct dcbx_ets_feature *p_ets, + struct qed_dcbx_params *p_params) +{ + u32 bw_map[2], tsa_map[2], pri_map; + int i; + + p_params->ets_willing = QED_MFW_GET_FIELD(p_ets->flags, + DCBX_ETS_WILLING); + p_params->ets_enabled = QED_MFW_GET_FIELD(p_ets->flags, + DCBX_ETS_ENABLED); + p_params->ets_cbs = QED_MFW_GET_FIELD(p_ets->flags, DCBX_ETS_CBS); + p_params->max_ets_tc = QED_MFW_GET_FIELD(p_ets->flags, + DCBX_ETS_MAX_TCS); + DP_VERBOSE(p_hwfn, QED_MSG_DCB, + "ETS params: willing %d, ets_cbs %d pri_tc_tbl_0 %x max_ets_tc %d\n", + p_params->ets_willing, + p_params->ets_cbs, + p_ets->pri_tc_tbl[0], p_params->max_ets_tc); + + /* 8 bit tsa and bw data corresponding to each of the 8 TC's are + * encoded in a type u32 array of size 2. + */ + bw_map[0] = be32_to_cpu(p_ets->tc_bw_tbl[0]); + bw_map[1] = be32_to_cpu(p_ets->tc_bw_tbl[1]); + tsa_map[0] = be32_to_cpu(p_ets->tc_tsa_tbl[0]); + tsa_map[1] = be32_to_cpu(p_ets->tc_tsa_tbl[1]); + pri_map = be32_to_cpu(p_ets->pri_tc_tbl[0]); + for (i = 0; i < QED_MAX_PFC_PRIORITIES; i++) { + p_params->ets_tc_bw_tbl[i] = ((u8 *)bw_map)[i]; + p_params->ets_tc_tsa_tbl[i] = ((u8 *)tsa_map)[i]; + p_params->ets_pri_tc_tbl[i] = QED_DCBX_PRIO2TC(pri_map, i); + DP_VERBOSE(p_hwfn, QED_MSG_DCB, + "elem %d bw_tbl %x tsa_tbl %x\n", + i, p_params->ets_tc_bw_tbl[i], + p_params->ets_tc_tsa_tbl[i]); + } +} + +static void +qed_dcbx_get_common_params(struct qed_hwfn *p_hwfn, + struct dcbx_app_priority_feature *p_app, + struct dcbx_app_priority_entry *p_tbl, + struct dcbx_ets_feature *p_ets, + u32 pfc, struct qed_dcbx_params *p_params) +{ + qed_dcbx_get_app_data(p_hwfn, p_app, p_tbl, p_params); + qed_dcbx_get_ets_data(p_hwfn, p_ets, p_params); + qed_dcbx_get_pfc_data(p_hwfn, pfc, p_params); +} + +static void +qed_dcbx_get_local_params(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_dcbx_get *params) +{ + struct dcbx_features *p_feat; + + p_feat = &p_hwfn->p_dcbx_info->local_admin.features; + qed_dcbx_get_common_params(p_hwfn, &p_feat->app, + p_feat->app.app_pri_tbl, &p_feat->ets, + p_feat->pfc, ¶ms->local.params); + params->local.valid = true; +} + +static void +qed_dcbx_get_remote_params(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, struct qed_dcbx_get *params) +{ + struct dcbx_features *p_feat; + + p_feat = &p_hwfn->p_dcbx_info->remote.features; + qed_dcbx_get_common_params(p_hwfn, &p_feat->app, + p_feat->app.app_pri_tbl, &p_feat->ets, + p_feat->pfc, ¶ms->remote.params); + params->remote.valid = true; +} + +static void +qed_dcbx_get_operational_params(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_dcbx_get *params) +{ + struct qed_dcbx_operational_params *p_operational; + struct qed_dcbx_results *p_results; + struct dcbx_features *p_feat; + bool enabled, err; + u32 flags; + bool val; + + flags = p_hwfn->p_dcbx_info->operational.flags; + + /* If DCBx version is non zero, then negotiation + * was successfuly performed + */ + p_operational = ¶ms->operational; + enabled = !!(QED_MFW_GET_FIELD(flags, DCBX_CONFIG_VERSION) != + DCBX_CONFIG_VERSION_DISABLED); + if (!enabled) { + p_operational->enabled = enabled; + p_operational->valid = false; + return; + } + + p_feat = &p_hwfn->p_dcbx_info->operational.features; + p_results = &p_hwfn->p_dcbx_info->results; + + val = !!(QED_MFW_GET_FIELD(flags, DCBX_CONFIG_VERSION) == + DCBX_CONFIG_VERSION_IEEE); + p_operational->ieee = val; + val = !!(QED_MFW_GET_FIELD(flags, DCBX_CONFIG_VERSION) == + DCBX_CONFIG_VERSION_CEE); + p_operational->cee = val; + + DP_VERBOSE(p_hwfn, QED_MSG_DCB, "Version support: ieee %d, cee %d\n", + p_operational->ieee, p_operational->cee); + + qed_dcbx_get_common_params(p_hwfn, &p_feat->app, + p_feat->app.app_pri_tbl, &p_feat->ets, + p_feat->pfc, ¶ms->operational.params); + qed_dcbx_get_priority_info(p_hwfn, &p_operational->app_prio, p_results); + err = QED_MFW_GET_FIELD(p_feat->app.flags, DCBX_APP_ERROR); + p_operational->err = err; + p_operational->enabled = enabled; + p_operational->valid = true; +} + +static void +qed_dcbx_get_local_lldp_params(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_dcbx_get *params) +{ + struct lldp_config_params_s *p_local; + + p_local = &p_hwfn->p_dcbx_info->lldp_local[LLDP_NEAREST_BRIDGE]; + + memcpy(params->lldp_local.local_chassis_id, p_local->local_chassis_id, + ARRAY_SIZE(p_local->local_chassis_id)); + memcpy(params->lldp_local.local_port_id, p_local->local_port_id, + ARRAY_SIZE(p_local->local_port_id)); +} + +static void +qed_dcbx_get_remote_lldp_params(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + struct qed_dcbx_get *params) +{ + struct lldp_status_params_s *p_remote; + + p_remote = &p_hwfn->p_dcbx_info->lldp_remote[LLDP_NEAREST_BRIDGE]; + + memcpy(params->lldp_remote.peer_chassis_id, p_remote->peer_chassis_id, + ARRAY_SIZE(p_remote->peer_chassis_id)); + memcpy(params->lldp_remote.peer_port_id, p_remote->peer_port_id, + ARRAY_SIZE(p_remote->peer_port_id)); +} + +static int +qed_dcbx_get_params(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_dcbx_get *p_params, + enum qed_mib_read_type type) +{ + switch (type) { + case QED_DCBX_REMOTE_MIB: + qed_dcbx_get_remote_params(p_hwfn, p_ptt, p_params); + break; + case QED_DCBX_LOCAL_MIB: + qed_dcbx_get_local_params(p_hwfn, p_ptt, p_params); + break; + case QED_DCBX_OPERATIONAL_MIB: + qed_dcbx_get_operational_params(p_hwfn, p_ptt, p_params); + break; + case QED_DCBX_REMOTE_LLDP_MIB: + qed_dcbx_get_remote_lldp_params(p_hwfn, p_ptt, p_params); + break; + case QED_DCBX_LOCAL_LLDP_MIB: + qed_dcbx_get_local_lldp_params(p_hwfn, p_ptt, p_params); + break; + default: + DP_ERR(p_hwfn, "MIB read err, unknown mib type %d\n", type); + return -EINVAL; + } + + return 0; +} +#endif + static int qed_dcbx_read_local_lldp_mib(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { @@ -561,3 +848,247 @@ void qed_dcbx_set_pf_update_params(struct qed_dcbx_results *p_src, p_dcb_data = &p_dest->eth_dcb_data; qed_dcbx_update_protocol_data(p_dcb_data, p_src, DCBX_PROTOCOL_ETH); } + +#ifdef CONFIG_DCB +static int qed_dcbx_query_params(struct qed_hwfn *p_hwfn, + struct qed_dcbx_get *p_get, + enum qed_mib_read_type type) +{ + struct qed_ptt *p_ptt; + int rc; + + p_ptt = qed_ptt_acquire(p_hwfn); + if (!p_ptt) + return -EBUSY; + + rc = qed_dcbx_read_mib(p_hwfn, p_ptt, type); + if (rc) + goto out; + + rc = qed_dcbx_get_params(p_hwfn, p_ptt, p_get, type); + +out: + qed_ptt_release(p_hwfn, p_ptt); + return rc; +} + +static void +qed_dcbx_set_pfc_data(struct qed_hwfn *p_hwfn, + u32 *pfc, struct qed_dcbx_params *p_params) +{ + u8 pfc_map = 0; + int i; + + if (p_params->pfc.willing) + *pfc |= DCBX_PFC_WILLING_MASK; + else + *pfc &= ~DCBX_PFC_WILLING_MASK; + + if (p_params->pfc.enabled) + *pfc |= DCBX_PFC_ENABLED_MASK; + else + *pfc &= ~DCBX_PFC_ENABLED_MASK; + + *pfc &= ~DCBX_PFC_CAPS_MASK; + *pfc |= (u32)p_params->pfc.max_tc << DCBX_PFC_CAPS_SHIFT; + + for (i = 0; i < QED_MAX_PFC_PRIORITIES; i++) + if (p_params->pfc.prio[i]) + pfc_map |= BIT(i); + + *pfc |= (pfc_map << DCBX_PFC_PRI_EN_BITMAP_SHIFT); + + DP_VERBOSE(p_hwfn, QED_MSG_DCB, "pfc = 0x%x\n", *pfc); +} + +static void +qed_dcbx_set_ets_data(struct qed_hwfn *p_hwfn, + struct dcbx_ets_feature *p_ets, + struct qed_dcbx_params *p_params) +{ + u8 *bw_map, *tsa_map; + u32 val; + int i; + + if (p_params->ets_willing) + p_ets->flags |= DCBX_ETS_WILLING_MASK; + else + p_ets->flags &= ~DCBX_ETS_WILLING_MASK; + + if (p_params->ets_cbs) + p_ets->flags |= DCBX_ETS_CBS_MASK; + else + p_ets->flags &= ~DCBX_ETS_CBS_MASK; + + if (p_params->ets_enabled) + p_ets->flags |= DCBX_ETS_ENABLED_MASK; + else + p_ets->flags &= ~DCBX_ETS_ENABLED_MASK; + + p_ets->flags &= ~DCBX_ETS_MAX_TCS_MASK; + p_ets->flags |= (u32)p_params->max_ets_tc << DCBX_ETS_MAX_TCS_SHIFT; + + bw_map = (u8 *)&p_ets->tc_bw_tbl[0]; + tsa_map = (u8 *)&p_ets->tc_tsa_tbl[0]; + p_ets->pri_tc_tbl[0] = 0; + for (i = 0; i < QED_MAX_PFC_PRIORITIES; i++) { + bw_map[i] = p_params->ets_tc_bw_tbl[i]; + tsa_map[i] = p_params->ets_tc_tsa_tbl[i]; + /* Copy the priority value to the corresponding 4 bits in the + * traffic class table. + */ + val = (((u32)p_params->ets_pri_tc_tbl[i]) << ((7 - i) * 4)); + p_ets->pri_tc_tbl[0] |= val; + } + p_ets->pri_tc_tbl[0] = cpu_to_be32(p_ets->pri_tc_tbl[0]); + for (i = 0; i < 2; i++) { + p_ets->tc_bw_tbl[i] = cpu_to_be32(p_ets->tc_bw_tbl[i]); + p_ets->tc_tsa_tbl[i] = cpu_to_be32(p_ets->tc_tsa_tbl[i]); + } +} + +static void +qed_dcbx_set_app_data(struct qed_hwfn *p_hwfn, + struct dcbx_app_priority_feature *p_app, + struct qed_dcbx_params *p_params) +{ + u32 *entry; + int i; + + if (p_params->app_willing) + p_app->flags |= DCBX_APP_WILLING_MASK; + else + p_app->flags &= ~DCBX_APP_WILLING_MASK; + + if (p_params->app_valid) + p_app->flags |= DCBX_APP_ENABLED_MASK; + else + p_app->flags &= ~DCBX_APP_ENABLED_MASK; + + p_app->flags &= ~DCBX_APP_NUM_ENTRIES_MASK; + p_app->flags |= (u32)p_params->num_app_entries << + DCBX_APP_NUM_ENTRIES_SHIFT; + + for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { + entry = &p_app->app_pri_tbl[i].entry; + *entry &= ~DCBX_APP_SF_MASK; + if (p_params->app_entry[i].ethtype) + *entry |= ((u32)DCBX_APP_SF_ETHTYPE << + DCBX_APP_SF_SHIFT); + else + *entry |= ((u32)DCBX_APP_SF_PORT << DCBX_APP_SF_SHIFT); + *entry &= ~DCBX_APP_PROTOCOL_ID_MASK; + *entry |= ((u32)p_params->app_entry[i].proto_id << + DCBX_APP_PROTOCOL_ID_SHIFT); + *entry &= ~DCBX_APP_PRI_MAP_MASK; + *entry |= ((u32)(p_params->app_entry[i].prio) << + DCBX_APP_PRI_MAP_SHIFT); + } +} + +static void +qed_dcbx_set_local_params(struct qed_hwfn *p_hwfn, + struct dcbx_local_params *local_admin, + struct qed_dcbx_set *params) +{ + local_admin->flags = 0; + memcpy(&local_admin->features, + &p_hwfn->p_dcbx_info->operational.features, + sizeof(local_admin->features)); + + if (params->enabled) + local_admin->config = params->ver_num; + else + local_admin->config = DCBX_CONFIG_VERSION_DISABLED; + + if (params->override_flags & QED_DCBX_OVERRIDE_PFC_CFG) + qed_dcbx_set_pfc_data(p_hwfn, &local_admin->features.pfc, + ¶ms->config.params); + + if (params->override_flags & QED_DCBX_OVERRIDE_ETS_CFG) + qed_dcbx_set_ets_data(p_hwfn, &local_admin->features.ets, + ¶ms->config.params); + + if (params->override_flags & QED_DCBX_OVERRIDE_APP_CFG) + qed_dcbx_set_app_data(p_hwfn, &local_admin->features.app, + ¶ms->config.params); +} + +int qed_dcbx_config_params(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_dcbx_set *params, bool hw_commit) +{ + struct dcbx_local_params local_admin; + struct qed_dcbx_mib_meta_data data; + u32 resp = 0, param = 0; + int rc = 0; + + if (!hw_commit) { + memcpy(&p_hwfn->p_dcbx_info->set, params, + sizeof(struct qed_dcbx_set)); + return 0; + } + + /* clear set-parmas cache */ + memset(&p_hwfn->p_dcbx_info->set, 0, sizeof(p_hwfn->p_dcbx_info->set)); + + memset(&local_admin, 0, sizeof(local_admin)); + qed_dcbx_set_local_params(p_hwfn, &local_admin, params); + + data.addr = p_hwfn->mcp_info->port_addr + + offsetof(struct public_port, local_admin_dcbx_mib); + data.local_admin = &local_admin; + data.size = sizeof(struct dcbx_local_params); + qed_memcpy_to(p_hwfn, p_ptt, data.addr, data.local_admin, data.size); + + rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_DCBX, + 1 << DRV_MB_PARAM_LLDP_SEND_SHIFT, &resp, ¶m); + if (rc) + DP_NOTICE(p_hwfn, "Failed to send DCBX update request\n"); + + return rc; +} + +int qed_dcbx_get_config_params(struct qed_hwfn *p_hwfn, + struct qed_dcbx_set *params) +{ + struct qed_dcbx_get *dcbx_info; + int rc; + + if (p_hwfn->p_dcbx_info->set.config.valid) { + memcpy(params, &p_hwfn->p_dcbx_info->set, + sizeof(struct qed_dcbx_set)); + return 0; + } + + dcbx_info = kmalloc(sizeof(*dcbx_info), GFP_KERNEL); + if (!dcbx_info) { + DP_ERR(p_hwfn, "Failed to allocate struct qed_dcbx_info\n"); + return -ENOMEM; + } + + rc = qed_dcbx_query_params(p_hwfn, dcbx_info, QED_DCBX_OPERATIONAL_MIB); + if (rc) { + kfree(dcbx_info); + return rc; + } + + p_hwfn->p_dcbx_info->set.override_flags = 0; + p_hwfn->p_dcbx_info->set.ver_num = DCBX_CONFIG_VERSION_DISABLED; + if (dcbx_info->operational.cee) + p_hwfn->p_dcbx_info->set.ver_num |= DCBX_CONFIG_VERSION_CEE; + if (dcbx_info->operational.ieee) + p_hwfn->p_dcbx_info->set.ver_num |= DCBX_CONFIG_VERSION_IEEE; + + p_hwfn->p_dcbx_info->set.enabled = dcbx_info->operational.enabled; + memcpy(&p_hwfn->p_dcbx_info->set.config.params, + &dcbx_info->operational.params, + sizeof(struct qed_dcbx_admin_params)); + p_hwfn->p_dcbx_info->set.config.valid = true; + + memcpy(params, &p_hwfn->p_dcbx_info->set, sizeof(struct qed_dcbx_set)); + + kfree(dcbx_info); + + return 0; +} +#endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h index e7f834dbda2d..9ba681643d05 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h @@ -33,6 +33,24 @@ struct qed_dcbx_app_data { u8 tc; /* Traffic Class */ }; +#ifdef CONFIG_DCB +#define QED_DCBX_VERSION_DISABLED 0 +#define QED_DCBX_VERSION_IEEE 1 +#define QED_DCBX_VERSION_CEE 2 + +struct qed_dcbx_set { +#define QED_DCBX_OVERRIDE_STATE BIT(0) +#define QED_DCBX_OVERRIDE_PFC_CFG BIT(1) +#define QED_DCBX_OVERRIDE_ETS_CFG BIT(2) +#define QED_DCBX_OVERRIDE_APP_CFG BIT(3) +#define QED_DCBX_OVERRIDE_DSCP_CFG BIT(4) + u32 override_flags; + bool enabled; + struct qed_dcbx_admin_params config; + u32 ver_num; +}; +#endif + struct qed_dcbx_results { bool dcbx_enabled; u8 pf_id; @@ -55,6 +73,9 @@ struct qed_dcbx_info { struct qed_dcbx_results results; struct dcbx_mib operational; struct dcbx_mib remote; +#ifdef CONFIG_DCB + struct qed_dcbx_set set; +#endif u8 dcbx_cap; }; @@ -67,6 +88,13 @@ struct qed_dcbx_mib_meta_data { u32 addr; }; +#ifdef CONFIG_DCB +int qed_dcbx_get_config_params(struct qed_hwfn *, struct qed_dcbx_set *); + +int qed_dcbx_config_params(struct qed_hwfn *, + struct qed_ptt *, struct qed_dcbx_set *, bool); +#endif + /* QED local interface routines */ int qed_dcbx_mib_update_event(struct qed_hwfn *, diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 72e0ad6d16c6..592784019994 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -7244,6 +7244,9 @@ struct public_drv_mb { #define DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK 0x000000FF #define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT 8 #define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK 0x0000FF00 +#define DRV_MB_PARAM_LLDP_SEND_MASK 0x00000001 +#define DRV_MB_PARAM_LLDP_SEND_SHIFT 0 + #define DRV_MB_PARAM_SET_LED_MODE_OPER 0x0 #define DRV_MB_PARAM_SET_LED_MODE_ON 0x1 diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index e8cc49f9688a..e1d5122e8a96 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -34,6 +34,96 @@ enum dcbx_protocol_type { DCBX_MAX_PROTOCOL_TYPE }; +#ifdef CONFIG_DCB +#define QED_LLDP_CHASSIS_ID_STAT_LEN 4 +#define QED_LLDP_PORT_ID_STAT_LEN 4 +#define QED_DCBX_MAX_APP_PROTOCOL 32 +#define QED_MAX_PFC_PRIORITIES 8 +#define QED_DCBX_DSCP_SIZE 64 + +struct qed_dcbx_lldp_remote { + u32 peer_chassis_id[QED_LLDP_CHASSIS_ID_STAT_LEN]; + u32 peer_port_id[QED_LLDP_PORT_ID_STAT_LEN]; + bool enable_rx; + bool enable_tx; + u32 tx_interval; + u32 max_credit; +}; + +struct qed_dcbx_lldp_local { + u32 local_chassis_id[QED_LLDP_CHASSIS_ID_STAT_LEN]; + u32 local_port_id[QED_LLDP_PORT_ID_STAT_LEN]; +}; + +struct qed_dcbx_app_prio { + u8 roce; + u8 roce_v2; + u8 fcoe; + u8 iscsi; + u8 eth; +}; + +struct qed_dbcx_pfc_params { + bool willing; + bool enabled; + u8 prio[QED_MAX_PFC_PRIORITIES]; + u8 max_tc; +}; + +struct qed_app_entry { + bool ethtype; + bool enabled; + u8 prio; + u16 proto_id; + enum dcbx_protocol_type proto_type; +}; + +struct qed_dcbx_params { + struct qed_app_entry app_entry[QED_DCBX_MAX_APP_PROTOCOL]; + u16 num_app_entries; + bool app_willing; + bool app_valid; + bool app_error; + bool ets_willing; + bool ets_enabled; + bool ets_cbs; + bool valid; + u8 ets_pri_tc_tbl[QED_MAX_PFC_PRIORITIES]; + u8 ets_tc_bw_tbl[QED_MAX_PFC_PRIORITIES]; + u8 ets_tc_tsa_tbl[QED_MAX_PFC_PRIORITIES]; + struct qed_dbcx_pfc_params pfc; + u8 max_ets_tc; +}; + +struct qed_dcbx_admin_params { + struct qed_dcbx_params params; + bool valid; +}; + +struct qed_dcbx_remote_params { + struct qed_dcbx_params params; + bool valid; +}; + +struct qed_dcbx_operational_params { + struct qed_dcbx_app_prio app_prio; + struct qed_dcbx_params params; + bool valid; + bool enabled; + bool ieee; + bool cee; + u32 err; +}; + +struct qed_dcbx_get { + struct qed_dcbx_operational_params operational; + struct qed_dcbx_lldp_remote lldp_remote; + struct qed_dcbx_lldp_local lldp_local; + struct qed_dcbx_remote_params remote; + struct qed_dcbx_admin_params local; +}; +#endif + enum qed_led_mode { QED_LED_MODE_OFF, QED_LED_MODE_ON, -- cgit v1.2.3 From a1d8d8a51e8317269dd127d94b9de14f67d9563f Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Wed, 8 Jun 2016 06:22:11 -0400 Subject: qed: Add dcbnl support. This patch adds the implementation for both cee/ieee dcbnl callbacks by using the qed query/config APIs. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 1090 ++++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_l2.c | 7 + include/linux/qed/qed_eth_if.h | 62 ++ 3 files changed, 1159 insertions(+) (limited to 'include/linux') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index e782484d2d89..d0dc28f93c0e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,9 @@ #include "qed_dcbx.h" #include "qed_hsi.h" #include "qed_sp.h" +#ifdef CONFIG_DCB +#include +#endif #define QED_DCBX_MAX_MIB_READ_TRY (100) #define QED_ETH_TYPE_DEFAULT (0) @@ -1091,4 +1095,1090 @@ int qed_dcbx_get_config_params(struct qed_hwfn *p_hwfn, return 0; } + +static struct qed_dcbx_get *qed_dcbnl_get_dcbx(struct qed_hwfn *hwfn, + enum qed_mib_read_type type) +{ + struct qed_dcbx_get *dcbx_info; + + dcbx_info = kmalloc(sizeof(*dcbx_info), GFP_KERNEL); + if (!dcbx_info) { + DP_ERR(hwfn->cdev, "Failed to allocate memory for dcbx_info\n"); + return NULL; + } + + if (qed_dcbx_query_params(hwfn, dcbx_info, type)) { + kfree(dcbx_info); + return NULL; + } + + if ((type == QED_DCBX_OPERATIONAL_MIB) && + !dcbx_info->operational.enabled) { + DP_INFO(hwfn, "DCBX is not enabled/operational\n"); + kfree(dcbx_info); + return NULL; + } + + return dcbx_info; +} + +static u8 qed_dcbnl_getstate(struct qed_dev *cdev) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + bool enabled; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return 0; + + enabled = dcbx_info->operational.enabled; + DP_VERBOSE(hwfn, QED_MSG_DCB, "DCB state = %d\n", enabled); + kfree(dcbx_info); + + return enabled; +} + +static u8 qed_dcbnl_setstate(struct qed_dev *cdev, u8 state) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "DCB state = %d\n", state); + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return 1; + + dcbx_set.enabled = !!state; + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return 1; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); + + return rc ? 1 : 0; +} + +static void qed_dcbnl_getpgtccfgtx(struct qed_dev *cdev, int tc, u8 *prio_type, + u8 *pgid, u8 *bw_pct, u8 *up_map) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "tc = %d\n", tc); + *prio_type = *pgid = *bw_pct = *up_map = 0; + if (tc < 0 || tc >= QED_MAX_PFC_PRIORITIES) { + DP_INFO(hwfn, "Invalid tc %d\n", tc); + return; + } + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return; + + *pgid = dcbx_info->operational.params.ets_pri_tc_tbl[tc]; + kfree(dcbx_info); +} + +static void qed_dcbnl_getpgbwgcfgtx(struct qed_dev *cdev, int pgid, u8 *bw_pct) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + + *bw_pct = 0; + DP_VERBOSE(hwfn, QED_MSG_DCB, "pgid = %d\n", pgid); + if (pgid < 0 || pgid >= QED_MAX_PFC_PRIORITIES) { + DP_INFO(hwfn, "Invalid pgid %d\n", pgid); + return; + } + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return; + + *bw_pct = dcbx_info->operational.params.ets_tc_bw_tbl[pgid]; + DP_VERBOSE(hwfn, QED_MSG_DCB, "bw_pct = %d\n", *bw_pct); + kfree(dcbx_info); +} + +static void qed_dcbnl_getpgtccfgrx(struct qed_dev *cdev, int tc, u8 *prio, + u8 *bwg_id, u8 *bw_pct, u8 *up_map) +{ + DP_INFO(QED_LEADING_HWFN(cdev), "Rx ETS is not supported\n"); + *prio = *bwg_id = *bw_pct = *up_map = 0; +} + +static void qed_dcbnl_getpgbwgcfgrx(struct qed_dev *cdev, + int bwg_id, u8 *bw_pct) +{ + DP_INFO(QED_LEADING_HWFN(cdev), "Rx ETS is not supported\n"); + *bw_pct = 0; +} + +static void qed_dcbnl_getpfccfg(struct qed_dev *cdev, + int priority, u8 *setting) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "priority = %d\n", priority); + if (priority < 0 || priority >= QED_MAX_PFC_PRIORITIES) { + DP_INFO(hwfn, "Invalid priority %d\n", priority); + return; + } + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return; + + *setting = dcbx_info->operational.params.pfc.prio[priority]; + DP_VERBOSE(hwfn, QED_MSG_DCB, "setting = %d\n", *setting); + kfree(dcbx_info); +} + +static void qed_dcbnl_setpfccfg(struct qed_dev *cdev, int priority, u8 setting) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "priority = %d setting = %d\n", + priority, setting); + if (priority < 0 || priority >= QED_MAX_PFC_PRIORITIES) { + DP_INFO(hwfn, "Invalid priority %d\n", priority); + return; + } + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return; + + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_PFC_CFG; + dcbx_set.config.params.pfc.prio[priority] = !!setting; + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); +} + +static u8 qed_dcbnl_getcap(struct qed_dev *cdev, int capid, u8 *cap) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + int rc = 0; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "capid = %d\n", capid); + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return 1; + + switch (capid) { + case DCB_CAP_ATTR_PG: + case DCB_CAP_ATTR_PFC: + case DCB_CAP_ATTR_UP2TC: + case DCB_CAP_ATTR_GSP: + *cap = true; + break; + case DCB_CAP_ATTR_PG_TCS: + case DCB_CAP_ATTR_PFC_TCS: + *cap = 0x80; + break; + case DCB_CAP_ATTR_DCBX: + *cap = (DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE | + DCB_CAP_DCBX_VER_IEEE); + break; + default: + *cap = false; + rc = 1; + } + + DP_VERBOSE(hwfn, QED_MSG_DCB, "id = %d caps = %d\n", capid, *cap); + kfree(dcbx_info); + + return rc; +} + +static int qed_dcbnl_getnumtcs(struct qed_dev *cdev, int tcid, u8 *num) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + int rc = 0; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "tcid = %d\n", tcid); + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return -EINVAL; + + switch (tcid) { + case DCB_NUMTCS_ATTR_PG: + *num = dcbx_info->operational.params.max_ets_tc; + break; + case DCB_NUMTCS_ATTR_PFC: + *num = dcbx_info->operational.params.pfc.max_tc; + break; + default: + rc = -EINVAL; + } + + kfree(dcbx_info); + DP_VERBOSE(hwfn, QED_MSG_DCB, "numtcs = %d\n", *num); + + return rc; +} + +static u8 qed_dcbnl_getpfcstate(struct qed_dev *cdev) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + bool enabled; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return 0; + + enabled = dcbx_info->operational.params.pfc.enabled; + DP_VERBOSE(hwfn, QED_MSG_DCB, "pfc state = %d\n", enabled); + kfree(dcbx_info); + + return enabled; +} + +static u8 qed_dcbnl_getdcbx(struct qed_dev *cdev) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + u8 mode = 0; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return 0; + + if (dcbx_info->operational.enabled) + mode |= DCB_CAP_DCBX_LLD_MANAGED; + if (dcbx_info->operational.ieee) + mode |= DCB_CAP_DCBX_VER_IEEE; + if (dcbx_info->operational.cee) + mode |= DCB_CAP_DCBX_VER_CEE; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "dcb mode = %d\n", mode); + kfree(dcbx_info); + + return mode; +} + +static void qed_dcbnl_setpgtccfgtx(struct qed_dev *cdev, + int tc, + u8 pri_type, u8 pgid, u8 bw_pct, u8 up_map) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + DP_VERBOSE(hwfn, QED_MSG_DCB, + "tc = %d pri_type = %d pgid = %d bw_pct = %d up_map = %d\n", + tc, pri_type, pgid, bw_pct, up_map); + + if (tc < 0 || tc >= QED_MAX_PFC_PRIORITIES) { + DP_INFO(hwfn, "Invalid tc %d\n", tc); + return; + } + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return; + + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_ETS_CFG; + dcbx_set.config.params.ets_pri_tc_tbl[tc] = pgid; + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); +} + +static void qed_dcbnl_setpgtccfgrx(struct qed_dev *cdev, int prio, + u8 pri_type, u8 pgid, u8 bw_pct, u8 up_map) +{ + DP_INFO(QED_LEADING_HWFN(cdev), "Rx ETS is not supported\n"); +} + +static void qed_dcbnl_setpgbwgcfgtx(struct qed_dev *cdev, int pgid, u8 bw_pct) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "pgid = %d bw_pct = %d\n", pgid, bw_pct); + if (pgid < 0 || pgid >= QED_MAX_PFC_PRIORITIES) { + DP_INFO(hwfn, "Invalid pgid %d\n", pgid); + return; + } + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return; + + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_ETS_CFG; + dcbx_set.config.params.ets_tc_bw_tbl[pgid] = bw_pct; + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); +} + +static void qed_dcbnl_setpgbwgcfgrx(struct qed_dev *cdev, int pgid, u8 bw_pct) +{ + DP_INFO(QED_LEADING_HWFN(cdev), "Rx ETS is not supported\n"); +} + +static u8 qed_dcbnl_setall(struct qed_dev *cdev) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return 1; + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return 1; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 1); + + qed_ptt_release(hwfn, ptt); + + return rc; +} + +static int qed_dcbnl_setnumtcs(struct qed_dev *cdev, int tcid, u8 num) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "tcid = %d num = %d\n", tcid, num); + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return 1; + + switch (tcid) { + case DCB_NUMTCS_ATTR_PG: + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_ETS_CFG; + dcbx_set.config.params.max_ets_tc = num; + break; + case DCB_NUMTCS_ATTR_PFC: + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_PFC_CFG; + dcbx_set.config.params.pfc.max_tc = num; + break; + default: + DP_INFO(hwfn, "Invalid tcid %d\n", tcid); + return -EINVAL; + } + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return -EINVAL; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); + + return 0; +} + +static void qed_dcbnl_setpfcstate(struct qed_dev *cdev, u8 state) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "new state = %d\n", state); + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return; + + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_PFC_CFG; + dcbx_set.config.params.pfc.enabled = !!state; + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); +} + +static int qed_dcbnl_getapp(struct qed_dev *cdev, u8 idtype, u16 idval) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + struct qed_app_entry *entry; + bool ethtype; + u8 prio = 0; + int i; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return -EINVAL; + + ethtype = !!(idtype == DCB_APP_IDTYPE_ETHTYPE); + for (i = 0; i < QED_DCBX_MAX_APP_PROTOCOL; i++) { + entry = &dcbx_info->operational.params.app_entry[i]; + if ((entry->ethtype == ethtype) && (entry->proto_id == idval)) { + prio = entry->prio; + break; + } + } + + if (i == QED_DCBX_MAX_APP_PROTOCOL) { + DP_ERR(cdev, "App entry (%d, %d) not found\n", idtype, idval); + kfree(dcbx_info); + return -EINVAL; + } + + kfree(dcbx_info); + + return prio; +} + +static int qed_dcbnl_setapp(struct qed_dev *cdev, + u8 idtype, u16 idval, u8 pri_map) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_app_entry *entry; + struct qed_ptt *ptt; + bool ethtype; + int rc, i; + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return -EINVAL; + + ethtype = !!(idtype == DCB_APP_IDTYPE_ETHTYPE); + for (i = 0; i < QED_DCBX_MAX_APP_PROTOCOL; i++) { + entry = &dcbx_set.config.params.app_entry[i]; + if ((entry->ethtype == ethtype) && (entry->proto_id == idval)) + break; + /* First empty slot */ + if (!entry->proto_id) + break; + } + + if (i == QED_DCBX_MAX_APP_PROTOCOL) { + DP_ERR(cdev, "App table is full\n"); + return -EBUSY; + } + + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_APP_CFG; + dcbx_set.config.params.app_entry[i].ethtype = ethtype; + dcbx_set.config.params.app_entry[i].proto_id = idval; + dcbx_set.config.params.app_entry[i].prio = pri_map; + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return -EBUSY; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); + + return rc; +} + +static u8 qed_dcbnl_setdcbx(struct qed_dev *cdev, u8 mode) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "new mode = %x\n", mode); + + if (!(mode & DCB_CAP_DCBX_VER_IEEE) && !(mode & DCB_CAP_DCBX_VER_CEE)) { + DP_INFO(hwfn, "Allowed mode is cee, ieee or both\n"); + return 1; + } + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return 1; + + dcbx_set.ver_num = 0; + if (mode & DCB_CAP_DCBX_VER_CEE) { + dcbx_set.ver_num |= DCBX_CONFIG_VERSION_CEE; + dcbx_set.enabled = true; + } + + if (mode & DCB_CAP_DCBX_VER_IEEE) { + dcbx_set.ver_num |= DCBX_CONFIG_VERSION_IEEE; + dcbx_set.enabled = true; + } + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return 1; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); + + return 0; +} + +static u8 qed_dcbnl_getfeatcfg(struct qed_dev *cdev, int featid, u8 *flags) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "Feature id = %d\n", featid); + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return 1; + + *flags = 0; + switch (featid) { + case DCB_FEATCFG_ATTR_PG: + if (dcbx_info->operational.params.ets_enabled) + *flags = DCB_FEATCFG_ENABLE; + else + *flags = DCB_FEATCFG_ERROR; + break; + case DCB_FEATCFG_ATTR_PFC: + if (dcbx_info->operational.params.pfc.enabled) + *flags = DCB_FEATCFG_ENABLE; + else + *flags = DCB_FEATCFG_ERROR; + break; + case DCB_FEATCFG_ATTR_APP: + if (dcbx_info->operational.params.app_valid) + *flags = DCB_FEATCFG_ENABLE; + else + *flags = DCB_FEATCFG_ERROR; + break; + default: + DP_INFO(hwfn, "Invalid feature-ID %d\n", featid); + kfree(dcbx_info); + return 1; + } + + DP_VERBOSE(hwfn, QED_MSG_DCB, "flags = %d\n", *flags); + kfree(dcbx_info); + + return 0; +} + +static u8 qed_dcbnl_setfeatcfg(struct qed_dev *cdev, int featid, u8 flags) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_set dcbx_set; + bool enabled, willing; + struct qed_ptt *ptt; + int rc; + + DP_VERBOSE(hwfn, QED_MSG_DCB, "featid = %d flags = %d\n", + featid, flags); + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return 1; + + enabled = !!(flags & DCB_FEATCFG_ENABLE); + willing = !!(flags & DCB_FEATCFG_WILLING); + switch (featid) { + case DCB_FEATCFG_ATTR_PG: + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_ETS_CFG; + dcbx_set.config.params.ets_enabled = enabled; + dcbx_set.config.params.ets_willing = willing; + break; + case DCB_FEATCFG_ATTR_PFC: + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_PFC_CFG; + dcbx_set.config.params.pfc.enabled = enabled; + dcbx_set.config.params.pfc.willing = willing; + break; + case DCB_FEATCFG_ATTR_APP: + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_APP_CFG; + dcbx_set.config.params.app_willing = willing; + break; + default: + DP_INFO(hwfn, "Invalid feature-ID %d\n", featid); + return 1; + } + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return 1; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); + + return 0; +} + +static int qed_dcbnl_peer_getappinfo(struct qed_dev *cdev, + struct dcb_peer_app_info *info, + u16 *app_count) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_REMOTE_MIB); + if (!dcbx_info) + return -EINVAL; + + info->willing = dcbx_info->remote.params.app_willing; + info->error = dcbx_info->remote.params.app_error; + *app_count = dcbx_info->remote.params.num_app_entries; + kfree(dcbx_info); + + return 0; +} + +static int qed_dcbnl_peer_getapptable(struct qed_dev *cdev, + struct dcb_app *table) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + int i; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_REMOTE_MIB); + if (!dcbx_info) + return -EINVAL; + + for (i = 0; i < dcbx_info->remote.params.num_app_entries; i++) { + if (dcbx_info->remote.params.app_entry[i].ethtype) + table[i].selector = DCB_APP_IDTYPE_ETHTYPE; + else + table[i].selector = DCB_APP_IDTYPE_PORTNUM; + table[i].priority = dcbx_info->remote.params.app_entry[i].prio; + table[i].protocol = + dcbx_info->remote.params.app_entry[i].proto_id; + } + + kfree(dcbx_info); + + return 0; +} + +static int qed_dcbnl_cee_peer_getpfc(struct qed_dev *cdev, struct cee_pfc *pfc) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + int i; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_REMOTE_MIB); + if (!dcbx_info) + return -EINVAL; + + for (i = 0; i < QED_MAX_PFC_PRIORITIES; i++) + if (dcbx_info->remote.params.pfc.prio[i]) + pfc->pfc_en |= BIT(i); + + pfc->tcs_supported = dcbx_info->remote.params.pfc.max_tc; + DP_VERBOSE(hwfn, QED_MSG_DCB, "pfc state = %d tcs_supported = %d\n", + pfc->pfc_en, pfc->tcs_supported); + kfree(dcbx_info); + + return 0; +} + +static int qed_dcbnl_cee_peer_getpg(struct qed_dev *cdev, struct cee_pg *pg) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + int i; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_REMOTE_MIB); + if (!dcbx_info) + return -EINVAL; + + pg->willing = dcbx_info->remote.params.ets_willing; + for (i = 0; i < QED_MAX_PFC_PRIORITIES; i++) { + pg->pg_bw[i] = dcbx_info->remote.params.ets_tc_bw_tbl[i]; + pg->prio_pg[i] = dcbx_info->remote.params.ets_pri_tc_tbl[i]; + } + + DP_VERBOSE(hwfn, QED_MSG_DCB, "willing = %d", pg->willing); + kfree(dcbx_info); + + return 0; +} + +static int qed_dcbnl_get_ieee_pfc(struct qed_dev *cdev, + struct ieee_pfc *pfc, bool remote) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_params *params; + struct qed_dcbx_get *dcbx_info; + int rc, i; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return -EINVAL; + + if (!dcbx_info->operational.ieee) { + DP_INFO(hwfn, "DCBX is not enabled/operational in IEEE mode\n"); + return -EINVAL; + } + + if (remote) { + memset(dcbx_info, 0, sizeof(*dcbx_info)); + rc = qed_dcbx_query_params(hwfn, dcbx_info, + QED_DCBX_REMOTE_MIB); + if (rc) { + kfree(dcbx_info); + return -EINVAL; + } + + params = &dcbx_info->remote.params; + } else { + params = &dcbx_info->operational.params; + } + + pfc->pfc_cap = params->pfc.max_tc; + pfc->pfc_en = 0; + for (i = 0; i < QED_MAX_PFC_PRIORITIES; i++) + if (params->pfc.prio[i]) + pfc->pfc_en |= BIT(i); + + kfree(dcbx_info); + + return 0; +} + +static int qed_dcbnl_ieee_getpfc(struct qed_dev *cdev, struct ieee_pfc *pfc) +{ + return qed_dcbnl_get_ieee_pfc(cdev, pfc, false); +} + +static int qed_dcbnl_ieee_setpfc(struct qed_dev *cdev, struct ieee_pfc *pfc) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc, i; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return -EINVAL; + + if (!dcbx_info->operational.ieee) { + DP_INFO(hwfn, "DCBX is not enabled/operational in IEEE mode\n"); + kfree(dcbx_info); + return -EINVAL; + } + + kfree(dcbx_info); + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return -EINVAL; + + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_PFC_CFG; + for (i = 0; i < QED_MAX_PFC_PRIORITIES; i++) + dcbx_set.config.params.pfc.prio[i] = !!(pfc->pfc_en & BIT(i)); + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return -EINVAL; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); + + return rc; +} + +static int qed_dcbnl_get_ieee_ets(struct qed_dev *cdev, + struct ieee_ets *ets, bool remote) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + struct qed_dcbx_params *params; + int rc; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return -EINVAL; + + if (!dcbx_info->operational.ieee) { + DP_INFO(hwfn, "DCBX is not enabled/operational in IEEE mode\n"); + kfree(dcbx_info); + return -EINVAL; + } + + if (remote) { + memset(dcbx_info, 0, sizeof(*dcbx_info)); + rc = qed_dcbx_query_params(hwfn, dcbx_info, + QED_DCBX_REMOTE_MIB); + if (rc) { + kfree(dcbx_info); + return -EINVAL; + } + + params = &dcbx_info->remote.params; + } else { + params = &dcbx_info->operational.params; + } + + ets->ets_cap = params->max_ets_tc; + ets->willing = params->ets_willing; + ets->cbs = params->ets_cbs; + memcpy(ets->tc_tx_bw, params->ets_tc_bw_tbl, sizeof(ets->tc_tx_bw)); + memcpy(ets->tc_tsa, params->ets_tc_tsa_tbl, sizeof(ets->tc_tsa)); + memcpy(ets->prio_tc, params->ets_pri_tc_tbl, sizeof(ets->prio_tc)); + kfree(dcbx_info); + + return 0; +} + +static int qed_dcbnl_ieee_getets(struct qed_dev *cdev, struct ieee_ets *ets) +{ + return qed_dcbnl_get_ieee_ets(cdev, ets, false); +} + +static int qed_dcbnl_ieee_setets(struct qed_dev *cdev, struct ieee_ets *ets) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + struct qed_dcbx_set dcbx_set; + struct qed_ptt *ptt; + int rc; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return -EINVAL; + + if (!dcbx_info->operational.ieee) { + DP_INFO(hwfn, "DCBX is not enabled/operational in IEEE mode\n"); + kfree(dcbx_info); + return -EINVAL; + } + + kfree(dcbx_info); + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return -EINVAL; + + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_ETS_CFG; + dcbx_set.config.params.max_ets_tc = ets->ets_cap; + dcbx_set.config.params.ets_willing = ets->willing; + dcbx_set.config.params.ets_cbs = ets->cbs; + memcpy(dcbx_set.config.params.ets_tc_bw_tbl, ets->tc_tx_bw, + sizeof(ets->tc_tx_bw)); + memcpy(dcbx_set.config.params.ets_tc_tsa_tbl, ets->tc_tsa, + sizeof(ets->tc_tsa)); + memcpy(dcbx_set.config.params.ets_pri_tc_tbl, ets->prio_tc, + sizeof(ets->prio_tc)); + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return -EINVAL; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); + + return rc; +} + +int qed_dcbnl_ieee_peer_getets(struct qed_dev *cdev, struct ieee_ets *ets) +{ + return qed_dcbnl_get_ieee_ets(cdev, ets, true); +} + +int qed_dcbnl_ieee_peer_getpfc(struct qed_dev *cdev, struct ieee_pfc *pfc) +{ + return qed_dcbnl_get_ieee_pfc(cdev, pfc, true); +} + +int qed_dcbnl_ieee_getapp(struct qed_dev *cdev, struct dcb_app *app) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + struct qed_app_entry *entry; + bool ethtype; + u8 prio = 0; + int i; + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return -EINVAL; + + if (!dcbx_info->operational.ieee) { + DP_INFO(hwfn, "DCBX is not enabled/operational in IEEE mode\n"); + kfree(dcbx_info); + return -EINVAL; + } + + /* ieee defines the selector field value for ethertype to be 1 */ + ethtype = !!((app->selector - 1) == DCB_APP_IDTYPE_ETHTYPE); + for (i = 0; i < QED_DCBX_MAX_APP_PROTOCOL; i++) { + entry = &dcbx_info->operational.params.app_entry[i]; + if ((entry->ethtype == ethtype) && + (entry->proto_id == app->protocol)) { + prio = entry->prio; + break; + } + } + + if (i == QED_DCBX_MAX_APP_PROTOCOL) { + DP_ERR(cdev, "App entry (%d, %d) not found\n", app->selector, + app->protocol); + kfree(dcbx_info); + return -EINVAL; + } + + app->priority = ffs(prio) - 1; + + kfree(dcbx_info); + + return 0; +} + +int qed_dcbnl_ieee_setapp(struct qed_dev *cdev, struct dcb_app *app) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + struct qed_dcbx_get *dcbx_info; + struct qed_dcbx_set dcbx_set; + struct qed_app_entry *entry; + struct qed_ptt *ptt; + bool ethtype; + int rc, i; + + if (app->priority < 0 || app->priority >= QED_MAX_PFC_PRIORITIES) { + DP_INFO(hwfn, "Invalid priority %d\n", app->priority); + return -EINVAL; + } + + dcbx_info = qed_dcbnl_get_dcbx(hwfn, QED_DCBX_OPERATIONAL_MIB); + if (!dcbx_info) + return -EINVAL; + + if (!dcbx_info->operational.ieee) { + DP_INFO(hwfn, "DCBX is not enabled/operational in IEEE mode\n"); + kfree(dcbx_info); + return -EINVAL; + } + + kfree(dcbx_info); + + memset(&dcbx_set, 0, sizeof(dcbx_set)); + rc = qed_dcbx_get_config_params(hwfn, &dcbx_set); + if (rc) + return -EINVAL; + + /* ieee defines the selector field value for ethertype to be 1 */ + ethtype = !!((app->selector - 1) == DCB_APP_IDTYPE_ETHTYPE); + for (i = 0; i < QED_DCBX_MAX_APP_PROTOCOL; i++) { + entry = &dcbx_set.config.params.app_entry[i]; + if ((entry->ethtype == ethtype) && + (entry->proto_id == app->protocol)) + break; + /* First empty slot */ + if (!entry->proto_id) + break; + } + + if (i == QED_DCBX_MAX_APP_PROTOCOL) { + DP_ERR(cdev, "App table is full\n"); + return -EBUSY; + } + + dcbx_set.override_flags |= QED_DCBX_OVERRIDE_APP_CFG; + dcbx_set.config.params.app_entry[i].ethtype = ethtype; + dcbx_set.config.params.app_entry[i].proto_id = app->protocol; + dcbx_set.config.params.app_entry[i].prio = BIT(app->priority); + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return -EBUSY; + + rc = qed_dcbx_config_params(hwfn, ptt, &dcbx_set, 0); + + qed_ptt_release(hwfn, ptt); + + return rc; +} + +const struct qed_eth_dcbnl_ops qed_dcbnl_ops_pass = { + .getstate = qed_dcbnl_getstate, + .setstate = qed_dcbnl_setstate, + .getpgtccfgtx = qed_dcbnl_getpgtccfgtx, + .getpgbwgcfgtx = qed_dcbnl_getpgbwgcfgtx, + .getpgtccfgrx = qed_dcbnl_getpgtccfgrx, + .getpgbwgcfgrx = qed_dcbnl_getpgbwgcfgrx, + .getpfccfg = qed_dcbnl_getpfccfg, + .setpfccfg = qed_dcbnl_setpfccfg, + .getcap = qed_dcbnl_getcap, + .getnumtcs = qed_dcbnl_getnumtcs, + .getpfcstate = qed_dcbnl_getpfcstate, + .getdcbx = qed_dcbnl_getdcbx, + .setpgtccfgtx = qed_dcbnl_setpgtccfgtx, + .setpgtccfgrx = qed_dcbnl_setpgtccfgrx, + .setpgbwgcfgtx = qed_dcbnl_setpgbwgcfgtx, + .setpgbwgcfgrx = qed_dcbnl_setpgbwgcfgrx, + .setall = qed_dcbnl_setall, + .setnumtcs = qed_dcbnl_setnumtcs, + .setpfcstate = qed_dcbnl_setpfcstate, + .setapp = qed_dcbnl_setapp, + .setdcbx = qed_dcbnl_setdcbx, + .setfeatcfg = qed_dcbnl_setfeatcfg, + .getfeatcfg = qed_dcbnl_getfeatcfg, + .getapp = qed_dcbnl_getapp, + .peer_getappinfo = qed_dcbnl_peer_getappinfo, + .peer_getapptable = qed_dcbnl_peer_getapptable, + .cee_peer_getpfc = qed_dcbnl_cee_peer_getpfc, + .cee_peer_getpg = qed_dcbnl_cee_peer_getpg, + .ieee_getpfc = qed_dcbnl_ieee_getpfc, + .ieee_setpfc = qed_dcbnl_ieee_setpfc, + .ieee_getets = qed_dcbnl_ieee_getets, + .ieee_setets = qed_dcbnl_ieee_setets, + .ieee_peer_getpfc = qed_dcbnl_ieee_peer_getpfc, + .ieee_peer_getets = qed_dcbnl_ieee_peer_getets, + .ieee_getapp = qed_dcbnl_ieee_getapp, + .ieee_setapp = qed_dcbnl_ieee_setapp, +}; + #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 2ee496e26df6..d121a8bf6b20 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -2166,10 +2166,17 @@ static int qed_fp_cqe_completion(struct qed_dev *dev, extern const struct qed_iov_hv_ops qed_iov_ops_pass; #endif +#ifdef CONFIG_DCB +extern const struct qed_eth_dcbnl_ops qed_dcbnl_ops_pass; +#endif + static const struct qed_eth_ops qed_eth_ops_pass = { .common = &qed_common_ops_pass, #ifdef CONFIG_QED_SRIOV .iov = &qed_iov_ops_pass, +#endif +#ifdef CONFIG_DCB + .dcb = &qed_dcbnl_ops_pass, #endif .fill_dev_info = &qed_fill_eth_dev_info, .register_ops = &qed_register_eth_ops, diff --git a/include/linux/qed/qed_eth_if.h b/include/linux/qed/qed_eth_if.h index f8ff71126d9e..71d523b4bc54 100644 --- a/include/linux/qed/qed_eth_if.h +++ b/include/linux/qed/qed_eth_if.h @@ -128,11 +128,73 @@ struct qed_eth_cb_ops { void (*force_mac) (void *dev, u8 *mac); }; +#ifdef CONFIG_DCB +/* Prototype declaration of qed_eth_dcbnl_ops should match with the declaration + * of dcbnl_rtnl_ops structure. + */ +struct qed_eth_dcbnl_ops { + /* IEEE 802.1Qaz std */ + int (*ieee_getpfc)(struct qed_dev *cdev, struct ieee_pfc *pfc); + int (*ieee_setpfc)(struct qed_dev *cdev, struct ieee_pfc *pfc); + int (*ieee_getets)(struct qed_dev *cdev, struct ieee_ets *ets); + int (*ieee_setets)(struct qed_dev *cdev, struct ieee_ets *ets); + int (*ieee_peer_getets)(struct qed_dev *cdev, struct ieee_ets *ets); + int (*ieee_peer_getpfc)(struct qed_dev *cdev, struct ieee_pfc *pfc); + int (*ieee_getapp)(struct qed_dev *cdev, struct dcb_app *app); + int (*ieee_setapp)(struct qed_dev *cdev, struct dcb_app *app); + + /* CEE std */ + u8 (*getstate)(struct qed_dev *cdev); + u8 (*setstate)(struct qed_dev *cdev, u8 state); + void (*getpgtccfgtx)(struct qed_dev *cdev, int prio, u8 *prio_type, + u8 *pgid, u8 *bw_pct, u8 *up_map); + void (*getpgbwgcfgtx)(struct qed_dev *cdev, int pgid, u8 *bw_pct); + void (*getpgtccfgrx)(struct qed_dev *cdev, int prio, u8 *prio_type, + u8 *pgid, u8 *bw_pct, u8 *up_map); + void (*getpgbwgcfgrx)(struct qed_dev *cdev, int pgid, u8 *bw_pct); + void (*getpfccfg)(struct qed_dev *cdev, int prio, u8 *setting); + void (*setpfccfg)(struct qed_dev *cdev, int prio, u8 setting); + u8 (*getcap)(struct qed_dev *cdev, int capid, u8 *cap); + int (*getnumtcs)(struct qed_dev *cdev, int tcid, u8 *num); + u8 (*getpfcstate)(struct qed_dev *cdev); + int (*getapp)(struct qed_dev *cdev, u8 idtype, u16 id); + u8 (*getfeatcfg)(struct qed_dev *cdev, int featid, u8 *flags); + + /* DCBX configuration */ + u8 (*getdcbx)(struct qed_dev *cdev); + void (*setpgtccfgtx)(struct qed_dev *cdev, int prio, + u8 pri_type, u8 pgid, u8 bw_pct, u8 up_map); + void (*setpgtccfgrx)(struct qed_dev *cdev, int prio, + u8 pri_type, u8 pgid, u8 bw_pct, u8 up_map); + void (*setpgbwgcfgtx)(struct qed_dev *cdev, int pgid, u8 bw_pct); + void (*setpgbwgcfgrx)(struct qed_dev *cdev, int pgid, u8 bw_pct); + u8 (*setall)(struct qed_dev *cdev); + int (*setnumtcs)(struct qed_dev *cdev, int tcid, u8 num); + void (*setpfcstate)(struct qed_dev *cdev, u8 state); + int (*setapp)(struct qed_dev *cdev, u8 idtype, u16 idval, u8 up); + u8 (*setdcbx)(struct qed_dev *cdev, u8 state); + u8 (*setfeatcfg)(struct qed_dev *cdev, int featid, u8 flags); + + /* Peer apps */ + int (*peer_getappinfo)(struct qed_dev *cdev, + struct dcb_peer_app_info *info, + u16 *app_count); + int (*peer_getapptable)(struct qed_dev *cdev, struct dcb_app *table); + + /* CEE peer */ + int (*cee_peer_getpfc)(struct qed_dev *cdev, struct cee_pfc *pfc); + int (*cee_peer_getpg)(struct qed_dev *cdev, struct cee_pg *pg); +}; +#endif + struct qed_eth_ops { const struct qed_common_ops *common; #ifdef CONFIG_QED_SRIOV const struct qed_iov_hv_ops *iov; #endif +#ifdef CONFIG_DCB + const struct qed_eth_dcbnl_ops *dcb; +#endif int (*fill_dev_info)(struct qed_dev *cdev, struct qed_dev_eth_info *info); -- cgit v1.2.3 From 123b36526592f009bf8eccb7c8833aeda296d9cf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2016 07:22:49 -0700 Subject: net: sched: fix missing doc annotations "make htmldocs" complains otherwise: .//net/core/gen_stats.c:168: warning: No description found for parameter 'running' .//include/linux/netdevice.h:1867: warning: No description found for parameter 'qdisc_running_key' Fixes: f9eb8aea2a1e ("net_sched: transform qdisc running bit into a seqcount") Fixes: edb09eb17ed8 ("net: sched: do not acquire qdisc spinlock in qdisc/class stats dump") Signed-off-by: Eric Dumazet Reported-by: kbuild test robot Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 ++- net/core/gen_stats.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 59d7e06d88d5..541562333ba5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1594,7 +1594,8 @@ enum netdev_priv_flags { * @phydev: Physical device may attach itself * for hardware timestamping * - * @qdisc_tx_busylock: XXX: need comments on this one + * @qdisc_tx_busylock: lockdep class annotating Qdisc->busylock spinlock + * @qdisc_running_key: lockdep class annotating Qdisc->running seqcount * * @proto_down: protocol port state information can be sent to the * switch driver and used to set the phys state of the diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c index d9c210caff32..32207e6a942c 100644 --- a/net/core/gen_stats.c +++ b/net/core/gen_stats.c @@ -150,6 +150,7 @@ EXPORT_SYMBOL(__gnet_stats_copy_basic); /** * gnet_stats_copy_basic - copy basic statistics into statistic TLV + * @running: seqcount_t pointer * @d: dumping handle * @cpu: copy statistic per cpu * @b: basic statistics -- cgit v1.2.3 From 117780eef7740729e803bdcc0d5f2f48137ea8e3 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 8 Jun 2016 12:38:38 -0700 Subject: x86, asm: use bool for bitops and other assembly outputs The gcc people have confirmed that using "bool" when combined with inline assembly always is treated as a byte-sized operand that can be assumed to be 0 or 1, which is exactly what the SET instruction emits. Change the output types and intermediate variables of as many operations as practical to "bool". Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1465414726-197858-3-git-send-email-hpa@linux.intel.com Reviewed-by: Andy Lutomirski Reviewed-by: Borislav Petkov Acked-by: Peter Zijlstra (Intel) --- arch/x86/boot/bitops.h | 8 +++++--- arch/x86/boot/boot.h | 8 ++++---- arch/x86/boot/string.c | 2 +- arch/x86/include/asm/apm.h | 6 +++--- arch/x86/include/asm/archrandom.h | 16 ++++++++-------- arch/x86/include/asm/atomic.h | 8 ++++---- arch/x86/include/asm/atomic64_64.h | 10 +++++----- arch/x86/include/asm/bitops.h | 28 ++++++++++++++-------------- arch/x86/include/asm/local.h | 8 ++++---- arch/x86/include/asm/percpu.h | 8 ++++---- arch/x86/include/asm/rmwcc.h | 4 ++-- arch/x86/include/asm/rwsem.h | 17 +++++++++-------- include/linux/random.h | 12 ++++++------ 13 files changed, 69 insertions(+), 66 deletions(-) (limited to 'include/linux') diff --git a/arch/x86/boot/bitops.h b/arch/x86/boot/bitops.h index 878e4b9940d9..0d41d68131cc 100644 --- a/arch/x86/boot/bitops.h +++ b/arch/x86/boot/bitops.h @@ -16,14 +16,16 @@ #define BOOT_BITOPS_H #define _LINUX_BITOPS_H /* Inhibit inclusion of */ -static inline int constant_test_bit(int nr, const void *addr) +#include + +static inline bool constant_test_bit(int nr, const void *addr) { const u32 *p = (const u32 *)addr; return ((1UL << (nr & 31)) & (p[nr >> 5])) != 0; } -static inline int variable_test_bit(int nr, const void *addr) +static inline bool variable_test_bit(int nr, const void *addr) { - u8 v; + bool v; const u32 *p = (const u32 *)addr; asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 9011a88353de..2edb2d53c3a2 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -176,16 +176,16 @@ static inline void wrgs32(u32 v, addr_t addr) } /* Note: these only return true/false, not a signed return value! */ -static inline int memcmp_fs(const void *s1, addr_t s2, size_t len) +static inline bool memcmp_fs(const void *s1, addr_t s2, size_t len) { - u8 diff; + bool diff; asm volatile("fs; repe; cmpsb; setnz %0" : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } -static inline int memcmp_gs(const void *s1, addr_t s2, size_t len) +static inline bool memcmp_gs(const void *s1, addr_t s2, size_t len) { - u8 diff; + bool diff; asm volatile("gs; repe; cmpsb; setnz %0" : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index 318b8465d302..cc3bd583dce1 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c @@ -17,7 +17,7 @@ int memcmp(const void *s1, const void *s2, size_t len) { - u8 diff; + bool diff; asm("repe; cmpsb; setnz %0" : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; diff --git a/arch/x86/include/asm/apm.h b/arch/x86/include/asm/apm.h index 20370c6db74b..93eebc636c76 100644 --- a/arch/x86/include/asm/apm.h +++ b/arch/x86/include/asm/apm.h @@ -45,11 +45,11 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, : "memory", "cc"); } -static inline u8 apm_bios_call_simple_asm(u32 func, u32 ebx_in, - u32 ecx_in, u32 *eax) +static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, + u32 ecx_in, u32 *eax) { int cx, dx, si; - u8 error; + bool error; /* * N.B. We do NOT need a cld after the BIOS call diff --git a/arch/x86/include/asm/archrandom.h b/arch/x86/include/asm/archrandom.h index 69f1366f1aa3..ab6f599ce2fd 100644 --- a/arch/x86/include/asm/archrandom.h +++ b/arch/x86/include/asm/archrandom.h @@ -43,7 +43,7 @@ #ifdef CONFIG_ARCH_RANDOM /* Instead of arch_get_random_long() when alternatives haven't run. */ -static inline int rdrand_long(unsigned long *v) +static inline bool rdrand_long(unsigned long *v) { int ok; asm volatile("1: " RDRAND_LONG "\n\t" @@ -53,13 +53,13 @@ static inline int rdrand_long(unsigned long *v) "2:" : "=r" (ok), "=a" (*v) : "0" (RDRAND_RETRY_LOOPS)); - return ok; + return !!ok; } /* A single attempt at RDSEED */ static inline bool rdseed_long(unsigned long *v) { - unsigned char ok; + bool ok; asm volatile(RDSEED_LONG "\n\t" "setc %0" : "=qm" (ok), "=a" (*v)); @@ -67,7 +67,7 @@ static inline bool rdseed_long(unsigned long *v) } #define GET_RANDOM(name, type, rdrand, nop) \ -static inline int name(type *v) \ +static inline bool name(type *v) \ { \ int ok; \ alternative_io("movl $0, %0\n\t" \ @@ -80,13 +80,13 @@ static inline int name(type *v) \ X86_FEATURE_RDRAND, \ ASM_OUTPUT2("=r" (ok), "=a" (*v)), \ "0" (RDRAND_RETRY_LOOPS)); \ - return ok; \ + return !!ok; \ } #define GET_SEED(name, type, rdseed, nop) \ -static inline int name(type *v) \ +static inline bool name(type *v) \ { \ - unsigned char ok; \ + bool ok; \ alternative_io("movb $0, %0\n\t" \ nop, \ rdseed "\n\t" \ @@ -119,7 +119,7 @@ GET_SEED(arch_get_random_seed_int, unsigned int, RDSEED_INT, ASM_NOP4); #else -static inline int rdrand_long(unsigned long *v) +static inline bool rdrand_long(unsigned long *v) { return 0; } diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 3e8674288198..17d881248e6c 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -75,7 +75,7 @@ static __always_inline void atomic_sub(int i, atomic_t *v) * true if the result is zero, or false for all * other cases. */ -static __always_inline int atomic_sub_and_test(int i, atomic_t *v) +static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) { GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", "e"); } @@ -112,7 +112,7 @@ static __always_inline void atomic_dec(atomic_t *v) * returns true if the result is 0, or false for all other * cases. */ -static __always_inline int atomic_dec_and_test(atomic_t *v) +static __always_inline bool atomic_dec_and_test(atomic_t *v) { GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e"); } @@ -125,7 +125,7 @@ static __always_inline int atomic_dec_and_test(atomic_t *v) * and returns true if the result is zero, or false for all * other cases. */ -static __always_inline int atomic_inc_and_test(atomic_t *v) +static __always_inline bool atomic_inc_and_test(atomic_t *v) { GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, "%0", "e"); } @@ -139,7 +139,7 @@ static __always_inline int atomic_inc_and_test(atomic_t *v) * if the result is negative, or false when * result is greater than or equal to zero. */ -static __always_inline int atomic_add_negative(int i, atomic_t *v) +static __always_inline bool atomic_add_negative(int i, atomic_t *v) { GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", "s"); } diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index 037351022f54..4f881d7f0c39 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h @@ -70,7 +70,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) * true if the result is zero, or false for all * other cases. */ -static inline int atomic64_sub_and_test(long i, atomic64_t *v) +static inline bool atomic64_sub_and_test(long i, atomic64_t *v) { GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, "er", i, "%0", "e"); } @@ -109,7 +109,7 @@ static __always_inline void atomic64_dec(atomic64_t *v) * returns true if the result is 0, or false for all other * cases. */ -static inline int atomic64_dec_and_test(atomic64_t *v) +static inline bool atomic64_dec_and_test(atomic64_t *v) { GEN_UNARY_RMWcc(LOCK_PREFIX "decq", v->counter, "%0", "e"); } @@ -122,7 +122,7 @@ static inline int atomic64_dec_and_test(atomic64_t *v) * and returns true if the result is zero, or false for all * other cases. */ -static inline int atomic64_inc_and_test(atomic64_t *v) +static inline bool atomic64_inc_and_test(atomic64_t *v) { GEN_UNARY_RMWcc(LOCK_PREFIX "incq", v->counter, "%0", "e"); } @@ -136,7 +136,7 @@ static inline int atomic64_inc_and_test(atomic64_t *v) * if the result is negative, or false when * result is greater than or equal to zero. */ -static inline int atomic64_add_negative(long i, atomic64_t *v) +static inline bool atomic64_add_negative(long i, atomic64_t *v) { GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, "er", i, "%0", "s"); } @@ -180,7 +180,7 @@ static inline long atomic64_xchg(atomic64_t *v, long new) * Atomically adds @a to @v, so long as it was not @u. * Returns the old value of @v. */ -static inline int atomic64_add_unless(atomic64_t *v, long a, long u) +static inline bool atomic64_add_unless(atomic64_t *v, long a, long u) { long c, old; c = atomic64_read(v); diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index b2b797d1f49a..8cbb7f495546 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -201,7 +201,7 @@ static __always_inline void change_bit(long nr, volatile unsigned long *addr) * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static __always_inline int test_and_set_bit(long nr, volatile unsigned long *addr) +static __always_inline bool test_and_set_bit(long nr, volatile unsigned long *addr) { GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", "c"); } @@ -213,7 +213,7 @@ static __always_inline int test_and_set_bit(long nr, volatile unsigned long *add * * This is the same as test_and_set_bit on x86. */ -static __always_inline int +static __always_inline bool test_and_set_bit_lock(long nr, volatile unsigned long *addr) { return test_and_set_bit(nr, addr); @@ -228,9 +228,9 @@ test_and_set_bit_lock(long nr, volatile unsigned long *addr) * If two examples of this operation race, one can appear to succeed * but actually fail. You must protect multiple accesses with a lock. */ -static __always_inline int __test_and_set_bit(long nr, volatile unsigned long *addr) +static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long *addr) { - unsigned char oldbit; + bool oldbit; asm("bts %2,%1\n\t" "setc %0" @@ -247,7 +247,7 @@ static __always_inline int __test_and_set_bit(long nr, volatile unsigned long *a * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static __always_inline int test_and_clear_bit(long nr, volatile unsigned long *addr) +static __always_inline bool test_and_clear_bit(long nr, volatile unsigned long *addr) { GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", "c"); } @@ -268,9 +268,9 @@ static __always_inline int test_and_clear_bit(long nr, volatile unsigned long *a * accessed from a hypervisor on the same CPU if running in a VM: don't change * this without also updating arch/x86/kernel/kvm.c */ -static __always_inline int __test_and_clear_bit(long nr, volatile unsigned long *addr) +static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr) { - unsigned char oldbit; + bool oldbit; asm volatile("btr %2,%1\n\t" "setc %0" @@ -280,9 +280,9 @@ static __always_inline int __test_and_clear_bit(long nr, volatile unsigned long } /* WARNING: non atomic and it can be reordered! */ -static __always_inline int __test_and_change_bit(long nr, volatile unsigned long *addr) +static __always_inline bool __test_and_change_bit(long nr, volatile unsigned long *addr) { - unsigned char oldbit; + bool oldbit; asm volatile("btc %2,%1\n\t" "setc %0" @@ -300,20 +300,20 @@ static __always_inline int __test_and_change_bit(long nr, volatile unsigned long * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static __always_inline int test_and_change_bit(long nr, volatile unsigned long *addr) +static __always_inline bool test_and_change_bit(long nr, volatile unsigned long *addr) { GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", "c"); } -static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr) +static __always_inline bool constant_test_bit(long nr, const volatile unsigned long *addr) { return ((1UL << (nr & (BITS_PER_LONG-1))) & (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; } -static __always_inline int variable_test_bit(long nr, volatile const unsigned long *addr) +static __always_inline bool variable_test_bit(long nr, volatile const unsigned long *addr) { - unsigned char oldbit; + bool oldbit; asm volatile("bt %2,%1\n\t" "setc %0" @@ -329,7 +329,7 @@ static __always_inline int variable_test_bit(long nr, volatile const unsigned lo * @nr: bit number to test * @addr: Address to start counting from */ -static int test_bit(int nr, const volatile unsigned long *addr); +static bool test_bit(int nr, const volatile unsigned long *addr); #endif #define test_bit(nr, addr) \ diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h index 4ad6560847b1..0cdc65b0d14d 100644 --- a/arch/x86/include/asm/local.h +++ b/arch/x86/include/asm/local.h @@ -50,7 +50,7 @@ static inline void local_sub(long i, local_t *l) * true if the result is zero, or false for all * other cases. */ -static inline int local_sub_and_test(long i, local_t *l) +static inline bool local_sub_and_test(long i, local_t *l) { GEN_BINARY_RMWcc(_ASM_SUB, l->a.counter, "er", i, "%0", "e"); } @@ -63,7 +63,7 @@ static inline int local_sub_and_test(long i, local_t *l) * returns true if the result is 0, or false for all other * cases. */ -static inline int local_dec_and_test(local_t *l) +static inline bool local_dec_and_test(local_t *l) { GEN_UNARY_RMWcc(_ASM_DEC, l->a.counter, "%0", "e"); } @@ -76,7 +76,7 @@ static inline int local_dec_and_test(local_t *l) * and returns true if the result is zero, or false for all * other cases. */ -static inline int local_inc_and_test(local_t *l) +static inline bool local_inc_and_test(local_t *l) { GEN_UNARY_RMWcc(_ASM_INC, l->a.counter, "%0", "e"); } @@ -90,7 +90,7 @@ static inline int local_inc_and_test(local_t *l) * if the result is negative, or false when * result is greater than or equal to zero. */ -static inline int local_add_negative(long i, local_t *l) +static inline bool local_add_negative(long i, local_t *l) { GEN_BINARY_RMWcc(_ASM_ADD, l->a.counter, "er", i, "%0", "s"); } diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 65039e9571db..184d7f3ecb9f 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -510,14 +510,14 @@ do { \ /* This is not atomic against other CPUs -- CPU preemption needs to be off */ #define x86_test_and_clear_bit_percpu(bit, var) \ ({ \ - unsigned char old__; \ + bool old__; \ asm volatile("btr %2,"__percpu_arg(1)"\n\tsetc %0" \ : "=qm" (old__), "+m" (var) \ : "dIr" (bit)); \ old__; \ }) -static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr, +static __always_inline bool x86_this_cpu_constant_test_bit(unsigned int nr, const unsigned long __percpu *addr) { unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG; @@ -529,10 +529,10 @@ static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr, #endif } -static inline int x86_this_cpu_variable_test_bit(int nr, +static inline bool x86_this_cpu_variable_test_bit(int nr, const unsigned long __percpu *addr) { - unsigned char oldbit; + bool oldbit; asm volatile("bt "__percpu_arg(2)",%1\n\t" "setc %0" diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index 8f7866a5b9a4..a15b73d90be3 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h @@ -23,11 +23,11 @@ cc_label: \ #define __GEN_RMWcc(fullop, var, cc, ...) \ do { \ - char c; \ + bool c; \ asm volatile (fullop "; set" cc " %1" \ : "+m" (var), "=qm" (c) \ : __VA_ARGS__ : "memory"); \ - return c != 0; \ + return c; \ } while (0) #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h index 453744c1d347..c5087706c02e 100644 --- a/arch/x86/include/asm/rwsem.h +++ b/arch/x86/include/asm/rwsem.h @@ -77,7 +77,7 @@ static inline void __down_read(struct rw_semaphore *sem) /* * trylock for reading -- returns 1 if successful, 0 if contention */ -static inline int __down_read_trylock(struct rw_semaphore *sem) +static inline bool __down_read_trylock(struct rw_semaphore *sem) { long result, tmp; asm volatile("# beginning __down_read_trylock\n\t" @@ -93,7 +93,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) : "+m" (sem->count), "=&a" (result), "=&r" (tmp) : "i" (RWSEM_ACTIVE_READ_BIAS) : "memory", "cc"); - return result >= 0 ? 1 : 0; + return result >= 0; } /* @@ -134,9 +134,10 @@ static inline int __down_write_killable(struct rw_semaphore *sem) /* * trylock for writing -- returns 1 if successful, 0 if contention */ -static inline int __down_write_trylock(struct rw_semaphore *sem) +static inline bool __down_write_trylock(struct rw_semaphore *sem) { - long result, tmp; + bool result; + long tmp0, tmp1; asm volatile("# beginning __down_write_trylock\n\t" " mov %0,%1\n\t" "1:\n\t" @@ -144,14 +145,14 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) /* was the active mask 0 before? */ " jnz 2f\n\t" " mov %1,%2\n\t" - " add %3,%2\n\t" + " add %4,%2\n\t" LOCK_PREFIX " cmpxchg %2,%0\n\t" " jnz 1b\n\t" "2:\n\t" - " sete %b1\n\t" - " movzbl %b1, %k1\n\t" + " sete %3\n\t" "# ending __down_write_trylock\n\t" - : "+m" (sem->count), "=&a" (result), "=&r" (tmp) + : "+m" (sem->count), "=&a" (tmp0), "=&r" (tmp1), + "=qm" (result) : "er" (RWSEM_ACTIVE_WRITE_BIAS) : "memory", "cc"); return result; diff --git a/include/linux/random.h b/include/linux/random.h index e47e533742b5..3d6e9815cd85 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -95,27 +95,27 @@ static inline void prandom_seed_state(struct rnd_state *state, u64 seed) #ifdef CONFIG_ARCH_RANDOM # include #else -static inline int arch_get_random_long(unsigned long *v) +static inline bool arch_get_random_long(unsigned long *v) { return 0; } -static inline int arch_get_random_int(unsigned int *v) +static inline bool arch_get_random_int(unsigned int *v) { return 0; } -static inline int arch_has_random(void) +static inline bool arch_has_random(void) { return 0; } -static inline int arch_get_random_seed_long(unsigned long *v) +static inline bool arch_get_random_seed_long(unsigned long *v) { return 0; } -static inline int arch_get_random_seed_int(unsigned int *v) +static inline bool arch_get_random_seed_int(unsigned int *v) { return 0; } -static inline int arch_has_random_seed(void) +static inline bool arch_has_random_seed(void) { return 0; } -- cgit v1.2.3 From f8bfc116cacbdf7e0e655d8a798a242087ed70a5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 3 Jun 2016 10:58:47 +0530 Subject: cpufreq: Remove cpufreq_frequency_get_table() Most of the callers of cpufreq_frequency_get_table() already have the pointer to a valid 'policy' structure and they don't really need to go through the per-cpu variable first and then a check to validate the frequency, in order to find the freq-table for the policy. Directly use the policy->freq_table field instead for them. Only one user of that API is left after above changes, cpu_cooling.c and it accesses the freq_table in a racy way as the policy can get freed in between. Fix it by using cpufreq_cpu_get() properly. Since there are no more users of cpufreq_frequency_get_table() left, get rid of it. Signed-off-by: Viresh Kumar Acked-by: Javi Merino (cpu_cooling.c) Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 38 +++++++++++++---------------------- drivers/cpufreq/cpufreq_ondemand.c | 2 +- drivers/cpufreq/cpufreq_stats.c | 3 +-- drivers/cpufreq/freq_table.c | 9 +++------ drivers/cpufreq/ppc_cbe_cpufreq_pmi.c | 3 +-- drivers/thermal/cpu_cooling.c | 24 +++++++++++++++++----- include/linux/cpufreq.h | 2 -- 7 files changed, 39 insertions(+), 42 deletions(-) (limited to 'include/linux') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index c6a14ba239a2..cc252eecc45a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -126,15 +126,6 @@ struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) } EXPORT_SYMBOL_GPL(get_governor_parent_kobj); -struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) -{ - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); - - return policy && !policy_is_inactive(policy) ? - policy->freq_table : NULL; -} -EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); - static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) { u64 idle_time; @@ -1950,7 +1941,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, if (!cpufreq_driver->target_index) return -EINVAL; - freq_table = cpufreq_frequency_get_table(policy->cpu); + freq_table = policy->freq_table; if (unlikely(!freq_table)) { pr_err("%s: Unable to find freq_table\n", __func__); return -EINVAL; @@ -2345,26 +2336,25 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = { *********************************************************************/ static int cpufreq_boost_set_sw(int state) { - struct cpufreq_frequency_table *freq_table; struct cpufreq_policy *policy; int ret = -EINVAL; for_each_active_policy(policy) { - freq_table = cpufreq_frequency_get_table(policy->cpu); - if (freq_table) { - ret = cpufreq_frequency_table_cpuinfo(policy, - freq_table); - if (ret) { - pr_err("%s: Policy frequency update failed\n", - __func__); - break; - } + if (!policy->freq_table) + continue; - down_write(&policy->rwsem); - policy->user_policy.max = policy->max; - cpufreq_governor_limits(policy); - up_write(&policy->rwsem); + ret = cpufreq_frequency_table_cpuinfo(policy, + policy->freq_table); + if (ret) { + pr_err("%s: Policy frequency update failed\n", + __func__); + break; } + + down_write(&policy->rwsem); + policy->user_policy.max = policy->max; + cpufreq_governor_limits(policy); + up_write(&policy->rwsem); } return ret; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index c84fc2240d49..4d2fe2710c5d 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -113,7 +113,7 @@ static void ondemand_powersave_bias_init(struct cpufreq_policy *policy) { struct od_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data); - dbs_info->freq_table = cpufreq_frequency_get_table(policy->cpu); + dbs_info->freq_table = policy->freq_table; dbs_info->freq_lo = 0; } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index c6e7f81a0397..06d3abdffd3a 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -157,11 +157,10 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) unsigned int i = 0, count = 0, ret = -ENOMEM; struct cpufreq_stats *stats; unsigned int alloc_size; - unsigned int cpu = policy->cpu; struct cpufreq_frequency_table *pos, *table; /* We need cpufreq table for creating stats table */ - table = cpufreq_frequency_get_table(cpu); + table = policy->freq_table; if (unlikely(!table)) return; diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 4e5c5dbfed7a..f52b5473b1f4 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -106,12 +106,10 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); */ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) { - struct cpufreq_frequency_table *table = - cpufreq_frequency_get_table(policy->cpu); - if (!table) + if (!policy->freq_table) return -ENODEV; - return cpufreq_frequency_table_verify(policy, table); + return cpufreq_frequency_table_verify(policy, policy->freq_table); } EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); @@ -210,9 +208,8 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, unsigned int freq) { - struct cpufreq_frequency_table *pos, *table; + struct cpufreq_frequency_table *pos, *table = policy->freq_table; - table = cpufreq_frequency_get_table(policy->cpu); if (unlikely(!table)) { pr_debug("%s: Unable to find frequency table\n", __func__); return -ENOENT; diff --git a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c index 7c4cd5c634f2..dc112481a408 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c @@ -94,7 +94,7 @@ static int pmi_notifier(struct notifier_block *nb, unsigned long event, void *data) { struct cpufreq_policy *policy = data; - struct cpufreq_frequency_table *cbe_freqs; + struct cpufreq_frequency_table *cbe_freqs = policy->freq_table; u8 node; /* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY @@ -103,7 +103,6 @@ static int pmi_notifier(struct notifier_block *nb, if (event == CPUFREQ_START) return 0; - cbe_freqs = cpufreq_frequency_get_table(policy->cpu); node = cbe_cpu_to_node(policy->cpu); pr_debug("got notified, event=%lu, node=%u\n", event, node); diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 6ceac4f2d4b2..4d678cfc81b1 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -787,22 +787,34 @@ __cpufreq_cooling_register(struct device_node *np, const struct cpumask *clip_cpus, u32 capacitance, get_static_t plat_static_func) { + struct cpufreq_policy *policy; struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_dev; char dev_name[THERMAL_NAME_LENGTH]; struct cpufreq_frequency_table *pos, *table; + struct cpumask temp_mask; unsigned int freq, i, num_cpus; int ret; - table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); + cpumask_and(&temp_mask, clip_cpus, cpu_online_mask); + policy = cpufreq_cpu_get(cpumask_first(&temp_mask)); + if (!policy) { + pr_debug("%s: CPUFreq policy not found\n", __func__); + return ERR_PTR(-EPROBE_DEFER); + } + + table = policy->freq_table; if (!table) { pr_debug("%s: CPUFreq table not found\n", __func__); - return ERR_PTR(-EPROBE_DEFER); + cool_dev = ERR_PTR(-ENODEV); + goto put_policy; } cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); - if (!cpufreq_dev) - return ERR_PTR(-ENOMEM); + if (!cpufreq_dev) { + cool_dev = ERR_PTR(-ENOMEM); + goto put_policy; + } num_cpus = cpumask_weight(clip_cpus); cpufreq_dev->time_in_idle = kcalloc(num_cpus, @@ -892,7 +904,7 @@ __cpufreq_cooling_register(struct device_node *np, CPUFREQ_POLICY_NOTIFIER); mutex_unlock(&cooling_cpufreq_lock); - return cool_dev; + goto put_policy; remove_idr: release_idr(&cpufreq_idr, cpufreq_dev->id); @@ -906,6 +918,8 @@ free_time_in_idle: kfree(cpufreq_dev->time_in_idle); free_cdev: kfree(cpufreq_dev); +put_policy: + cpufreq_cpu_put(policy); return cool_dev; } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 7ed93c310c08..1342cbc0f25e 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -632,8 +632,6 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy) return false; } #endif -/* the following funtion is for cpufreq core use only */ -struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu); /* the following are really really optional */ extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; -- cgit v1.2.3 From 7ab4aabbaa98fbf9f8967fd93162d675439337e1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 3 Jun 2016 10:58:49 +0530 Subject: cpufreq: Drop freq-table param to cpufreq_frequency_table_target() The policy already has this pointer set, use it instead. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- Documentation/cpu-freq/cpu-drivers.txt | 1 - drivers/cpufreq/amd_freq_sensitivity.c | 3 +-- drivers/cpufreq/cpufreq.c | 4 ++-- drivers/cpufreq/cpufreq_ondemand.c | 11 +++++------ drivers/cpufreq/freq_table.c | 2 +- drivers/cpufreq/powernv-cpufreq.c | 3 +-- drivers/cpufreq/s3c24xx-cpufreq.c | 11 +++++------ drivers/cpufreq/s5pv210-cpufreq.c | 3 +-- include/linux/cpufreq.h | 1 - 9 files changed, 16 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index decbb8cb5573..74e812f0719c 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -244,7 +244,6 @@ policy->max, and all other criteria are met. This is helpful for the ->verify call. int cpufreq_frequency_table_target(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table, unsigned int target_freq, unsigned int relation, unsigned int *index); diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c index bc86816693a8..3bea1bb791a9 100644 --- a/drivers/cpufreq/amd_freq_sensitivity.c +++ b/drivers/cpufreq/amd_freq_sensitivity.c @@ -92,8 +92,7 @@ static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy, unsigned int index; cpufreq_frequency_table_target(policy, - policy->freq_table, policy->cur - 1, - CPUFREQ_RELATION_H, &index); + policy->cur - 1, CPUFREQ_RELATION_H, &index); freq_next = policy->freq_table[index].frequency; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index cc252eecc45a..a28144697128 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1947,8 +1947,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, return -EINVAL; } - retval = cpufreq_frequency_table_target(policy, freq_table, target_freq, - relation, &index); + retval = cpufreq_frequency_table_target(policy, target_freq, relation, + &index); if (unlikely(retval)) { pr_err("%s: Unable to find matching freq\n", __func__); return retval; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 528353f204fd..2ee476f5a2bd 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -79,20 +79,19 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy, return freq_next; } - cpufreq_frequency_table_target(policy, freq_table, freq_next, relation, - &index); + cpufreq_frequency_table_target(policy, freq_next, relation, &index); freq_req = freq_table[index].frequency; freq_reduc = freq_req * od_tuners->powersave_bias / 1000; freq_avg = freq_req - freq_reduc; /* Find freq bounds for freq_avg in freq_table */ index = 0; - cpufreq_frequency_table_target(policy, freq_table, freq_avg, - CPUFREQ_RELATION_H, &index); + cpufreq_frequency_table_target(policy, freq_avg, CPUFREQ_RELATION_H, + &index); freq_lo = freq_table[index].frequency; index = 0; - cpufreq_frequency_table_target(policy, freq_table, freq_avg, - CPUFREQ_RELATION_L, &index); + cpufreq_frequency_table_target(policy, freq_avg, CPUFREQ_RELATION_L, + &index); freq_hi = freq_table[index].frequency; /* Find out how long we have to be in hi and lo freqs */ diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index f52b5473b1f4..f145b64649ef 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -114,7 +114,6 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); int cpufreq_frequency_table_target(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table, unsigned int target_freq, unsigned int relation, unsigned int *index) @@ -128,6 +127,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, .frequency = 0, }; struct cpufreq_frequency_table *pos; + struct cpufreq_frequency_table *table = policy->freq_table; unsigned int freq, diff, i = 0; pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 54c45368e3f1..bf267c2dfe20 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -760,8 +760,7 @@ void powernv_cpufreq_work_fn(struct work_struct *work) struct cpufreq_policy policy; cpufreq_get_policy(&policy, cpu); - cpufreq_frequency_table_target(&policy, policy.freq_table, - policy.cur, + cpufreq_frequency_table_target(&policy, policy.cur, CPUFREQ_RELATION_C, &index); powernv_cpufreq_target_index(&policy, index); cpumask_andnot(&mask, &mask, policy.cpus); diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 4567c3cab095..05a9737278f3 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -293,9 +293,8 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, __func__, policy, target_freq, relation); if (ftab) { - if (cpufreq_frequency_table_target(policy, ftab, - target_freq, relation, - &index)) { + if (cpufreq_frequency_table_target(policy, target_freq, + relation, &index)) { s3c_freq_dbg("%s: table failed\n", __func__); return -EINVAL; } @@ -323,14 +322,14 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, tmp_policy.min = policy->min * 1000; tmp_policy.max = policy->max * 1000; tmp_policy.cpu = policy->cpu; + tmp_policy.freq_table = pll_reg; /* cpufreq_frequency_table_target uses a pointer to 'index' * which is the number of the table entry, not the value of * the table entry's index field. */ - ret = cpufreq_frequency_table_target(&tmp_policy, pll_reg, - target_freq, relation, - &index); + ret = cpufreq_frequency_table_target(&tmp_policy, target_freq, + relation, &index); if (ret < 0) { pr_err("%s: no PLL available\n", __func__); diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 06d85917b6d5..6b0cfc3b8c46 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -246,8 +246,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) new_freq = s5pv210_freq_table[index].frequency; /* Finding current running level index */ - if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, - old_freq, CPUFREQ_RELATION_H, + if (cpufreq_frequency_table_target(policy, old_freq, CPUFREQ_RELATION_H, &priv_index)) { ret = -EINVAL; goto exit; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 1342cbc0f25e..bdd7f0c035ae 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -598,7 +598,6 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy); int cpufreq_frequency_table_target(struct cpufreq_policy *policy, - struct cpufreq_frequency_table *table, unsigned int target_freq, unsigned int relation, unsigned int *index); -- cgit v1.2.3 From d218ed773915a2b762d132be6bb765637338c360 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 3 Jun 2016 10:58:51 +0530 Subject: cpufreq: Return index from cpufreq_frequency_table_target() This routine can't fail unless the frequency table is invalid and doesn't contain any valid entries. Make it return the index and WARN() in case it is used for an invalid table. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- Documentation/cpu-freq/cpu-drivers.txt | 7 +++---- drivers/cpufreq/amd_freq_sensitivity.c | 4 ++-- drivers/cpufreq/cpufreq.c | 9 ++------- drivers/cpufreq/cpufreq_ondemand.c | 14 ++++++-------- drivers/cpufreq/freq_table.c | 24 +++++++++++++----------- drivers/cpufreq/powernv-cpufreq.c | 4 ++-- drivers/cpufreq/s3c24xx-cpufreq.c | 26 ++++++-------------------- drivers/cpufreq/s5pv210-cpufreq.c | 7 ++----- include/linux/cpufreq.h | 3 +-- 9 files changed, 37 insertions(+), 61 deletions(-) (limited to 'include/linux') diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt index 74e812f0719c..772b94fde264 100644 --- a/Documentation/cpu-freq/cpu-drivers.txt +++ b/Documentation/cpu-freq/cpu-drivers.txt @@ -245,12 +245,11 @@ policy->max, and all other criteria are met. This is helpful for the int cpufreq_frequency_table_target(struct cpufreq_policy *policy, unsigned int target_freq, - unsigned int relation, - unsigned int *index); + unsigned int relation); is the corresponding frequency table helper for the ->target -stage. Just pass the values to this function, and the unsigned int -index returns the number of the frequency table entry which contains +stage. Just pass the values to this function, and this function +returns the number of the frequency table entry which contains the frequency the CPU shall be set to. The following macros can be used as iterators over cpufreq_frequency_table: diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c index 3bea1bb791a9..6d5dc04c3a37 100644 --- a/drivers/cpufreq/amd_freq_sensitivity.c +++ b/drivers/cpufreq/amd_freq_sensitivity.c @@ -91,8 +91,8 @@ static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy, else { unsigned int index; - cpufreq_frequency_table_target(policy, - policy->cur - 1, CPUFREQ_RELATION_H, &index); + index = cpufreq_frequency_table_target(policy, + policy->cur - 1, CPUFREQ_RELATION_H); freq_next = policy->freq_table[index].frequency; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1685e930770f..07c933c6c29a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1914,7 +1914,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int relation) { unsigned int old_target_freq = target_freq; - int index, retval; + int index; if (cpufreq_disabled()) return -ENODEV; @@ -1943,12 +1943,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, if (!cpufreq_driver->target_index) return -EINVAL; - retval = cpufreq_frequency_table_target(policy, target_freq, relation, - &index); - if (unlikely(retval)) { - pr_err("%s: Unable to find matching freq\n", __func__); - return retval; - } + index = cpufreq_frequency_table_target(policy, target_freq, relation); return __target_index(policy, index); } diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 2ee476f5a2bd..0c93cd9dee99 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -65,7 +65,7 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy, { unsigned int freq_req, freq_reduc, freq_avg; unsigned int freq_hi, freq_lo; - unsigned int index = 0; + unsigned int index; unsigned int delay_hi_us; struct policy_dbs_info *policy_dbs = policy->governor_data; struct od_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs); @@ -79,19 +79,17 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy, return freq_next; } - cpufreq_frequency_table_target(policy, freq_next, relation, &index); + index = cpufreq_frequency_table_target(policy, freq_next, relation); freq_req = freq_table[index].frequency; freq_reduc = freq_req * od_tuners->powersave_bias / 1000; freq_avg = freq_req - freq_reduc; /* Find freq bounds for freq_avg in freq_table */ - index = 0; - cpufreq_frequency_table_target(policy, freq_avg, CPUFREQ_RELATION_H, - &index); + index = cpufreq_frequency_table_target(policy, freq_avg, + CPUFREQ_RELATION_H); freq_lo = freq_table[index].frequency; - index = 0; - cpufreq_frequency_table_target(policy, freq_avg, CPUFREQ_RELATION_L, - &index); + index = cpufreq_frequency_table_target(policy, freq_avg, + CPUFREQ_RELATION_L); freq_hi = freq_table[index].frequency; /* Find out how long we have to be in hi and lo freqs */ diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index f145b64649ef..eac8bcbdaad1 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -114,9 +114,8 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); int cpufreq_frequency_table_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation, - unsigned int *index) + unsigned int target_freq, + unsigned int relation) { struct cpufreq_frequency_table optimal = { .driver_data = ~0, @@ -129,6 +128,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, struct cpufreq_frequency_table *pos; struct cpufreq_frequency_table *table = policy->freq_table; unsigned int freq, diff, i = 0; + int index; pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu); @@ -192,16 +192,18 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, } } if (optimal.driver_data > i) { - if (suboptimal.driver_data > i) - return -EINVAL; - *index = suboptimal.driver_data; - } else - *index = optimal.driver_data; + if (suboptimal.driver_data > i) { + WARN(1, "Invalid frequency table: %d\n", policy->cpu); + return 0; + } - pr_debug("target index is %u, freq is:%u kHz\n", *index, - table[*index].frequency); + index = suboptimal.driver_data; + } else + index = optimal.driver_data; - return 0; + pr_debug("target index is %u, freq is:%u kHz\n", index, + table[index].frequency); + return index; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index bf267c2dfe20..b29c5c20c3a1 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -760,8 +760,8 @@ void powernv_cpufreq_work_fn(struct work_struct *work) struct cpufreq_policy policy; cpufreq_get_policy(&policy, cpu); - cpufreq_frequency_table_target(&policy, policy.cur, - CPUFREQ_RELATION_C, &index); + index = cpufreq_frequency_table_target(&policy, policy.cur, + CPUFREQ_RELATION_C); powernv_cpufreq_target_index(&policy, index); cpumask_andnot(&mask, &mask, policy.cpus); } diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 05a9737278f3..7b596fa38ad2 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -293,11 +293,8 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, __func__, policy, target_freq, relation); if (ftab) { - if (cpufreq_frequency_table_target(policy, target_freq, - relation, &index)) { - s3c_freq_dbg("%s: table failed\n", __func__); - return -EINVAL; - } + index = cpufreq_frequency_table_target(policy, target_freq, + relation); s3c_freq_dbg("%s: adjust %d to entry %d (%u)\n", __func__, target_freq, index, ftab[index].frequency); @@ -314,7 +311,6 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, pll = NULL; } else { struct cpufreq_policy tmp_policy; - int ret; /* we keep the cpu pll table in Hz, to ensure we get an * accurate value for the PLL output. */ @@ -324,18 +320,12 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, tmp_policy.cpu = policy->cpu; tmp_policy.freq_table = pll_reg; - /* cpufreq_frequency_table_target uses a pointer to 'index' - * which is the number of the table entry, not the value of + /* cpufreq_frequency_table_target returns the index + * of the table entry, not the value of * the table entry's index field. */ - ret = cpufreq_frequency_table_target(&tmp_policy, target_freq, - relation, &index); - - if (ret < 0) { - pr_err("%s: no PLL available\n", __func__); - goto err_notpossible; - } - + index = cpufreq_frequency_table_target(&tmp_policy, target_freq, + relation); pll = pll_reg + index; s3c_freq_dbg("%s: target %u => %u\n", @@ -345,10 +335,6 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, } return s3c_cpufreq_settarget(policy, target_freq, pll); - - err_notpossible: - pr_err("no compatible settings for %d\n", target_freq); - return -EINVAL; } struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 6b0cfc3b8c46..4f4e9df9b7fc 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -246,11 +246,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) new_freq = s5pv210_freq_table[index].frequency; /* Finding current running level index */ - if (cpufreq_frequency_table_target(policy, old_freq, CPUFREQ_RELATION_H, - &priv_index)) { - ret = -EINVAL; - goto exit; - } + priv_index = cpufreq_frequency_table_target(policy, old_freq, + CPUFREQ_RELATION_H); arm_volt = dvs_conf[index].arm_volt; int_volt = dvs_conf[index].int_volt; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index bdd7f0c035ae..c378776628b4 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -599,8 +599,7 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy); int cpufreq_frequency_table_target(struct cpufreq_policy *policy, unsigned int target_freq, - unsigned int relation, - unsigned int *index); + unsigned int relation); int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, unsigned int freq); -- cgit v1.2.3 From fc1e1c4a249e8bf0aff68576fad776dd5adc0562 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 9 Jun 2016 10:49:02 +0100 Subject: regulator: Remove regulator_can_change_voltage() There is little obvious use case for a regualtor driver to know if it is possible to vary voltages at all by itself. If a consumer needs to limit what voltages it tries to set based on the system configuration then it will need to enumerate the possible voltages, and without that even if it is possible to change voltages that doesn't mean that constraints or other consumers will allow whatever change the driver is trying to do at a given time. It doesn't even indicate if _set_voltage() calls will work as noop _set_voltage() calls return success. There were no users of this API that weren't abusing it and now they're all gone so remove the API. Signed-off-by: Mark Brown --- drivers/regulator/core.c | 27 --------------------------- include/linux/regulator/consumer.h | 6 ------ 2 files changed, 33 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ec8184d53f13..db320e8fa865 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2508,33 +2508,6 @@ int regulator_is_enabled(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_is_enabled); -/** - * regulator_can_change_voltage - check if regulator can change voltage - * @regulator: regulator source - * - * Returns positive if the regulator driver backing the source/client - * can change its voltage, false otherwise. Useful for detecting fixed - * or dummy regulators and disabling voltage change logic in the client - * driver. - */ -int regulator_can_change_voltage(struct regulator *regulator) -{ - struct regulator_dev *rdev = regulator->rdev; - - if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1) - return 1; - - if (rdev->desc->continuous_voltage_range && - rdev->constraints->min_uV && rdev->constraints->max_uV && - rdev->constraints->min_uV != rdev->constraints->max_uV) - return 1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(regulator_can_change_voltage); - /** * regulator_count_voltages - count regulator_list_voltage() selectors * @regulator: regulator source diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 48603506f8de..cae500b2c1d7 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -224,7 +224,6 @@ int regulator_bulk_force_disable(int num_consumers, void regulator_bulk_free(int num_consumers, struct regulator_bulk_data *consumers); -int regulator_can_change_voltage(struct regulator *regulator); int regulator_count_voltages(struct regulator *regulator); int regulator_list_voltage(struct regulator *regulator, unsigned selector); int regulator_is_supported_voltage(struct regulator *regulator, @@ -436,11 +435,6 @@ static inline void regulator_bulk_free(int num_consumers, { } -static inline int regulator_can_change_voltage(struct regulator *regulator) -{ - return 0; -} - static inline int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { -- cgit v1.2.3 From ca93e45347e61cd85e5d71961f6c94fad143593d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 9 Jun 2016 16:00:35 +0200 Subject: block: better packing for struct request Keep the 32-bit CPU and cmd_type flags together to avoid holes on 64-bit architectures. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0c9f8793c87e..9746d223494c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -96,12 +96,11 @@ struct request { struct request_queue *q; struct blk_mq_ctx *mq_ctx; - u64 cmd_flags; + int cpu; unsigned cmd_type; + u64 cmd_flags; unsigned long atomic_flags; - int cpu; - /* the following two fields are internal, NEVER access directly */ unsigned int __data_len; /* total data len */ sector_t __sector; /* sector cursor */ -- cgit v1.2.3 From 288dab8a35a0bde426a09870943c8d3ee3a50dab Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 9 Jun 2016 16:00:36 +0200 Subject: block: add a separate operation type for secure erase Instead of overloading the discard support with the REQ_SECURE flag. Use the opportunity to rename the queue flag as well, and remove the dead checks for this flag in the RAID 1 and RAID 10 drivers that don't claim support for secure erase. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- block/blk-core.c | 27 +++++++++++++++++---------- block/blk-lib.c | 25 ++++++++++++++----------- block/blk-merge.c | 6 ++---- drivers/block/xen-blkback/xenbus.c | 2 +- drivers/block/xen-blkfront.c | 14 +++++++++----- drivers/md/raid1.c | 3 +-- drivers/md/raid10.c | 5 ++--- drivers/mmc/card/block.c | 10 ++++++---- drivers/mmc/card/queue.c | 2 +- include/linux/blk_types.h | 5 ++--- include/linux/blkdev.h | 23 ++++------------------- kernel/trace/blktrace.c | 6 ++++-- 12 files changed, 63 insertions(+), 65 deletions(-) (limited to 'include/linux') diff --git a/block/blk-core.c b/block/blk-core.c index 32a283eb7274..db31a2981223 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1977,16 +1977,21 @@ generic_make_request_checks(struct bio *bio) } } - if ((bio_op(bio) == REQ_OP_DISCARD) && - (!blk_queue_discard(q) || - ((bio->bi_rw & REQ_SECURE) && !blk_queue_secdiscard(q)))) { - err = -EOPNOTSUPP; - goto end_io; - } - - if (bio_op(bio) == REQ_OP_WRITE_SAME && !bdev_write_same(bio->bi_bdev)) { - err = -EOPNOTSUPP; - goto end_io; + switch (bio_op(bio)) { + case REQ_OP_DISCARD: + if (!blk_queue_discard(q)) + goto not_supported; + break; + case REQ_OP_SECURE_ERASE: + if (!blk_queue_secure_erase(q)) + goto not_supported; + break; + case REQ_OP_WRITE_SAME: + if (!bdev_write_same(bio->bi_bdev)) + goto not_supported; + break; + default: + break; } /* @@ -2003,6 +2008,8 @@ generic_make_request_checks(struct bio *bio) trace_block_bio_queue(q, bio); return true; +not_supported: + err = -EOPNOTSUPP; end_io: bio->bi_error = err; bio_endio(bio); diff --git a/block/blk-lib.c b/block/blk-lib.c index ff2a7f04af4d..78626c2fde33 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -23,20 +23,27 @@ static struct bio *next_bio(struct bio *bio, unsigned int nr_pages, } int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, int op_flags, + sector_t nr_sects, gfp_t gfp_mask, int flags, struct bio **biop) { struct request_queue *q = bdev_get_queue(bdev); struct bio *bio = *biop; unsigned int granularity; + enum req_op op; int alignment; if (!q) return -ENXIO; - if (!blk_queue_discard(q)) - return -EOPNOTSUPP; - if ((op_flags & REQ_SECURE) && !blk_queue_secdiscard(q)) - return -EOPNOTSUPP; + + if (flags & BLKDEV_DISCARD_SECURE) { + if (!blk_queue_secure_erase(q)) + return -EOPNOTSUPP; + op = REQ_OP_SECURE_ERASE; + } else { + if (!blk_queue_discard(q)) + return -EOPNOTSUPP; + op = REQ_OP_DISCARD; + } /* Zero-sector (unknown) and one-sector granularities are the same. */ granularity = max(q->limits.discard_granularity >> 9, 1U); @@ -66,7 +73,7 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, bio = next_bio(bio, 1, gfp_mask); bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; - bio_set_op_attrs(bio, REQ_OP_DISCARD, op_flags); + bio_set_op_attrs(bio, op, 0); bio->bi_iter.bi_size = req_sects << 9; nr_sects -= req_sects; @@ -100,16 +107,12 @@ EXPORT_SYMBOL(__blkdev_issue_discard); int blkdev_issue_discard(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, unsigned long flags) { - int op_flags = 0; struct bio *bio = NULL; struct blk_plug plug; int ret; - if (flags & BLKDEV_DISCARD_SECURE) - op_flags |= REQ_SECURE; - blk_start_plug(&plug); - ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, op_flags, + ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, flags, &bio); if (!ret && bio) { ret = submit_bio_wait(bio); diff --git a/block/blk-merge.c b/block/blk-merge.c index c265348b75d1..9772308a8391 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -649,8 +649,7 @@ static int attempt_merge(struct request_queue *q, struct request *req, if (!rq_mergeable(req) || !rq_mergeable(next)) return 0; - if (!blk_check_merge_flags(req->cmd_flags, req_op(req), next->cmd_flags, - req_op(next))) + if (req_op(req) != req_op(next)) return 0; /* @@ -752,8 +751,7 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) if (!rq_mergeable(rq) || !bio_mergeable(bio)) return false; - if (!blk_check_merge_flags(rq->cmd_flags, req_op(rq), bio->bi_rw, - bio_op(bio))) + if (req_op(rq) != bio_op(bio)) return false; /* different data direction or already started, don't merge */ diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 3355f1cdd4e5..2994cfa44c8a 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -480,7 +480,7 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle, if (q && test_bit(QUEUE_FLAG_WC, &q->queue_flags)) vbd->flush_support = true; - if (q && blk_queue_secdiscard(q)) + if (q && blk_queue_secure_erase(q)) vbd->discard_secure = true; pr_debug("Successful creation of handle=%04x (dom=%u)\n", diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 343ef7abe5fd..10711292da2c 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -545,7 +545,7 @@ static int blkif_queue_discard_req(struct request *req, struct blkfront_ring_inf ring_req->u.discard.nr_sectors = blk_rq_sectors(req); ring_req->u.discard.id = id; ring_req->u.discard.sector_number = (blkif_sector_t)blk_rq_pos(req); - if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard) + if (req_op(req) == REQ_OP_SECURE_ERASE && info->feature_secdiscard) ring_req->u.discard.flag = BLKIF_DISCARD_SECURE; else ring_req->u.discard.flag = 0; @@ -841,7 +841,7 @@ static int blkif_queue_request(struct request *req, struct blkfront_ring_info *r return 1; if (unlikely(req_op(req) == REQ_OP_DISCARD || - req->cmd_flags & REQ_SECURE)) + req_op(req) == REQ_OP_SECURE_ERASE)) return blkif_queue_discard_req(req, rinfo); else return blkif_queue_rw_req(req, rinfo); @@ -955,7 +955,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size, rq->limits.discard_granularity = info->discard_granularity; rq->limits.discard_alignment = info->discard_alignment; if (info->feature_secdiscard) - queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, rq); + queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, rq); } /* Hard sector size and max sectors impersonate the equiv. hardware. */ @@ -1595,7 +1595,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) info->feature_discard = 0; info->feature_secdiscard = 0; queue_flag_clear(QUEUE_FLAG_DISCARD, rq); - queue_flag_clear(QUEUE_FLAG_SECDISCARD, rq); + queue_flag_clear(QUEUE_FLAG_SECERASE, rq); } blk_mq_complete_request(req, error); break; @@ -2052,10 +2052,14 @@ static int blkif_recover(struct blkfront_info *info) */ if (req_op(copy[i].request) == REQ_OP_FLUSH || req_op(copy[i].request) == REQ_OP_DISCARD || - copy[i].request->cmd_flags & (REQ_FUA | REQ_SECURE)) { + req_op(copy[i].request) == REQ_OP_SECURE_ERASE || + copy[i].request->cmd_flags & REQ_FUA) { /* * Flush operations don't contain bios, so * we need to requeue the whole request + * + * XXX: but this doesn't make any sense for a + * write with the FUA flag set.. */ list_add(©[i].request->queuelist, &requests); continue; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 10e53cd6a995..41d9c31da3b3 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1058,7 +1058,6 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio) const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_flush_fua = (bio->bi_rw & (REQ_PREFLUSH | REQ_FUA)); - const unsigned long do_sec = (bio->bi_rw & REQ_SECURE); struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; struct raid1_plug_cb *plug = NULL; @@ -1376,7 +1375,7 @@ read_again: conf->mirrors[i].rdev->data_offset); mbio->bi_bdev = conf->mirrors[i].rdev->bdev; mbio->bi_end_io = raid1_end_write_request; - bio_set_op_attrs(mbio, op, do_flush_fua | do_sync | do_sec); + bio_set_op_attrs(mbio, op, do_flush_fua | do_sync); mbio->bi_private = r1_bio; atomic_inc(&r1_bio->remaining); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 245640b50153..26ae74fd0d01 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1062,7 +1062,6 @@ static void __make_request(struct mddev *mddev, struct bio *bio) const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_fua = (bio->bi_rw & REQ_FUA); - const unsigned long do_sec = (bio->bi_rw & REQ_SECURE); unsigned long flags; struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; @@ -1362,7 +1361,7 @@ retry_write: rdev)); mbio->bi_bdev = rdev->bdev; mbio->bi_end_io = raid10_end_write_request; - bio_set_op_attrs(mbio, op, do_sync | do_fua | do_sec); + bio_set_op_attrs(mbio, op, do_sync | do_fua); mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); @@ -1404,7 +1403,7 @@ retry_write: r10_bio, rdev)); mbio->bi_bdev = rdev->bdev; mbio->bi_end_io = raid10_end_write_request; - bio_set_op_attrs(mbio, op, do_sync | do_fua | do_sec); + bio_set_op_attrs(mbio, op, do_sync | do_fua); mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index bca20f88a8b2..383184743f9a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2167,10 +2167,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) /* complete ongoing async transfer before issuing discard */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - if (req->cmd_flags & REQ_SECURE) - ret = mmc_blk_issue_secdiscard_rq(mq, req); - else - ret = mmc_blk_issue_discard_rq(mq, req); + ret = mmc_blk_issue_discard_rq(mq, req); + } else if (req && req_op(req) == REQ_OP_SECURE_ERASE) { + /* complete ongoing async transfer before issuing secure erase*/ + if (card->host->areq) + mmc_blk_issue_rw_rq(mq, NULL); + ret = mmc_blk_issue_secdiscard_rq(mq, req); } else if (req && req_op(req) == REQ_OP_FLUSH) { /* complete ongoing async transfer before issuing flush */ if (card->host->areq) diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index c2d5f6f35145..bf14642a576a 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -171,7 +171,7 @@ static void mmc_queue_setup_discard(struct request_queue *q, if (card->pref_erase > max_discard) q->limits.discard_granularity = 0; if (mmc_can_secure_erase_trim(card)) - queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); + queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q); } /** diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 562ab8301217..efba1f2ace2e 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -163,7 +163,6 @@ enum rq_flag_bits { __REQ_SYNC, /* request is sync (sync write or read) */ __REQ_META, /* metadata io request */ __REQ_PRIO, /* boost priority in cfq */ - __REQ_SECURE, /* secure discard (used with REQ_OP_DISCARD) */ __REQ_NOIDLE, /* don't anticipate more IO after this one */ __REQ_INTEGRITY, /* I/O includes block integrity payload */ @@ -212,7 +211,7 @@ enum rq_flag_bits { (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER) #define REQ_COMMON_MASK \ (REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | REQ_NOIDLE | \ - REQ_PREFLUSH | REQ_FUA | REQ_SECURE | REQ_INTEGRITY | REQ_NOMERGE) + REQ_PREFLUSH | REQ_FUA | REQ_INTEGRITY | REQ_NOMERGE) #define REQ_CLONE_MASK REQ_COMMON_MASK /* This mask is used for both bio and request merge checking */ @@ -239,7 +238,6 @@ enum rq_flag_bits { #define REQ_FLUSH_SEQ (1ULL << __REQ_FLUSH_SEQ) #define REQ_IO_STAT (1ULL << __REQ_IO_STAT) #define REQ_MIXED_MERGE (1ULL << __REQ_MIXED_MERGE) -#define REQ_SECURE (1ULL << __REQ_SECURE) #define REQ_PM (1ULL << __REQ_PM) #define REQ_HASHED (1ULL << __REQ_HASHED) #define REQ_MQ_INFLIGHT (1ULL << __REQ_MQ_INFLIGHT) @@ -248,6 +246,7 @@ enum req_op { REQ_OP_READ, REQ_OP_WRITE, REQ_OP_DISCARD, /* request to discard sectors */ + REQ_OP_SECURE_ERASE, /* request to securely erase sectors */ REQ_OP_WRITE_SAME, /* write same block many times */ REQ_OP_FLUSH, /* request for cache flush */ }; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0c9f8793c87e..53fee6123893 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -497,7 +497,7 @@ struct request_queue { #define QUEUE_FLAG_DISCARD 14 /* supports DISCARD */ #define QUEUE_FLAG_NOXMERGES 15 /* No extended merges */ #define QUEUE_FLAG_ADD_RANDOM 16 /* Contributes to random pool */ -#define QUEUE_FLAG_SECDISCARD 17 /* supports SECDISCARD */ +#define QUEUE_FLAG_SECERASE 17 /* supports secure erase */ #define QUEUE_FLAG_SAME_FORCE 18 /* force complete on same CPU */ #define QUEUE_FLAG_DEAD 19 /* queue tear-down finished */ #define QUEUE_FLAG_INIT_DONE 20 /* queue is initialized */ @@ -593,8 +593,8 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define blk_queue_stackable(q) \ test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags) #define blk_queue_discard(q) test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags) -#define blk_queue_secdiscard(q) (blk_queue_discard(q) && \ - test_bit(QUEUE_FLAG_SECDISCARD, &(q)->queue_flags)) +#define blk_queue_secure_erase(q) \ + (test_bit(QUEUE_FLAG_SECERASE, &(q)->queue_flags)) #define blk_noretry_request(rq) \ ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ @@ -675,21 +675,6 @@ static inline bool rq_mergeable(struct request *rq) return true; } -static inline bool blk_check_merge_flags(unsigned int flags1, unsigned int op1, - unsigned int flags2, unsigned int op2) -{ - if ((op1 == REQ_OP_DISCARD) != (op2 == REQ_OP_DISCARD)) - return false; - - if ((flags1 & REQ_SECURE) != (flags2 & REQ_SECURE)) - return false; - - if ((op1 == REQ_OP_WRITE_SAME) != (op2 == REQ_OP_WRITE_SAME)) - return false; - - return true; -} - static inline bool blk_write_same_mergeable(struct bio *a, struct bio *b) { if (bio_data(a) == bio_data(b)) @@ -1158,7 +1143,7 @@ extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *); extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, unsigned long flags); extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, int op_flags, + sector_t nr_sects, gfp_t gfp_mask, int flags, struct bio **biop); extern int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, struct page *page); diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 03b0dd98ff0e..af49caf973eb 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -1791,6 +1791,10 @@ void blk_fill_rwbs(char *rwbs, int op, u32 rw, int bytes) case REQ_OP_DISCARD: rwbs[i++] = 'D'; break; + case REQ_OP_SECURE_ERASE: + rwbs[i++] = 'D'; + rwbs[i++] = 'E'; + break; case REQ_OP_FLUSH: rwbs[i++] = 'F'; break; @@ -1809,8 +1813,6 @@ void blk_fill_rwbs(char *rwbs, int op, u32 rw, int bytes) rwbs[i++] = 'S'; if (rw & REQ_META) rwbs[i++] = 'M'; - if (rw & REQ_SECURE) - rwbs[i++] = 'E'; rwbs[i] = '\0'; } -- cgit v1.2.3 From 8fc554552c9d89e7bf76cd4cbc0085648bf3125b Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 9 Jun 2016 10:00:58 -0600 Subject: block: move bvec iterator into include/linux/bvec.h bvec iterator helpers should be used to implement by iterate_bvec():lib/iov_iter.c too, and move them into one header, so that we can keep bvec iterator header out of CONFIG_BLOCK. Then we can remove the reinventing of wheel in iterate_bvec(). Reviewed-by: Christoph Hellwig Signed-off-by: Ming Lei Tested-by: Hannes Reinecke Signed-off-by: Jens Axboe --- include/linux/bio.h | 51 +----------------------------------- include/linux/bvec.h | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 50 deletions(-) create mode 100644 include/linux/bvec.h (limited to 'include/linux') diff --git a/include/linux/bio.h b/include/linux/bio.h index 0bbb2e332410..8e0f677c26d2 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -31,6 +31,7 @@ /* struct bio, bio_vec and BIO_* flags are defined in blk_types.h */ #include +#include #define BIO_DEBUG @@ -47,29 +48,6 @@ #define bio_prio(bio) (bio)->bi_ioprio #define bio_set_prio(bio, prio) ((bio)->bi_ioprio = prio) -/* - * various member access, note that bio_data should of course not be used - * on highmem page vectors - */ -#define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) - -#define bvec_iter_page(bvec, iter) \ - (__bvec_iter_bvec((bvec), (iter))->bv_page) - -#define bvec_iter_len(bvec, iter) \ - min((iter).bi_size, \ - __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) - -#define bvec_iter_offset(bvec, iter) \ - (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) - -#define bvec_iter_bvec(bvec, iter) \ -((struct bio_vec) { \ - .bv_page = bvec_iter_page((bvec), (iter)), \ - .bv_len = bvec_iter_len((bvec), (iter)), \ - .bv_offset = bvec_iter_offset((bvec), (iter)), \ -}) - #define bio_iter_iovec(bio, iter) \ bvec_iter_bvec((bio)->bi_io_vec, (iter)) @@ -188,33 +166,6 @@ static inline void *bio_data(struct bio *bio) #define bio_for_each_segment_all(bvl, bio, i) \ for (i = 0, bvl = (bio)->bi_io_vec; i < (bio)->bi_vcnt; i++, bvl++) -static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter, - unsigned bytes) -{ - WARN_ONCE(bytes > iter->bi_size, - "Attempted to advance past end of bvec iter\n"); - - while (bytes) { - unsigned len = min(bytes, bvec_iter_len(bv, *iter)); - - bytes -= len; - iter->bi_size -= len; - iter->bi_bvec_done += len; - - if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) { - iter->bi_bvec_done = 0; - iter->bi_idx++; - } - } -} - -#define for_each_bvec(bvl, bio_vec, iter, start) \ - for (iter = (start); \ - (iter).bi_size && \ - ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1); \ - bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len)) - - static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, unsigned bytes) { diff --git a/include/linux/bvec.h b/include/linux/bvec.h new file mode 100644 index 000000000000..29c459da277e --- /dev/null +++ b/include/linux/bvec.h @@ -0,0 +1,74 @@ +/* + * bvec iterator + * + * Copyright (C) 2001 Ming Lei + * + * 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 in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public Licens + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- + */ +#ifndef __LINUX_BVEC_ITER_H +#define __LINUX_BVEC_ITER_H + +#include + +/* + * various member access, note that bio_data should of course not be used + * on highmem page vectors + */ +#define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) + +#define bvec_iter_page(bvec, iter) \ + (__bvec_iter_bvec((bvec), (iter))->bv_page) + +#define bvec_iter_len(bvec, iter) \ + min((iter).bi_size, \ + __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) + +#define bvec_iter_offset(bvec, iter) \ + (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) + +#define bvec_iter_bvec(bvec, iter) \ +((struct bio_vec) { \ + .bv_page = bvec_iter_page((bvec), (iter)), \ + .bv_len = bvec_iter_len((bvec), (iter)), \ + .bv_offset = bvec_iter_offset((bvec), (iter)), \ +}) + +static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter, + unsigned bytes) +{ + WARN_ONCE(bytes > iter->bi_size, + "Attempted to advance past end of bvec iter\n"); + + while (bytes) { + unsigned len = min(bytes, bvec_iter_len(bv, *iter)); + + bytes -= len; + iter->bi_size -= len; + iter->bi_bvec_done += len; + + if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) { + iter->bi_bvec_done = 0; + iter->bi_idx++; + } + } +} + +#define for_each_bvec(bvl, bio_vec, iter, start) \ + for (iter = (start); \ + (iter).bi_size && \ + ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1); \ + bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len)) + +#endif /* __LINUX_BVEC_ITER_H */ -- cgit v1.2.3 From 0781e79eb206a62c30cc3eff75aaa889cd85b276 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 30 May 2016 21:34:30 +0800 Subject: block: move two bvec structure into bvec.h This patch moves 'struct bio_vec' and 'struct bvec_iter' into 'include/linux/bvec.h', then always include this header into 'include/linux/blk_types.h'. With this change, both 'struct bvec_iter' and bvec iterator helpers don't depend on CONFIG_BLOCK any more, then we can use bvec iterator to implement iterate_bvec(): lib/iov_iter.c. Reviewed-by: Christoph Hellwig Suggested-by: Christoph Hellwig Signed-off-by: Ming Lei Tested-by: Hannes Reinecke Signed-off-by: Jens Axboe --- include/linux/bio.h | 1 - include/linux/blk_types.h | 22 +--------------------- include/linux/bvec.h | 23 ++++++++++++++++++++++- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bio.h b/include/linux/bio.h index 8e0f677c26d2..95500fee0544 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -31,7 +31,6 @@ /* struct bio, bio_vec and BIO_* flags are defined in blk_types.h */ #include -#include #define BIO_DEBUG diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 562ab8301217..b588e968dc01 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -6,6 +6,7 @@ #define __LINUX_BLK_TYPES_H #include +#include struct bio_set; struct bio; @@ -17,28 +18,7 @@ struct cgroup_subsys_state; typedef void (bio_end_io_t) (struct bio *); typedef void (bio_destructor_t) (struct bio *); -/* - * was unsigned short, but we might as well be ready for > 64kB I/O pages - */ -struct bio_vec { - struct page *bv_page; - unsigned int bv_len; - unsigned int bv_offset; -}; - #ifdef CONFIG_BLOCK - -struct bvec_iter { - sector_t bi_sector; /* device address in 512 byte - sectors */ - unsigned int bi_size; /* residual I/O count */ - - unsigned int bi_idx; /* current index into bvl_vec */ - - unsigned int bi_bvec_done; /* number of bytes completed in - current bvec */ -}; - /* * main unit of I/O for the block layer and lower layers (ie drivers and * stacking drivers) diff --git a/include/linux/bvec.h b/include/linux/bvec.h index 29c459da277e..096efd2c83e5 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -20,7 +20,28 @@ #ifndef __LINUX_BVEC_ITER_H #define __LINUX_BVEC_ITER_H -#include +#include +#include + +/* + * was unsigned short, but we might as well be ready for > 64kB I/O pages + */ +struct bio_vec { + struct page *bv_page; + unsigned int bv_len; + unsigned int bv_offset; +}; + +struct bvec_iter { + sector_t bi_sector; /* device address in 512 byte + sectors */ + unsigned int bi_size; /* residual I/O count */ + + unsigned int bi_idx; /* current index into bvl_vec */ + + unsigned int bi_bvec_done; /* number of bytes completed in + current bvec */ +}; /* * various member access, note that bio_data should of course not be used -- cgit v1.2.3 From 80f162ff061c9e280589bb1a1890c7fc21c932cd Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 30 May 2016 21:34:31 +0800 Subject: block: mark 1st parameter of bvec_iter_advance as const bvec_iter_advance() only writes the parameter of iterator, so the base address of bvec can be marked as const safely. Without the change, we can see compiling warning in the following patch for implementing iterate_bvec(): lib/iov_iter.c with bvec iterator. Reviewed-by: Christoph Hellwig Signed-off-by: Ming Lei Tested-by: Hannes Reinecke Signed-off-by: Jens Axboe --- include/linux/bvec.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/bvec.h b/include/linux/bvec.h index 096efd2c83e5..701b64a3b7c5 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -66,7 +66,8 @@ struct bvec_iter { .bv_offset = bvec_iter_offset((bvec), (iter)), \ }) -static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter, +static inline void bvec_iter_advance(const struct bio_vec *bv, + struct bvec_iter *iter, unsigned bytes) { WARN_ONCE(bytes > iter->bi_size, -- cgit v1.2.3 From 30ac4607d553277b927457678e48bb2e5de1717d Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 9 Jun 2016 10:03:28 -0600 Subject: block: bio: remove BIO_MAX_SECTORS No one need this macro, so remove it. The motivation is for supporting multipage bvecs, in which we only know what the max count of bvecs is supported in the bio, instead of max size or max sectors. Reviewed-by: Christoph Hellwig Signed-off-by: Ming Lei Tested-by: Hannes Reinecke Signed-off-by: Jens Axboe --- include/linux/bio.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/bio.h b/include/linux/bio.h index 95500fee0544..b64a3d9434d4 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -42,7 +42,6 @@ #define BIO_MAX_PAGES 256 #define BIO_MAX_SIZE (BIO_MAX_PAGES << PAGE_SHIFT) -#define BIO_MAX_SECTORS (BIO_MAX_SIZE >> 9) #define bio_prio(bio) (bio)->bi_ioprio #define bio_set_prio(bio, prio) ((bio)->bi_ioprio = prio) -- cgit v1.2.3 From 1c7fe6b438433e16d5b1211380c305351ac38299 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 9 Jun 2016 20:10:11 +0200 Subject: mtd: nand: add ESMT manufacturer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I got device with ESMT (Elite Semiconductor Memory Technology Inc) F59L1G81MA flash that was detected as: [ 0.852034] nand: device found, Manufacturer ID: 0xc8, Chip ID: 0xd1 [ 0.858402] nand: Unknown NAND 128MiB 3,3V 8-bit [ 0.863031] nand: 128MiB, SLC, page size: 2048, OOB size: 64 According to the F59L1G81MA datasheet (and Read Id documentation) C8h is a "Maker Code" which should mean ESMT. Add it to fix above "Unknown". Signed-off-by: Rafał Miłecki Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_ids.c | 1 + include/linux/mtd/nand.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index ccc05f5b2695..2af9869a115e 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -168,6 +168,7 @@ struct nand_flash_dev nand_flash_ids[] = { /* Manufacturer IDs */ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_TOSHIBA, "Toshiba"}, + {NAND_MFR_ESMT, "ESMT"}, {NAND_MFR_SAMSUNG, "Samsung"}, {NAND_MFR_FUJITSU, "Fujitsu"}, {NAND_MFR_NATIONAL, "National"}, diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index fbe8e164a4ee..8dd6e01f45c0 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -783,6 +783,7 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) * NAND Flash Manufacturer ID Codes */ #define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_ESMT 0xc8 #define NAND_MFR_SAMSUNG 0xec #define NAND_MFR_FUJITSU 0x04 #define NAND_MFR_NATIONAL 0x8f -- cgit v1.2.3 From d3fff6c443fe8f8a5ef2bdcea45e2ff39db948c7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 9 Jun 2016 07:45:12 -0700 Subject: net: add netdev_lockdep_set_classes() helper It is time to add netdev_lockdep_set_classes() helper so that lockdep annotations per device type are easier to manage. This removes a lot of copies and missing annotations. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 24 +----------------------- drivers/net/ppp/ppp_generic.c | 6 +----- drivers/net/team/team.c | 21 +-------------------- include/linux/netdevice.h | 17 +++++++++++++++++ net/bluetooth/6lowpan.c | 15 +-------------- net/ieee802154/6lowpan/core.c | 16 +--------------- net/l2tp/l2tp_eth.c | 6 +----- 7 files changed, 23 insertions(+), 82 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 681af31a60ed..90157e20357e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4607,28 +4607,6 @@ static int bond_check_params(struct bond_params *params) return 0; } -static struct lock_class_key bonding_netdev_xmit_lock_key; -static struct lock_class_key bonding_netdev_addr_lock_key; -static struct lock_class_key bonding_tx_busylock_key; -static struct lock_class_key bonding_qdisc_running_key; - -static void bond_set_lockdep_class_one(struct net_device *dev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, - &bonding_netdev_xmit_lock_key); -} - -static void bond_set_lockdep_class(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, - &bonding_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL); - dev->qdisc_tx_busylock = &bonding_tx_busylock_key; - dev->qdisc_running_key = &bonding_qdisc_running_key; -} - /* Called from registration process */ static int bond_init(struct net_device *bond_dev) { @@ -4641,7 +4619,7 @@ static int bond_init(struct net_device *bond_dev) if (!bond->wq) return -ENOMEM; - bond_set_lockdep_class(bond_dev); + netdev_lockdep_set_classes(bond_dev); list_add_tail(&bond->bond_list, &bn->dev_list); diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index aeabaa42317f..17953ab15000 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -1312,13 +1312,9 @@ ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64) return stats64; } -static struct lock_class_key ppp_tx_busylock; -static struct lock_class_key ppp_qdisc_running_key; - static int ppp_dev_init(struct net_device *dev) { - dev->qdisc_tx_busylock = &ppp_tx_busylock; - dev->qdisc_running_key = &ppp_qdisc_running_key; + netdev_lockdep_set_classes(dev); return 0; } diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 00eb38956a2c..0a1bb8387d96 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1574,25 +1574,6 @@ static const struct team_option team_options[] = { }, }; -static struct lock_class_key team_netdev_xmit_lock_key; -static struct lock_class_key team_netdev_addr_lock_key; -static struct lock_class_key team_tx_busylock_key; -static struct lock_class_key team_qdisc_running_key; - -static void team_set_lockdep_class_one(struct net_device *dev, - struct netdev_queue *txq, - void *unused) -{ - lockdep_set_class(&txq->_xmit_lock, &team_netdev_xmit_lock_key); -} - -static void team_set_lockdep_class(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, &team_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, team_set_lockdep_class_one, NULL); - dev->qdisc_tx_busylock = &team_tx_busylock_key; - dev->qdisc_running_key = &team_qdisc_running_key; -} static int team_init(struct net_device *dev) { @@ -1628,7 +1609,7 @@ static int team_init(struct net_device *dev) goto err_options_register; netif_carrier_off(dev); - team_set_lockdep_class(dev); + netdev_lockdep_set_classes(dev); return 0; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 541562333ba5..4f234b102892 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1946,6 +1946,23 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev, f(dev, &dev->_tx[i], arg); } +#define netdev_lockdep_set_classes(dev) \ +{ \ + static struct lock_class_key qdisc_tx_busylock_key; \ + static struct lock_class_key qdisc_running_key; \ + static struct lock_class_key qdisc_xmit_lock_key; \ + static struct lock_class_key dev_addr_list_lock_key; \ + unsigned int i; \ + \ + (dev)->qdisc_tx_busylock = &qdisc_tx_busylock_key; \ + (dev)->qdisc_running_key = &qdisc_running_key; \ + lockdep_set_class(&(dev)->addr_list_lock, \ + &dev_addr_list_lock_key); \ + for (i = 0; i < (dev)->num_tx_queues; i++) \ + lockdep_set_class(&(dev)->_tx[i]._xmit_lock, \ + &qdisc_xmit_lock_key); \ +} + struct netdev_queue *netdev_pick_tx(struct net_device *dev, struct sk_buff *skb, void *accel_priv); diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 977a11e418d0..d020299baba4 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -627,22 +627,9 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) return err < 0 ? NET_XMIT_DROP : err; } -static struct lock_class_key bt_tx_busylock; -static struct lock_class_key bt_netdev_xmit_lock_key; -static struct lock_class_key bt_qdisc_running_key; - -static void bt_set_lockdep_class_one(struct net_device *dev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, &bt_netdev_xmit_lock_key); -} - static int bt_dev_init(struct net_device *dev) { - netdev_for_each_tx_queue(dev, bt_set_lockdep_class_one, NULL); - dev->qdisc_tx_busylock = &bt_tx_busylock; - dev->qdisc_running_key = &bt_qdisc_running_key; + netdev_lockdep_set_classes(dev); return 0; } diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index 14aa5effd29a..4e2b30894224 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -58,23 +58,9 @@ static struct header_ops lowpan_header_ops = { .create = lowpan_header_create, }; -static struct lock_class_key lowpan_tx_busylock; -static struct lock_class_key lowpan_netdev_xmit_lock_key; -static struct lock_class_key lowpan_qdisc_running_key; - -static void lowpan_set_lockdep_class_one(struct net_device *ldev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, - &lowpan_netdev_xmit_lock_key); -} - static int lowpan_dev_init(struct net_device *ldev) { - netdev_for_each_tx_queue(ldev, lowpan_set_lockdep_class_one, NULL); - ldev->qdisc_tx_busylock = &lowpan_tx_busylock; - ldev->qdisc_running_key = &lowpan_qdisc_running_key; + netdev_lockdep_set_classes(ldev); return 0; } diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index c00d72d182fa..57fc5a46ce06 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -67,9 +67,6 @@ static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net) return net_generic(net, l2tp_eth_net_id); } -static struct lock_class_key l2tp_eth_tx_busylock; -static struct lock_class_key l2tp_qdisc_running_key; - static int l2tp_eth_dev_init(struct net_device *dev) { struct l2tp_eth *priv = netdev_priv(dev); @@ -77,8 +74,7 @@ static int l2tp_eth_dev_init(struct net_device *dev) priv->dev = dev; eth_hw_addr_random(dev); eth_broadcast_addr(dev->broadcast); - dev->qdisc_tx_busylock = &l2tp_eth_tx_busylock; - dev->qdisc_running_key = &l2tp_qdisc_running_key; + netdev_lockdep_set_classes(dev); return 0; } -- cgit v1.2.3 From 830ae442202e314c2bdf7cb4c7cc64d76db0e197 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 31 May 2016 17:32:30 +0900 Subject: extcon: Remove the deprecated extcon functions This patch removes the deprecated extcon functions using string type to identify the type of external connector. The Commit 2a9de9c0f08d61 ("extcon: Use the unique id for external connector instead of string) uses the unique id to separate the type of external connector instead of string name. - extcon_register_interest() - extcon_unregister_interest() - extcon_set_cable_state() - extcon_get_cable_state() And, extcon_register_interest() finds the first extcon device to include the requested external connector from extcon client device and then register the notifier if extcon device argument is NULL. Instead, extcon_register_notifier() supports this feature. But, this patch remains the deprecatd function definition to prevent the build break. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 201 ++++++------------------------------------------ include/linux/extcon.h | 80 ++++++------------- 2 files changed, 47 insertions(+), 234 deletions(-) (limited to 'include/linux') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 21a123cadf78..4fef9ab4b148 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -127,38 +127,6 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id return -EINVAL; } -static int find_cable_id_by_name(struct extcon_dev *edev, const char *name) -{ - int id = -EINVAL; - int i = 0; - - /* Find the id of extcon cable */ - while (extcon_name[i]) { - if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) { - id = i; - break; - } - i++; - } - - return id; -} - -static int find_cable_index_by_name(struct extcon_dev *edev, const char *name) -{ - int id; - - if (edev->max_supported == 0) - return -EINVAL; - - /* Find the the number of extcon cable */ - id = find_cable_id_by_name(edev, name); - if (id < 0) - return id; - - return find_cable_index_by_id(edev, id); -} - static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) { if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) { @@ -373,25 +341,6 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) } EXPORT_SYMBOL_GPL(extcon_get_cable_state_); -/** - * extcon_get_cable_state() - Get the status of a specific cable. - * @edev: the extcon device that has the cable. - * @cable_name: cable name. - * - * Note that this is slower than extcon_get_cable_state_. - */ -int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name) -{ - int id; - - id = find_cable_id_by_name(edev, cable_name); - if (id < 0) - return id; - - return extcon_get_cable_state_(edev, id); -} -EXPORT_SYMBOL_GPL(extcon_get_cable_state); - /** * extcon_set_cable_state_() - Set the status of a specific cable. * @edev: the extcon device that has the cable. @@ -421,28 +370,6 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, } EXPORT_SYMBOL_GPL(extcon_set_cable_state_); -/** - * extcon_set_cable_state() - Set the status of a specific cable. - * @edev: the extcon device that has the cable. - * @cable_name: cable name. - * @cable_state: the new cable status. The default semantics is - * true: attached / false: detached. - * - * Note that this is slower than extcon_set_cable_state_. - */ -int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, bool cable_state) -{ - int id; - - id = find_cable_id_by_name(edev, cable_name); - if (id < 0) - return id; - - return extcon_set_cable_state_(edev, id, cable_state); -} -EXPORT_SYMBOL_GPL(extcon_set_cable_state); - /** * extcon_get_extcon_dev() - Get the extcon device instance from the name * @extcon_name: The extcon name provided with extcon_dev_register() @@ -466,105 +393,6 @@ out: } EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); -/** - * extcon_register_interest() - Register a notifier for a state change of a - * specific cable, not an entier set of cables of a - * extcon device. - * @obj: an empty extcon_specific_cable_nb object to be returned. - * @extcon_name: the name of extcon device. - * if NULL, extcon_register_interest will register - * every cable with the target cable_name given. - * @cable_name: the target cable name. - * @nb: the notifier block to get notified. - * - * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets - * the struct for you. - * - * extcon_register_interest is a helper function for those who want to get - * notification for a single specific cable's status change. If a user wants - * to get notification for any changes of all cables of a extcon device, - * he/she should use the general extcon_register_notifier(). - * - * Note that the second parameter given to the callback of nb (val) is - * "old_state", not the current state. The current state can be retrieved - * by looking at the third pameter (edev pointer)'s state value. - */ -int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, const char *cable_name, - struct notifier_block *nb) -{ - unsigned long flags; - int ret; - - if (!obj || !cable_name || !nb) - return -EINVAL; - - if (extcon_name) { - obj->edev = extcon_get_extcon_dev(extcon_name); - if (!obj->edev) - return -ENODEV; - - obj->cable_index = find_cable_index_by_name(obj->edev, - cable_name); - if (obj->cable_index < 0) - return obj->cable_index; - - obj->user_nb = nb; - - spin_lock_irqsave(&obj->edev->lock, flags); - ret = raw_notifier_chain_register( - &obj->edev->nh[obj->cable_index], - obj->user_nb); - spin_unlock_irqrestore(&obj->edev->lock, flags); - } else { - struct class_dev_iter iter; - struct extcon_dev *extd; - struct device *dev; - - if (!extcon_class) - return -ENODEV; - class_dev_iter_init(&iter, extcon_class, NULL, NULL); - while ((dev = class_dev_iter_next(&iter))) { - extd = dev_get_drvdata(dev); - - if (find_cable_index_by_name(extd, cable_name) < 0) - continue; - - class_dev_iter_exit(&iter); - return extcon_register_interest(obj, extd->name, - cable_name, nb); - } - - ret = -ENODEV; - } - - return ret; -} -EXPORT_SYMBOL_GPL(extcon_register_interest); - -/** - * extcon_unregister_interest() - Unregister the notifier registered by - * extcon_register_interest(). - * @obj: the extcon_specific_cable_nb object returned by - * extcon_register_interest(). - */ -int extcon_unregister_interest(struct extcon_specific_cable_nb *obj) -{ - unsigned long flags; - int ret; - - if (!obj) - return -EINVAL; - - spin_lock_irqsave(&obj->edev->lock, flags); - ret = raw_notifier_chain_unregister( - &obj->edev->nh[obj->cable_index], obj->user_nb); - spin_unlock_irqrestore(&obj->edev->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(extcon_unregister_interest); - /** * extcon_register_notifier() - Register a notifiee to get notified by * any attach status changes from the extcon. @@ -582,14 +410,33 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, unsigned long flags; int ret, idx; - if (!edev || !nb) + if (!nb) return -EINVAL; - idx = find_cable_index_by_id(edev, id); + if (edev) { + idx = find_cable_index_by_id(edev, id); - spin_lock_irqsave(&edev->lock, flags); - ret = raw_notifier_chain_register(&edev->nh[idx], nb); - spin_unlock_irqrestore(&edev->lock, flags); + spin_lock_irqsave(&edev->lock, flags); + ret = raw_notifier_chain_register(&edev->nh[idx], nb); + spin_unlock_irqrestore(&edev->lock, flags); + } else { + struct extcon_dev *extd; + + mutex_lock(&extcon_dev_list_lock); + list_for_each_entry(extd, &extcon_dev_list, entry) { + idx = find_cable_index_by_id(extd, id); + if (idx >= 0) + break; + } + mutex_unlock(&extcon_dev_list_lock); + + if (idx >= 0) { + edev = extd; + return extcon_register_notifier(extd, id, nb); + } else { + ret = -ENODEV; + } + } return ret; } diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 7abf674c388c..cec5c543afc6 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -146,22 +146,6 @@ struct extcon_cable { struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ }; -/** - * struct extcon_specific_cable_nb - An internal data for - * extcon_register_interest(). - * @user_nb: user provided notifier block for events from - * a specific cable. - * @cable_index: the target cable. - * @edev: the target extcon device. - * @previous_value: the saved previous event value. - */ -struct extcon_specific_cable_nb { - struct notifier_block *user_nb; - int cable_index; - struct extcon_dev *edev; - unsigned long previous_value; -}; - #if IS_ENABLED(CONFIG_EXTCON) /* @@ -207,23 +191,6 @@ extern int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id); extern int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, bool cable_state); -extern int extcon_get_cable_state(struct extcon_dev *edev, - const char *cable_name); -extern int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, bool cable_state); - -/* - * Following APIs are for notifiees (those who want to be notified) - * to register a callback for events from a specific cable of the extcon. - * Notifiees are the connected device drivers wanting to get notified by - * a specific external port of a connection device. - */ -extern int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, - const char *cable_name, - struct notifier_block *nb); -extern int extcon_unregister_interest(struct extcon_specific_cable_nb *nb); - /* * Following APIs are to monitor every action of a notifier. * Registrar gets notified for every external port of a connection device. @@ -246,6 +213,7 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, /* Following API to get information of extcon device */ extern const char *extcon_get_edev_name(struct extcon_dev *edev); + #else /* CONFIG_EXTCON */ static inline int extcon_dev_register(struct extcon_dev *edev) { @@ -306,18 +274,6 @@ static inline int extcon_set_cable_state_(struct extcon_dev *edev, return 0; } -static inline int extcon_get_cable_state(struct extcon_dev *edev, - const char *cable_name) -{ - return 0; -} - -static inline int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, int state) -{ - return 0; -} - static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { return NULL; @@ -337,24 +293,34 @@ static inline int extcon_unregister_notifier(struct extcon_dev *edev, return 0; } -static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, - const char *cable_name, - struct notifier_block *nb) +static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, + int index) { - return 0; + return ERR_PTR(-ENODEV); } +#endif /* CONFIG_EXTCON */ -static inline int extcon_unregister_interest(struct extcon_specific_cable_nb - *obj) +/* + * Following structure and API are deprecated. EXTCON remains the function + * definition to prevent the build break. + */ +struct extcon_specific_cable_nb { + struct notifier_block *user_nb; + int cable_index; + struct extcon_dev *edev; + unsigned long previous_value; +}; + +static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj, + const char *extcon_name, const char *cable_name, + struct notifier_block *nb) { - return 0; + return -EINVAL; } -static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, - int index) +static inline int extcon_unregister_interest(struct extcon_specific_cable_nb + *obj) { - return ERR_PTR(-ENODEV); + return -EINVAL; } -#endif /* CONFIG_EXTCON */ #endif /* __LINUX_EXTCON_H__ */ -- cgit v1.2.3 From 1a89694f7899d39aa58cc6f061e97a17089ac025 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 10 Jun 2016 11:27:12 +0800 Subject: block: bio: kill BIO_MAX_SIZE No one need this macro now, so remove it. Basically only how many bvecs in one bio matters instead of how many bytes in this bio. The motivation is for supporting multipage bvecs, in which we only know what the max count of bvecs is supported in the bio. Reviewed-by: Christoph Hellwig Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- include/linux/bio.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/bio.h b/include/linux/bio.h index b64a3d9434d4..b7e1a00810f2 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -41,7 +41,6 @@ #endif #define BIO_MAX_PAGES 256 -#define BIO_MAX_SIZE (BIO_MAX_PAGES << PAGE_SHIFT) #define bio_prio(bio) (bio)->bi_ioprio #define bio_set_prio(bio, prio) ((bio)->bi_ioprio = prio) -- cgit v1.2.3 From 967dd82ffc52e9d8ea0defde094f9a39a3f4eeed Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 9 Jun 2016 18:23:53 -0700 Subject: net: dsa: b53: Add support for Broadcom RoboSwitch This patch adds support for Broadcom's BCM53xx switch family, also known as RoboSwitch. Some of these switches are ubiquituous, found in home routers, Wi-Fi routers, DSL and cable modem gateways and other networking related products. This drivers adds the library driver (b53_common.c) as well as a few bus glue drivers for MDIO, SPI, Switch Register Access Block (SRAB) and memory-mapped I/O into a SoC's address space (Broadcom BCM63xx/33xx). Basic operations are supported to bring the Layer 1/2 up and running, but not much more at this point, subsequent patches add the remaining features. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/dsa/b53.txt | 88 ++ MAINTAINERS | 8 + drivers/net/dsa/Kconfig | 2 + drivers/net/dsa/Makefile | 2 + drivers/net/dsa/b53/Kconfig | 33 + drivers/net/dsa/b53/Makefile | 6 + drivers/net/dsa/b53/b53_common.c | 1158 +++++++++++++++++++++ drivers/net/dsa/b53/b53_mdio.c | 381 +++++++ drivers/net/dsa/b53/b53_mmap.c | 260 +++++ drivers/net/dsa/b53/b53_priv.h | 322 ++++++ drivers/net/dsa/b53/b53_regs.h | 358 +++++++ drivers/net/dsa/b53/b53_spi.c | 331 ++++++ drivers/net/dsa/b53/b53_srab.c | 415 ++++++++ include/linux/platform_data/b53.h | 33 + 14 files changed, 3397 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/dsa/b53.txt create mode 100644 drivers/net/dsa/b53/Kconfig create mode 100644 drivers/net/dsa/b53/Makefile create mode 100644 drivers/net/dsa/b53/b53_common.c create mode 100644 drivers/net/dsa/b53/b53_mdio.c create mode 100644 drivers/net/dsa/b53/b53_mmap.c create mode 100644 drivers/net/dsa/b53/b53_priv.h create mode 100644 drivers/net/dsa/b53/b53_regs.h create mode 100644 drivers/net/dsa/b53/b53_spi.c create mode 100644 drivers/net/dsa/b53/b53_srab.c create mode 100644 include/linux/platform_data/b53.h (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/net/dsa/b53.txt b/Documentation/devicetree/bindings/net/dsa/b53.txt new file mode 100644 index 000000000000..ca752db14dff --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/b53.txt @@ -0,0 +1,88 @@ +Broadcom BCM53xx Ethernet switches +================================== + +Required properties: + +- compatible: For external switch chips, compatible string must be exactly one + of: "brcm,bcm5325" + "brcm,bcm53115" + "brcm,bcm53125" + "brcm,bcm53128" + "brcm,bcm5365" + "brcm,bcm5395" + "brcm,bcm5397" + "brcm,bcm5398" + + For the BCM5310x SoCs with an integrated switch, must be one of: + "brcm,bcm53010-srab" + "brcm,bcm53011-srab" + "brcm,bcm53012-srab" + "brcm,bcm53018-srab" + "brcm,bcm53019-srab" and the mandatory "brcm,bcm5301x-srab" string + + For the BCM63xx/33xx SoCs with an integrated switch, must be one of: + "brcm,bcm3384-switch" + "brcm,bcm6328-switch" + "brcm,bcm6368-switch" and the mandatory "brcm,bcm63xx-switch" + +See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional +required and optional properties. + +Examples: + +Ethernet switch connected via MDIO to the host, CPU port wired to eth0: + + eth0: ethernet@10001000 { + compatible = "brcm,unimac"; + reg = <0x10001000 0x1000>; + + fixed-link { + speed = <1000>; + duplex-full; + }; + }; + + mdio0: mdio@10000000 { + compatible = "brcm,unimac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + switch0: ethernet-switch@30 { + compatible = "brcm,bcm53125"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + port0@0 { + reg = <0>; + label = "lan1"; + }; + + port1@1 { + reg = <1>; + label = "lan2"; + }; + + port5@5 { + reg = <5>; + label = "cable-modem"; + fixed-link { + speed = <1000>; + duplex-full; + }; + phy-mode = "rgmii-txid"; + }; + + port8@8 { + reg = <8>; + label = "cpu"; + fixed-link { + speed = <1000>; + duplex-full; + }; + phy-mode = "rgmii-txid"; + ethernet = <ð0>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 16e1500d7c52..b29a08884eed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2454,6 +2454,14 @@ L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/broadcom/b44.* +BROADCOM B53 ETHERNET SWITCH DRIVER +M: Florian Fainelli +L: netdev@vger.kernel.org +L: openwrt-devel@lists.openwrt.org (subscribers-only) +S: Supported +F: drivers/net/dsa/b53/* +F: include/linux/platform_data/b53.h + BROADCOM GENET ETHERNET DRIVER M: Florian Fainelli L: netdev@vger.kernel.org diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 200663c43ce9..be481e15ec9b 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -28,4 +28,6 @@ config NET_DSA_BCM_SF2 This enables support for the Broadcom Starfighter 2 Ethernet switch chips. +source "drivers/net/dsa/b53/Kconfig" + endmenu diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index 76b751dd9efd..97bc70a7f3c7 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -1,3 +1,5 @@ obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o + +obj-y += b53/ diff --git a/drivers/net/dsa/b53/Kconfig b/drivers/net/dsa/b53/Kconfig new file mode 100644 index 000000000000..27f32a50df57 --- /dev/null +++ b/drivers/net/dsa/b53/Kconfig @@ -0,0 +1,33 @@ +menuconfig B53 + tristate "Broadcom BCM53xx managed switch support" + depends on NET_DSA + help + This driver adds support for Broadcom managed switch chips. It supports + BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX + integrated switches. + +config B53_SPI_DRIVER + tristate "B53 SPI connected switch driver" + depends on B53 && SPI + help + Select to enable support for registering switches configured through SPI. + +config B53_MDIO_DRIVER + tristate "B53 MDIO connected switch driver" + depends on B53 + help + Select to enable support for registering switches configured through MDIO. + +config B53_MMAP_DRIVER + tristate "B53 MMAP connected switch driver" + depends on B53 && HAS_IOMEM + help + Select to enable support for memory-mapped switches like the BCM63XX + integrated switches. + +config B53_SRAB_DRIVER + tristate "B53 SRAB connected switch driver" + depends on B53 && HAS_IOMEM + help + Select to enable support for memory-mapped Switch Register Access + Bridge Registers (SRAB) like it is found on the BCM53010 diff --git a/drivers/net/dsa/b53/Makefile b/drivers/net/dsa/b53/Makefile new file mode 100644 index 000000000000..7e6f9a8bfd75 --- /dev/null +++ b/drivers/net/dsa/b53/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_B53) += b53_common.o + +obj-$(CONFIG_B53_SPI_DRIVER) += b53_spi.o +obj-$(CONFIG_B53_MDIO_DRIVER) += b53_mdio.o +obj-$(CONFIG_B53_MMAP_DRIVER) += b53_mmap.o +obj-$(CONFIG_B53_SRAB_DRIVER) += b53_srab.o diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c new file mode 100644 index 000000000000..6f0337d6dfa4 --- /dev/null +++ b/drivers/net/dsa/b53/b53_common.c @@ -0,0 +1,1158 @@ +/* + * B53 switch driver main logic + * + * Copyright (C) 2011-2013 Jonas Gorski + * Copyright (C) 2016 Florian Fainelli + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b53_regs.h" +#include "b53_priv.h" + +struct b53_mib_desc { + u8 size; + u8 offset; + const char *name; +}; + +/* BCM5365 MIB counters */ +static const struct b53_mib_desc b53_mibs_65[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x44, "RxOctets" }, + { 4, 0x4c, "RxUndersizePkts" }, + { 4, 0x50, "RxPausePkts" }, + { 4, 0x54, "Pkts64Octets" }, + { 4, 0x58, "Pkts65to127Octets" }, + { 4, 0x5c, "Pkts128to255Octets" }, + { 4, 0x60, "Pkts256to511Octets" }, + { 4, 0x64, "Pkts512to1023Octets" }, + { 4, 0x68, "Pkts1024to1522Octets" }, + { 4, 0x6c, "RxOversizePkts" }, + { 4, 0x70, "RxJabbers" }, + { 4, 0x74, "RxAlignmentErrors" }, + { 4, 0x78, "RxFCSErrors" }, + { 8, 0x7c, "RxGoodOctets" }, + { 4, 0x84, "RxDropPkts" }, + { 4, 0x88, "RxUnicastPkts" }, + { 4, 0x8c, "RxMulticastPkts" }, + { 4, 0x90, "RxBroadcastPkts" }, + { 4, 0x94, "RxSAChanges" }, + { 4, 0x98, "RxFragments" }, +}; + +#define B53_MIBS_65_SIZE ARRAY_SIZE(b53_mibs_65) + +/* BCM63xx MIB counters */ +static const struct b53_mib_desc b53_mibs_63xx[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x0c, "TxQoSPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x3c, "TxQoSOctets" }, + { 8, 0x44, "RxOctets" }, + { 4, 0x4c, "RxUndersizePkts" }, + { 4, 0x50, "RxPausePkts" }, + { 4, 0x54, "Pkts64Octets" }, + { 4, 0x58, "Pkts65to127Octets" }, + { 4, 0x5c, "Pkts128to255Octets" }, + { 4, 0x60, "Pkts256to511Octets" }, + { 4, 0x64, "Pkts512to1023Octets" }, + { 4, 0x68, "Pkts1024to1522Octets" }, + { 4, 0x6c, "RxOversizePkts" }, + { 4, 0x70, "RxJabbers" }, + { 4, 0x74, "RxAlignmentErrors" }, + { 4, 0x78, "RxFCSErrors" }, + { 8, 0x7c, "RxGoodOctets" }, + { 4, 0x84, "RxDropPkts" }, + { 4, 0x88, "RxUnicastPkts" }, + { 4, 0x8c, "RxMulticastPkts" }, + { 4, 0x90, "RxBroadcastPkts" }, + { 4, 0x94, "RxSAChanges" }, + { 4, 0x98, "RxFragments" }, + { 4, 0xa0, "RxSymbolErrors" }, + { 4, 0xa4, "RxQoSPkts" }, + { 8, 0xa8, "RxQoSOctets" }, + { 4, 0xb0, "Pkts1523to2047Octets" }, + { 4, 0xb4, "Pkts2048to4095Octets" }, + { 4, 0xb8, "Pkts4096to8191Octets" }, + { 4, 0xbc, "Pkts8192to9728Octets" }, + { 4, 0xc0, "RxDiscarded" }, +}; + +#define B53_MIBS_63XX_SIZE ARRAY_SIZE(b53_mibs_63xx) + +/* MIB counters */ +static const struct b53_mib_desc b53_mibs[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x50, "RxOctets" }, + { 4, 0x58, "RxUndersizePkts" }, + { 4, 0x5c, "RxPausePkts" }, + { 4, 0x60, "Pkts64Octets" }, + { 4, 0x64, "Pkts65to127Octets" }, + { 4, 0x68, "Pkts128to255Octets" }, + { 4, 0x6c, "Pkts256to511Octets" }, + { 4, 0x70, "Pkts512to1023Octets" }, + { 4, 0x74, "Pkts1024to1522Octets" }, + { 4, 0x78, "RxOversizePkts" }, + { 4, 0x7c, "RxJabbers" }, + { 4, 0x80, "RxAlignmentErrors" }, + { 4, 0x84, "RxFCSErrors" }, + { 8, 0x88, "RxGoodOctets" }, + { 4, 0x90, "RxDropPkts" }, + { 4, 0x94, "RxUnicastPkts" }, + { 4, 0x98, "RxMulticastPkts" }, + { 4, 0x9c, "RxBroadcastPkts" }, + { 4, 0xa0, "RxSAChanges" }, + { 4, 0xa4, "RxFragments" }, + { 4, 0xa8, "RxJumboPkts" }, + { 4, 0xac, "RxSymbolErrors" }, + { 4, 0xc0, "RxDiscarded" }, +}; + +#define B53_MIBS_SIZE ARRAY_SIZE(b53_mibs) + +static int b53_do_vlan_op(struct b53_device *dev, u8 op) +{ + unsigned int i; + + b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op); + + for (i = 0; i < 10; i++) { + u8 vta; + + b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta); + if (!(vta & VTA_START_CMD)) + return 0; + + usleep_range(100, 200); + } + + return -EIO; +} + +static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, + u16 untag) +{ + if (is5325(dev)) { + u32 entry = 0; + + if (members) { + entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) | + members; + if (dev->core_rev >= 3) + entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S; + else + entry |= VA_VALID_25; + } + + b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry); + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + } else if (is5365(dev)) { + u16 entry = 0; + + if (members) + entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) | + members | VA_VALID_65; + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry); + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + } else { + b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); + b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], + (untag << VTE_UNTAG_S) | members); + + b53_do_vlan_op(dev, VTA_CMD_WRITE); + } +} + +void b53_set_forwarding(struct b53_device *dev, int enable) +{ + u8 mgmt; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (enable) + mgmt |= SM_SW_FWD_EN; + else + mgmt &= ~SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); +} + +static void b53_enable_vlan(struct b53_device *dev, int enable) +{ + u8 mgmt, vc0, vc1, vc4 = 0, vc5; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1); + + if (is5325(dev) || is5365(dev)) { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5); + } else if (is63xx(dev)) { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5); + } else { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); + } + + mgmt &= ~SM_SW_FWD_MODE; + + if (enable) { + vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; + vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; + vc5 |= VC5_DROP_VTABLE_MISS; + + if (is5325(dev)) + vc0 &= ~VC0_RESERVED_1; + + if (is5325(dev) || is5365(dev)) + vc1 |= VC1_RX_MCST_TAG_EN; + + if (!is5325(dev) && !is5365(dev)) { + if (dev->allow_vid_4095) + vc5 |= VC5_VID_FFF_EN; + else + vc5 &= ~VC5_VID_FFF_EN; + } + } else { + vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); + vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc5 &= ~VC5_DROP_VTABLE_MISS; + + if (is5325(dev) || is5365(dev)) + vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; + else + vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S; + + if (is5325(dev) || is5365(dev)) + vc1 &= ~VC1_RX_MCST_TAG_EN; + + if (!is5325(dev) && !is5365(dev)) + vc5 &= ~VC5_VID_FFF_EN; + } + + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1); + + if (is5325(dev) || is5365(dev)) { + /* enable the high 8 bit vid check on 5325 */ + if (is5325(dev) && enable) + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, + VC3_HIGH_8BIT_EN); + else + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); + + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5); + } else if (is63xx(dev)) { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5); + } else { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5); + } + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); +} + +static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100) +{ + u32 port_mask = 0; + u16 max_size = JMS_MIN_SIZE; + + if (is5325(dev) || is5365(dev)) + return -EINVAL; + + if (enable) { + port_mask = dev->enabled_ports; + max_size = JMS_MAX_SIZE; + if (allow_10_100) + port_mask |= JPM_10_100_JUMBO_EN; + } + + b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask); + return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size); +} + +static int b53_flush_arl(struct b53_device *dev) +{ + unsigned int i; + + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC); + + for (i = 0; i < 10; i++) { + u8 fast_age_ctrl; + + b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + &fast_age_ctrl); + + if (!(fast_age_ctrl & FAST_AGE_DONE)) + goto out; + + msleep(1); + } + + return -ETIMEDOUT; +out: + /* Only age dynamic entries (default behavior) */ + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, FAST_AGE_DYNAMIC); + return 0; +} + +static int b53_enable_port(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct b53_device *dev = ds_to_priv(ds); + + /* Clear the Rx and Tx disable bits and set to no spanning tree */ + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0); + + return 0; +} + +static void b53_disable_port(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct b53_device *dev = ds_to_priv(ds); + u8 reg; + + /* Disable Tx/Rx for the port */ + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), ®); + reg |= PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg); +} + +static void b53_enable_cpu_port(struct b53_device *dev) +{ + unsigned int cpu_port = dev->cpu_port; + u8 port_ctrl; + + /* BCM5325 CPU port is at 8 */ + if ((is5325(dev) || is5365(dev)) && cpu_port == B53_CPU_PORT_25) + cpu_port = B53_CPU_PORT; + + port_ctrl = PORT_CTRL_RX_BCST_EN | + PORT_CTRL_RX_MCST_EN | + PORT_CTRL_RX_UCST_EN; + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(cpu_port), port_ctrl); +} + +static void b53_enable_mib(struct b53_device *dev) +{ + u8 gc; + + b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); + gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN); + b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); +} + +static int b53_configure_vlan(struct b53_device *dev) +{ + int i; + + /* clear all vlan entries */ + if (is5325(dev) || is5365(dev)) { + for (i = 1; i < dev->num_vlans; i++) + b53_set_vlan_entry(dev, i, 0, 0); + } else { + b53_do_vlan_op(dev, VTA_CMD_CLEAR); + } + + b53_enable_vlan(dev, false); + + b53_for_each_port(dev, i) + b53_write16(dev, B53_VLAN_PAGE, + B53_VLAN_PORT_DEF_TAG(i), 1); + + if (!is5325(dev) && !is5365(dev)) + b53_set_jumbo(dev, dev->enable_jumbo, false); + + return 0; +} + +static void b53_switch_reset_gpio(struct b53_device *dev) +{ + int gpio = dev->reset_gpio; + + if (gpio < 0) + return; + + /* Reset sequence: RESET low(50ms)->high(20ms) + */ + gpio_set_value(gpio, 0); + mdelay(50); + + gpio_set_value(gpio, 1); + mdelay(20); + + dev->current_page = 0xff; +} + +static int b53_switch_reset(struct b53_device *dev) +{ + u8 mgmt; + + b53_switch_reset_gpio(dev); + + if (is539x(dev)) { + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83); + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00); + } + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + mgmt &= ~SM_SW_FWD_MODE; + mgmt |= SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + dev_err(dev->dev, "Failed to enable switch!\n"); + return -EINVAL; + } + } + + b53_enable_mib(dev); + + return b53_flush_arl(dev); +} + +static int b53_phy_read16(struct dsa_switch *ds, int addr, int reg) +{ + struct b53_device *priv = ds_to_priv(ds); + u16 value = 0; + int ret; + + if (priv->ops->phy_read16) + ret = priv->ops->phy_read16(priv, addr, reg, &value); + else + ret = b53_read16(priv, B53_PORT_MII_PAGE(addr), + reg * 2, &value); + + return ret ? ret : value; +} + +static int b53_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) +{ + struct b53_device *priv = ds_to_priv(ds); + + if (priv->ops->phy_write16) + return priv->ops->phy_write16(priv, addr, reg, val); + + return b53_write16(priv, B53_PORT_MII_PAGE(addr), reg * 2, val); +} + +static int b53_reset_switch(struct b53_device *priv) +{ + /* reset vlans */ + priv->enable_jumbo = false; + + memset(priv->ports, 0, sizeof(*priv->ports) * priv->num_ports); + + return b53_switch_reset(priv); +} + +static int b53_apply_config(struct b53_device *priv) +{ + /* disable switching */ + b53_set_forwarding(priv, 0); + + b53_configure_vlan(priv); + + /* enable switching */ + b53_set_forwarding(priv, 1); + + return 0; +} + +static void b53_reset_mib(struct b53_device *priv) +{ + u8 gc; + + b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); + + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB); + msleep(1); + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB); + msleep(1); +} + +static const struct b53_mib_desc *b53_get_mib(struct b53_device *dev) +{ + if (is5365(dev)) + return b53_mibs_65; + else if (is63xx(dev)) + return b53_mibs_63xx; + else + return b53_mibs; +} + +static unsigned int b53_get_mib_size(struct b53_device *dev) +{ + if (is5365(dev)) + return B53_MIBS_65_SIZE; + else if (is63xx(dev)) + return B53_MIBS_63XX_SIZE; + else + return B53_MIBS_SIZE; +} + +static void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +{ + struct b53_device *dev = ds_to_priv(ds); + const struct b53_mib_desc *mibs = b53_get_mib(dev); + unsigned int mib_size = b53_get_mib_size(dev); + unsigned int i; + + for (i = 0; i < mib_size; i++) + memcpy(data + i * ETH_GSTRING_LEN, + mibs[i].name, ETH_GSTRING_LEN); +} + +static void b53_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *data) +{ + struct b53_device *dev = ds_to_priv(ds); + const struct b53_mib_desc *mibs = b53_get_mib(dev); + unsigned int mib_size = b53_get_mib_size(dev); + const struct b53_mib_desc *s; + unsigned int i; + u64 val = 0; + + if (is5365(dev) && port == 5) + port = 8; + + mutex_lock(&dev->stats_mutex); + + for (i = 0; i < mib_size; i++) { + s = &mibs[i]; + + if (mibs->size == 8) { + b53_read64(dev, B53_MIB_PAGE(port), s->offset, &val); + } else { + u32 val32; + + b53_read32(dev, B53_MIB_PAGE(port), s->offset, + &val32); + val = val32; + } + data[i] = (u64)val; + } + + mutex_unlock(&dev->stats_mutex); +} + +static int b53_get_sset_count(struct dsa_switch *ds) +{ + struct b53_device *dev = ds_to_priv(ds); + + return b53_get_mib_size(dev); +} + +static int b53_set_addr(struct dsa_switch *ds, u8 *addr) +{ + return 0; +} + +static int b53_setup(struct dsa_switch *ds) +{ + struct b53_device *dev = ds_to_priv(ds); + unsigned int port; + int ret; + + ret = b53_reset_switch(dev); + if (ret) { + dev_err(ds->dev, "failed to reset switch\n"); + return ret; + } + + b53_reset_mib(dev); + + ret = b53_apply_config(dev); + if (ret) + dev_err(ds->dev, "failed to apply configuration\n"); + + for (port = 0; port < dev->num_ports; port++) { + if (BIT(port) & ds->enabled_port_mask) + b53_enable_port(ds, port, NULL); + else if (dsa_is_cpu_port(ds, port)) + b53_enable_cpu_port(dev); + else + b53_disable_port(ds, port, NULL); + } + + return ret; +} + +static void b53_adjust_link(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct b53_device *dev = ds_to_priv(ds); + u8 rgmii_ctrl = 0, reg = 0, off; + + if (!phy_is_pseudo_fixed_link(phydev)) + return; + + /* Override the port settings */ + if (port == dev->cpu_port) { + off = B53_PORT_OVERRIDE_CTRL; + reg = PORT_OVERRIDE_EN; + } else { + off = B53_GMII_PORT_OVERRIDE_CTRL(port); + reg = GMII_PO_EN; + } + + /* Set the link UP */ + if (phydev->link) + reg |= PORT_OVERRIDE_LINK; + + if (phydev->duplex == DUPLEX_FULL) + reg |= PORT_OVERRIDE_FULL_DUPLEX; + + switch (phydev->speed) { + case 2000: + reg |= PORT_OVERRIDE_SPEED_2000M; + /* fallthrough */ + case SPEED_1000: + reg |= PORT_OVERRIDE_SPEED_1000M; + break; + case SPEED_100: + reg |= PORT_OVERRIDE_SPEED_100M; + break; + case SPEED_10: + reg |= PORT_OVERRIDE_SPEED_10M; + break; + default: + dev_err(ds->dev, "unknown speed: %d\n", phydev->speed); + return; + } + + /* Enable flow control on BCM5301x's CPU port */ + if (is5301x(dev) && port == dev->cpu_port) + reg |= PORT_OVERRIDE_RX_FLOW | PORT_OVERRIDE_TX_FLOW; + + if (phydev->pause) { + if (phydev->asym_pause) + reg |= PORT_OVERRIDE_TX_FLOW; + reg |= PORT_OVERRIDE_RX_FLOW; + } + + b53_write8(dev, B53_CTRL_PAGE, off, reg); + + if (is531x5(dev) && phy_interface_is_rgmii(phydev)) { + if (port == 8) + off = B53_RGMII_CTRL_IMP; + else + off = B53_RGMII_CTRL_P(port); + + /* Configure the port RGMII clock delay by DLL disabled and + * tx_clk aligned timing (restoring to reset defaults) + */ + b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl); + rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC | + RGMII_CTRL_TIMING_SEL); + + /* PHY_INTERFACE_MODE_RGMII_TXID means TX internal delay, make + * sure that we enable the port TX clock internal delay to + * account for this internal delay that is inserted, otherwise + * the switch won't be able to receive correctly. + * + * PHY_INTERFACE_MODE_RGMII means that we are not introducing + * any delay neither on transmission nor reception, so the + * BCM53125 must also be configured accordingly to account for + * the lack of delay and introduce + * + * The BCM53125 switch has its RX clock and TX clock control + * swapped, hence the reason why we modify the TX clock path in + * the "RGMII" case + */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + rgmii_ctrl |= RGMII_CTRL_DLL_TXC; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) + rgmii_ctrl |= RGMII_CTRL_DLL_TXC | RGMII_CTRL_DLL_RXC; + rgmii_ctrl |= RGMII_CTRL_TIMING_SEL; + b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl); + + dev_info(ds->dev, "Configured port %d for %s\n", port, + phy_modes(phydev->interface)); + } + + /* configure MII port if necessary */ + if (is5325(dev)) { + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + ®); + + /* reverse mii needs to be enabled */ + if (!(reg & PORT_OVERRIDE_RV_MII_25)) { + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + reg | PORT_OVERRIDE_RV_MII_25); + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + ®); + + if (!(reg & PORT_OVERRIDE_RV_MII_25)) { + dev_err(ds->dev, + "Failed to enable reverse MII mode\n"); + return; + } + } + } else if (is5301x(dev)) { + if (port != dev->cpu_port) { + u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(dev->cpu_port); + u8 gmii_po; + + b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); + gmii_po |= GMII_PO_LINK | + GMII_PO_RX_FLOW | + GMII_PO_TX_FLOW | + GMII_PO_EN | + GMII_PO_SPEED_2000M; + b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); + } + } +} + +static struct dsa_switch_driver b53_switch_ops = { + .tag_protocol = DSA_TAG_PROTO_NONE, + .setup = b53_setup, + .set_addr = b53_set_addr, + .get_strings = b53_get_strings, + .get_ethtool_stats = b53_get_ethtool_stats, + .get_sset_count = b53_get_sset_count, + .phy_read = b53_phy_read16, + .phy_write = b53_phy_write16, + .adjust_link = b53_adjust_link, + .port_enable = b53_enable_port, + .port_disable = b53_disable_port, +}; + +struct b53_chip_data { + u32 chip_id; + const char *dev_name; + u16 vlans; + u16 enabled_ports; + u8 cpu_port; + u8 vta_regs[3]; + u8 duplex_reg; + u8 jumbo_pm_reg; + u8 jumbo_size_reg; +}; + +#define B53_VTA_REGS \ + { B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY } +#define B53_VTA_REGS_9798 \ + { B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 } +#define B53_VTA_REGS_63XX \ + { B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX } + +static const struct b53_chip_data b53_switch_chips[] = { + { + .chip_id = BCM5325_DEVICE_ID, + .dev_name = "BCM5325", + .vlans = 16, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + }, + { + .chip_id = BCM5365_DEVICE_ID, + .dev_name = "BCM5365", + .vlans = 256, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + }, + { + .chip_id = BCM5395_DEVICE_ID, + .dev_name = "BCM5395", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM5397_DEVICE_ID, + .dev_name = "BCM5397", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM5398_DEVICE_ID, + .dev_name = "BCM5398", + .vlans = 4096, + .enabled_ports = 0x7f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM53115_DEVICE_ID, + .dev_name = "BCM53115", + .vlans = 4096, + .enabled_ports = 0x1f, + .vta_regs = B53_VTA_REGS, + .cpu_port = B53_CPU_PORT, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM53125_DEVICE_ID, + .dev_name = "BCM53125", + .vlans = 4096, + .enabled_ports = 0xff, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM53128_DEVICE_ID, + .dev_name = "BCM53128", + .vlans = 4096, + .enabled_ports = 0x1ff, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM63XX_DEVICE_ID, + .dev_name = "BCM63xx", + .vlans = 4096, + .enabled_ports = 0, /* pdata must provide them */ + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_63XX, + .duplex_reg = B53_DUPLEX_STAT_63XX, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, + }, + { + .chip_id = BCM53010_DEVICE_ID, + .dev_name = "BCM53010", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM53011_DEVICE_ID, + .dev_name = "BCM53011", + .vlans = 4096, + .enabled_ports = 0x1bf, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM53012_DEVICE_ID, + .dev_name = "BCM53012", + .vlans = 4096, + .enabled_ports = 0x1bf, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM53018_DEVICE_ID, + .dev_name = "BCM53018", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, + { + .chip_id = BCM53019_DEVICE_ID, + .dev_name = "BCM53019", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, +}; + +static int b53_switch_init(struct b53_device *dev) +{ + struct dsa_switch *ds = dev->ds; + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) { + const struct b53_chip_data *chip = &b53_switch_chips[i]; + + if (chip->chip_id == dev->chip_id) { + if (!dev->enabled_ports) + dev->enabled_ports = chip->enabled_ports; + dev->name = chip->dev_name; + dev->duplex_reg = chip->duplex_reg; + dev->vta_regs[0] = chip->vta_regs[0]; + dev->vta_regs[1] = chip->vta_regs[1]; + dev->vta_regs[2] = chip->vta_regs[2]; + dev->jumbo_pm_reg = chip->jumbo_pm_reg; + ds->drv = &b53_switch_ops; + dev->cpu_port = chip->cpu_port; + dev->num_vlans = chip->vlans; + break; + } + } + + /* check which BCM5325x version we have */ + if (is5325(dev)) { + u8 vc4; + + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); + + /* check reserved bits */ + switch (vc4 & 3) { + case 1: + /* BCM5325E */ + break; + case 3: + /* BCM5325F - do not use port 4 */ + dev->enabled_ports &= ~BIT(4); + break; + default: +/* On the BCM47XX SoCs this is the supported internal switch.*/ +#ifndef CONFIG_BCM47XX + /* BCM5325M */ + return -EINVAL; +#else + break; +#endif + } + } else if (dev->chip_id == BCM53115_DEVICE_ID) { + u64 strap_value; + + b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); + /* use second IMP port if GMII is enabled */ + if (strap_value & SV_GMII_CTRL_115) + dev->cpu_port = 5; + } + + /* cpu port is always last */ + dev->num_ports = dev->cpu_port + 1; + dev->enabled_ports |= BIT(dev->cpu_port); + + dev->ports = devm_kzalloc(dev->dev, + sizeof(struct b53_port) * dev->num_ports, + GFP_KERNEL); + if (!dev->ports) + return -ENOMEM; + + dev->reset_gpio = b53_switch_get_reset_gpio(dev); + if (dev->reset_gpio >= 0) { + ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, + GPIOF_OUT_INIT_HIGH, "robo_reset"); + if (ret) + return ret; + } + + return 0; +} + +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv) +{ + struct dsa_switch *ds; + struct b53_device *dev; + + ds = devm_kzalloc(base, sizeof(*ds) + sizeof(*dev), GFP_KERNEL); + if (!ds) + return NULL; + + dev = (struct b53_device *)(ds + 1); + + ds->priv = dev; + ds->dev = base; + dev->dev = base; + + dev->ds = ds; + dev->priv = priv; + dev->ops = ops; + mutex_init(&dev->reg_mutex); + mutex_init(&dev->stats_mutex); + + return dev; +} +EXPORT_SYMBOL(b53_switch_alloc); + +int b53_switch_detect(struct b53_device *dev) +{ + u32 id32; + u16 tmp; + u8 id8; + int ret; + + ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8); + if (ret) + return ret; + + switch (id8) { + case 0: + /* BCM5325 and BCM5365 do not have this register so reads + * return 0. But the read operation did succeed, so assume this + * is one of them. + * + * Next check if we can write to the 5325's VTA register; for + * 5365 it is read only. + */ + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); + b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); + + if (tmp == 0xf) + dev->chip_id = BCM5325_DEVICE_ID; + else + dev->chip_id = BCM5365_DEVICE_ID; + break; + case BCM5395_DEVICE_ID: + case BCM5397_DEVICE_ID: + case BCM5398_DEVICE_ID: + dev->chip_id = id8; + break; + default: + ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32); + if (ret) + return ret; + + switch (id32) { + case BCM53115_DEVICE_ID: + case BCM53125_DEVICE_ID: + case BCM53128_DEVICE_ID: + case BCM53010_DEVICE_ID: + case BCM53011_DEVICE_ID: + case BCM53012_DEVICE_ID: + case BCM53018_DEVICE_ID: + case BCM53019_DEVICE_ID: + dev->chip_id = id32; + break; + default: + pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n", + id8, id32); + return -ENODEV; + } + } + + if (dev->chip_id == BCM5325_DEVICE_ID) + return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25, + &dev->core_rev); + else + return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, + &dev->core_rev); +} +EXPORT_SYMBOL(b53_switch_detect); + +int b53_switch_register(struct b53_device *dev) +{ + int ret; + + if (dev->pdata) { + dev->chip_id = dev->pdata->chip_id; + dev->enabled_ports = dev->pdata->enabled_ports; + } + + if (!dev->chip_id && b53_switch_detect(dev)) + return -EINVAL; + + ret = b53_switch_init(dev); + if (ret) + return ret; + + pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev); + + return dsa_register_switch(dev->ds, dev->ds->dev->of_node); +} +EXPORT_SYMBOL(b53_switch_register); + +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 switch library"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c new file mode 100644 index 000000000000..c6cf7cf57cc3 --- /dev/null +++ b/drivers/net/dsa/b53/b53_mdio.c @@ -0,0 +1,381 @@ +/* + * B53 register access through MII registers + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "b53_priv.h" + +/* MII registers */ +#define REG_MII_PAGE 0x10 /* MII Page register */ +#define REG_MII_ADDR 0x11 /* MII Address register */ +#define REG_MII_DATA0 0x18 /* MII Data register 0 */ +#define REG_MII_DATA1 0x19 /* MII Data register 1 */ +#define REG_MII_DATA2 0x1a /* MII Data register 2 */ +#define REG_MII_DATA3 0x1b /* MII Data register 3 */ + +#define REG_MII_PAGE_ENABLE BIT(0) +#define REG_MII_ADDR_WRITE BIT(0) +#define REG_MII_ADDR_READ BIT(1) + +static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op) +{ + int i; + u16 v; + int ret; + struct mii_bus *bus = dev->priv; + + if (dev->current_page != page) { + /* set page number */ + v = (page << 8) | REG_MII_PAGE_ENABLE; + ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_PAGE, v); + if (ret) + return ret; + dev->current_page = page; + } + + /* set register address */ + v = (reg << 8) | op; + ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_ADDR, v); + if (ret) + return ret; + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + v = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_ADDR); + if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) + break; + usleep_range(10, 100); + } + + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA0) & 0xff; + + return 0; +} + +static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0); + + return 0; +} + +static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0); + *val |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA1) << 16; + + return 0; +} + +static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct mii_bus *bus = dev->priv; + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 2; i >= 0; i--) { + temp <<= 16; + temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct mii_bus *bus = dev->priv; + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 3; i >= 0; i--) { + temp <<= 16; + temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + struct mii_bus *bus = dev->priv; + unsigned int i; + u32 temp = value; + + for (i = 0; i < 2; i++) { + int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct mii_bus *bus = dev->priv; + unsigned int i; + u64 temp = value; + + for (i = 0; i < 3; i++) { + int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct mii_bus *bus = dev->priv; + unsigned int i; + u64 temp = value; + + for (i = 0; i < 4; i++) { + int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, + REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_phy_read16(struct b53_device *dev, int addr, int reg, + u16 *value) +{ + struct mii_bus *bus = dev->priv; + + *value = mdiobus_read_nested(bus, addr, reg); + + return 0; +} + +static int b53_mdio_phy_write16(struct b53_device *dev, int addr, int reg, + u16 value) +{ + struct mii_bus *bus = dev->bus; + + return mdiobus_write_nested(bus, addr, reg, value); +} + +static struct b53_io_ops b53_mdio_ops = { + .read8 = b53_mdio_read8, + .read16 = b53_mdio_read16, + .read32 = b53_mdio_read32, + .read48 = b53_mdio_read48, + .read64 = b53_mdio_read64, + .write8 = b53_mdio_write8, + .write16 = b53_mdio_write16, + .write32 = b53_mdio_write32, + .write48 = b53_mdio_write48, + .write64 = b53_mdio_write64, + .phy_read16 = b53_mdio_phy_read16, + .phy_write16 = b53_mdio_phy_write16, +}; + +#define B53_BRCM_OUI_1 0x0143bc00 +#define B53_BRCM_OUI_2 0x03625c00 +#define B53_BRCM_OUI_3 0x00406000 + +static int b53_mdio_probe(struct mdio_device *mdiodev) +{ + struct b53_device *dev; + u32 phy_id; + int ret; + + /* allow the generic PHY driver to take over the non-management MDIO + * addresses + */ + if (mdiodev->addr != BRCM_PSEUDO_PHY_ADDR && mdiodev->addr != 0) { + dev_err(&mdiodev->dev, "leaving address %d to PHY\n", + mdiodev->addr); + return -ENODEV; + } + + /* read the first port's id */ + phy_id = mdiobus_read(mdiodev->bus, 0, 2) << 16; + phy_id |= mdiobus_read(mdiodev->bus, 0, 3); + + /* BCM5325, BCM539x (OUI_1) + * BCM53125, BCM53128 (OUI_2) + * BCM5365 (OUI_3) + */ + if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 && + (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 && + (phy_id & 0xfffffc00) != B53_BRCM_OUI_3) { + dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id); + return -ENODEV; + } + + dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus); + if (!dev) + return -ENOMEM; + + /* we don't use page 0xff, so force a page set */ + dev->current_page = 0xff; + dev->bus = mdiodev->bus; + + dev_set_drvdata(&mdiodev->dev, dev); + + ret = b53_switch_register(dev); + if (ret) { + dev_err(&mdiodev->dev, "failed to register switch: %i\n", ret); + return ret; + } + + return ret; +} + +static void b53_mdio_remove(struct mdio_device *mdiodev) +{ + struct b53_device *dev = dev_get_drvdata(&mdiodev->dev); + struct dsa_switch *ds = dev->ds; + + dsa_unregister_switch(ds); +} + +static const struct of_device_id b53_of_match[] = { + { .compatible = "brcm,bcm5325" }, + { .compatible = "brcm,bcm53115" }, + { .compatible = "brcm,bcm53125" }, + { .compatible = "brcm,bcm53128" }, + { .compatible = "brcm,bcm5365" }, + { .compatible = "brcm,bcm5395" }, + { .compatible = "brcm,bcm5397" }, + { .compatible = "brcm,bcm5398" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, b53_of_match); + +static struct mdio_driver b53_mdio_driver = { + .probe = b53_mdio_probe, + .remove = b53_mdio_remove, + .mdiodrv.driver = { + .name = "bcm53xx", + .of_match_table = b53_of_match, + }, +}; + +static int __init b53_mdio_driver_register(void) +{ + return mdio_driver_register(&b53_mdio_driver); +} +module_init(b53_mdio_driver_register); + +static void __exit b53_mdio_driver_unregister(void) +{ + mdio_driver_unregister(&b53_mdio_driver); +} +module_exit(b53_mdio_driver_unregister); + +MODULE_DESCRIPTION("B53 MDIO access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c new file mode 100644 index 000000000000..f115ee25c0e8 --- /dev/null +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -0,0 +1,260 @@ +/* + * B53 register access through memory mapped registers + * + * Copyright (C) 2012-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "b53_priv.h" + +struct b53_mmap_priv { + void __iomem *regs; +}; + +static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + u8 __iomem *regs = dev->priv; + + *val = readb(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata && + dev->pdata->big_endian) + *val = __raw_readw(regs + (page << 8) + reg); + else + *val = readw(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata && + dev->pdata->big_endian) + *val = __raw_readl(regs + (page << 8) + reg); + else + *val = readl(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (reg % 4) { + u16 lo; + u32 hi; + + b53_mmap_read16(dev, page, reg, &lo); + b53_mmap_read32(dev, page, reg + 2, &hi); + + *val = ((u64)hi << 16) | lo; + } else { + u32 lo; + u16 hi; + + b53_mmap_read32(dev, page, reg, &lo); + b53_mmap_read16(dev, page, reg + 4, &hi); + + *val = ((u64)hi << 32) | lo; + } + + return 0; +} + +static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u32 hi, lo; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + b53_mmap_read32(dev, page, reg, &lo); + b53_mmap_read32(dev, page, reg + 4, &hi); + + *val = ((u64)hi << 32) | lo; + + return 0; +} + +static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + u8 __iomem *regs = dev->priv; + + writeb(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata && + dev->pdata->big_endian) + __raw_writew(value, regs + (page << 8) + reg); + else + writew(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata && + dev->pdata->big_endian) + __raw_writel(value, regs + (page << 8) + reg); + else + writel(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (reg % 4) { + u32 hi = (u32)(value >> 16); + u16 lo = (u16)value; + + b53_mmap_write16(dev, page, reg, lo); + b53_mmap_write32(dev, page, reg + 2, hi); + } else { + u16 hi = (u16)(value >> 32); + u32 lo = (u32)value; + + b53_mmap_write32(dev, page, reg, lo); + b53_mmap_write16(dev, page, reg + 4, hi); + } + + return 0; +} + +static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u32 hi, lo; + + hi = upper_32_bits(value); + lo = lower_32_bits(value); + + if (WARN_ON(reg % 4)) + return -EINVAL; + + b53_mmap_write32(dev, page, reg, lo); + b53_mmap_write32(dev, page, reg + 4, hi); + + return 0; +} + +static struct b53_io_ops b53_mmap_ops = { + .read8 = b53_mmap_read8, + .read16 = b53_mmap_read16, + .read32 = b53_mmap_read32, + .read48 = b53_mmap_read48, + .read64 = b53_mmap_read64, + .write8 = b53_mmap_write8, + .write16 = b53_mmap_write16, + .write32 = b53_mmap_write32, + .write48 = b53_mmap_write48, + .write64 = b53_mmap_write64, +}; + +static int b53_mmap_probe(struct platform_device *pdev) +{ + struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_device *dev; + + if (!pdata) + return -EINVAL; + + dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); + if (!dev) + return -ENOMEM; + + if (pdata) + dev->pdata = pdata; + + platform_set_drvdata(pdev, dev); + + return b53_switch_register(dev); +} + +static int b53_mmap_remove(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static const struct of_device_id b53_mmap_of_table[] = { + { .compatible = "brcm,bcm3384-switch" }, + { .compatible = "brcm,bcm6328-switch" }, + { .compatible = "brcm,bcm6368-switch" }, + { .compatible = "brcm,bcm63xx-switch" }, + { /* sentinel */ }, +}; + +static struct platform_driver b53_mmap_driver = { + .probe = b53_mmap_probe, + .remove = b53_mmap_remove, + .driver = { + .name = "b53-switch", + .of_match_table = b53_mmap_of_table, + }, +}; + +module_platform_driver(b53_mmap_driver); +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 MMAP access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h new file mode 100644 index 000000000000..c4844155546b --- /dev/null +++ b/drivers/net/dsa/b53/b53_priv.h @@ -0,0 +1,322 @@ +/* + * B53 common definitions + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_PRIV_H +#define __B53_PRIV_H + +#include +#include +#include +#include + +struct b53_device; + +struct b53_io_ops { + int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value); + int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value); + int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value); + int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value); + int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value); + int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value); + int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value); + int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value); + int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value); + int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value); + int (*phy_read16)(struct b53_device *dev, int addr, int reg, u16 *value); + int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value); +}; + +enum { + BCM5325_DEVICE_ID = 0x25, + BCM5365_DEVICE_ID = 0x65, + BCM5395_DEVICE_ID = 0x95, + BCM5397_DEVICE_ID = 0x97, + BCM5398_DEVICE_ID = 0x98, + BCM53115_DEVICE_ID = 0x53115, + BCM53125_DEVICE_ID = 0x53125, + BCM53128_DEVICE_ID = 0x53128, + BCM63XX_DEVICE_ID = 0x6300, + BCM53010_DEVICE_ID = 0x53010, + BCM53011_DEVICE_ID = 0x53011, + BCM53012_DEVICE_ID = 0x53012, + BCM53018_DEVICE_ID = 0x53018, + BCM53019_DEVICE_ID = 0x53019, +}; + +#define B53_N_PORTS 9 +#define B53_N_PORTS_25 6 + +struct b53_port { +}; + +struct b53_device { + struct dsa_switch *ds; + struct b53_platform_data *pdata; + const char *name; + + struct mutex reg_mutex; + struct mutex stats_mutex; + const struct b53_io_ops *ops; + + /* chip specific data */ + u32 chip_id; + u8 core_rev; + u8 vta_regs[3]; + u8 duplex_reg; + u8 jumbo_pm_reg; + u8 jumbo_size_reg; + int reset_gpio; + + /* used ports mask */ + u16 enabled_ports; + unsigned int cpu_port; + + /* connect specific data */ + u8 current_page; + struct device *dev; + + /* Master MDIO bus we got probed from */ + struct mii_bus *bus; + + /* Slave MDIO bus we created */ + struct mii_bus *slave_bus; + void *priv; + + /* run time configuration */ + unsigned enable_jumbo:1; + unsigned allow_vid_4095:1; + unsigned int num_vlans; + unsigned int num_ports; + struct b53_port *ports; +}; + +#define b53_for_each_port(dev, i) \ + for (i = 0; i < B53_N_PORTS; i++) \ + if (dev->enabled_ports & BIT(i)) + + +static inline int is5325(struct b53_device *dev) +{ + return dev->chip_id == BCM5325_DEVICE_ID; +} + +static inline int is5365(struct b53_device *dev) +{ +#ifdef CONFIG_BCM47XX + return dev->chip_id == BCM5365_DEVICE_ID; +#else + return 0; +#endif +} + +static inline int is5397_98(struct b53_device *dev) +{ + return dev->chip_id == BCM5397_DEVICE_ID || + dev->chip_id == BCM5398_DEVICE_ID; +} + +static inline int is539x(struct b53_device *dev) +{ + return dev->chip_id == BCM5395_DEVICE_ID || + dev->chip_id == BCM5397_DEVICE_ID || + dev->chip_id == BCM5398_DEVICE_ID; +} + +static inline int is531x5(struct b53_device *dev) +{ + return dev->chip_id == BCM53115_DEVICE_ID || + dev->chip_id == BCM53125_DEVICE_ID || + dev->chip_id == BCM53128_DEVICE_ID; +} + +static inline int is63xx(struct b53_device *dev) +{ +#ifdef CONFIG_BCM63XX + return dev->chip_id == BCM63XX_DEVICE_ID; +#else + return 0; +#endif +} + +static inline int is5301x(struct b53_device *dev) +{ + return dev->chip_id == BCM53010_DEVICE_ID || + dev->chip_id == BCM53011_DEVICE_ID || + dev->chip_id == BCM53012_DEVICE_ID || + dev->chip_id == BCM53018_DEVICE_ID || + dev->chip_id == BCM53019_DEVICE_ID; +} + +#define B53_CPU_PORT_25 5 +#define B53_CPU_PORT 8 + +static inline int is_cpu_port(struct b53_device *dev, int port) +{ + return dev->cpu_port; +} + +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv); + +int b53_switch_detect(struct b53_device *dev); + +int b53_switch_register(struct b53_device *dev); + +static inline void b53_switch_remove(struct b53_device *dev) +{ + dsa_unregister_switch(dev->ds); +} + +static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read8(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read16(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read32(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read48(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read64(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write8(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write16(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write32(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write48(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write64(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +#ifdef CONFIG_BCM47XX + +#include +#include +#include +static inline int b53_switch_get_reset_gpio(struct b53_device *dev) +{ + enum bcm47xx_board board = bcm47xx_board_get(); + + switch (board) { + case BCM47XX_BOARD_LINKSYS_WRT300NV11: + case BCM47XX_BOARD_LINKSYS_WRT310NV1: + return 8; + default: + return bcm47xx_nvram_gpio_pin("robo_reset"); + } +} +#else +static inline int b53_switch_get_reset_gpio(struct b53_device *dev) +{ + return -ENOENT; +} +#endif +#endif diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h new file mode 100644 index 000000000000..ccf8af7717d3 --- /dev/null +++ b/drivers/net/dsa/b53/b53_regs.h @@ -0,0 +1,358 @@ +/* + * B53 register definitions + * + * Copyright (C) 2004 Broadcom Corporation + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_REGS_H +#define __B53_REGS_H + +/* Management Port (SMP) Page offsets */ +#define B53_CTRL_PAGE 0x00 /* Control */ +#define B53_STAT_PAGE 0x01 /* Status */ +#define B53_MGMT_PAGE 0x02 /* Management Mode */ +#define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */ +#define B53_ARLCTRL_PAGE 0x04 /* ARL Control */ +#define B53_ARLIO_PAGE 0x05 /* ARL Access */ +#define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */ +#define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */ + +/* PHY Registers */ +#define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */ +#define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */ +#define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */ + +/* MIB registers */ +#define B53_MIB_PAGE(i) (0x20 + (i)) + +/* Quality of Service (QoS) Registers */ +#define B53_QOS_PAGE 0x30 + +/* Port VLAN Page */ +#define B53_PVLAN_PAGE 0x31 + +/* VLAN Registers */ +#define B53_VLAN_PAGE 0x34 + +/* Jumbo Frame Registers */ +#define B53_JUMBO_PAGE 0x40 + +/* CFP Configuration Registers Page */ +#define B53_CFP_PAGE 0xa1 + +/************************************************************************* + * Control Page registers + *************************************************************************/ + +/* Port Control Register (8 bit) */ +#define B53_PORT_CTRL(i) (0x00 + (i)) +#define PORT_CTRL_RX_DISABLE BIT(0) +#define PORT_CTRL_TX_DISABLE BIT(1) +#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */ +#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */ +#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */ +#define PORT_CTRL_STP_STATE_S 5 +#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S) + +/* SMP Control Register (8 bit) */ +#define B53_SMP_CTRL 0x0a + +/* Switch Mode Control Register (8 bit) */ +#define B53_SWITCH_MODE 0x0b +#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */ +#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */ + +/* IMP Port state override register (8 bit) */ +#define B53_PORT_OVERRIDE_CTRL 0x0e +#define PORT_OVERRIDE_LINK BIT(0) +#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define PORT_OVERRIDE_SPEED_S 2 +#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */ +#define PORT_OVERRIDE_RX_FLOW BIT(4) +#define PORT_OVERRIDE_TX_FLOW BIT(5) +#define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */ +#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */ + +/* Power-down mode control */ +#define B53_PD_MODE_CTRL_25 0x0f + +/* IP Multicast control (8 bit) */ +#define B53_IP_MULTICAST_CTRL 0x21 +#define B53_IPMC_FWD_EN BIT(1) +#define B53_UC_FWD_EN BIT(6) +#define B53_MC_FWD_EN BIT(7) + +/* (16 bit) */ +#define B53_UC_FLOOD_MASK 0x32 +#define B53_MC_FLOOD_MASK 0x34 +#define B53_IPMC_FLOOD_MASK 0x36 + +/* + * Override Ports 0-7 State on devices with xMII interfaces (8 bit) + * + * For port 8 still use B53_PORT_OVERRIDE_CTRL + * Please note that not all ports are available on every hardware, e.g. BCM5301X + * don't include overriding port 6, BCM63xx also have some limitations. + */ +#define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i)) +#define GMII_PO_LINK BIT(0) +#define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define GMII_PO_SPEED_S 2 +#define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S) +#define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S) +#define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S) +#define GMII_PO_RX_FLOW BIT(4) +#define GMII_PO_TX_FLOW BIT(5) +#define GMII_PO_EN BIT(6) /* Use the register contents */ +#define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */ + +#define B53_RGMII_CTRL_IMP 0x60 +#define RGMII_CTRL_ENABLE_GMII BIT(7) +#define RGMII_CTRL_TIMING_SEL BIT(2) +#define RGMII_CTRL_DLL_RXC BIT(1) +#define RGMII_CTRL_DLL_TXC BIT(0) + +#define B53_RGMII_CTRL_P(i) (B53_RGMII_CTRL_IMP + (i)) + +/* Software reset register (8 bit) */ +#define B53_SOFTRESET 0x79 +#define SW_RST BIT(7) +#define EN_SW_RST BIT(4) + +/* Fast Aging Control register (8 bit) */ +#define B53_FAST_AGE_CTRL 0x88 +#define FAST_AGE_STATIC BIT(0) +#define FAST_AGE_DYNAMIC BIT(1) +#define FAST_AGE_PORT BIT(2) +#define FAST_AGE_VLAN BIT(3) +#define FAST_AGE_STP BIT(4) +#define FAST_AGE_MC BIT(5) +#define FAST_AGE_DONE BIT(7) + +/************************************************************************* + * Status Page registers + *************************************************************************/ + +/* Link Status Summary Register (16bit) */ +#define B53_LINK_STAT 0x00 + +/* Link Status Change Register (16 bit) */ +#define B53_LINK_STAT_CHANGE 0x02 + +/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */ +#define B53_SPEED_STAT 0x04 +#define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1) +#define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3) +#define SPEED_STAT_10M 0 +#define SPEED_STAT_100M 1 +#define SPEED_STAT_1000M 2 + +/* Duplex Status Summary (16 bit) */ +#define B53_DUPLEX_STAT_FE 0x06 +#define B53_DUPLEX_STAT_GE 0x08 +#define B53_DUPLEX_STAT_63XX 0x0c + +/* Revision ID register for BCM5325 */ +#define B53_REV_ID_25 0x50 + +/* Strap Value (48 bit) */ +#define B53_STRAP_VALUE 0x70 +#define SV_GMII_CTRL_115 BIT(27) + +/************************************************************************* + * Management Mode Page Registers + *************************************************************************/ + +/* Global Management Config Register (8 bit) */ +#define B53_GLOBAL_CONFIG 0x00 +#define GC_RESET_MIB 0x01 +#define GC_RX_BPDU_EN 0x02 +#define GC_MIB_AC_HDR_EN 0x10 +#define GC_MIB_AC_EN 0x20 +#define GC_FRM_MGMT_PORT_M 0xC0 +#define GC_FRM_MGMT_PORT_04 0x00 +#define GC_FRM_MGMT_PORT_MII 0x80 + +/* Broadcom Header control register (8 bit) */ +#define B53_BRCM_HDR 0x03 +#define BRCM_HDR_P8_EN BIT(0) /* Enable tagging on port 8 */ +#define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */ + +/* Device ID register (8 or 32 bit) */ +#define B53_DEVICE_ID 0x30 + +/* Revision ID register (8 bit) */ +#define B53_REV_ID 0x40 + +/************************************************************************* + * ARL Access Page Registers + *************************************************************************/ + +/* VLAN Table Access Register (8 bit) */ +#define B53_VT_ACCESS 0x80 +#define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */ +#define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */ +#define VTA_CMD_WRITE 0 +#define VTA_CMD_READ 1 +#define VTA_CMD_CLEAR 2 +#define VTA_START_CMD BIT(7) + +/* VLAN Table Index Register (16 bit) */ +#define B53_VT_INDEX 0x81 +#define B53_VT_INDEX_9798 0x61 +#define B53_VT_INDEX_63XX 0x62 + +/* VLAN Table Entry Register (32 bit) */ +#define B53_VT_ENTRY 0x83 +#define B53_VT_ENTRY_9798 0x63 +#define B53_VT_ENTRY_63XX 0x64 +#define VTE_MEMBERS 0x1ff +#define VTE_UNTAG_S 9 +#define VTE_UNTAG (0x1ff << 9) + +/************************************************************************* + * Port VLAN Registers + *************************************************************************/ + +/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */ +#define B53_PVLAN_PORT_MASK(i) ((i) * 2) + +/************************************************************************* + * 802.1Q Page Registers + *************************************************************************/ + +/* Global QoS Control (8 bit) */ +#define B53_QOS_GLOBAL_CTL 0x00 + +/* Enable 802.1Q for individual Ports (16 bit) */ +#define B53_802_1P_EN 0x04 + +/************************************************************************* + * VLAN Page Registers + *************************************************************************/ + +/* VLAN Control 0 (8 bit) */ +#define B53_VLAN_CTRL0 0x00 +#define VC0_8021PF_CTRL_MASK 0x3 +#define VC0_8021PF_CTRL_NONE 0x0 +#define VC0_8021PF_CTRL_CHANGE_PRI 0x1 +#define VC0_8021PF_CTRL_CHANGE_VID 0x2 +#define VC0_8021PF_CTRL_CHANGE_BOTH 0x3 +#define VC0_8021QF_CTRL_MASK 0xc +#define VC0_8021QF_CTRL_CHANGE_PRI 0x1 +#define VC0_8021QF_CTRL_CHANGE_VID 0x2 +#define VC0_8021QF_CTRL_CHANGE_BOTH 0x3 +#define VC0_RESERVED_1 BIT(1) +#define VC0_DROP_VID_MISS BIT(4) +#define VC0_VID_HASH_VID BIT(5) +#define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */ +#define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */ + +/* VLAN Control 1 (8 bit) */ +#define B53_VLAN_CTRL1 0x01 +#define VC1_RX_MCST_TAG_EN BIT(1) +#define VC1_RX_MCST_FWD_EN BIT(2) +#define VC1_RX_MCST_UNTAG_EN BIT(3) + +/* VLAN Control 2 (8 bit) */ +#define B53_VLAN_CTRL2 0x02 + +/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */ +#define B53_VLAN_CTRL3 0x03 +#define B53_VLAN_CTRL3_63XX 0x04 +#define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */ +#define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */ + +/* VLAN Control 4 (8 bit) */ +#define B53_VLAN_CTRL4 0x05 +#define B53_VLAN_CTRL4_25 0x04 +#define B53_VLAN_CTRL4_63XX 0x06 +#define VC4_ING_VID_CHECK_S 6 +#define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S) +#define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */ +#define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */ +#define VC4_NO_ING_VID_CHK 2 /* do not check */ +#define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */ + +/* VLAN Control 5 (8 bit) */ +#define B53_VLAN_CTRL5 0x06 +#define B53_VLAN_CTRL5_25 0x05 +#define B53_VLAN_CTRL5_63XX 0x07 +#define VC5_VID_FFF_EN BIT(2) +#define VC5_DROP_VTABLE_MISS BIT(3) + +/* VLAN Control 6 (8 bit) */ +#define B53_VLAN_CTRL6 0x07 +#define B53_VLAN_CTRL6_63XX 0x08 + +/* VLAN Table Access Register (16 bit) */ +#define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */ +#define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */ +#define VTA_VID_LOW_MASK_25 0xf +#define VTA_VID_LOW_MASK_65 0xff +#define VTA_VID_HIGH_S_25 4 +#define VTA_VID_HIGH_S_65 8 +#define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E) +#define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65) +#define VTA_RW_STATE BIT(12) +#define VTA_RW_STATE_RD 0 +#define VTA_RW_STATE_WR BIT(12) +#define VTA_RW_OP_EN BIT(13) + +/* VLAN Read/Write Registers for (16/32 bit) */ +#define B53_VLAN_WRITE_25 0x08 +#define B53_VLAN_WRITE_65 0x0a +#define B53_VLAN_READ 0x0c +#define VA_MEMBER_MASK 0x3f +#define VA_UNTAG_S_25 6 +#define VA_UNTAG_MASK_25 0x3f +#define VA_UNTAG_S_65 7 +#define VA_UNTAG_MASK_65 0x1f +#define VA_VID_HIGH_S 12 +#define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S) +#define VA_VALID_25 BIT(20) +#define VA_VALID_25_R4 BIT(24) +#define VA_VALID_65 BIT(14) + +/* VLAN Port Default Tag (16 bit) */ +#define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i)) + +/************************************************************************* + * Jumbo Frame Page Registers + *************************************************************************/ + +/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */ +#define B53_JUMBO_PORT_MASK 0x01 +#define B53_JUMBO_PORT_MASK_63XX 0x04 +#define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */ + +/* Good Frame Max Size without 802.1Q TAG (16 bit) */ +#define B53_JUMBO_MAX_SIZE 0x05 +#define B53_JUMBO_MAX_SIZE_63XX 0x08 +#define JMS_MIN_SIZE 1518 +#define JMS_MAX_SIZE 9724 + +/************************************************************************* + * CFP Configuration Page Registers + *************************************************************************/ + +/* CFP Control Register with ports map (8 bit) */ +#define B53_CFP_CTRL 0x00 + +#endif /* !__B53_REGS_H */ diff --git a/drivers/net/dsa/b53/b53_spi.c b/drivers/net/dsa/b53/b53_spi.c new file mode 100644 index 000000000000..2bda0b5f1578 --- /dev/null +++ b/drivers/net/dsa/b53/b53_spi.c @@ -0,0 +1,331 @@ +/* + * B53 register access through SPI + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "b53_priv.h" + +#define B53_SPI_DATA 0xf0 + +#define B53_SPI_STATUS 0xfe +#define B53_SPI_CMD_SPIF BIT(7) +#define B53_SPI_CMD_RACK BIT(5) + +#define B53_SPI_CMD_READ 0x00 +#define B53_SPI_CMD_WRITE 0x01 +#define B53_SPI_CMD_NORMAL 0x60 +#define B53_SPI_CMD_FAST 0x10 + +#define B53_SPI_PAGE_SELECT 0xff + +static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val, + unsigned int len) +{ + u8 txbuf[2]; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ; + txbuf[1] = reg; + + return spi_write_then_read(spi, txbuf, 2, val, len); +} + +static inline int b53_spi_clear_status(struct spi_device *spi) +{ + unsigned int i; + u8 rxbuf; + int ret; + + for (i = 0; i < 10; i++) { + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); + if (ret) + return ret; + + if (!(rxbuf & B53_SPI_CMD_SPIF)) + break; + + mdelay(1); + } + + if (i == 10) + return -EIO; + + return 0; +} + +static inline int b53_spi_set_page(struct spi_device *spi, u8 page) +{ + u8 txbuf[3]; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = B53_SPI_PAGE_SELECT; + txbuf[2] = page; + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page) +{ + int ret = b53_spi_clear_status(spi); + + if (ret) + return ret; + + return b53_spi_set_page(spi, page); +} + +static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg) +{ + u8 rxbuf; + int retry_count; + int ret; + + ret = b53_spi_read_reg(spi, reg, &rxbuf, 1); + if (ret) + return ret; + + for (retry_count = 0; retry_count < 10; retry_count++) { + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); + if (ret) + return ret; + + if (rxbuf & B53_SPI_CMD_RACK) + break; + + mdelay(1); + } + + if (retry_count == 10) + return -EIO; + + return 0; +} + +static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data, + unsigned int len) +{ + struct spi_device *spi = dev->priv; + int ret; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + ret = b53_spi_prepare_reg_read(spi, reg); + if (ret) + return ret; + + return b53_spi_read_reg(spi, B53_SPI_DATA, data, len); +} + +static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + return b53_spi_read(dev, page, reg, val, 1); +} + +static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2); + + if (!ret) + *val = le16_to_cpu(*val); + + return ret; +} + +static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4); + + if (!ret) + *val = le32_to_cpu(*val); + + return ret; +} + +static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + *val = 0; + ret = b53_spi_read(dev, page, reg, (u8 *)val, 6); + if (!ret) + *val = le64_to_cpu(*val); + + return ret; +} + +static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8); + + if (!ret) + *val = le64_to_cpu(*val); + + return ret; +} + +static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[3]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + txbuf[2] = value; + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[4]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le16(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[6]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le32(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[10]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le64(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf) - 2); +} + +static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[10]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le64(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static struct b53_io_ops b53_spi_ops = { + .read8 = b53_spi_read8, + .read16 = b53_spi_read16, + .read32 = b53_spi_read32, + .read48 = b53_spi_read48, + .read64 = b53_spi_read64, + .write8 = b53_spi_write8, + .write16 = b53_spi_write16, + .write32 = b53_spi_write32, + .write48 = b53_spi_write48, + .write64 = b53_spi_write64, +}; + +static int b53_spi_probe(struct spi_device *spi) +{ + struct b53_device *dev; + int ret; + + dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi); + if (!dev) + return -ENOMEM; + + if (spi->dev.platform_data) + dev->pdata = spi->dev.platform_data; + + ret = b53_switch_register(dev); + if (ret) + return ret; + + spi_set_drvdata(spi, dev); + + return 0; +} + +static int b53_spi_remove(struct spi_device *spi) +{ + struct b53_device *dev = spi_get_drvdata(spi); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static struct spi_driver b53_spi_driver = { + .driver = { + .name = "b53-switch", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = b53_spi_probe, + .remove = b53_spi_remove, +}; + +module_spi_driver(b53_spi_driver); + +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 SPI access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c new file mode 100644 index 000000000000..70fd47284535 --- /dev/null +++ b/drivers/net/dsa/b53/b53_srab.c @@ -0,0 +1,415 @@ +/* + * B53 register access through Switch Register Access Bridge Registers + * + * Copyright (C) 2013 Hauke Mehrtens + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "b53_priv.h" + +/* command and status register of the SRAB */ +#define B53_SRAB_CMDSTAT 0x2c +#define B53_SRAB_CMDSTAT_RST BIT(2) +#define B53_SRAB_CMDSTAT_WRITE BIT(1) +#define B53_SRAB_CMDSTAT_GORDYN BIT(0) +#define B53_SRAB_CMDSTAT_PAGE 24 +#define B53_SRAB_CMDSTAT_REG 16 + +/* high order word of write data to switch registe */ +#define B53_SRAB_WD_H 0x30 + +/* low order word of write data to switch registe */ +#define B53_SRAB_WD_L 0x34 + +/* high order word of read data from switch register */ +#define B53_SRAB_RD_H 0x38 + +/* low order word of read data from switch register */ +#define B53_SRAB_RD_L 0x3c + +/* command and status register of the SRAB */ +#define B53_SRAB_CTRLS 0x40 +#define B53_SRAB_CTRLS_RCAREQ BIT(3) +#define B53_SRAB_CTRLS_RCAGNT BIT(4) +#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) + +/* the register captures interrupt pulses from the switch */ +#define B53_SRAB_INTR 0x44 +#define B53_SRAB_INTR_P(x) BIT(x) +#define B53_SRAB_SWITCH_PHY BIT(8) +#define B53_SRAB_1588_SYNC BIT(9) +#define B53_SRAB_IMP1_SLEEP_TIMER BIT(10) +#define B53_SRAB_P7_SLEEP_TIMER BIT(11) +#define B53_SRAB_IMP0_SLEEP_TIMER BIT(12) + +struct b53_srab_priv { + void __iomem *regs; +}; + +static int b53_srab_request_grant(struct b53_device *dev) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + u32 ctrls; + int i; + + ctrls = readl(regs + B53_SRAB_CTRLS); + ctrls |= B53_SRAB_CTRLS_RCAREQ; + writel(ctrls, regs + B53_SRAB_CTRLS); + + for (i = 0; i < 20; i++) { + ctrls = readl(regs + B53_SRAB_CTRLS); + if (ctrls & B53_SRAB_CTRLS_RCAGNT) + break; + usleep_range(10, 100); + } + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static void b53_srab_release_grant(struct b53_device *dev) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + u32 ctrls; + + ctrls = readl(regs + B53_SRAB_CTRLS); + ctrls &= ~B53_SRAB_CTRLS_RCAREQ; + writel(ctrls, regs + B53_SRAB_CTRLS); +} + +static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int i; + u32 cmdstat; + + /* set register address */ + cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) | + (reg << B53_SRAB_CMDSTAT_REG) | + B53_SRAB_CMDSTAT_GORDYN | + op; + writel(cmdstat, regs + B53_SRAB_CMDSTAT); + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + cmdstat = readl(regs + B53_SRAB_CMDSTAT); + if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN)) + break; + usleep_range(10, 100); + } + + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L) & 0xff; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L) & 0xffff; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + *val += (u64)readl(regs + B53_SRAB_RD_H) << 32; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel((u32)value, regs + B53_SRAB_WD_L); + writel((u16)(value >> 32), regs + B53_SRAB_WD_H); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct b53_srab_priv *priv = dev->priv; + u8 __iomem *regs = priv->regs; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel((u32)value, regs + B53_SRAB_WD_L); + writel((u32)(value >> 32), regs + B53_SRAB_WD_H); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static struct b53_io_ops b53_srab_ops = { + .read8 = b53_srab_read8, + .read16 = b53_srab_read16, + .read32 = b53_srab_read32, + .read48 = b53_srab_read48, + .read64 = b53_srab_read64, + .write8 = b53_srab_write8, + .write16 = b53_srab_write16, + .write32 = b53_srab_write32, + .write48 = b53_srab_write48, + .write64 = b53_srab_write64, +}; + +static int b53_srab_probe(struct platform_device *pdev) +{ + struct b53_srab_priv *priv; + struct b53_device *dev; + struct resource *r; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->regs)) + return -ENOMEM; + + dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv); + if (!dev) + return -ENOMEM; + + platform_set_drvdata(pdev, dev); + + return b53_switch_register(dev); +} + +static int b53_srab_remove(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static const struct of_device_id b53_srab_of_match[] = { + { .compatible = "brcm,bcm53010-srab" }, + { .compatible = "brcm,bcm53011-srab" }, + { .compatible = "brcm,bcm53012-srab" }, + { .compatible = "brcm,bcm53018-srab" }, + { .compatible = "brcm,bcm53019-srab" }, + { .compatible = "brcm,bcm5301x-srab" }, + { /* sentinel */ }, +}; + +static struct platform_driver b53_srab_driver = { + .probe = b53_srab_probe, + .remove = b53_srab_remove, + .driver = { + .name = "b53-srab-switch", + .of_match_table = b53_srab_of_match, + }, +}; + +module_platform_driver(b53_srab_driver); +MODULE_AUTHOR("Hauke Mehrtens "); +MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/include/linux/platform_data/b53.h b/include/linux/platform_data/b53.h new file mode 100644 index 000000000000..69d279c0da96 --- /dev/null +++ b/include/linux/platform_data/b53.h @@ -0,0 +1,33 @@ +/* + * B53 platform data + * + * Copyright (C) 2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_H +#define __B53_H + +#include + +struct b53_platform_data { + u32 chip_id; + u16 enabled_ports; + + /* only used by MMAP'd driver */ + unsigned big_endian:1; + void __iomem *regs; +}; + +#endif -- cgit v1.2.3 From 2341e0775747864b684abe8627f3d45b167f2940 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 Jun 2016 23:02:51 +0100 Subject: rxrpc: Simplify connect() implementation and simplify sendmsg() op Simplify the RxRPC connect() implementation. It will just note the destination address it is given, and if a sendmsg() comes along with no address, this will be assigned as the address. No transport struct will be held internally, which will allow us to remove this later. Simplify sendmsg() also. Whilst a call is active, userspace refers to it by a private unique user ID specified in a control message. When sendmsg() sees a user ID that doesn't map to an extant call, it creates a new call for that user ID and attempts to add it. If, when we try to add it, the user ID is now registered, we now reject the message with -EEXIST. We should never see this situation unless two threads are racing, trying to create a call with the same ID - which would be an error. It also isn't required to provide sendmsg() with an address - provided the control message data holds a user ID that maps to a currently active call. Signed-off-by: David Howells Signed-off-by: David S. Miller --- include/linux/rxrpc.h | 18 +++-- net/rxrpc/af_rxrpc.c | 177 ++++++++++++++++--------------------------- net/rxrpc/ar-call.c | 158 ++++++++++++++++----------------------- net/rxrpc/ar-connection.c | 17 ----- net/rxrpc/ar-internal.h | 22 +++--- net/rxrpc/ar-output.c | 186 ++++++++++++++++++++++------------------------ 6 files changed, 234 insertions(+), 344 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rxrpc.h b/include/linux/rxrpc.h index a53915cd5581..1e8f216e2cf1 100644 --- a/include/linux/rxrpc.h +++ b/include/linux/rxrpc.h @@ -40,16 +40,18 @@ struct sockaddr_rxrpc { /* * RxRPC control messages + * - If neither abort or accept are specified, the message is a data message. * - terminal messages mean that a user call ID tag can be recycled + * - s/r/- indicate whether these are applicable to sendmsg() and/or recvmsg() */ -#define RXRPC_USER_CALL_ID 1 /* user call ID specifier */ -#define RXRPC_ABORT 2 /* abort request / notification [terminal] */ -#define RXRPC_ACK 3 /* [Server] RPC op final ACK received [terminal] */ -#define RXRPC_NET_ERROR 5 /* network error received [terminal] */ -#define RXRPC_BUSY 6 /* server busy received [terminal] */ -#define RXRPC_LOCAL_ERROR 7 /* local error generated [terminal] */ -#define RXRPC_NEW_CALL 8 /* [Server] new incoming call notification */ -#define RXRPC_ACCEPT 9 /* [Server] accept request */ +#define RXRPC_USER_CALL_ID 1 /* sr: user call ID specifier */ +#define RXRPC_ABORT 2 /* sr: abort request / notification [terminal] */ +#define RXRPC_ACK 3 /* -r: [Service] RPC op final ACK received [terminal] */ +#define RXRPC_NET_ERROR 5 /* -r: network error received [terminal] */ +#define RXRPC_BUSY 6 /* -r: server busy received [terminal] */ +#define RXRPC_LOCAL_ERROR 7 /* -r: local error generated [terminal] */ +#define RXRPC_NEW_CALL 8 /* -r: [Service] new incoming call notification */ +#define RXRPC_ACCEPT 9 /* s-: [Service] accept request */ /* * RxRPC security levels diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 7840b8e7da80..38512a200db6 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -139,33 +139,33 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len) lock_sock(&rx->sk); - if (rx->sk.sk_state != RXRPC_UNCONNECTED) { + if (rx->sk.sk_state != RXRPC_UNBOUND) { ret = -EINVAL; goto error_unlock; } memcpy(&rx->srx, srx, sizeof(rx->srx)); - /* Find or create a local transport endpoint to use */ local = rxrpc_lookup_local(&rx->srx); if (IS_ERR(local)) { ret = PTR_ERR(local); goto error_unlock; } - rx->local = local; - if (srx->srx_service) { + if (rx->srx.srx_service) { write_lock_bh(&local->services_lock); list_for_each_entry(prx, &local->services, listen_link) { - if (prx->srx.srx_service == srx->srx_service) + if (prx->srx.srx_service == rx->srx.srx_service) goto service_in_use; } + rx->local = local; list_add_tail(&rx->listen_link, &local->services); write_unlock_bh(&local->services_lock); rx->sk.sk_state = RXRPC_SERVER_BOUND; } else { + rx->local = local; rx->sk.sk_state = RXRPC_CLIENT_BOUND; } @@ -174,8 +174,9 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len) return 0; service_in_use: - ret = -EADDRINUSE; write_unlock_bh(&local->services_lock); + rxrpc_put_local(local); + ret = -EADDRINUSE; error_unlock: release_sock(&rx->sk); error: @@ -197,11 +198,11 @@ static int rxrpc_listen(struct socket *sock, int backlog) lock_sock(&rx->sk); switch (rx->sk.sk_state) { - case RXRPC_UNCONNECTED: + case RXRPC_UNBOUND: ret = -EADDRNOTAVAIL; break; + case RXRPC_CLIENT_UNBOUND: case RXRPC_CLIENT_BOUND: - case RXRPC_CLIENT_CONNECTED: default: ret = -EBUSY; break; @@ -221,20 +222,18 @@ static int rxrpc_listen(struct socket *sock, int backlog) /* * find a transport by address */ -static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock, - struct sockaddr *addr, - int addr_len, int flags, - gfp_t gfp) +struct rxrpc_transport *rxrpc_name_to_transport(struct rxrpc_sock *rx, + struct sockaddr *addr, + int addr_len, int flags, + gfp_t gfp) { struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr; struct rxrpc_transport *trans; - struct rxrpc_sock *rx = rxrpc_sk(sock->sk); struct rxrpc_peer *peer; _enter("%p,%p,%d,%d", rx, addr, addr_len, flags); ASSERT(rx->local != NULL); - ASSERT(rx->sk.sk_state > RXRPC_UNCONNECTED); if (rx->srx.transport_type != srx->transport_type) return ERR_PTR(-ESOCKTNOSUPPORT); @@ -256,7 +255,7 @@ static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock, /** * rxrpc_kernel_begin_call - Allow a kernel service to begin a call * @sock: The socket on which to make the call - * @srx: The address of the peer to contact (defaults to socket setting) + * @srx: The address of the peer to contact * @key: The security context to use (defaults to socket setting) * @user_call_ID: The ID to use * @@ -282,25 +281,14 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, lock_sock(&rx->sk); - if (srx) { - trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx, - sizeof(*srx), 0, gfp); - if (IS_ERR(trans)) { - call = ERR_CAST(trans); - trans = NULL; - goto out_notrans; - } - } else { - trans = rx->trans; - if (!trans) { - call = ERR_PTR(-ENOTCONN); - goto out_notrans; - } - atomic_inc(&trans->usage); + trans = rxrpc_name_to_transport(rx, (struct sockaddr *)srx, + sizeof(*srx), 0, gfp); + if (IS_ERR(trans)) { + call = ERR_CAST(trans); + trans = NULL; + goto out_notrans; } - if (!srx) - srx = &rx->srx; if (!key) key = rx->key; if (key && !key->payload.data[0]) @@ -312,8 +300,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, goto out; } - call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID, true, - gfp); + call = rxrpc_new_client_call(rx, trans, bundle, user_call_ID, gfp); rxrpc_put_bundle(trans, bundle); out: rxrpc_put_transport(trans); @@ -369,11 +356,8 @@ EXPORT_SYMBOL(rxrpc_kernel_intercept_rx_messages); static int rxrpc_connect(struct socket *sock, struct sockaddr *addr, int addr_len, int flags) { - struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr; - struct sock *sk = sock->sk; - struct rxrpc_transport *trans; - struct rxrpc_local *local; - struct rxrpc_sock *rx = rxrpc_sk(sk); + struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)addr; + struct rxrpc_sock *rx = rxrpc_sk(sock->sk); int ret; _enter("%p,%p,%d,%d", rx, addr, addr_len, flags); @@ -386,45 +370,28 @@ static int rxrpc_connect(struct socket *sock, struct sockaddr *addr, lock_sock(&rx->sk); + ret = -EISCONN; + if (test_bit(RXRPC_SOCK_CONNECTED, &rx->flags)) + goto error; + switch (rx->sk.sk_state) { - case RXRPC_UNCONNECTED: - /* find a local transport endpoint if we don't have one already */ - ASSERTCMP(rx->local, ==, NULL); - rx->srx.srx_family = AF_RXRPC; - rx->srx.srx_service = 0; - rx->srx.transport_type = srx->transport_type; - rx->srx.transport_len = sizeof(sa_family_t); - rx->srx.transport.family = srx->transport.family; - local = rxrpc_lookup_local(&rx->srx); - if (IS_ERR(local)) { - release_sock(&rx->sk); - return PTR_ERR(local); - } - rx->local = local; - rx->sk.sk_state = RXRPC_CLIENT_BOUND; + case RXRPC_UNBOUND: + rx->sk.sk_state = RXRPC_CLIENT_UNBOUND; + case RXRPC_CLIENT_UNBOUND: case RXRPC_CLIENT_BOUND: break; - case RXRPC_CLIENT_CONNECTED: - release_sock(&rx->sk); - return -EISCONN; default: - release_sock(&rx->sk); - return -EBUSY; /* server sockets can't connect as well */ - } - - trans = rxrpc_name_to_transport(sock, addr, addr_len, flags, - GFP_KERNEL); - if (IS_ERR(trans)) { - release_sock(&rx->sk); - _leave(" = %ld", PTR_ERR(trans)); - return PTR_ERR(trans); + ret = -EBUSY; + goto error; } - rx->trans = trans; - rx->sk.sk_state = RXRPC_CLIENT_CONNECTED; + rx->connect_srx = *srx; + set_bit(RXRPC_SOCK_CONNECTED, &rx->flags); + ret = 0; +error: release_sock(&rx->sk); - return 0; + return ret; } /* @@ -438,7 +405,7 @@ static int rxrpc_connect(struct socket *sock, struct sockaddr *addr, */ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len) { - struct rxrpc_transport *trans; + struct rxrpc_local *local; struct rxrpc_sock *rx = rxrpc_sk(sock->sk); int ret; @@ -455,48 +422,38 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len) } } - trans = NULL; lock_sock(&rx->sk); - if (m->msg_name) { - ret = -EISCONN; - trans = rxrpc_name_to_transport(sock, m->msg_name, - m->msg_namelen, 0, GFP_KERNEL); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - trans = NULL; - goto out; - } - } else { - trans = rx->trans; - if (trans) - atomic_inc(&trans->usage); - } - switch (rx->sk.sk_state) { - case RXRPC_SERVER_LISTENING: - if (!m->msg_name) { - ret = rxrpc_server_sendmsg(rx, m, len); - break; + case RXRPC_UNBOUND: + local = rxrpc_lookup_local(&rx->srx); + if (IS_ERR(local)) { + ret = PTR_ERR(local); + goto error_unlock; } - case RXRPC_SERVER_BOUND: + + rx->local = local; + rx->sk.sk_state = RXRPC_CLIENT_UNBOUND; + /* Fall through */ + + case RXRPC_CLIENT_UNBOUND: case RXRPC_CLIENT_BOUND: - if (!m->msg_name) { - ret = -ENOTCONN; - break; + if (!m->msg_name && + test_bit(RXRPC_SOCK_CONNECTED, &rx->flags)) { + m->msg_name = &rx->connect_srx; + m->msg_namelen = sizeof(rx->connect_srx); } - case RXRPC_CLIENT_CONNECTED: - ret = rxrpc_client_sendmsg(rx, trans, m, len); + case RXRPC_SERVER_BOUND: + case RXRPC_SERVER_LISTENING: + ret = rxrpc_do_sendmsg(rx, m, len); break; default: - ret = -ENOTCONN; + ret = -EINVAL; break; } -out: +error_unlock: release_sock(&rx->sk); - if (trans) - rxrpc_put_transport(trans); _leave(" = %d", ret); return ret; } @@ -523,7 +480,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname, if (optlen != 0) goto error; ret = -EISCONN; - if (rx->sk.sk_state != RXRPC_UNCONNECTED) + if (rx->sk.sk_state != RXRPC_UNBOUND) goto error; set_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags); goto success; @@ -533,7 +490,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname, if (rx->key) goto error; ret = -EISCONN; - if (rx->sk.sk_state != RXRPC_UNCONNECTED) + if (rx->sk.sk_state != RXRPC_UNBOUND) goto error; ret = rxrpc_request_key(rx, optval, optlen); goto error; @@ -543,7 +500,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname, if (rx->key) goto error; ret = -EISCONN; - if (rx->sk.sk_state != RXRPC_UNCONNECTED) + if (rx->sk.sk_state != RXRPC_UNBOUND) goto error; ret = rxrpc_server_keyring(rx, optval, optlen); goto error; @@ -553,7 +510,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname, if (optlen != sizeof(unsigned int)) goto error; ret = -EISCONN; - if (rx->sk.sk_state != RXRPC_UNCONNECTED) + if (rx->sk.sk_state != RXRPC_UNBOUND) goto error; ret = get_user(min_sec_level, (unsigned int __user *) optval); @@ -632,7 +589,7 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol, return -ENOMEM; sock_init_data(sock, sk); - sk->sk_state = RXRPC_UNCONNECTED; + sk->sk_state = RXRPC_UNBOUND; sk->sk_write_space = rxrpc_write_space; sk->sk_max_ack_backlog = sysctl_rxrpc_max_qlen; sk->sk_destruct = rxrpc_sock_destructor; @@ -705,14 +662,6 @@ static int rxrpc_release_sock(struct sock *sk) rx->conn = NULL; } - if (rx->bundle) { - rxrpc_put_bundle(rx->trans, rx->bundle); - rx->bundle = NULL; - } - if (rx->trans) { - rxrpc_put_transport(rx->trans); - rx->trans = NULL; - } if (rx->local) { rxrpc_put_local(rx->local); rx->local = NULL; diff --git a/net/rxrpc/ar-call.c b/net/rxrpc/ar-call.c index 1fbaae1cba5f..68125dc4cb7c 100644 --- a/net/rxrpc/ar-call.c +++ b/net/rxrpc/ar-call.c @@ -195,6 +195,43 @@ struct rxrpc_call *rxrpc_find_call_hash( return ret; } +/* + * find an extant server call + * - called in process context with IRQs enabled + */ +struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *rx, + unsigned long user_call_ID) +{ + struct rxrpc_call *call; + struct rb_node *p; + + _enter("%p,%lx", rx, user_call_ID); + + read_lock(&rx->call_lock); + + p = rx->calls.rb_node; + while (p) { + call = rb_entry(p, struct rxrpc_call, sock_node); + + if (user_call_ID < call->user_call_ID) + p = p->rb_left; + else if (user_call_ID > call->user_call_ID) + p = p->rb_right; + else + goto found_extant_call; + } + + read_unlock(&rx->call_lock); + _leave(" = NULL"); + return NULL; + +found_extant_call: + rxrpc_get_call(call); + read_unlock(&rx->call_lock); + _leave(" = %p [%d]", call, atomic_read(&call->usage)); + return call; +} + /* * allocate a new call */ @@ -311,51 +348,27 @@ static struct rxrpc_call *rxrpc_alloc_client_call( * set up a call for the given data * - called in process context with IRQs enabled */ -struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *rx, +struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, struct rxrpc_transport *trans, struct rxrpc_conn_bundle *bundle, unsigned long user_call_ID, - int create, gfp_t gfp) { - struct rxrpc_call *call, *candidate; - struct rb_node *p, *parent, **pp; + struct rxrpc_call *call, *xcall; + struct rb_node *parent, **pp; - _enter("%p,%d,%d,%lx,%d", - rx, trans ? trans->debug_id : -1, bundle ? bundle->debug_id : -1, - user_call_ID, create); + _enter("%p,%d,%d,%lx", + rx, trans->debug_id, bundle ? bundle->debug_id : -1, + user_call_ID); - /* search the extant calls first for one that matches the specified - * user ID */ - read_lock(&rx->call_lock); - - p = rx->calls.rb_node; - while (p) { - call = rb_entry(p, struct rxrpc_call, sock_node); - - if (user_call_ID < call->user_call_ID) - p = p->rb_left; - else if (user_call_ID > call->user_call_ID) - p = p->rb_right; - else - goto found_extant_call; + call = rxrpc_alloc_client_call(rx, trans, bundle, gfp); + if (IS_ERR(call)) { + _leave(" = %ld", PTR_ERR(call)); + return call; } - read_unlock(&rx->call_lock); - - if (!create || !trans) - return ERR_PTR(-EBADSLT); - - /* not yet present - create a candidate for a new record and then - * redo the search */ - candidate = rxrpc_alloc_client_call(rx, trans, bundle, gfp); - if (IS_ERR(candidate)) { - _leave(" = %ld", PTR_ERR(candidate)); - return candidate; - } - - candidate->user_call_ID = user_call_ID; - __set_bit(RXRPC_CALL_HAS_USERID, &candidate->flags); + call->user_call_ID = user_call_ID; + __set_bit(RXRPC_CALL_HAS_USERID, &call->flags); write_lock(&rx->call_lock); @@ -363,19 +376,16 @@ struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *rx, parent = NULL; while (*pp) { parent = *pp; - call = rb_entry(parent, struct rxrpc_call, sock_node); + xcall = rb_entry(parent, struct rxrpc_call, sock_node); - if (user_call_ID < call->user_call_ID) + if (user_call_ID < xcall->user_call_ID) pp = &(*pp)->rb_left; - else if (user_call_ID > call->user_call_ID) + else if (user_call_ID > xcall->user_call_ID) pp = &(*pp)->rb_right; else - goto found_extant_second; + goto found_user_ID_now_present; } - /* second search also failed; add the new call */ - call = candidate; - candidate = NULL; rxrpc_get_call(call); rb_link_node(&call->sock_node, parent, pp); @@ -391,20 +401,16 @@ struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *rx, _leave(" = %p [new]", call); return call; - /* we found the call in the list immediately */ -found_extant_call: - rxrpc_get_call(call); - read_unlock(&rx->call_lock); - _leave(" = %p [extant %d]", call, atomic_read(&call->usage)); - return call; - - /* we found the call on the second time through the list */ -found_extant_second: - rxrpc_get_call(call); + /* We unexpectedly found the user ID in the list after taking + * the call_lock. This shouldn't happen unless the user races + * with itself and tries to add the same user ID twice at the + * same time in different threads. + */ +found_user_ID_now_present: write_unlock(&rx->call_lock); - rxrpc_put_call(candidate); - _leave(" = %p [second %d]", call, atomic_read(&call->usage)); - return call; + rxrpc_put_call(call); + _leave(" = -EEXIST [%p]", call); + return ERR_PTR(-EEXIST); } /* @@ -565,46 +571,6 @@ old_call: return ERR_PTR(-ECONNRESET); } -/* - * find an extant server call - * - called in process context with IRQs enabled - */ -struct rxrpc_call *rxrpc_find_server_call(struct rxrpc_sock *rx, - unsigned long user_call_ID) -{ - struct rxrpc_call *call; - struct rb_node *p; - - _enter("%p,%lx", rx, user_call_ID); - - /* search the extant calls for one that matches the specified user - * ID */ - read_lock(&rx->call_lock); - - p = rx->calls.rb_node; - while (p) { - call = rb_entry(p, struct rxrpc_call, sock_node); - - if (user_call_ID < call->user_call_ID) - p = p->rb_left; - else if (user_call_ID > call->user_call_ID) - p = p->rb_right; - else - goto found_extant_call; - } - - read_unlock(&rx->call_lock); - _leave(" = NULL"); - return NULL; - - /* we found the call in the list immediately */ -found_extant_call: - rxrpc_get_call(call); - read_unlock(&rx->call_lock); - _leave(" = %p [%d]", call, atomic_read(&call->usage)); - return call; -} - /* * detach a call from a socket and set up for release */ diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c index d67b1f1b5001..8ecde4b77b55 100644 --- a/net/rxrpc/ar-connection.c +++ b/net/rxrpc/ar-connection.c @@ -80,11 +80,6 @@ struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *rx, _enter("%p{%x},%x,%hx,", rx, key_serial(key), trans->debug_id, service_id); - if (rx->trans == trans && rx->bundle) { - atomic_inc(&rx->bundle->usage); - return rx->bundle; - } - /* search the extant bundles first for one that matches the specified * user ID */ spin_lock(&trans->client_lock); @@ -138,10 +133,6 @@ struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *rx, rb_insert_color(&bundle->node, &trans->bundles); spin_unlock(&trans->client_lock); _net("BUNDLE new on trans %d", trans->debug_id); - if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) { - atomic_inc(&bundle->usage); - rx->bundle = bundle; - } _leave(" = %p [new]", bundle); return bundle; @@ -150,10 +141,6 @@ found_extant_bundle: atomic_inc(&bundle->usage); spin_unlock(&trans->client_lock); _net("BUNDLE old on trans %d", trans->debug_id); - if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) { - atomic_inc(&bundle->usage); - rx->bundle = bundle; - } _leave(" = %p [extant %d]", bundle, atomic_read(&bundle->usage)); return bundle; @@ -163,10 +150,6 @@ found_extant_second: spin_unlock(&trans->client_lock); kfree(candidate); _net("BUNDLE old2 on trans %d", trans->debug_id); - if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) { - atomic_inc(&bundle->usage); - rx->bundle = bundle; - } _leave(" = %p [second %d]", bundle, atomic_read(&bundle->usage)); return bundle; } diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 18ab5c50ba87..b89dcdcbc65a 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -39,9 +39,9 @@ struct rxrpc_crypt { * sk_state for RxRPC sockets */ enum { - RXRPC_UNCONNECTED = 0, + RXRPC_UNBOUND = 0, + RXRPC_CLIENT_UNBOUND, /* Unbound socket used as client */ RXRPC_CLIENT_BOUND, /* client local address bound */ - RXRPC_CLIENT_CONNECTED, /* client is connected */ RXRPC_SERVER_BOUND, /* server local address bound */ RXRPC_SERVER_LISTENING, /* server listening for connections */ RXRPC_CLOSE, /* socket is being closed */ @@ -55,8 +55,6 @@ struct rxrpc_sock { struct sock sk; rxrpc_interceptor_t interceptor; /* kernel service Rx interceptor function */ struct rxrpc_local *local; /* local endpoint */ - struct rxrpc_transport *trans; /* transport handler */ - struct rxrpc_conn_bundle *bundle; /* virtual connection bundle */ struct rxrpc_connection *conn; /* exclusive virtual connection */ struct list_head listen_link; /* link in the local endpoint's listen list */ struct list_head secureq; /* calls awaiting connection security clearance */ @@ -65,11 +63,13 @@ struct rxrpc_sock { struct key *securities; /* list of server security descriptors */ struct rb_root calls; /* outstanding calls on this socket */ unsigned long flags; +#define RXRPC_SOCK_CONNECTED 0 /* connect_srx is set */ #define RXRPC_SOCK_EXCLUSIVE_CONN 1 /* exclusive connection for a client socket */ rwlock_t call_lock; /* lock for calls */ u32 min_sec_level; /* minimum security level */ #define RXRPC_SECURITY_MAX RXRPC_SECURITY_ENCRYPT struct sockaddr_rxrpc srx; /* local address */ + struct sockaddr_rxrpc connect_srx; /* Default client address from connect() */ sa_family_t proto; /* protocol created with */ }; @@ -477,6 +477,10 @@ extern u32 rxrpc_epoch; extern atomic_t rxrpc_debug_id; extern struct workqueue_struct *rxrpc_workqueue; +extern struct rxrpc_transport *rxrpc_name_to_transport(struct rxrpc_sock *, + struct sockaddr *, + int, int, gfp_t); + /* * ar-accept.c */ @@ -502,14 +506,14 @@ extern rwlock_t rxrpc_call_lock; struct rxrpc_call *rxrpc_find_call_hash(struct rxrpc_host_header *, void *, sa_family_t, const void *); -struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *, +struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *, unsigned long); +struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *, struct rxrpc_transport *, struct rxrpc_conn_bundle *, - unsigned long, int, gfp_t); + unsigned long, gfp_t); struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *, struct rxrpc_connection *, struct rxrpc_host_header *); -struct rxrpc_call *rxrpc_find_server_call(struct rxrpc_sock *, unsigned long); void rxrpc_release_call(struct rxrpc_call *); void rxrpc_release_calls_on_socket(struct rxrpc_sock *); void __rxrpc_put_call(struct rxrpc_call *); @@ -581,9 +585,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time_t, extern unsigned int rxrpc_resend_timeout; int rxrpc_send_packet(struct rxrpc_transport *, struct sk_buff *); -int rxrpc_client_sendmsg(struct rxrpc_sock *, struct rxrpc_transport *, - struct msghdr *, size_t); -int rxrpc_server_sendmsg(struct rxrpc_sock *, struct msghdr *, size_t); +int rxrpc_do_sendmsg(struct rxrpc_sock *, struct msghdr *, size_t); /* * ar-peer.c diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c index ea619535f0ed..2e3c4064e29c 100644 --- a/net/rxrpc/ar-output.c +++ b/net/rxrpc/ar-output.c @@ -32,13 +32,13 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, /* * extract control messages from the sendmsg() control buffer */ -static int rxrpc_sendmsg_cmsg(struct rxrpc_sock *rx, struct msghdr *msg, +static int rxrpc_sendmsg_cmsg(struct msghdr *msg, unsigned long *user_call_ID, enum rxrpc_command *command, - u32 *abort_code, - bool server) + u32 *abort_code) { struct cmsghdr *cmsg; + bool got_user_ID = false; int len; *command = RXRPC_CMD_SEND_DATA; @@ -70,6 +70,7 @@ static int rxrpc_sendmsg_cmsg(struct rxrpc_sock *rx, struct msghdr *msg, CMSG_DATA(cmsg); } _debug("User Call ID %lx", *user_call_ID); + got_user_ID = true; break; case RXRPC_ABORT: @@ -90,8 +91,6 @@ static int rxrpc_sendmsg_cmsg(struct rxrpc_sock *rx, struct msghdr *msg, *command = RXRPC_CMD_ACCEPT; if (len != 0) return -EINVAL; - if (!server) - return -EISCONN; break; default: @@ -99,6 +98,8 @@ static int rxrpc_sendmsg_cmsg(struct rxrpc_sock *rx, struct msghdr *msg, } } + if (!got_user_ID) + return -EINVAL; _leave(" = 0"); return 0; } @@ -125,56 +126,97 @@ static void rxrpc_send_abort(struct rxrpc_call *call, u32 abort_code) write_unlock_bh(&call->state_lock); } +/* + * Create a new client call for sendmsg(). + */ +static struct rxrpc_call * +rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, + unsigned long user_call_ID) +{ + struct rxrpc_conn_bundle *bundle; + struct rxrpc_transport *trans; + struct rxrpc_call *call; + struct key *key; + long ret; + + DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx, msg->msg_name); + + _enter(""); + + if (!msg->msg_name) + return ERR_PTR(-EDESTADDRREQ); + + trans = rxrpc_name_to_transport(rx, msg->msg_name, msg->msg_namelen, 0, + GFP_KERNEL); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out; + } + + key = rx->key; + if (key && !rx->key->payload.data[0]) + key = NULL; + bundle = rxrpc_get_bundle(rx, trans, key, srx->srx_service, GFP_KERNEL); + if (IS_ERR(bundle)) { + ret = PTR_ERR(bundle); + goto out_trans; + } + + call = rxrpc_new_client_call(rx, trans, bundle, user_call_ID, + GFP_KERNEL); + rxrpc_put_bundle(trans, bundle); + rxrpc_put_transport(trans); + if (IS_ERR(call)) { + ret = PTR_ERR(call); + goto out_trans; + } + + _leave(" = %p\n", call); + return call; + +out_trans: + rxrpc_put_transport(trans); +out: + _leave(" = %ld", ret); + return ERR_PTR(ret); +} + /* * send a message forming part of a client call through an RxRPC socket * - caller holds the socket locked * - the socket may be either a client socket or a server socket */ -int rxrpc_client_sendmsg(struct rxrpc_sock *rx, struct rxrpc_transport *trans, - struct msghdr *msg, size_t len) +int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) { - struct rxrpc_conn_bundle *bundle; enum rxrpc_command cmd; struct rxrpc_call *call; unsigned long user_call_ID = 0; - struct key *key; - u16 service_id; u32 abort_code = 0; int ret; _enter(""); - ASSERT(trans != NULL); - - ret = rxrpc_sendmsg_cmsg(rx, msg, &user_call_ID, &cmd, &abort_code, - false); + ret = rxrpc_sendmsg_cmsg(msg, &user_call_ID, &cmd, &abort_code); if (ret < 0) return ret; - bundle = NULL; - if (trans) { - service_id = rx->srx.srx_service; - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx, - msg->msg_name); - service_id = srx->srx_service; - } - key = rx->key; - if (key && !rx->key->payload.data[0]) - key = NULL; - bundle = rxrpc_get_bundle(rx, trans, key, service_id, - GFP_KERNEL); - if (IS_ERR(bundle)) - return PTR_ERR(bundle); + if (cmd == RXRPC_CMD_ACCEPT) { + if (rx->sk.sk_state != RXRPC_SERVER_LISTENING) + return -EINVAL; + call = rxrpc_accept_call(rx, user_call_ID); + if (IS_ERR(call)) + return PTR_ERR(call); + rxrpc_put_call(call); + return 0; } - call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID, - abort_code == 0, GFP_KERNEL); - if (trans) - rxrpc_put_bundle(trans, bundle); - if (IS_ERR(call)) { - _leave(" = %ld", PTR_ERR(call)); - return PTR_ERR(call); + call = rxrpc_find_call_by_user_ID(rx, user_call_ID); + if (!call) { + if (cmd != RXRPC_CMD_SEND_DATA) + return -EBADSLT; + call = rxrpc_new_client_call_for_sendmsg(rx, msg, user_call_ID); + if (IS_ERR(call)) + return PTR_ERR(call); } _debug("CALL %d USR %lx ST %d on CONN %p", @@ -182,14 +224,21 @@ int rxrpc_client_sendmsg(struct rxrpc_sock *rx, struct rxrpc_transport *trans, if (call->state >= RXRPC_CALL_COMPLETE) { /* it's too late for this call */ - ret = -ESHUTDOWN; + ret = -ECONNRESET; } else if (cmd == RXRPC_CMD_SEND_ABORT) { rxrpc_send_abort(call, abort_code); + ret = 0; } else if (cmd != RXRPC_CMD_SEND_DATA) { ret = -EINVAL; - } else if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST) { + } else if (!call->in_clientflag && + call->state != RXRPC_CALL_CLIENT_SEND_REQUEST) { /* request phase complete for this client call */ ret = -EPROTO; + } else if (call->in_clientflag && + call->state != RXRPC_CALL_SERVER_ACK_REQUEST && + call->state != RXRPC_CALL_SERVER_SEND_REPLY) { + /* Reply phase not begun or not complete for service call. */ + ret = -EPROTO; } else { ret = rxrpc_send_data(rx, call, msg, len); } @@ -267,67 +316,6 @@ void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code) EXPORT_SYMBOL(rxrpc_kernel_abort_call); -/* - * send a message through a server socket - * - caller holds the socket locked - */ -int rxrpc_server_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) -{ - enum rxrpc_command cmd; - struct rxrpc_call *call; - unsigned long user_call_ID = 0; - u32 abort_code = 0; - int ret; - - _enter(""); - - ret = rxrpc_sendmsg_cmsg(rx, msg, &user_call_ID, &cmd, &abort_code, - true); - if (ret < 0) - return ret; - - if (cmd == RXRPC_CMD_ACCEPT) { - call = rxrpc_accept_call(rx, user_call_ID); - if (IS_ERR(call)) - return PTR_ERR(call); - rxrpc_put_call(call); - return 0; - } - - call = rxrpc_find_server_call(rx, user_call_ID); - if (!call) - return -EBADSLT; - if (call->state >= RXRPC_CALL_COMPLETE) { - ret = -ESHUTDOWN; - goto out; - } - - switch (cmd) { - case RXRPC_CMD_SEND_DATA: - if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST && - call->state != RXRPC_CALL_SERVER_ACK_REQUEST && - call->state != RXRPC_CALL_SERVER_SEND_REPLY) { - /* Tx phase not yet begun for this call */ - ret = -EPROTO; - break; - } - - ret = rxrpc_send_data(rx, call, msg, len); - break; - - case RXRPC_CMD_SEND_ABORT: - rxrpc_send_abort(call, abort_code); - break; - default: - BUG(); - } - - out: - rxrpc_put_call(call); - _leave(" = %d", ret); - return ret; -} - /* * send a packet through the transport endpoint */ -- cgit v1.2.3 From e434863718d4b99dd0d6e0cefd3c5e79e4fa2083 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 9 Jun 2016 10:21:00 -0700 Subject: net: vrf: Fix crash when IPv6 is disabled at boot time Frank Kellermann reported a kernel crash with 4.5.0 when IPv6 is disabled at boot using the kernel option ipv6.disable=1. Using current net-next with the boot option: $ ip link add red type vrf table 1001 Generates: [12210.919584] BUG: unable to handle kernel NULL pointer dereference at 0000000000000748 [12210.921341] IP: [] fib6_get_table+0x2c/0x5a [12210.922537] PGD b79e3067 PUD bb32b067 PMD 0 [12210.923479] Oops: 0000 [#1] SMP [12210.924001] Modules linked in: ipvlan 8021q garp mrp stp llc [12210.925130] CPU: 3 PID: 1177 Comm: ip Not tainted 4.7.0-rc1+ #235 [12210.926168] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 [12210.928065] task: ffff8800b9ac4640 ti: ffff8800bacac000 task.ti: ffff8800bacac000 [12210.929328] RIP: 0010:[] [] fib6_get_table+0x2c/0x5a [12210.930697] RSP: 0018:ffff8800bacaf888 EFLAGS: 00010202 [12210.931563] RAX: 0000000000000748 RBX: ffffffff81a9e280 RCX: ffff8800b9ac4e28 [12210.932688] RDX: 00000000000000e9 RSI: 0000000000000002 RDI: 0000000000000286 [12210.933820] RBP: ffff8800bacaf898 R08: ffff8800b9ac4df0 R09: 000000000052001b [12210.934941] R10: 00000000657c0000 R11: 000000000000c649 R12: 00000000000003e9 [12210.936032] R13: 00000000000003e9 R14: ffff8800bace7800 R15: ffff8800bb3ec000 [12210.937103] FS: 00007faa1766c700(0000) GS:ffff88013ac00000(0000) knlGS:0000000000000000 [12210.938321] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [12210.939166] CR2: 0000000000000748 CR3: 00000000b79d6000 CR4: 00000000000406e0 [12210.940278] Stack: [12210.940603] ffff8800bb3ec000 ffffffff81a9e280 ffff8800bacaf8c8 ffffffff814b3135 [12210.941818] ffff8800bb3ec000 ffffffff81a9e280 ffffffff81a9e280 ffff8800bace7800 [12210.943040] ffff8800bacaf8f0 ffffffff81397c88 ffff8800bb3ec000 ffffffff81a9e280 [12210.944288] Call Trace: [12210.944688] [] fib6_new_table+0x24/0x8a [12210.945516] [] vrf_dev_init+0xd4/0x162 [12210.946328] [] register_netdevice+0x100/0x396 [12210.947209] [] vrf_newlink+0x40/0xb3 [12210.948001] [] rtnl_newlink+0x5d3/0x6d5 ... The problem above is due to the fact that the fib hash table is not allocated when IPv6 is disabled at boot. As for the VRF driver it should not do any IPv6 initializations if IPv6 is disabled, so it needs to know if IPv6 is disabled at boot. The disable parameter is private to the IPv6 module, so provide an accessor for modules to determine if IPv6 was disabled at boot time. Fixes: 35402e3136634 ("net: Add IPv6 support to VRF device") Signed-off-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/vrf.c | 7 +++++++ include/linux/ipv6.h | 7 +++++++ net/ipv6/af_inet6.c | 6 ++++++ 3 files changed, 20 insertions(+) (limited to 'include/linux') diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index b82e3527924e..b4d746943bc5 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -407,6 +407,10 @@ static int vrf_rt6_create(struct net_device *dev) struct rt6_info *rt6, *rt6_local; int rc = -ENOMEM; + /* IPv6 can be CONFIG enabled and then disabled runtime */ + if (!ipv6_mod_enabled()) + return 0; + rt6i_table = fib6_new_table(net, vrf->tb_id); if (!rt6i_table) goto out; @@ -919,6 +923,9 @@ static int vrf_fib_rule(const struct net_device *dev, __u8 family, bool add_it) struct sk_buff *skb; int err; + if (family == AF_INET6 && !ipv6_mod_enabled()) + return 0; + skb = nlmsg_new(vrf_fib_rule_nl_size(), GFP_KERNEL); if (!skb) return -ENOMEM; diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 5c91b0b055d4..c6dbcd84a2c7 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -283,6 +283,8 @@ struct tcp6_timewait_sock { }; #if IS_ENABLED(CONFIG_IPV6) +bool ipv6_mod_enabled(void); + static inline struct ipv6_pinfo *inet6_sk(const struct sock *__sk) { return sk_fullsock(__sk) ? inet_sk(__sk)->pinet6 : NULL; @@ -326,6 +328,11 @@ static inline int inet_v6_ipv6only(const struct sock *sk) #define ipv6_only_sock(sk) 0 #define ipv6_sk_rxinfo(sk) 0 +static inline bool ipv6_mod_enabled(void) +{ + return false; +} + static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk) { return NULL; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index bfa86f040c16..2076c21107d0 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -92,6 +92,12 @@ MODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces"); module_param_named(autoconf, ipv6_defaults.autoconf, int, 0444); MODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces"); +bool ipv6_mod_enabled(void) +{ + return disable_ipv6_mod == 0; +} +EXPORT_SYMBOL_GPL(ipv6_mod_enabled); + static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) { const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo); -- cgit v1.2.3 From 7486216b3a0bd26375b17b2cc168a311106cea70 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 9 Jun 2016 15:11:34 +0300 Subject: {net,IB}/mlx5: mlx5_ifc updates Introducing mlx5_ifc updates for upcoming ConnectX-4 features. Needed bits and hardware structures for mlx5e netdev: - MLX5_CQ_PERIOD_NUM_MODES for adaptive moderation support - QoS rate limiting - SQ context rate limiting - Auto negotiation fields in PTYS register - Source SQN field in flow table entry match structure - DCBX parameters Needed bits and hardware structures for IB: - New XRQ opcodes, commands and capabilities layout - Extend q counters definition to support IB. Signed-off-by: Saeed Mahameed Signed-off-by: Leon Romanovsky Signed-off-by: Leon Romanovsky --- include/linux/mlx5/mlx5_ifc.h | 275 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 263 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 9a05cd7e5890..209add93159f 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -123,6 +123,10 @@ enum { MLX5_CMD_OP_DRAIN_DCT = 0x712, MLX5_CMD_OP_QUERY_DCT = 0x713, MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION = 0x714, + MLX5_CMD_OP_CREATE_XRQ = 0x717, + MLX5_CMD_OP_DESTROY_XRQ = 0x718, + MLX5_CMD_OP_QUERY_XRQ = 0x719, + MLX5_CMD_OP_ARM_XRQ = 0x71a, MLX5_CMD_OP_QUERY_VPORT_STATE = 0x750, MLX5_CMD_OP_MODIFY_VPORT_STATE = 0x751, MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT = 0x752, @@ -139,6 +143,8 @@ enum { MLX5_CMD_OP_ALLOC_Q_COUNTER = 0x771, MLX5_CMD_OP_DEALLOC_Q_COUNTER = 0x772, MLX5_CMD_OP_QUERY_Q_COUNTER = 0x773, + MLX5_CMD_OP_SET_RATE_LIMIT = 0x780, + MLX5_CMD_OP_QUERY_RATE_LIMIT = 0x781, MLX5_CMD_OP_ALLOC_PD = 0x800, MLX5_CMD_OP_DEALLOC_PD = 0x801, MLX5_CMD_OP_ALLOC_UAR = 0x802, @@ -361,7 +367,8 @@ struct mlx5_ifc_fte_match_set_lyr_2_4_bits { }; struct mlx5_ifc_fte_match_set_misc_bits { - u8 reserved_at_0[0x20]; + u8 reserved_at_0[0x8]; + u8 source_sqn[0x18]; u8 reserved_at_20[0x10]; u8 source_port[0x10]; @@ -505,6 +512,17 @@ struct mlx5_ifc_e_switch_cap_bits { u8 reserved_at_20[0x7e0]; }; +struct mlx5_ifc_qos_cap_bits { + u8 packet_pacing[0x1]; + u8 reserved_0[0x1f]; + u8 reserved_1[0x20]; + u8 packet_pacing_max_rate[0x20]; + u8 packet_pacing_min_rate[0x20]; + u8 reserved_2[0x10]; + u8 packet_pacing_rate_table_size[0x10]; + u8 reserved_3[0x760]; +}; + struct mlx5_ifc_per_protocol_networking_offload_caps_bits { u8 csum_cap[0x1]; u8 vlan_cap[0x1]; @@ -744,7 +762,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 out_of_seq_cnt[0x1]; u8 vport_counters[0x1]; - u8 reserved_at_182[0x4]; + u8 retransmission_q_counters[0x1]; + u8 reserved_at_183[0x3]; u8 max_qp_cnt[0xa]; u8 pkey_table_size[0x10]; @@ -771,7 +790,9 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 log_max_msg[0x5]; u8 reserved_at_1c8[0x4]; u8 max_tc[0x4]; - u8 reserved_at_1d0[0x6]; + u8 reserved_at_1d0[0x1]; + u8 dcbx[0x1]; + u8 reserved_at_1d2[0x4]; u8 rol_s[0x1]; u8 rol_g[0x1]; u8 reserved_at_1d8[0x1]; @@ -803,7 +824,7 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 tph[0x1]; u8 rf[0x1]; u8 dct[0x1]; - u8 reserved_at_21b[0x1]; + u8 qos[0x1]; u8 eth_net_offloads[0x1]; u8 roce[0x1]; u8 atomic[0x1]; @@ -929,7 +950,15 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 cqe_compression_timeout[0x10]; u8 cqe_compression_max_num[0x10]; - u8 reserved_at_5e0[0x220]; + u8 reserved_at_5e0[0x10]; + u8 tag_matching[0x1]; + u8 rndv_offload_rc[0x1]; + u8 rndv_offload_dc[0x1]; + u8 log_tag_matching_list_sz[0x5]; + u8 reserved_at_5e8[0x3]; + u8 log_max_xrq[0x5]; + + u8 reserved_at_5f0[0x200]; }; enum mlx5_flow_destination_type { @@ -1967,7 +1996,7 @@ struct mlx5_ifc_qpc_bits { u8 reserved_at_560[0x5]; u8 rq_type[0x3]; - u8 srqn_rmpn[0x18]; + u8 srqn_rmpn_xrqn[0x18]; u8 reserved_at_580[0x8]; u8 rmsn[0x18]; @@ -2018,6 +2047,7 @@ union mlx5_ifc_hca_cap_union_bits { struct mlx5_ifc_flow_table_eswitch_cap_bits flow_table_eswitch_cap; struct mlx5_ifc_e_switch_cap_bits e_switch_cap; struct mlx5_ifc_vector_calc_cap_bits vector_calc_cap; + struct mlx5_ifc_qos_cap_bits qos_cap; u8 reserved_at_0[0x8000]; }; @@ -2244,8 +2274,9 @@ struct mlx5_ifc_sqc_bits { u8 reserved_at_40[0x8]; u8 cqn[0x18]; - u8 reserved_at_60[0xa0]; + u8 reserved_at_60[0x90]; + u8 packet_pacing_rate_limit_index[0x10]; u8 tis_lst_sz[0x10]; u8 reserved_at_110[0x10]; @@ -2593,7 +2624,7 @@ struct mlx5_ifc_dctc_bits { u8 reserved_at_98[0x8]; u8 reserved_at_a0[0x8]; - u8 srqn[0x18]; + u8 srqn_xrqn[0x18]; u8 reserved_at_c0[0x8]; u8 pd[0x18]; @@ -2645,6 +2676,7 @@ enum { enum { MLX5_CQ_PERIOD_MODE_START_FROM_EQE = 0x0, MLX5_CQ_PERIOD_MODE_START_FROM_CQE = 0x1, + MLX5_CQ_PERIOD_NUM_MODES }; struct mlx5_ifc_cqc_bits { @@ -2722,6 +2754,54 @@ struct mlx5_ifc_query_adapter_param_block_bits { u8 vsd_contd_psid[16][0x8]; }; +enum { + MLX5_XRQC_STATE_GOOD = 0x0, + MLX5_XRQC_STATE_ERROR = 0x1, +}; + +enum { + MLX5_XRQC_TOPOLOGY_NO_SPECIAL_TOPOLOGY = 0x0, + MLX5_XRQC_TOPOLOGY_TAG_MATCHING = 0x1, +}; + +enum { + MLX5_XRQC_OFFLOAD_RNDV = 0x1, +}; + +struct mlx5_ifc_tag_matching_topology_context_bits { + u8 log_matching_list_sz[0x4]; + u8 reserved_at_4[0xc]; + u8 append_next_index[0x10]; + + u8 sw_phase_cnt[0x10]; + u8 hw_phase_cnt[0x10]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_xrqc_bits { + u8 state[0x4]; + u8 rlkey[0x1]; + u8 reserved_at_5[0xf]; + u8 topology[0x4]; + u8 reserved_at_18[0x4]; + u8 offload[0x4]; + + u8 reserved_at_20[0x8]; + u8 user_index[0x18]; + + u8 reserved_at_40[0x8]; + u8 cqn[0x18]; + + u8 reserved_at_60[0xa0]; + + struct mlx5_ifc_tag_matching_topology_context_bits tag_matching_topology_context; + + u8 reserved_at_180[0x180]; + + struct mlx5_ifc_wq_bits wq; +}; + union mlx5_ifc_modify_field_select_resize_field_select_auto_bits { struct mlx5_ifc_modify_field_select_bits modify_field_select; struct mlx5_ifc_resize_field_select_bits resize_field_select; @@ -3144,6 +3224,30 @@ struct mlx5_ifc_rst2init_qp_in_bits { u8 reserved_at_800[0x80]; }; +struct mlx5_ifc_query_xrq_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x40]; + + struct mlx5_ifc_xrqc_bits xrq_context; +}; + +struct mlx5_ifc_query_xrq_in_bits { + u8 opcode[0x10]; + u8 reserved_at_10[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x8]; + u8 xrqn[0x18]; + + u8 reserved_at_60[0x20]; +}; + struct mlx5_ifc_query_xrc_srq_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -3547,7 +3651,27 @@ struct mlx5_ifc_query_q_counter_out_bits { u8 out_of_sequence[0x20]; - u8 reserved_at_1e0[0x620]; + u8 reserved_at_1e0[0x20]; + + u8 duplicate_request[0x20]; + + u8 reserved_at_220[0x20]; + + u8 rnr_nak_retry_err[0x20]; + + u8 reserved_at_260[0x20]; + + u8 packet_seq_err[0x20]; + + u8 reserved_at_2a0[0x20]; + + u8 implied_nak_seq_err[0x20]; + + u8 reserved_at_2e0[0x20]; + + u8 local_ack_timeout_err[0x20]; + + u8 reserved_at_320[0x4e0]; }; struct mlx5_ifc_query_q_counter_in_bits { @@ -4998,6 +5122,28 @@ struct mlx5_ifc_detach_from_mcg_in_bits { u8 multicast_gid[16][0x8]; }; +struct mlx5_ifc_destroy_xrq_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_destroy_xrq_in_bits { + u8 opcode[0x10]; + u8 reserved_at_10[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x8]; + u8 xrqn[0x18]; + + u8 reserved_at_60[0x20]; +}; + struct mlx5_ifc_destroy_xrc_srq_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -5583,6 +5729,30 @@ struct mlx5_ifc_dealloc_flow_counter_in_bits { u8 reserved_at_60[0x20]; }; +struct mlx5_ifc_create_xrq_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x8]; + u8 xrqn[0x18]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_create_xrq_in_bits { + u8 opcode[0x10]; + u8 reserved_at_10[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x40]; + + struct mlx5_ifc_xrqc_bits xrq_context; +}; + struct mlx5_ifc_create_xrc_srq_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -6124,6 +6294,29 @@ struct mlx5_ifc_attach_to_mcg_in_bits { u8 multicast_gid[16][0x8]; }; +struct mlx5_ifc_arm_xrq_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_arm_xrq_in_bits { + u8 opcode[0x10]; + u8 reserved_at_10[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x8]; + u8 xrqn[0x18]; + + u8 reserved_at_60[0x10]; + u8 lwm[0x10]; +}; + struct mlx5_ifc_arm_xrc_srq_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -6161,7 +6354,8 @@ struct mlx5_ifc_arm_rq_out_bits { }; enum { - MLX5_ARM_RQ_IN_OP_MOD_SRQ_ = 0x1, + MLX5_ARM_RQ_IN_OP_MOD_SRQ = 0x1, + MLX5_ARM_RQ_IN_OP_MOD_XRQ = 0x2, }; struct mlx5_ifc_arm_rq_in_bits { @@ -6354,6 +6548,30 @@ struct mlx5_ifc_add_vxlan_udp_dport_in_bits { u8 vxlan_udp_port[0x10]; }; +struct mlx5_ifc_set_rate_limit_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_set_rate_limit_in_bits { + u8 opcode[0x10]; + u8 reserved_at_10[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 reserved_at_40[0x10]; + u8 rate_limit_index[0x10]; + + u8 reserved_at_60[0x20]; + + u8 rate_limit[0x20]; +}; + struct mlx5_ifc_access_register_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -6478,12 +6696,15 @@ struct mlx5_ifc_pude_reg_bits { }; struct mlx5_ifc_ptys_reg_bits { - u8 reserved_at_0[0x8]; + u8 an_disable_cap[0x1]; + u8 an_disable_admin[0x1]; + u8 reserved_at_2[0x6]; u8 local_port[0x8]; u8 reserved_at_10[0xd]; u8 proto_mask[0x3]; - u8 reserved_at_20[0x40]; + u8 an_status[0x4]; + u8 reserved_at_24[0x3c]; u8 eth_proto_capability[0x20]; @@ -7444,4 +7665,34 @@ struct mlx5_ifc_mcia_reg_bits { u8 dword_11[0x20]; }; +struct mlx5_ifc_dcbx_param_bits { + u8 dcbx_cee_cap[0x1]; + u8 dcbx_ieee_cap[0x1]; + u8 dcbx_standby_cap[0x1]; + u8 reserved_at_0[0x5]; + u8 port_number[0x8]; + u8 reserved_at_10[0xa]; + u8 max_application_table_size[6]; + u8 reserved_at_20[0x15]; + u8 version_oper[0x3]; + u8 reserved_at_38[5]; + u8 version_admin[0x3]; + u8 willing_admin[0x1]; + u8 reserved_at_41[0x3]; + u8 pfc_cap_oper[0x4]; + u8 reserved_at_48[0x4]; + u8 pfc_cap_admin[0x4]; + u8 reserved_at_50[0x4]; + u8 num_of_tc_oper[0x4]; + u8 reserved_at_58[0x4]; + u8 num_of_tc_admin[0x4]; + u8 remote_willing[0x1]; + u8 reserved_at_61[3]; + u8 remote_pfc_cap[4]; + u8 reserved_at_68[0x14]; + u8 remote_num_of_tc[0x4]; + u8 reserved_at_80[0x18]; + u8 error[0x8]; + u8 reserved_at_a0[0x160]; +}; #endif /* MLX5_IFC_H */ -- cgit v1.2.3 From 53ae95f6d5455ac1bbf50649fbd5158e0ef5f16c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 May 2016 11:23:46 +0300 Subject: ARM: OMAP3: McBSP: New callback for McBSP2/3 ICLK idle configuration McBSP2/3 module's sidetone module operates using the module's ICLK clock. When the Sidetone is in use the interface clock of the module must not idle. The new callback expects to receive the *clk of the module's ick and not the id number of the McBSP. This will allow us more cleanups and going to simplify the ICLK handling. Signed-off-by: Peter Ujfalusi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/mcbsp.c | 12 ++++++++++++ include/linux/platform_data/asoc-ti-mcbsp.h | 1 + 2 files changed, 13 insertions(+) (limited to 'include/linux') diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index b4ac3af1160c..959cb4cb1062 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -48,6 +48,17 @@ static int omap3_enable_st_clock(unsigned int id, bool enable) return omap2_clk_allow_idle(mcbsp_iclks[id]); } +static int omap3_mcbsp_force_ick_on(struct clk *clk, bool force_on) +{ + if (!clk) + return 0; + + if (force_on) + return omap2_clk_deny_idle(clk); + else + return omap2_clk_allow_idle(clk); +} + static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused) { int id, count = 1; @@ -97,6 +108,7 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused) oh_device[1] = omap_hwmod_lookup(( (struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone); pdata->enable_st_clock = omap3_enable_st_clock; + pdata->force_ick_on = omap3_mcbsp_force_ick_on; sprintf(clk_name, "mcbsp%d_ick", id); mcbsp_iclks[id] = clk_get(NULL, clk_name); count++; diff --git a/include/linux/platform_data/asoc-ti-mcbsp.h b/include/linux/platform_data/asoc-ti-mcbsp.h index 3c73c045f8da..73e5e832fa23 100644 --- a/include/linux/platform_data/asoc-ti-mcbsp.h +++ b/include/linux/platform_data/asoc-ti-mcbsp.h @@ -45,6 +45,7 @@ struct omap_mcbsp_platform_data { bool has_wakeup; /* Wakeup capability */ bool has_ccr; /* Transceiver has configuration control registers */ int (*enable_st_clock)(unsigned int, bool); + int (*force_ick_on)(struct clk *clk, bool force_on); }; /** -- cgit v1.2.3 From c26c84c92ba8907402faaab760dc0e4ecec89dd0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 May 2016 11:23:47 +0300 Subject: ARM: OMAP3: pdata-quirks: Add support for McBSP2/3 sidetone handling McBSP2/3 module's sidetone module operates using the module's ICLK clock. When the Sidetone is in use the interface clock of the module must not idle. To prevent the iclk idling the driver expects to have pdata callback to call. With this patch the callback is going to be set up for DT boot also. Signed-off-by: Peter Ujfalusi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/mcbsp.c | 9 +++++++++ arch/arm/mach-omap2/pdata-quirks.c | 18 ++++++++++++++++++ include/linux/platform_data/asoc-ti-mcbsp.h | 2 ++ 3 files changed, 29 insertions(+) (limited to 'include/linux') diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index 959cb4cb1062..edf4f41c0135 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -59,6 +59,15 @@ static int omap3_mcbsp_force_ick_on(struct clk *clk, bool force_on) return omap2_clk_allow_idle(clk); } +void __init omap3_mcbsp_init_pdata_callback( + struct omap_mcbsp_platform_data *pdata) +{ + if (!pdata) + return; + + pdata->force_ick_on = omap3_mcbsp_force_ick_on; +} + static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused) { int id, count = 1; diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 6571ad959908..ab2b2b2b90e5 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "common.h" @@ -505,6 +506,16 @@ static struct platform_device __maybe_unused rx51_lirc_device = { }, }; +#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP) +static struct omap_mcbsp_platform_data mcbsp_pdata; +static void __init omap3_mcbsp_init(void) +{ + omap3_mcbsp_init_pdata_callback(&mcbsp_pdata); +} +#else +static void __init omap3_mcbsp_init(void) {} +#endif + /* * Few boards still need auxdata populated before we populate * the dev entries in of_platform_populate(). @@ -536,6 +547,11 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL), OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0", &am35xx_emac_pdata), + /* McBSP modules with sidetone core */ +#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP) + OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49022000, "49022000.mcbsp", &mcbsp_pdata), + OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49024000, "49024000.mcbsp", &mcbsp_pdata), +#endif #endif #ifdef CONFIG_SOC_AM33XX OF_DEV_AUXDATA("ti,am3352-wkup-m3", 0x44d00000, "44d00000.wkup_m3", @@ -608,6 +624,8 @@ void __init pdata_quirks_init(const struct of_device_id *omap_dt_match_table) of_machine_is_compatible("ti,omap3")) omap_sdrc_init(NULL, NULL); + if (of_machine_is_compatible("ti,omap3")) + omap3_mcbsp_init(); pdata_quirks_check(auxdata_quirks); of_platform_populate(NULL, omap_dt_match_table, omap_auxdata_lookup, NULL); diff --git a/include/linux/platform_data/asoc-ti-mcbsp.h b/include/linux/platform_data/asoc-ti-mcbsp.h index 73e5e832fa23..5530971abf4d 100644 --- a/include/linux/platform_data/asoc-ti-mcbsp.h +++ b/include/linux/platform_data/asoc-ti-mcbsp.h @@ -56,4 +56,6 @@ struct omap_mcbsp_dev_attr { const char *sidetone; }; +void omap3_mcbsp_init_pdata_callback(struct omap_mcbsp_platform_data *pdata); + #endif -- cgit v1.2.3 From 3774bec74ea7cb30b8e80c87dd64396586d645c7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 May 2016 11:23:50 +0300 Subject: ARM: OMAP2+: McBSP: Remove the old iclk allow/deny idle code The new pdata callback (force_ick_on) is now used by the driver and the old callback related code can be removed. Signed-off-by: Peter Ujfalusi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/mcbsp.c | 18 ------------------ include/linux/platform_data/asoc-ti-mcbsp.h | 1 - 2 files changed, 19 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index edf4f41c0135..fc04be74e064 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -34,20 +34,6 @@ #include "cm3xxx.h" #include "cm-regbits-34xx.h" -static struct clk *mcbsp_iclks[5]; - -static int omap3_enable_st_clock(unsigned int id, bool enable) -{ - /* - * Sidetone uses McBSP ICLK - which must not idle when sidetones - * are enabled or sidetones start sounding ugly. - */ - if (enable) - return omap2_clk_deny_idle(mcbsp_iclks[id]); - else - return omap2_clk_allow_idle(mcbsp_iclks[id]); -} - static int omap3_mcbsp_force_ick_on(struct clk *clk, bool force_on) { if (!clk) @@ -75,7 +61,6 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused) struct omap_hwmod *oh_device[2]; struct omap_mcbsp_platform_data *pdata = NULL; struct platform_device *pdev; - char clk_name[11]; sscanf(oh->name, "mcbsp%d", &id); @@ -116,10 +101,7 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused) if (oh->dev_attr) { oh_device[1] = omap_hwmod_lookup(( (struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone); - pdata->enable_st_clock = omap3_enable_st_clock; pdata->force_ick_on = omap3_mcbsp_force_ick_on; - sprintf(clk_name, "mcbsp%d_ick", id); - mcbsp_iclks[id] = clk_get(NULL, clk_name); count++; } pdev = omap_device_build_ss(name, id, oh_device, count, pdata, diff --git a/include/linux/platform_data/asoc-ti-mcbsp.h b/include/linux/platform_data/asoc-ti-mcbsp.h index 5530971abf4d..e684543254f3 100644 --- a/include/linux/platform_data/asoc-ti-mcbsp.h +++ b/include/linux/platform_data/asoc-ti-mcbsp.h @@ -44,7 +44,6 @@ struct omap_mcbsp_platform_data { /* McBSP platform and instance specific features */ bool has_wakeup; /* Wakeup capability */ bool has_ccr; /* Transceiver has configuration control registers */ - int (*enable_st_clock)(unsigned int, bool); int (*force_ick_on)(struct clk *clk, bool force_on); }; -- cgit v1.2.3 From 3a3d1a4e32ab47323d7b8c8b7631a8d36a3098b2 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 8 Jun 2016 10:21:23 +0100 Subject: pwm: Add PWM capture support Supply a PWM capture callback op in order to pass back information obtained by running analysis on a PWM signal. This would normally (at least during testing) be called from the sysfs routines with a view to printing out PWM capture data which has been encoded into a string. Signed-off-by: Lee Jones [thierry.reding@gmail.com: make capture data unsigned int for symmetry] Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 27 +++++++++++++++++++++++++++ include/linux/pwm.h | 24 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'include/linux') diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index dba3843c53b8..8f40604046d6 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -524,6 +524,33 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) } EXPORT_SYMBOL_GPL(pwm_apply_state); +/** + * pwm_capture() - capture and report a PWM signal + * @pwm: PWM device + * @result: structure to fill with capture result + * @timeout: time to wait, in milliseconds, before giving up on capture + * + * Returns: 0 on success or a negative error code on failure. + */ +int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, + unsigned long timeout) +{ + int err; + + if (!pwm || !pwm->chip->ops) + return -EINVAL; + + if (!pwm->chip->ops->capture) + return -ENOSYS; + + mutex_lock(&pwm_lock); + err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout); + mutex_unlock(&pwm_lock); + + return err; +} +EXPORT_SYMBOL_GPL(pwm_capture); + /** * pwm_adjust_config() - adjust the current PWM config to the PWM arguments * @pwm: PWM device diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 17018f3c066e..8402b5dd3e06 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -5,7 +5,9 @@ #include #include +struct pwm_capture; struct seq_file; + struct pwm_chip; /** @@ -153,6 +155,7 @@ static inline void pwm_get_args(const struct pwm_device *pwm, * @free: optional hook for freeing a PWM * @config: configure duty cycles and period length for this PWM * @set_polarity: configure the polarity of this PWM + * @capture: capture and report PWM signal * @enable: enable PWM output toggling * @disable: disable PWM output toggling * @apply: atomically apply a new PWM config. The state argument @@ -172,6 +175,8 @@ struct pwm_ops { int duty_ns, int period_ns); int (*set_polarity)(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity); + int (*capture)(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_capture *result, unsigned long timeout); int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm); void (*disable)(struct pwm_chip *chip, struct pwm_device *pwm); int (*apply)(struct pwm_chip *chip, struct pwm_device *pwm, @@ -212,6 +217,16 @@ struct pwm_chip { bool can_sleep; }; +/** + * struct pwm_capture - PWM capture data + * @period: period of the PWM signal (in nanoseconds) + * @duty_cycle: duty cycle of the PWM signal (in nanoseconds) + */ +struct pwm_capture { + unsigned int period; + unsigned int duty_cycle; +}; + #if IS_ENABLED(CONFIG_PWM) /* PWM user APIs */ struct pwm_device *pwm_request(int pwm_id, const char *label); @@ -322,6 +337,8 @@ static inline void pwm_disable(struct pwm_device *pwm) /* PWM provider APIs */ +int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, + unsigned long timeout); int pwm_set_chip_data(struct pwm_device *pwm, void *data); void *pwm_get_chip_data(struct pwm_device *pwm); @@ -373,6 +390,13 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns, return -EINVAL; } +static inline int pwm_capture(struct pwm_device *pwm, + struct pwm_capture *result, + unsigned long timeout) +{ + return -EINVAL; +} + static inline int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity) { -- cgit v1.2.3 From e83068a5faafb8ca65d3b58bd1e1e3959ce1ddce Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 24 May 2016 21:16:51 -0400 Subject: dm mpath: add optional "queue_mode" feature Allow a user to specify an optional feature 'queue_mode ' where may be "bio", "rq" or "mq" -- which corresponds to bio-based, request_fn rq-based, and blk-mq rq-based respectively. If the queue_mode feature isn't specified the default for the "multipath" target is still "rq" but if dm_mod.use_blk_mq is set to Y it'll default to mode "mq". This new queue_mode feature introduces the ability for each multipath device to have its own queue_mode (whereas before this feature all multipath devices effectively had to have the same queue_mode). This commit also goes a long way to eliminate the awkward (ab)use of DM_TYPE_*, the associated filter_md_type() and other relatively fragile and difficult to maintain code. Signed-off-by: Mike Snitzer --- drivers/md/dm-mpath.c | 149 +++++++++++++++++++++++------------------- drivers/md/dm-rq.c | 19 ++++-- drivers/md/dm-rq.h | 2 +- drivers/md/dm-table.c | 67 ++++++++++++------- drivers/md/dm.c | 15 +---- drivers/md/dm.h | 10 +-- include/linux/device-mapper.h | 16 +++++ 7 files changed, 159 insertions(+), 119 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 2d10ff780d84..7eac080fcb18 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -90,6 +90,8 @@ struct multipath { atomic_t pg_init_in_progress; /* Only one pg_init allowed at once */ atomic_t pg_init_count; /* Number of times pg_init called */ + unsigned queue_mode; + /* * We must use a mempool of dm_mpath_io structs so that we * can resubmit bios on error. @@ -131,7 +133,6 @@ static void process_queued_bios(struct work_struct *work); #define MPATHF_PG_INIT_DISABLED 4 /* pg_init is not currently allowed */ #define MPATHF_PG_INIT_REQUIRED 5 /* pg_init needs calling? */ #define MPATHF_PG_INIT_DELAY_RETRY 6 /* Delay pg_init retry? */ -#define MPATHF_BIO_BASED 7 /* Device is bio-based? */ /*----------------------------------------------- * Allocation routines @@ -191,8 +192,7 @@ static void free_priority_group(struct priority_group *pg, kfree(pg); } -static struct multipath *alloc_multipath(struct dm_target *ti, bool use_blk_mq, - bool bio_based) +static struct multipath *alloc_multipath(struct dm_target *ti) { struct multipath *m; @@ -210,25 +210,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti, bool use_blk_mq, mutex_init(&m->work_mutex); m->mpio_pool = NULL; - if (!use_blk_mq && !bio_based) { - unsigned min_ios = dm_get_reserved_rq_based_ios(); - - m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache); - if (!m->mpio_pool) { - kfree(m); - return NULL; - } - } - - if (bio_based) { - INIT_WORK(&m->process_queued_bios, process_queued_bios); - set_bit(MPATHF_BIO_BASED, &m->flags); - /* - * bio-based doesn't support any direct scsi_dh management; - * it just discovers if a scsi_dh is attached. - */ - set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); - } + m->queue_mode = DM_TYPE_NONE; m->ti = ti; ti->private = m; @@ -237,6 +219,39 @@ static struct multipath *alloc_multipath(struct dm_target *ti, bool use_blk_mq, return m; } +static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) +{ + if (m->queue_mode == DM_TYPE_NONE) { + /* + * Default to request-based. + */ + if (dm_use_blk_mq(dm_table_get_md(ti->table))) + m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; + else + m->queue_mode = DM_TYPE_REQUEST_BASED; + } + + if (m->queue_mode == DM_TYPE_REQUEST_BASED) { + unsigned min_ios = dm_get_reserved_rq_based_ios(); + + m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache); + if (!m->mpio_pool) + return -ENOMEM; + } + else if (m->queue_mode == DM_TYPE_BIO_BASED) { + INIT_WORK(&m->process_queued_bios, process_queued_bios); + /* + * bio-based doesn't support any direct scsi_dh management; + * it just discovers if a scsi_dh is attached. + */ + set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags); + } + + dm_table_set_type(ti->table, m->queue_mode); + + return 0; +} + static void free_multipath(struct multipath *m) { struct priority_group *pg, *tmp; @@ -653,7 +668,7 @@ static int multipath_map_bio(struct dm_target *ti, struct bio *bio) static void process_queued_bios_list(struct multipath *m) { - if (test_bit(MPATHF_BIO_BASED, &m->flags)) + if (m->queue_mode == DM_TYPE_BIO_BASED) queue_work(kmultipathd, &m->process_queued_bios); } @@ -964,7 +979,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) if (!hw_argc) return 0; - if (test_bit(MPATHF_BIO_BASED, &m->flags)) { + if (m->queue_mode == DM_TYPE_BIO_BASED) { dm_consume_args(as, hw_argc); DMERR("bio-based multipath doesn't allow hardware handler args"); return 0; @@ -1005,7 +1020,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) const char *arg_name; static struct dm_arg _args[] = { - {0, 6, "invalid number of feature args"}, + {0, 8, "invalid number of feature args"}, {1, 50, "pg_init_retries must be between 1 and 50"}, {0, 60000, "pg_init_delay_msecs must be between 0 and 60000"}, }; @@ -1045,6 +1060,24 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) continue; } + if (!strcasecmp(arg_name, "queue_mode") && + (argc >= 1)) { + const char *queue_mode_name = dm_shift_arg(as); + + if (!strcasecmp(queue_mode_name, "bio")) + m->queue_mode = DM_TYPE_BIO_BASED; + else if (!strcasecmp(queue_mode_name, "rq")) + m->queue_mode = DM_TYPE_REQUEST_BASED; + else if (!strcasecmp(queue_mode_name, "mq")) + m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; + else { + ti->error = "Unknown 'queue_mode' requested"; + r = -EINVAL; + } + argc--; + continue; + } + ti->error = "Unrecognised multipath feature request"; r = -EINVAL; } while (argc && !r); @@ -1052,8 +1085,7 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m) return r; } -static int __multipath_ctr(struct dm_target *ti, unsigned int argc, - char **argv, bool bio_based) +static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) { /* target arguments */ static struct dm_arg _args[] = { @@ -1066,12 +1098,11 @@ static int __multipath_ctr(struct dm_target *ti, unsigned int argc, struct dm_arg_set as; unsigned pg_count = 0; unsigned next_pg_num; - bool use_blk_mq = dm_use_blk_mq(dm_table_get_md(ti->table)); as.argc = argc; as.argv = argv; - m = alloc_multipath(ti, use_blk_mq, bio_based); + m = alloc_multipath(ti); if (!m) { ti->error = "can't allocate multipath"; return -EINVAL; @@ -1081,6 +1112,10 @@ static int __multipath_ctr(struct dm_target *ti, unsigned int argc, if (r) goto bad; + r = alloc_multipath_stage2(ti, m); + if (r) + goto bad; + r = parse_hw_handler(&as, m); if (r) goto bad; @@ -1130,9 +1165,9 @@ static int __multipath_ctr(struct dm_target *ti, unsigned int argc, ti->num_flush_bios = 1; ti->num_discard_bios = 1; ti->num_write_same_bios = 1; - if (bio_based) + if (m->queue_mode == DM_TYPE_BIO_BASED) ti->per_io_data_size = multipath_per_bio_data_size(); - else if (use_blk_mq) + else if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED) ti->per_io_data_size = sizeof(struct dm_mpath_io); return 0; @@ -1142,16 +1177,6 @@ static int __multipath_ctr(struct dm_target *ti, unsigned int argc, return r; } -static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) -{ - return __multipath_ctr(ti, argc, argv, false); -} - -static int multipath_bio_ctr(struct dm_target *ti, unsigned argc, char **argv) -{ - return __multipath_ctr(ti, argc, argv, true); -} - static void multipath_wait_for_pg_init_completion(struct multipath *m) { DECLARE_WAITQUEUE(wait, current); @@ -1700,7 +1725,9 @@ static void multipath_status(struct dm_target *ti, status_type_t type, DMEMIT("%u ", test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) + (m->pg_init_retries > 0) * 2 + (m->pg_init_delay_msecs != DM_PG_INIT_DELAY_DEFAULT) * 2 + - test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)); + test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags) + + (m->queue_mode != DM_TYPE_REQUEST_BASED) * 2); + if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) DMEMIT("queue_if_no_path "); if (m->pg_init_retries) @@ -1709,6 +1736,16 @@ static void multipath_status(struct dm_target *ti, status_type_t type, DMEMIT("pg_init_delay_msecs %u ", m->pg_init_delay_msecs); if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)) DMEMIT("retain_attached_hw_handler "); + if (m->queue_mode != DM_TYPE_REQUEST_BASED) { + switch(m->queue_mode) { + case DM_TYPE_BIO_BASED: + DMEMIT("queue_mode bio "); + break; + case DM_TYPE_MQ_REQUEST_BASED: + DMEMIT("queue_mode mq "); + break; + } + } } if (!m->hw_handler_name || type == STATUSTYPE_INFO) @@ -1995,7 +2032,7 @@ static int multipath_busy(struct dm_target *ti) *---------------------------------------------------------------*/ static struct target_type multipath_target = { .name = "multipath", - .version = {1, 11, 0}, + .version = {1, 12, 0}, .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE, .module = THIS_MODULE, .ctr = multipath_ctr, @@ -2004,22 +2041,6 @@ static struct target_type multipath_target = { .clone_and_map_rq = multipath_clone_and_map, .release_clone_rq = multipath_release_clone, .rq_end_io = multipath_end_io, - .presuspend = multipath_presuspend, - .postsuspend = multipath_postsuspend, - .resume = multipath_resume, - .status = multipath_status, - .message = multipath_message, - .prepare_ioctl = multipath_prepare_ioctl, - .iterate_devices = multipath_iterate_devices, - .busy = multipath_busy, -}; - -static struct target_type multipath_bio_target = { - .name = "multipath-bio", - .version = {1, 0, 0}, - .module = THIS_MODULE, - .ctr = multipath_bio_ctr, - .dtr = multipath_dtr, .map = multipath_map_bio, .end_io = multipath_end_io_bio, .presuspend = multipath_presuspend, @@ -2048,13 +2069,6 @@ static int __init dm_multipath_init(void) goto bad_register_target; } - r = dm_register_target(&multipath_bio_target); - if (r < 0) { - DMERR("bio-based register failed %d", r); - r = -EINVAL; - goto bad_register_bio_based_target; - } - kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0); if (!kmultipathd) { DMERR("failed to create workqueue kmpathd"); @@ -2081,8 +2095,6 @@ static int __init dm_multipath_init(void) bad_alloc_kmpath_handlerd: destroy_workqueue(kmultipathd); bad_alloc_kmultipathd: - dm_unregister_target(&multipath_bio_target); -bad_register_bio_based_target: dm_unregister_target(&multipath_target); bad_register_target: kmem_cache_destroy(_mpio_cache); @@ -2096,7 +2108,6 @@ static void __exit dm_multipath_exit(void) destroy_workqueue(kmultipathd); dm_unregister_target(&multipath_target); - dm_unregister_target(&multipath_bio_target); kmem_cache_destroy(_mpio_cache); } diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index 787c81b16a26..266f7b674108 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -230,7 +230,14 @@ static void free_rq_clone(struct request *clone) blk_rq_unprep_clone(clone); - if (md->type == DM_TYPE_MQ_REQUEST_BASED) + /* + * It is possible for a clone_old_rq() allocated clone to + * get passed in -- it may not yet have a request_queue. + * This is known to occur if the error target replaces + * a multipath target that has a request_fn queue stacked + * on blk-mq queue(s). + */ + if (clone->q && clone->q->mq_ops) /* stacked on blk-mq queue(s) */ tio->ti->type->release_clone_rq(clone); else if (!md->queue->mq_ops) @@ -561,7 +568,7 @@ static struct dm_rq_target_io *dm_old_prep_tio(struct request *rq, * Must clone a request if this .request_fn DM device * is stacked on .request_fn device(s). */ - if (!dm_table_mq_request_based(table)) { + if (!dm_table_all_blk_mq_devices(table)) { if (!clone_old_rq(rq, md, tio, gfp_mask)) { dm_put_live_table(md, srcu_idx); free_old_rq_tio(tio); @@ -711,7 +718,7 @@ ssize_t dm_attr_rq_based_seq_io_merge_deadline_store(struct mapped_device *md, { unsigned deadline; - if (!dm_request_based(md) || md->use_blk_mq) + if (dm_get_md_type(md) != DM_TYPE_REQUEST_BASED) return count; if (kstrtouint(buf, 10, &deadline)) @@ -886,12 +893,13 @@ static struct blk_mq_ops dm_mq_ops = { .init_request = dm_mq_init_request, }; -int dm_mq_init_request_queue(struct mapped_device *md, struct dm_target *immutable_tgt) +int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t) { struct request_queue *q; + struct dm_target *immutable_tgt; int err; - if (dm_get_md_type(md) == DM_TYPE_REQUEST_BASED) { + if (!dm_table_all_blk_mq_devices(t)) { DMERR("request-based dm-mq may only be stacked on blk-mq device(s)"); return -EINVAL; } @@ -908,6 +916,7 @@ int dm_mq_init_request_queue(struct mapped_device *md, struct dm_target *immutab md->tag_set->driver_data = md; md->tag_set->cmd_size = sizeof(struct dm_rq_target_io); + immutable_tgt = dm_table_get_immutable_target(t); if (immutable_tgt && immutable_tgt->per_io_data_size) { /* any target-specific per-io data is immediately after the tio */ md->tag_set->cmd_size += immutable_tgt->per_io_data_size; diff --git a/drivers/md/dm-rq.h b/drivers/md/dm-rq.h index 1559f6486024..9e6f0a3773d4 100644 --- a/drivers/md/dm-rq.h +++ b/drivers/md/dm-rq.h @@ -49,7 +49,7 @@ bool dm_use_blk_mq_default(void); bool dm_use_blk_mq(struct mapped_device *md); int dm_old_init_request_queue(struct mapped_device *md); -int dm_mq_init_request_queue(struct mapped_device *md, struct dm_target *immutable_tgt); +int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t); void dm_mq_cleanup_mapped_device(struct mapped_device *md); void dm_start_queue(struct request_queue *q); diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index a682d51111dd..88f01744ac16 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -43,8 +43,10 @@ struct dm_table { struct dm_target *targets; struct target_type *immutable_target_type; - unsigned integrity_supported:1; - unsigned singleton:1; + + bool integrity_supported:1; + bool singleton:1; + bool all_blk_mq:1; /* * Indicates the rw permissions for the new logical @@ -206,6 +208,7 @@ int dm_table_create(struct dm_table **result, fmode_t mode, return -ENOMEM; } + t->type = DM_TYPE_NONE; t->mode = mode; t->md = md; *result = t; @@ -703,7 +706,7 @@ int dm_table_add_target(struct dm_table *t, const char *type, dm_device_name(t->md), type); return -EINVAL; } - t->singleton = 1; + t->singleton = true; } if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) { @@ -830,16 +833,29 @@ static bool __table_type_request_based(unsigned table_type) table_type == DM_TYPE_MQ_REQUEST_BASED); } -static int dm_table_set_type(struct dm_table *t) +void dm_table_set_type(struct dm_table *t, unsigned type) +{ + t->type = type; +} +EXPORT_SYMBOL_GPL(dm_table_set_type); + +static int dm_table_determine_type(struct dm_table *t) { unsigned i; unsigned bio_based = 0, request_based = 0, hybrid = 0; - bool use_blk_mq = false; + bool verify_blk_mq = false; struct dm_target *tgt; struct dm_dev_internal *dd; - struct list_head *devices; + struct list_head *devices = dm_table_get_devices(t); unsigned live_md_type = dm_get_md_type(t->md); + if (t->type != DM_TYPE_NONE) { + /* target already set the table's type */ + if (t->type == DM_TYPE_BIO_BASED) + return 0; + goto verify_rq_based; + } + for (i = 0; i < t->num_targets; i++) { tgt = t->targets + i; if (dm_target_hybrid(tgt)) @@ -876,6 +892,19 @@ static int dm_table_set_type(struct dm_table *t) BUG_ON(!request_based); /* No targets in this table */ + if (list_empty(devices) && __table_type_request_based(live_md_type)) { + /* inherit live MD type */ + t->type = live_md_type; + return 0; + } + + /* + * The only way to establish DM_TYPE_MQ_REQUEST_BASED is by + * having a compatible target use dm_table_set_type. + */ + t->type = DM_TYPE_REQUEST_BASED; + +verify_rq_based: /* * Request-based dm supports only tables that have a single target now. * To support multiple targets, request splitting support is needed, @@ -888,7 +917,6 @@ static int dm_table_set_type(struct dm_table *t) } /* Non-request-stackable devices can't be used for request-based dm */ - devices = dm_table_get_devices(t); list_for_each_entry(dd, devices, list) { struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev); @@ -899,10 +927,10 @@ static int dm_table_set_type(struct dm_table *t) } if (q->mq_ops) - use_blk_mq = true; + verify_blk_mq = true; } - if (use_blk_mq) { + if (verify_blk_mq) { /* verify _all_ devices in the table are blk-mq devices */ list_for_each_entry(dd, devices, list) if (!bdev_get_queue(dd->dm_dev->bdev)->mq_ops) { @@ -910,14 +938,9 @@ static int dm_table_set_type(struct dm_table *t) " are blk-mq request-stackable"); return -EINVAL; } - t->type = DM_TYPE_MQ_REQUEST_BASED; - } else if (list_empty(devices) && __table_type_request_based(live_md_type)) { - /* inherit live MD type */ - t->type = live_md_type; - - } else - t->type = DM_TYPE_REQUEST_BASED; + t->all_blk_mq = true; + } return 0; } @@ -961,9 +984,9 @@ bool dm_table_request_based(struct dm_table *t) return __table_type_request_based(dm_table_get_type(t)); } -bool dm_table_mq_request_based(struct dm_table *t) +bool dm_table_all_blk_mq_devices(struct dm_table *t) { - return dm_table_get_type(t) == DM_TYPE_MQ_REQUEST_BASED; + return t->all_blk_mq; } static int dm_table_alloc_md_mempools(struct dm_table *t, struct mapped_device *md) @@ -1106,7 +1129,7 @@ static int dm_table_register_integrity(struct dm_table *t) return 0; if (!integrity_profile_exists(dm_disk(md))) { - t->integrity_supported = 1; + t->integrity_supported = true; /* * Register integrity profile during table load; we can do * this because the final profile must match during resume. @@ -1129,7 +1152,7 @@ static int dm_table_register_integrity(struct dm_table *t) } /* Preserve existing integrity profile */ - t->integrity_supported = 1; + t->integrity_supported = true; return 0; } @@ -1141,9 +1164,9 @@ int dm_table_complete(struct dm_table *t) { int r; - r = dm_table_set_type(t); + r = dm_table_determine_type(t); if (r) { - DMERR("unable to set table type"); + DMERR("unable to determine table type"); return r; } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 8f22527134e9..2c907bc10fe9 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1738,23 +1738,14 @@ struct queue_limits *dm_get_queue_limits(struct mapped_device *md) } EXPORT_SYMBOL_GPL(dm_get_queue_limits); -static unsigned filter_md_type(unsigned type, struct mapped_device *md) -{ - if (type == DM_TYPE_BIO_BASED) - return type; - - return !md->use_blk_mq ? DM_TYPE_REQUEST_BASED : DM_TYPE_MQ_REQUEST_BASED; -} - /* * Setup the DM device's queue based on md's type */ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) { int r; - unsigned md_type = filter_md_type(dm_get_md_type(md), md); - switch (md_type) { + switch (dm_get_md_type(md)) { case DM_TYPE_REQUEST_BASED: r = dm_old_init_request_queue(md); if (r) { @@ -1763,7 +1754,7 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) } break; case DM_TYPE_MQ_REQUEST_BASED: - r = dm_mq_init_request_queue(md, dm_table_get_immutable_target(t)); + r = dm_mq_init_request_queue(md, t); if (r) { DMERR("Cannot initialize queue for request-based dm-mq mapped device"); return r; @@ -2472,8 +2463,6 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t if (!pools) return NULL; - type = filter_md_type(type, md); - switch (type) { case DM_TYPE_BIO_BASED: cachep = _io_cache; diff --git a/drivers/md/dm.h b/drivers/md/dm.h index b611b3064a7c..2e0e4a53a312 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -33,14 +33,6 @@ */ #define DM_STATUS_NOFLUSH_FLAG (1 << 0) -/* - * Type of table and mapped_device's mempool - */ -#define DM_TYPE_NONE 0 -#define DM_TYPE_BIO_BASED 1 -#define DM_TYPE_REQUEST_BASED 2 -#define DM_TYPE_MQ_REQUEST_BASED 3 - /* * List of devices that a metadevice uses and should open/close. */ @@ -77,7 +69,7 @@ struct target_type *dm_table_get_immutable_target_type(struct dm_table *t); struct dm_target *dm_table_get_immutable_target(struct dm_table *t); struct dm_target *dm_table_get_wildcard_target(struct dm_table *t); bool dm_table_request_based(struct dm_table *t); -bool dm_table_mq_request_based(struct dm_table *t); +bool dm_table_all_blk_mq_devices(struct dm_table *t); void dm_table_free_md_mempools(struct dm_table *t); struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t); diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index 0830c9e86f0d..2ce339212b6e 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -19,6 +19,14 @@ struct dm_table; struct mapped_device; struct bio_vec; +/* + * Type of table, mapped_device's mempool and request_queue + */ +#define DM_TYPE_NONE 0 +#define DM_TYPE_BIO_BASED 1 +#define DM_TYPE_REQUEST_BASED 2 +#define DM_TYPE_MQ_REQUEST_BASED 3 + typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t; union map_info { @@ -443,6 +451,14 @@ int dm_table_add_target(struct dm_table *t, const char *type, */ void dm_table_add_target_callbacks(struct dm_table *t, struct dm_target_callbacks *cb); +/* + * Target can use this to set the table's type. + * Can only ever be called from a target's ctr. + * Useful for "hybrid" target (supports both bio-based + * and request-based). + */ +void dm_table_set_type(struct dm_table *t, unsigned type); + /* * Finally call this to make the table ready for use. */ -- cgit v1.2.3 From 80955f9ee51760db64795b3778365ccb8c3a2729 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Fri, 10 Jun 2016 21:55:09 +0200 Subject: PCI: Move ecam.h to linux/include/pci-ecam.h This header will be used from arch/arm64 for ACPI PCI implementation so it needs to be moved out of drivers/pci. Update users of the header file to use the new name. No functional changes. Signed-off-by: Jayachandran C Signed-off-by: Bjorn Helgaas Acked-by: Lorenzo Pieralisi --- drivers/pci/ecam.c | 3 +- drivers/pci/ecam.h | 67 ------------------------------------- drivers/pci/host/pci-host-common.c | 3 +- drivers/pci/host/pci-host-generic.c | 3 +- drivers/pci/host/pci-thunder-ecam.c | 3 +- drivers/pci/host/pci-thunder-pem.c | 3 +- include/linux/pci-ecam.h | 67 +++++++++++++++++++++++++++++++++++++ 7 files changed, 72 insertions(+), 77 deletions(-) delete mode 100644 drivers/pci/ecam.h create mode 100644 include/linux/pci-ecam.h (limited to 'include/linux') diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c index f9832ad8efe2..820e26b473f4 100644 --- a/drivers/pci/ecam.c +++ b/drivers/pci/ecam.c @@ -19,10 +19,9 @@ #include #include #include +#include #include -#include "ecam.h" - /* * On 64-bit systems, we do a single ioremap for the whole config space * since we have enough virtual address range available. On 32-bit, we diff --git a/drivers/pci/ecam.h b/drivers/pci/ecam.h deleted file mode 100644 index 9878bebd45bb..000000000000 --- a/drivers/pci/ecam.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2016 Broadcom - * - * 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 (the "GPL"). - * - * 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 version 2 (GPLv2) for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 (GPLv2) along with this source code. - */ -#ifndef DRIVERS_PCI_ECAM_H -#define DRIVERS_PCI_ECAM_H - -#include -#include - -/* - * struct to hold pci ops and bus shift of the config window - * for a PCI controller. - */ -struct pci_config_window; -struct pci_ecam_ops { - unsigned int bus_shift; - struct pci_ops pci_ops; - int (*init)(struct device *, - struct pci_config_window *); -}; - -/* - * struct to hold the mappings of a config space window. This - * is expected to be used as sysdata for PCI controllers that - * use ECAM. - */ -struct pci_config_window { - struct resource res; - struct resource busr; - void *priv; - struct pci_ecam_ops *ops; - union { - void __iomem *win; /* 64-bit single mapping */ - void __iomem **winp; /* 32-bit per-bus mapping */ - }; -}; - -/* create and free pci_config_window */ -struct pci_config_window *pci_ecam_create(struct device *dev, - struct resource *cfgres, struct resource *busr, - struct pci_ecam_ops *ops); -void pci_ecam_free(struct pci_config_window *cfg); - -/* map_bus when ->sysdata is an instance of pci_config_window */ -void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, - int where); -/* default ECAM ops */ -extern struct pci_ecam_ops pci_generic_ecam_ops; - -#ifdef CONFIG_PCI_HOST_GENERIC -/* for DT-based PCI controllers that support ECAM */ -int pci_host_common_probe(struct platform_device *pdev, - struct pci_ecam_ops *ops); -#endif -#endif diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c index 8cba7ab73df9..c18b9e3bb8bd 100644 --- a/drivers/pci/host/pci-host-common.c +++ b/drivers/pci/host/pci-host-common.c @@ -20,10 +20,9 @@ #include #include #include +#include #include -#include "../ecam.h" - static int gen_pci_parse_request_of_pci_ranges(struct device *dev, struct list_head *resources, struct resource **bus_range) { diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 6eaceab1bf04..f0ca6de0d87e 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c @@ -23,10 +23,9 @@ #include #include #include +#include #include -#include "../ecam.h" - static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = { .bus_shift = 16, .pci_ops = { diff --git a/drivers/pci/host/pci-thunder-ecam.c b/drivers/pci/host/pci-thunder-ecam.c index 540d030613eb..a9fc1c9105fd 100644 --- a/drivers/pci/host/pci-thunder-ecam.c +++ b/drivers/pci/host/pci-thunder-ecam.c @@ -11,10 +11,9 @@ #include #include #include +#include #include -#include "../ecam.h" - static void set_val(u32 v, int where, int size, u32 *val) { int shift = (where & 3) * 8; diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c index 9b8ab94f3c8c..5020d3d61ba7 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/host/pci-thunder-pem.c @@ -18,10 +18,9 @@ #include #include #include +#include #include -#include "../ecam.h" - #define PEM_CFG_WR 0x28 #define PEM_CFG_RD 0x30 diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h new file mode 100644 index 000000000000..9878bebd45bb --- /dev/null +++ b/include/linux/pci-ecam.h @@ -0,0 +1,67 @@ +/* + * Copyright 2016 Broadcom + * + * 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 (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ +#ifndef DRIVERS_PCI_ECAM_H +#define DRIVERS_PCI_ECAM_H + +#include +#include + +/* + * struct to hold pci ops and bus shift of the config window + * for a PCI controller. + */ +struct pci_config_window; +struct pci_ecam_ops { + unsigned int bus_shift; + struct pci_ops pci_ops; + int (*init)(struct device *, + struct pci_config_window *); +}; + +/* + * struct to hold the mappings of a config space window. This + * is expected to be used as sysdata for PCI controllers that + * use ECAM. + */ +struct pci_config_window { + struct resource res; + struct resource busr; + void *priv; + struct pci_ecam_ops *ops; + union { + void __iomem *win; /* 64-bit single mapping */ + void __iomem **winp; /* 32-bit per-bus mapping */ + }; +}; + +/* create and free pci_config_window */ +struct pci_config_window *pci_ecam_create(struct device *dev, + struct resource *cfgres, struct resource *busr, + struct pci_ecam_ops *ops); +void pci_ecam_free(struct pci_config_window *cfg); + +/* map_bus when ->sysdata is an instance of pci_config_window */ +void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, + int where); +/* default ECAM ops */ +extern struct pci_ecam_ops pci_generic_ecam_ops; + +#ifdef CONFIG_PCI_HOST_GENERIC +/* for DT-based PCI controllers that support ECAM */ +int pci_host_common_probe(struct platform_device *pdev, + struct pci_ecam_ops *ops); +#endif +#endif -- cgit v1.2.3 From 5c3d14f76fccd14f0882fe2a11e19534a11a1674 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Fri, 10 Jun 2016 21:55:10 +0200 Subject: PCI: Add parent device field to ECAM struct pci_config_window Add a parent device field to struct pci_config_window. The parent is not saved now, but will be useful to save it in some cases. For ACPI on ARM64, it can be used to setup ACPI companion and domain. Since the parent dev is in struct pci_config_window now, we need not pass it to the init function as a separate argument. Signed-off-by: Jayachandran C Signed-off-by: Bjorn Helgaas Acked-by: Lorenzo Pieralisi --- drivers/pci/ecam.c | 3 ++- drivers/pci/host/pci-thunder-pem.c | 3 ++- include/linux/pci-ecam.h | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c index 820e26b473f4..66e0d718472f 100644 --- a/drivers/pci/ecam.c +++ b/drivers/pci/ecam.c @@ -51,6 +51,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev, if (!cfg) return ERR_PTR(-ENOMEM); + cfg->parent = dev; cfg->ops = ops; cfg->busr.start = busr->start; cfg->busr.end = busr->end; @@ -94,7 +95,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev, } if (ops->init) { - err = ops->init(dev, cfg); + err = ops->init(cfg); if (err) goto err_exit; } diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c index 5020d3d61ba7..91f6fc68d374 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/host/pci-thunder-pem.c @@ -284,8 +284,9 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn, return pci_generic_config_write(bus, devfn, where, size, val); } -static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg) +static int thunder_pem_init(struct pci_config_window *cfg) { + struct device *dev = cfg->parent; resource_size_t bar4_start; struct resource *res_pem; struct thunder_pem_pci *pem_pci; diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 9878bebd45bb..7adad206b1f4 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -27,8 +27,7 @@ struct pci_config_window; struct pci_ecam_ops { unsigned int bus_shift; struct pci_ops pci_ops; - int (*init)(struct device *, - struct pci_config_window *); + int (*init)(struct pci_config_window *); }; /* @@ -45,6 +44,7 @@ struct pci_config_window { void __iomem *win; /* 64-bit single mapping */ void __iomem **winp; /* 32-bit per-bus mapping */ }; + struct device *parent;/* ECAM res was from this dev */ }; /* create and free pci_config_window */ -- cgit v1.2.3 From 4d3f13845957a87729a324cce8509fad8826ef52 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 10 Jun 2016 21:55:11 +0200 Subject: PCI: Add pci_unmap_iospace() to unmap I/O resources Add pci_unmap_iospace() to undo what pci_remap_iospace() did. This is needed to support hotplug removal of host bridges that use pci_remap_iospace(). [bhelgaas: changelog] Signed-off-by: Sinan Kaya Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas Acked-by: Lorenzo Pieralisi --- drivers/pci/pci.c | 18 ++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 19 insertions(+) (limited to 'include/linux') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c8b4dbdd1bdd..eb431b5c3685 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "pci.h" @@ -3165,6 +3166,23 @@ int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) #endif } +/** + * pci_unmap_iospace - Unmap the memory mapped I/O space + * @res: resource to be unmapped + * + * Unmap the CPU virtual address @res from virtual address space. + * Only architectures that have memory mapped IO functions defined + * (and the PCI_IOBASE value defined) should call this function. + */ +void pci_unmap_iospace(struct resource *res) +{ +#if defined(PCI_IOBASE) && defined(CONFIG_MMU) + unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start; + + unmap_kernel_range(vaddr, resource_size(res)); +#endif +} + static void __pci_set_master(struct pci_dev *dev, bool enable) { u16 old_cmd, cmd; diff --git a/include/linux/pci.h b/include/linux/pci.h index b67e4df20801..12349deb688c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1167,6 +1167,7 @@ int pci_register_io_range(phys_addr_t addr, resource_size_t size); unsigned long pci_address_to_pio(phys_addr_t addr); phys_addr_t pci_pio_to_address(unsigned long pio); int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr); +void pci_unmap_iospace(struct resource *res); static inline pci_bus_addr_t pci_bus_address(struct pci_dev *pdev, int bar) { -- cgit v1.2.3 From 935c760ec8101413248da23b6df45f0a7a643c62 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 10 Jun 2016 21:55:13 +0200 Subject: PCI/ACPI: Add generic MCFG table handling On ACPI systems that support memory-mapped config space access, i.e., ECAM, the PCI Firmware Specification says the OS can learn where the ECAM space is from either: - the static MCFG table (for non-hotpluggable bridges), or - the _CBA method (for hotpluggable bridges) The current MCFG table handling code cannot be easily generalized owing to x86-specific quirks, which makes it hard to reuse on other architectures. Implement generic MCFG handling from scratch, including: - Simple MCFG table parsing (via pci_mmcfg_late_init() as in current x86) - MCFG region lookup for a (domain, bus_start, bus_end) tuple [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki Signed-off-by: Jayachandran C Signed-off-by: Bjorn Helgaas Reviewed-by: Lorenzo Pieralisi --- drivers/acpi/Kconfig | 3 ++ drivers/acpi/Makefile | 1 + drivers/acpi/pci_mcfg.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci-acpi.h | 2 ++ include/linux/pci.h | 2 +- 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 drivers/acpi/pci_mcfg.c (limited to 'include/linux') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index b7e2e776397d..f98c3287256e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -217,6 +217,9 @@ config ACPI_PROCESSOR_IDLE bool select CPU_IDLE +config ACPI_MCFG + bool + config ACPI_CPPC_LIB bool depends on ACPI_PROCESSOR diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 251ce85a66fb..632e81feef69 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o +obj-$(CONFIG_ACPI_MCFG) += pci_mcfg.o acpi-y += acpi_lpss.o acpi_apd.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c new file mode 100644 index 000000000000..b5b376e081f5 --- /dev/null +++ b/drivers/acpi/pci_mcfg.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 Broadcom + * Author: Jayachandran C + * Copyright (C) 2016 Semihalf + * Author: Tomasz Nowicki + * + * 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 (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +#define pr_fmt(fmt) "ACPI: " fmt + +#include +#include +#include + +/* Structure to hold entries from the MCFG table */ +struct mcfg_entry { + struct list_head list; + phys_addr_t addr; + u16 segment; + u8 bus_start; + u8 bus_end; +}; + +/* List to save MCFG entries */ +static LIST_HEAD(pci_mcfg_list); + +phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res) +{ + struct mcfg_entry *e; + + /* + * We expect exact match, unless MCFG entry end bus covers more than + * specified by caller. + */ + list_for_each_entry(e, &pci_mcfg_list, list) { + if (e->segment == seg && e->bus_start == bus_res->start && + e->bus_end >= bus_res->end) + return e->addr; + } + + return 0; +} + +static __init int pci_mcfg_parse(struct acpi_table_header *header) +{ + struct acpi_table_mcfg *mcfg; + struct acpi_mcfg_allocation *mptr; + struct mcfg_entry *e, *arr; + int i, n; + + if (header->length < sizeof(struct acpi_table_mcfg)) + return -EINVAL; + + n = (header->length - sizeof(struct acpi_table_mcfg)) / + sizeof(struct acpi_mcfg_allocation); + mcfg = (struct acpi_table_mcfg *)header; + mptr = (struct acpi_mcfg_allocation *) &mcfg[1]; + + arr = kcalloc(n, sizeof(*arr), GFP_KERNEL); + if (!arr) + return -ENOMEM; + + for (i = 0, e = arr; i < n; i++, mptr++, e++) { + e->segment = mptr->pci_segment; + e->addr = mptr->address; + e->bus_start = mptr->start_bus_number; + e->bus_end = mptr->end_bus_number; + list_add(&e->list, &pci_mcfg_list); + } + + pr_info("MCFG table detected, %d entries\n", n); + return 0; +} + +/* Interface called by ACPI - parse and save MCFG table */ +void __init pci_mmcfg_late_init(void) +{ + int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse); + if (err) + pr_err("Failed to parse MCFG (%d)\n", err); +} diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 89ab0572dbc6..7d63a66e8ed4 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -24,6 +24,8 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev) } extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle); +extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res); + static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) { struct pci_bus *pbus = pdev->bus; diff --git a/include/linux/pci.h b/include/linux/pci.h index 12349deb688c..ce03d650279b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1723,7 +1723,7 @@ void pcibios_free_irq(struct pci_dev *dev); extern struct dev_pm_ops pcibios_pm_ops; #endif -#ifdef CONFIG_PCI_MMCONFIG +#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG) void __init pci_mmcfg_early_init(void); void __init pci_mmcfg_late_init(void); #else -- cgit v1.2.3 From 9c7cb891ecfea3b88e4fa255afeec0da84ea6a86 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 10 Jun 2016 21:55:14 +0200 Subject: PCI: Refactor pci_bus_assign_domain_nr() for CONFIG_PCI_DOMAINS_GENERIC Instead of assigning bus->domain_nr inside pci_bus_assign_domain_nr(), return the domain and let the caller do the assignment. Rename pci_bus_assign_domain_nr() to pci_bus_find_domain_nr() to reflect this. No functional change intended. [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas Reviewed-by: Lorenzo Pieralisi --- drivers/pci/pci.c | 4 ++-- drivers/pci/probe.c | 4 +++- include/linux/pci.h | 7 +------ 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index eb431b5c3685..b9a783385eae 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4941,7 +4941,7 @@ int pci_get_new_domain_nr(void) } #ifdef CONFIG_PCI_DOMAINS_GENERIC -void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) +int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent) { static int use_dt_domains = -1; int domain = -1; @@ -4985,7 +4985,7 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) domain = -1; } - bus->domain_nr = domain; + return domain; } #endif #endif diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8e3ef720997d..380d46dc9a70 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2127,7 +2127,9 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, b->sysdata = sysdata; b->ops = ops; b->number = b->busn_res.start = bus; - pci_bus_assign_domain_nr(b, parent); +#ifdef CONFIG_PCI_DOMAINS_GENERIC + b->domain_nr = pci_bus_find_domain_nr(b, parent); +#endif b2 = pci_find_bus(pci_domain_nr(b), bus); if (b2) { /* If we already got to this bus through a different bridge, ignore it */ diff --git a/include/linux/pci.h b/include/linux/pci.h index ce03d650279b..48839e817ef2 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1390,12 +1390,7 @@ static inline int pci_domain_nr(struct pci_bus *bus) { return bus->domain_nr; } -void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent); -#else -static inline void pci_bus_assign_domain_nr(struct pci_bus *bus, - struct device *parent) -{ -} +int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent); #endif /* some architectures require additional setup to direct VGA traffic */ -- cgit v1.2.3 From 2ab51ddeca2fc32a7040d8560415be3366fa9ba7 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 10 Jun 2016 15:36:26 -0500 Subject: ARM64: PCI: Add acpi_pci_bus_find_domain_nr() Extend pci_bus_find_domain_nr() so it can find the domain from either: - ACPI, via the new acpi_pci_bus_find_domain_nr() interface, or - DT, via of_pci_bus_find_domain_nr() Note that this is only used for CONFIG_PCI_DOMAINS_GENERIC=y, so it does not affect x86 or ia64. [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas --- arch/arm64/kernel/pci.c | 7 +++++++ drivers/pci/pci.c | 4 +++- include/linux/pci.h | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 3c4e308b40a0..d5d3d26834cf 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* @@ -85,6 +86,12 @@ EXPORT_SYMBOL(pcibus_to_node); #endif #ifdef CONFIG_ACPI + +int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) +{ + return 0; +} + /* Root bridge scanning */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) { diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 97f7cd4a7e86..4834ceeca0d2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -7,6 +7,7 @@ * Copyright 1997 -- 2000 Martin Mares */ +#include #include #include #include @@ -4990,7 +4991,8 @@ static int of_pci_bus_find_domain_nr(struct device *parent) int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent) { - return of_pci_bus_find_domain_nr(parent); + return acpi_disabled ? of_pci_bus_find_domain_nr(parent) : + acpi_pci_bus_find_domain_nr(bus); } #endif #endif diff --git a/include/linux/pci.h b/include/linux/pci.h index 48839e817ef2..0671e9a840cb 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1390,6 +1390,12 @@ static inline int pci_domain_nr(struct pci_bus *bus) { return bus->domain_nr; } +#ifdef CONFIG_ACPI +int acpi_pci_bus_find_domain_nr(struct pci_bus *bus); +#else +static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) +{ return 0; } +#endif int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent); #endif -- cgit v1.2.3 From a70b506efe899dc8d650eafcc0b11fc9ee746627 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 10 Jun 2016 21:19:06 +0200 Subject: bpf: enforce recursion limit on redirects Respect the stack's xmit_recursion limit for calls into dev_queue_xmit(). Currently, they are not handeled by the limiter when attached to clsact's egress parent, for example, and a buggy program redirecting it to the same device again could run into stack overflow eventually. It would be good if we could notify an admin to give him a chance to react. We reuse xmit_recursion instead of having one private to eBPF, so that the stack's current recursion depth will be taken into account as well. Follow-up to commit 3896d655f4d4 ("bpf: introduce bpf_clone_redirect() helper") and 27b29f63058d ("bpf: add bpf_redirect() helper"). Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 6 ++---- net/core/filter.c | 55 +++++++++++++++++++++++++++++------------------ 3 files changed, 38 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4f234b102892..94eef356a65f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2389,6 +2389,8 @@ void synchronize_net(void); int init_dummy_netdev(struct net_device *dev); DECLARE_PER_CPU(int, xmit_recursion); +#define XMIT_RECURSION_LIMIT 10 + static inline int dev_recursion_level(void) { return this_cpu_read(xmit_recursion); diff --git a/net/core/dev.c b/net/core/dev.c index c43c9d2a88cf..b14835757141 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3144,8 +3144,6 @@ static void skb_update_prio(struct sk_buff *skb) DEFINE_PER_CPU(int, xmit_recursion); EXPORT_SYMBOL(xmit_recursion); -#define RECURSION_LIMIT 10 - /** * dev_loopback_xmit - loop back @skb * @net: network namespace this loopback is happening in @@ -3388,8 +3386,8 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv) int cpu = smp_processor_id(); /* ok because BHs are off */ if (txq->xmit_lock_owner != cpu) { - - if (__this_cpu_read(xmit_recursion) > RECURSION_LIMIT) + if (unlikely(__this_cpu_read(xmit_recursion) > + XMIT_RECURSION_LIMIT)) goto recursion_alert; skb = validate_xmit_skb(skb, dev); diff --git a/net/core/filter.c b/net/core/filter.c index 68adb5f52110..d11744d10e00 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1603,9 +1603,36 @@ static const struct bpf_func_proto bpf_csum_diff_proto = { .arg5_type = ARG_ANYTHING, }; +static inline int __bpf_rx_skb(struct net_device *dev, struct sk_buff *skb) +{ + if (skb_at_tc_ingress(skb)) + skb_postpush_rcsum(skb, skb_mac_header(skb), skb->mac_len); + + return dev_forward_skb(dev, skb); +} + +static inline int __bpf_tx_skb(struct net_device *dev, struct sk_buff *skb) +{ + int ret; + + if (unlikely(__this_cpu_read(xmit_recursion) > XMIT_RECURSION_LIMIT)) { + net_crit_ratelimited("bpf: recursion limit reached on datapath, buggy bpf program?\n"); + kfree_skb(skb); + return -ENETDOWN; + } + + skb->dev = dev; + + __this_cpu_inc(xmit_recursion); + ret = dev_queue_xmit(skb); + __this_cpu_dec(xmit_recursion); + + return ret; +} + static u64 bpf_clone_redirect(u64 r1, u64 ifindex, u64 flags, u64 r4, u64 r5) { - struct sk_buff *skb = (struct sk_buff *) (long) r1, *skb2; + struct sk_buff *skb = (struct sk_buff *) (long) r1; struct net_device *dev; if (unlikely(flags & ~(BPF_F_INGRESS))) @@ -1615,19 +1642,12 @@ static u64 bpf_clone_redirect(u64 r1, u64 ifindex, u64 flags, u64 r4, u64 r5) if (unlikely(!dev)) return -EINVAL; - skb2 = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!skb2)) + skb = skb_clone(skb, GFP_ATOMIC); + if (unlikely(!skb)) return -ENOMEM; - if (flags & BPF_F_INGRESS) { - if (skb_at_tc_ingress(skb2)) - skb_postpush_rcsum(skb2, skb_mac_header(skb2), - skb2->mac_len); - return dev_forward_skb(dev, skb2); - } - - skb2->dev = dev; - return dev_queue_xmit(skb2); + return flags & BPF_F_INGRESS ? + __bpf_rx_skb(dev, skb) : __bpf_tx_skb(dev, skb); } static const struct bpf_func_proto bpf_clone_redirect_proto = { @@ -1671,15 +1691,8 @@ int skb_do_redirect(struct sk_buff *skb) return -EINVAL; } - if (ri->flags & BPF_F_INGRESS) { - if (skb_at_tc_ingress(skb)) - skb_postpush_rcsum(skb, skb_mac_header(skb), - skb->mac_len); - return dev_forward_skb(dev, skb); - } - - skb->dev = dev; - return dev_queue_xmit(skb); + return ri->flags & BPF_F_INGRESS ? + __bpf_rx_skb(dev, skb) : __bpf_tx_skb(dev, skb); } static const struct bpf_func_proto bpf_redirect_proto = { -- cgit v1.2.3 From 8387ff2577eb9ed245df9a39947f66976c6bcd02 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 10 Jun 2016 07:51:30 -0700 Subject: vfs: make the string hashes salt the hash We always mixed in the parent pointer into the dentry name hash, but we did it late at lookup time. It turns out that we can simplify that lookup-time action by salting the hash with the parent pointer early instead of late. A few other users of our string hashes also wanted to mix in their own pointers into the hash, and those are updated to use the same mechanism. Hash users that don't have any particular initial salt can just use the NULL pointer as a no-salt. Cc: Vegard Nossum Cc: George Spelvin Cc: Al Viro Signed-off-by: Linus Torvalds --- drivers/staging/lustre/lustre/llite/statahead.c | 8 +++-- fs/adfs/dir.c | 2 +- fs/affs/namei.c | 8 ++--- fs/autofs4/waitq.c | 2 +- fs/ceph/inode.c | 4 +-- fs/ceph/mds_client.c | 2 +- fs/cifs/dir.c | 2 +- fs/dcache.c | 21 ++++++------- fs/efivarfs/super.c | 4 +-- fs/fat/namei_msdos.c | 2 +- fs/fat/namei_vfat.c | 4 +-- fs/fuse/dev.c | 2 -- fs/fuse/dir.c | 3 +- fs/hfs/string.c | 2 +- fs/hfsplus/unicode.c | 2 +- fs/hpfs/dentry.c | 2 +- fs/isofs/inode.c | 14 ++++----- fs/jffs2/dir.c | 8 +++-- fs/jffs2/readinode.c | 2 +- fs/jffs2/scan.c | 2 +- fs/jffs2/summary.c | 2 +- fs/jffs2/write.c | 4 +-- fs/jfs/namei.c | 2 +- fs/kernfs/dir.c | 4 +-- fs/namei.c | 42 +++++++++++++++---------- fs/ncpfs/dir.c | 2 +- fs/nfs/dir.c | 4 +-- fs/ntfs/namei.c | 2 +- fs/ocfs2/dlm/dlmcommon.h | 2 +- fs/proc/proc_sysctl.c | 2 +- fs/sysv/namei.c | 2 +- include/linux/stringhash.h | 6 ++-- include/linux/sunrpc/svcauth.h | 4 +-- lib/test_hash.c | 4 +-- net/core/dev.c | 2 +- security/smack/smack_access.c | 4 +-- security/tomoyo/memory.c | 2 +- security/tomoyo/util.c | 2 +- 38 files changed, 99 insertions(+), 89 deletions(-) (limited to 'include/linux') diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 6322f88661e8..79d9830b2997 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -174,7 +174,8 @@ static inline int is_omitted_entry(struct ll_statahead_info *sai, __u64 index) * Insert it into sai_entries tail when init. */ static struct ll_sa_entry * -ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index, +ll_sa_entry_alloc(struct dentry *parent, + struct ll_statahead_info *sai, __u64 index, const char *name, int len) { struct ll_inode_info *lli; @@ -221,7 +222,8 @@ ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index, dname = (char *)entry + sizeof(struct ll_sa_entry); memcpy(dname, name, len); dname[len] = 0; - entry->se_qstr.hash = full_name_hash(name, len); + + entry->se_qstr.hash = full_name_hash(parent, name, len); entry->se_qstr.len = len; entry->se_qstr.name = dname; @@ -902,7 +904,7 @@ static void ll_statahead_one(struct dentry *parent, const char *entry_name, int rc; int rc1; - entry = ll_sa_entry_alloc(sai, sai->sai_index, entry_name, + entry = ll_sa_entry_alloc(parent, sai, sai->sai_index, entry_name, entry_name_len); if (IS_ERR(entry)) return; diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index fd4cf2c48e48..bec25f7017c0 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -207,7 +207,7 @@ adfs_hash(const struct dentry *parent, struct qstr *qstr) */ qstr->len = i = name_len; name = qstr->name; - hash = init_name_hash(); + hash = init_name_hash(parent); while (i--) { char c; diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 00d3002a6780..eb32029bc776 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -61,7 +61,7 @@ affs_get_toupper(struct super_block *sb) * Note: the dentry argument is the parent dentry. */ static inline int -__affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate) +__affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate) { const u8 *name = qstr->name; unsigned long hash; @@ -72,7 +72,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate) if (retval) return retval; - hash = init_name_hash(); + hash = init_name_hash(dentry); len = min(qstr->len, AFFSNAMEMAX); for (; len > 0; name++, len--) hash = partial_name_hash(toupper(*name), hash); @@ -84,7 +84,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate) static int affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr) { - return __affs_hash_dentry(qstr, affs_toupper, + return __affs_hash_dentry(dentry, qstr, affs_toupper, affs_nofilenametruncate(dentry)); } @@ -92,7 +92,7 @@ affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr) static int affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr) { - return __affs_hash_dentry(qstr, affs_intl_toupper, + return __affs_hash_dentry(dentry, qstr, affs_intl_toupper, affs_nofilenametruncate(dentry)); } diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 0146d911f468..f620160ceb6c 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -397,7 +397,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, } } qstr.name = name; - qstr.hash = full_name_hash(name, qstr.len); + qstr.hash = full_name_hash(dentry, name, qstr.len); if (mutex_lock_interruptible(&sbi->wq_mutex)) { kfree(qstr.name); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index f059b5997072..99bdef66213a 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1164,7 +1164,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, dname.name = rinfo->dname; dname.len = rinfo->dname_len; - dname.hash = full_name_hash(dname.name, dname.len); + dname.hash = full_name_hash(parent, dname.name, dname.len); vino.ino = le64_to_cpu(rinfo->targeti.in->ino); vino.snap = le64_to_cpu(rinfo->targeti.in->snapid); retry_lookup: @@ -1508,7 +1508,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, dname.name = rde->name; dname.len = rde->name_len; - dname.hash = full_name_hash(dname.name, dname.len); + dname.hash = full_name_hash(parent, dname.name, dname.len); vino.ino = le64_to_cpu(rde->inode.in->ino); vino.snap = le64_to_cpu(rde->inode.in->snapid); diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 2103b823bec0..4e8678a612b6 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -3204,7 +3204,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, WARN_ON(1); goto release; /* hrm... */ } - dname.hash = full_name_hash(dname.name, dname.len); + dname.hash = full_name_hash(parent, dname.name, dname.len); dentry = d_lookup(parent, &dname); dput(parent); if (!dentry) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index c3eb998a99bd..916b2d7d3a9b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -856,7 +856,7 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q) wchar_t c; int i, charlen; - hash = init_name_hash(); + hash = init_name_hash(dentry); for (i = 0; i < q->len; i += charlen) { charlen = codepage->char2uni(&q->name[i], q->len - i, &c); /* error out if we can't convert the character */ diff --git a/fs/dcache.c b/fs/dcache.c index 817c243c1ff1..9522b8b63871 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -104,10 +104,8 @@ static unsigned int d_hash_shift __read_mostly; static struct hlist_bl_head *dentry_hashtable __read_mostly; -static inline struct hlist_bl_head *d_hash(const struct dentry *parent, - unsigned int hash) +static inline struct hlist_bl_head *d_hash(unsigned int hash) { - hash += (unsigned long) parent / L1_CACHE_BYTES; return dentry_hashtable + hash_32(hash, d_hash_shift); } @@ -488,7 +486,7 @@ void __d_drop(struct dentry *dentry) if (unlikely(IS_ROOT(dentry))) b = &dentry->d_sb->s_anon; else - b = d_hash(dentry->d_parent, dentry->d_name.hash); + b = d_hash(dentry->d_name.hash); hlist_bl_lock(b); __hlist_bl_del(&dentry->d_hash); @@ -1670,7 +1668,7 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name) struct qstr q; q.name = name; - q.hash_len = hashlen_string(name); + q.hash_len = hashlen_string(parent, name); return d_alloc(parent, &q); } EXPORT_SYMBOL(d_alloc_name); @@ -2094,7 +2092,7 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent, { u64 hashlen = name->hash_len; const unsigned char *str = name->name; - struct hlist_bl_head *b = d_hash(parent, hashlen_hash(hashlen)); + struct hlist_bl_head *b = d_hash(hashlen_hash(hashlen)); struct hlist_bl_node *node; struct dentry *dentry; @@ -2211,7 +2209,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) unsigned int len = name->len; unsigned int hash = name->hash; const unsigned char *str = name->name; - struct hlist_bl_head *b = d_hash(parent, hash); + struct hlist_bl_head *b = d_hash(hash); struct hlist_bl_node *node; struct dentry *found = NULL; struct dentry *dentry; @@ -2291,7 +2289,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) * calculate the standard hash first, as the d_op->d_hash() * routine may choose to leave the hash value unchanged. */ - name->hash = full_name_hash(name->name, name->len); + name->hash = full_name_hash(dir, name->name, name->len); if (dir->d_flags & DCACHE_OP_HASH) { int err = dir->d_op->d_hash(dir, name); if (unlikely(err < 0)) @@ -2364,7 +2362,7 @@ static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b) static void _d_rehash(struct dentry * entry) { - __d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash)); + __d_rehash(entry, d_hash(entry->d_name.hash)); } /** @@ -2821,7 +2819,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target, * for the same hash queue because of how unlikely it is. */ __d_drop(dentry); - __d_rehash(dentry, d_hash(target->d_parent, target->d_name.hash)); + __d_rehash(dentry, d_hash(target->d_name.hash)); /* * Unhash the target (d_delete() is not usable here). If exchanging @@ -2829,8 +2827,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target, */ __d_drop(target); if (exchange) { - __d_rehash(target, - d_hash(dentry->d_parent, dentry->d_name.hash)); + __d_rehash(target, d_hash(dentry->d_name.hash)); } /* Switch the names.. */ diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 9cb54a38832d..a5e607e8f056 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -65,7 +65,7 @@ static int efivarfs_d_compare(const struct dentry *parent, static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr) { - unsigned long hash = init_name_hash(); + unsigned long hash = init_name_hash(dentry); const unsigned char *s = qstr->name; unsigned int len = qstr->len; @@ -98,7 +98,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) q.name = name; q.len = strlen(name); - err = efivarfs_d_hash(NULL, &q); + err = efivarfs_d_hash(parent, &q); if (err) return ERR_PTR(err); diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index b7e2b33aa793..1337c0c7527d 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -154,7 +154,7 @@ static int msdos_hash(const struct dentry *dentry, struct qstr *qstr) error = msdos_format_name(qstr->name, qstr->len, msdos_name, options); if (!error) - qstr->hash = full_name_hash(msdos_name, MSDOS_NAME); + qstr->hash = full_name_hash(dentry, msdos_name, MSDOS_NAME); return 0; } diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 7092584f424a..6ccdf3f34f90 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -107,7 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr) */ static int vfat_hash(const struct dentry *dentry, struct qstr *qstr) { - qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr)); + qstr->hash = full_name_hash(dentry, qstr->name, vfat_striptail_len(qstr)); return 0; } @@ -127,7 +127,7 @@ static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr) name = qstr->name; len = vfat_striptail_len(qstr); - hash = init_name_hash(); + hash = init_name_hash(dentry); while (len--) hash = partial_name_hash(nls_tolower(t, *name++), hash); qstr->hash = end_name_hash(hash); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index cbece1221417..203adf3b75db 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1525,7 +1525,6 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, goto err; fuse_copy_finish(cs); buf[outarg.namelen] = 0; - name.hash = full_name_hash(name.name, name.len); down_read(&fc->killsb); err = -ENOENT; @@ -1576,7 +1575,6 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size, goto err; fuse_copy_finish(cs); buf[outarg.namelen] = 0; - name.hash = full_name_hash(name.name, name.len); down_read(&fc->killsb); err = -ENOENT; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index ccd4971cc6c1..112ab4068115 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -953,6 +953,7 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, if (!dir) goto unlock; + name->hash = full_name_hash(dir, name->name, name->len); entry = d_lookup(dir, name); dput(dir); if (!entry) @@ -1202,7 +1203,7 @@ static int fuse_direntplus_link(struct file *file, fc = get_fuse_conn(dir); - name.hash = full_name_hash(name.name, name.len); + name.hash = full_name_hash(parent, name.name, name.len); dentry = d_lookup(parent, &name); if (!dentry) { retry: diff --git a/fs/hfs/string.c b/fs/hfs/string.c index 85b610c3909f..ec9f164c35a5 100644 --- a/fs/hfs/string.c +++ b/fs/hfs/string.c @@ -59,7 +59,7 @@ int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this) if (len > HFS_NAMELEN) len = HFS_NAMELEN; - hash = init_name_hash(); + hash = init_name_hash(dentry); for (; len; len--) hash = partial_name_hash(caseorder[*name++], hash); this->hash = end_name_hash(hash); diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index e8ef121a4d8b..c13c8a240be3 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c @@ -346,7 +346,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str) casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); - hash = init_name_hash(); + hash = init_name_hash(dentry); astr = str->name; len = str->len; while (len > 0) { diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c index fa27980f2229..60e6d334d79a 100644 --- a/fs/hpfs/dentry.c +++ b/fs/hpfs/dentry.c @@ -26,7 +26,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr) /*return -ENOENT;*/ x: - hash = init_name_hash(); + hash = init_name_hash(dentry); for (i = 0; i < l; i++) hash = partial_name_hash(hpfs_upcase(hpfs_sb(dentry->d_sb)->sb_cp_table,qstr->name[i]), hash); qstr->hash = end_name_hash(hash); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 131dedc920d8..761fade7680f 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -174,7 +174,7 @@ struct iso9660_options{ * Compute the hash for the isofs name corresponding to the dentry. */ static int -isofs_hashi_common(struct qstr *qstr, int ms) +isofs_hashi_common(const struct dentry *dentry, struct qstr *qstr, int ms) { const char *name; int len; @@ -188,7 +188,7 @@ isofs_hashi_common(struct qstr *qstr, int ms) len--; } - hash = init_name_hash(); + hash = init_name_hash(dentry); while (len--) { c = tolower(*name++); hash = partial_name_hash(c, hash); @@ -231,7 +231,7 @@ static int isofs_dentry_cmp_common( static int isofs_hashi(const struct dentry *dentry, struct qstr *qstr) { - return isofs_hashi_common(qstr, 0); + return isofs_hashi_common(dentry, qstr, 0); } static int @@ -246,7 +246,7 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry, * Compute the hash for the isofs name corresponding to the dentry. */ static int -isofs_hash_common(struct qstr *qstr, int ms) +isofs_hash_common(const struct dentry *dentry, struct qstr *qstr, int ms) { const char *name; int len; @@ -258,7 +258,7 @@ isofs_hash_common(struct qstr *qstr, int ms) len--; } - qstr->hash = full_name_hash(name, len); + qstr->hash = full_name_hash(dentry, name, len); return 0; } @@ -266,13 +266,13 @@ isofs_hash_common(struct qstr *qstr, int ms) static int isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr) { - return isofs_hash_common(qstr, 1); + return isofs_hash_common(dentry, qstr, 1); } static int isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr) { - return isofs_hashi_common(qstr, 1); + return isofs_hashi_common(dentry, qstr, 1); } static int diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 84c4bf3631a2..30eb33ff8189 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -81,6 +81,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, struct jffs2_full_dirent *fd = NULL, *fd_list; uint32_t ino = 0; struct inode *inode = NULL; + unsigned int nhash; jffs2_dbg(1, "jffs2_lookup()\n"); @@ -89,11 +90,14 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, dir_f = JFFS2_INODE_INFO(dir_i); + /* The 'nhash' on the fd_list is not the same as the dentry hash */ + nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len); + mutex_lock(&dir_f->sem); /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ - for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { - if (fd_list->nhash == target->d_name.hash && + for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) { + if (fd_list->nhash == nhash && (!fd || fd_list->version > fd->version) && strlen(fd_list->name) == target->d_name.len && !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index bfebbf13698c..06a71dbd4833 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -674,7 +674,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r } } - fd->nhash = full_name_hash(fd->name, rd->nsize); + fd->nhash = full_name_hash(NULL, fd->name, rd->nsize); fd->next = NULL; fd->name[rd->nsize] = '\0'; diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 9ad5ba4b299b..90431dd613b8 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -1100,7 +1100,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(fd->name, checkedlen); + fd->nhash = full_name_hash(NULL, fd->name, checkedlen); fd->type = rd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index bc5385471a6e..be7c8a6a5748 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -476,7 +476,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras fd->next = NULL; fd->version = je32_to_cpu(spd->version); fd->ino = je32_to_cpu(spd->ino); - fd->nhash = full_name_hash(fd->name, checkedlen); + fd->nhash = full_name_hash(NULL, fd->name, checkedlen); fd->type = spd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 7fb187ab2682..cda9a361368e 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -245,7 +245,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(name, namelen); + fd->nhash = full_name_hash(NULL, name, namelen); fd->type = rd->type; memcpy(fd->name, name, namelen); fd->name[namelen]=0; @@ -598,7 +598,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, jffs2_add_fd_to_list(c, fd, &dir_f->dents); mutex_unlock(&dir_f->sem); } else { - uint32_t nhash = full_name_hash(name, namelen); + uint32_t nhash = full_name_hash(NULL, name, namelen); fd = dir_f->dents; /* We don't actually want to reserve any space, but we do diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 539deddecbb0..04baf0dfc40c 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1564,7 +1564,7 @@ static int jfs_ci_hash(const struct dentry *dir, struct qstr *this) unsigned long hash; int i; - hash = init_name_hash(); + hash = init_name_hash(dir); for (i=0; i < this->len; i++) hash = partial_name_hash(tolower(this->name[i]), hash); this->hash = end_name_hash(hash); diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 8a652404eef6..e57174d43683 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -336,11 +336,11 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) */ static unsigned int kernfs_name_hash(const char *name, const void *ns) { - unsigned long hash = init_name_hash(); + unsigned long hash = init_name_hash(ns); unsigned int len = strlen(name); while (len--) hash = partial_name_hash(*name++, hash); - hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31)); + hash = end_name_hash(hash); hash &= 0x7fffffffU; /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ if (hash < 2) diff --git a/fs/namei.c b/fs/namei.c index 70580ab1445c..7cb9be3e200a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1890,9 +1890,9 @@ static inline unsigned int fold_hash(unsigned long x, unsigned long y) * payload bytes, to match the way that hash_name() iterates until it * finds the delimiter after the name. */ -unsigned int full_name_hash(const char *name, unsigned int len) +unsigned int full_name_hash(const void *salt, const char *name, unsigned int len) { - unsigned long a, x = 0, y = 0; + unsigned long a, x = 0, y = (unsigned long)salt; for (;;) { if (!len) @@ -1911,15 +1911,19 @@ done: EXPORT_SYMBOL(full_name_hash); /* Return the "hash_len" (hash and length) of a null-terminated string */ -u64 hashlen_string(const char *name) +u64 hashlen_string(const void *salt, const char *name) { - unsigned long a = 0, x = 0, y = 0, adata, mask, len; + unsigned long a = 0, x = 0, y = (unsigned long)salt; + unsigned long adata, mask, len; const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; - len = -sizeof(unsigned long); + len = 0; + goto inside; + do { HASH_MIX(x, y, a); len += sizeof(unsigned long); +inside: a = load_unaligned_zeropad(name+len); } while (!has_zero(a, &adata, &constants)); @@ -1935,15 +1939,19 @@ EXPORT_SYMBOL(hashlen_string); * Calculate the length and hash of the path component, and * return the "hash_len" as the result. */ -static inline u64 hash_name(const char *name) +static inline u64 hash_name(const void *salt, const char *name) { - unsigned long a = 0, b, x = 0, y = 0, adata, bdata, mask, len; + unsigned long a = 0, b, x = 0, y = (unsigned long)salt; + unsigned long adata, bdata, mask, len; const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; - len = -sizeof(unsigned long); + len = 0; + goto inside; + do { HASH_MIX(x, y, a); len += sizeof(unsigned long); +inside: a = load_unaligned_zeropad(name+len); b = a ^ REPEAT_BYTE('/'); } while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants))); @@ -1959,9 +1967,9 @@ static inline u64 hash_name(const char *name) #else /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */ /* Return the hash of a string of known length */ -unsigned int full_name_hash(const char *name, unsigned int len) +unsigned int full_name_hash(const void *salt, const char *name, unsigned int len) { - unsigned long hash = init_name_hash(); + unsigned long hash = init_name_hash(salt); while (len--) hash = partial_name_hash((unsigned char)*name++, hash); return end_name_hash(hash); @@ -1969,9 +1977,9 @@ unsigned int full_name_hash(const char *name, unsigned int len) EXPORT_SYMBOL(full_name_hash); /* Return the "hash_len" (hash and length) of a null-terminated string */ -u64 hashlen_string(const char *name) +u64 hashlen_string(const void *salt, const char *name) { - unsigned long hash = init_name_hash(); + unsigned long hash = init_name_hash(salt); unsigned long len = 0, c; c = (unsigned char)*name; @@ -1988,9 +1996,9 @@ EXPORT_SYMBOL(hashlen_string); * We know there's a real path component here of at least * one character. */ -static inline u64 hash_name(const char *name) +static inline u64 hash_name(const void *salt, const char *name) { - unsigned long hash = init_name_hash(); + unsigned long hash = init_name_hash(salt); unsigned long len = 0, c; c = (unsigned char)*name; @@ -2030,7 +2038,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) if (err) return err; - hash_len = hash_name(name); + hash_len = hash_name(nd->path.dentry, name); type = LAST_NORM; if (name[0] == '.') switch (hashlen_len(hash_len)) { @@ -2436,7 +2444,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) this.name = name; this.len = len; - this.hash = full_name_hash(name, len); + this.hash = full_name_hash(base, name, len); if (!len) return ERR_PTR(-EACCES); @@ -2489,7 +2497,7 @@ struct dentry *lookup_one_len_unlocked(const char *name, this.name = name; this.len = len; - this.hash = full_name_hash(name, len); + this.hash = full_name_hash(base, name, len); if (!len) return ERR_PTR(-EACCES); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index bfdad003ee56..9add7ab747a5 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -139,7 +139,7 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this) int i; t = NCP_IO_TABLE(sb); - hash = init_name_hash(); + hash = init_name_hash(dentry); for (i=0; ilen ; i++) hash = partial_name_hash(ncp_tolower(t, this->name[i]), hash); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index aaf7bd0cbae2..d6935a9e8fdd 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -232,7 +232,7 @@ int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int le * in a page cache page which kmemleak does not scan. */ kmemleak_not_leak(string->name); - string->hash = full_name_hash(name, len); + string->hash = full_name_hash(NULL, name, len); return 0; } @@ -497,7 +497,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) if (filename.len == 2 && filename.name[1] == '.') return; } - filename.hash = full_name_hash(filename.name, filename.len); + filename.hash = full_name_hash(parent, filename.name, filename.len); dentry = d_lookup(parent, &filename); again: diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index 443abecf01b7..358258364616 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c @@ -253,7 +253,7 @@ handle_name: err = (signed)nls_name.len; goto err_out; } - nls_name.hash = full_name_hash(nls_name.name, nls_name.len); + nls_name.hash = full_name_hash(dent, nls_name.name, nls_name.len); dent = d_add_ci(dent, dent_inode, &nls_name); kfree(nls_name.name); diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index 004f2cbe8f71..8107d0d0c3f6 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h @@ -47,7 +47,7 @@ #define DLM_HASH_BUCKETS (DLM_HASH_PAGES * DLM_BUCKETS_PER_PAGE) /* Intended to make it easier for us to switch out hash functions */ -#define dlm_lockid_hash(_n, _l) full_name_hash(_n, _l) +#define dlm_lockid_hash(_n, _l) full_name_hash(NULL, _n, _l) enum dlm_mle_type { DLM_MLE_BLOCK = 0, diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 5e57c3e46e1d..b59db94d2ff4 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -623,7 +623,7 @@ static bool proc_sys_fill_cache(struct file *file, qname.name = table->procname; qname.len = strlen(table->procname); - qname.hash = full_name_hash(qname.name, qname.len); + qname.hash = full_name_hash(dir, qname.name, qname.len); child = d_lookup(dir, &qname); if (!child) { diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index 90b60c03b588..a42de45ce40d 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -33,7 +33,7 @@ static int sysv_hash(const struct dentry *dentry, struct qstr *qstr) function. */ if (qstr->len > SYSV_NAMELEN) { qstr->len = SYSV_NAMELEN; - qstr->hash = full_name_hash(qstr->name, qstr->len); + qstr->hash = full_name_hash(dentry, qstr->name, qstr->len); } return 0; } diff --git a/include/linux/stringhash.h b/include/linux/stringhash.h index 451771d9b9c0..eb7debb280c0 100644 --- a/include/linux/stringhash.h +++ b/include/linux/stringhash.h @@ -34,7 +34,7 @@ */ /* Hash courtesy of the R5 hash in reiserfs modulo sign bits */ -#define init_name_hash() 0 +#define init_name_hash(salt) (unsigned long)(salt) /* partial hash update function. Assume roughly 4 bits per character */ static inline unsigned long @@ -60,7 +60,7 @@ static inline unsigned long end_name_hash(unsigned long hash) * * If not set, this falls back to a wrapper around the preceding. */ -extern unsigned int __pure full_name_hash(const char *, unsigned int); +extern unsigned int __pure full_name_hash(const void *salt, const char *, unsigned int); /* * A hash_len is a u64 with the hash of a string in the low @@ -71,6 +71,6 @@ extern unsigned int __pure full_name_hash(const char *, unsigned int); #define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash)) /* Return the "hash_len" (hash and length) of a null-terminated string */ -extern u64 __pure hashlen_string(const char *name); +extern u64 __pure hashlen_string(const void *salt, const char *name); #endif /* __LINUX_STRINGHASH_H */ diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index 91d5a5d6f52b..d03932055328 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h @@ -172,12 +172,12 @@ extern void unix_gid_cache_destroy(struct net *net); */ static inline unsigned long hash_str(char const *name, int bits) { - return hashlen_hash(hashlen_string(name)) >> (32 - bits); + return hashlen_hash(hashlen_string(NULL, name)) >> (32 - bits); } static inline unsigned long hash_mem(char const *buf, int length, int bits) { - return full_name_hash(buf, length) >> (32 - bits); + return full_name_hash(NULL, buf, length) >> (32 - bits); } #endif /* __KERNEL__ */ diff --git a/lib/test_hash.c b/lib/test_hash.c index c9549c8b4909..66c5fc8351e8 100644 --- a/lib/test_hash.c +++ b/lib/test_hash.c @@ -155,8 +155,8 @@ test_hash_init(void) buf[j] = '\0'; for (i = 0; i <= j; i++) { - u64 hashlen = hashlen_string(buf+i); - u32 h0 = full_name_hash(buf+i, j-i); + u64 hashlen = hashlen_string(buf+i, buf+i); + u32 h0 = full_name_hash(buf+i, buf+i, j-i); /* Check that hashlen_string gets the length right */ if (hashlen_len(hashlen) != j-i) { diff --git a/net/core/dev.c b/net/core/dev.c index 904ff431d570..7f7d7ef1caa5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -196,7 +196,7 @@ static inline void dev_base_seq_inc(struct net *net) static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) { - unsigned int hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); + unsigned int hash = full_name_hash(net, name, strnlen(name, IFNAMSIZ)); return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)]; } diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index a283f9e796c1..23e5808a0970 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -413,7 +413,7 @@ void smk_insert_entry(struct smack_known *skp) unsigned int hash; struct hlist_head *head; - hash = full_name_hash(skp->smk_known, strlen(skp->smk_known)); + hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known)); head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; hlist_add_head_rcu(&skp->smk_hashed, head); @@ -433,7 +433,7 @@ struct smack_known *smk_find_entry(const char *string) struct hlist_head *head; struct smack_known *skp; - hash = full_name_hash(string, strlen(string)); + hash = full_name_hash(NULL, string, strlen(string)); head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; hlist_for_each_entry_rcu(skp, head, smk_hashed) diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index 0e995716cc25..1598b559ac42 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c @@ -154,7 +154,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) if (!name) return NULL; len = strlen(name) + 1; - hash = full_name_hash((const unsigned char *) name, len - 1); + hash = full_name_hash(NULL, (const unsigned char *) name, len - 1); head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; if (mutex_lock_interruptible(&tomoyo_policy_lock)) return NULL; diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index b974a6997d7f..5fe3679137ae 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -666,7 +666,7 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) ptr->const_len = tomoyo_const_part_length(name); ptr->is_dir = len && (name[len - 1] == '/'); ptr->is_patterned = (ptr->const_len < len); - ptr->hash = full_name_hash(name, len); + ptr->hash = full_name_hash(NULL, name, len); } /** -- cgit v1.2.3 From fd2a0437dc33b6425cabf74cc7fc7fdba6d5903b Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 8 Jun 2016 16:09:18 +0300 Subject: virtio_net: introduce virtio_net_hdr_{from,to}_skb The code for conversion between virtio_net_hdr and skb GSO info is duplicated at several places. Let's put it to a common place to allow reuse. Signed-off-by: Mike Rapoport Signed-off-by: David S. Miller --- include/linux/virtio_net.h | 101 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 include/linux/virtio_net.h (limited to 'include/linux') diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h new file mode 100644 index 000000000000..1c912f85e041 --- /dev/null +++ b/include/linux/virtio_net.h @@ -0,0 +1,101 @@ +#ifndef _LINUX_VIRTIO_NET_H +#define _LINUX_VIRTIO_NET_H + +#include +#include + +static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, + const struct virtio_net_hdr *hdr, + bool little_endian) +{ + unsigned short gso_type = 0; + + if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { + switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { + case VIRTIO_NET_HDR_GSO_TCPV4: + gso_type = SKB_GSO_TCPV4; + break; + case VIRTIO_NET_HDR_GSO_TCPV6: + gso_type = SKB_GSO_TCPV6; + break; + case VIRTIO_NET_HDR_GSO_UDP: + gso_type = SKB_GSO_UDP; + break; + default: + return -EINVAL; + } + + if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN) + gso_type |= SKB_GSO_TCP_ECN; + + if (hdr->gso_size == 0) + return -EINVAL; + } + + if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { + u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start); + u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset); + + if (!skb_partial_csum_set(skb, start, off)) + return -EINVAL; + } + + if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { + u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size); + + skb_shinfo(skb)->gso_size = gso_size; + skb_shinfo(skb)->gso_type = gso_type; + + /* Header must be checked, and gso_segs computed. */ + skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; + skb_shinfo(skb)->gso_segs = 0; + } + + return 0; +} + +static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb, + struct virtio_net_hdr *hdr, + bool little_endian) +{ + memset(hdr, 0, sizeof(*hdr)); + + if (skb_is_gso(skb)) { + struct skb_shared_info *sinfo = skb_shinfo(skb); + + /* This is a hint as to how much should be linear. */ + hdr->hdr_len = __cpu_to_virtio16(little_endian, + skb_headlen(skb)); + hdr->gso_size = __cpu_to_virtio16(little_endian, + sinfo->gso_size); + if (sinfo->gso_type & SKB_GSO_TCPV4) + hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; + else if (sinfo->gso_type & SKB_GSO_TCPV6) + hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; + else if (sinfo->gso_type & SKB_GSO_UDP) + hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP; + else + return -EINVAL; + if (sinfo->gso_type & SKB_GSO_TCP_ECN) + hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN; + } else + hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; + if (skb_vlan_tag_present(skb)) + hdr->csum_start = __cpu_to_virtio16(little_endian, + skb_checksum_start_offset(skb) + VLAN_HLEN); + else + hdr->csum_start = __cpu_to_virtio16(little_endian, + skb_checksum_start_offset(skb)); + hdr->csum_offset = __cpu_to_virtio16(little_endian, + skb->csum_offset); + } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { + hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID; + } /* else everything is zero */ + + return 0; +} + +#endif /* _LINUX_VIRTIO_BYTEORDER */ -- cgit v1.2.3 From 002245cc6407c8ff65b8024554080eb6de1a8e2c Mon Sep 17 00:00:00 2001 From: Zi Shen Lim Date: Wed, 8 Jun 2016 21:18:47 -0700 Subject: bpf: fix missing header inclusion Commit 0fc174dea545 ("ebpf: make internal bpf API independent of CONFIG_BPF_SYSCALL ifdefs") introduced usage of ERR_PTR() in bpf_prog_get(), however did not include linux/err.h. Without this patch, when compiling arm64 BPF without CONFIG_BPF_SYSCALL: ... In file included from arch/arm64/net/bpf_jit_comp.c:21:0: include/linux/bpf.h: In function 'bpf_prog_get': include/linux/bpf.h:235:9: error: implicit declaration of function 'ERR_PTR' [-Werror=implicit-function-declaration] return ERR_PTR(-EOPNOTSUPP); ^ include/linux/bpf.h:235:9: warning: return makes pointer from integer without a cast [-Wint-conversion] In file included from include/linux/rwsem.h:17:0, from include/linux/mm_types.h:10, from include/linux/sched.h:27, from arch/arm64/include/asm/compat.h:25, from arch/arm64/include/asm/stat.h:23, from include/linux/stat.h:5, from include/linux/compat.h:12, from include/linux/filter.h:10, from arch/arm64/net/bpf_jit_comp.c:22: include/linux/err.h: At top level: include/linux/err.h:23:35: error: conflicting types for 'ERR_PTR' static inline void * __must_check ERR_PTR(long error) ^ In file included from arch/arm64/net/bpf_jit_comp.c:21:0: include/linux/bpf.h:235:9: note: previous implicit declaration of 'ERR_PTR' was here return ERR_PTR(-EOPNOTSUPP); ^ ... Fixes: 0fc174dea545 ("ebpf: make internal bpf API independent of CONFIG_BPF_SYSCALL ifdefs") Suggested-by: Daniel Borkmann Signed-off-by: Zi Shen Lim Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/bpf.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8ee27b8afe81..1bcae82c6cb1 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -11,6 +11,7 @@ #include #include #include +#include struct bpf_map; -- cgit v1.2.3 From f20e6657a8758fe8d074889a6f1883674f01c7f2 Mon Sep 17 00:00:00 2001 From: Pramod Kumar Date: Fri, 10 Jun 2016 11:03:45 +0530 Subject: mdio: mux: Enhanced MDIO mux framework for integrated multiplexers An integrated multiplexer uses same address space for "muxed bus selection" and "generation of mdio transaction" hence its good to register parent bus from mux driver. Hence added a mechanism where mux driver could register a parent bus and pass it down to framework via mdio_mux_init api. Signed-off-by: Pramod Kumar Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/mdio-mux-gpio.c | 2 +- drivers/net/phy/mdio-mux-mmioreg.c | 2 +- drivers/net/phy/mdio-mux.c | 28 ++++++++++++++++++---------- include/linux/mdio-mux.h | 4 +++- 4 files changed, 23 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c index 7ddb1ab70891..919949960a10 100644 --- a/drivers/net/phy/mdio-mux-gpio.c +++ b/drivers/net/phy/mdio-mux-gpio.c @@ -55,7 +55,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev) return PTR_ERR(s->gpios); r = mdio_mux_init(&pdev->dev, - mdio_mux_gpio_switch_fn, &s->mux_handle, s); + mdio_mux_gpio_switch_fn, &s->mux_handle, s, NULL); if (r != 0) { gpiod_put_array(s->gpios); diff --git a/drivers/net/phy/mdio-mux-mmioreg.c b/drivers/net/phy/mdio-mux-mmioreg.c index 7fde454fbc4f..d0bed52c8d16 100644 --- a/drivers/net/phy/mdio-mux-mmioreg.c +++ b/drivers/net/phy/mdio-mux-mmioreg.c @@ -126,7 +126,7 @@ static int mdio_mux_mmioreg_probe(struct platform_device *pdev) } ret = mdio_mux_init(&pdev->dev, mdio_mux_mmioreg_switch_fn, - &s->mux_handle, s); + &s->mux_handle, s, NULL); if (ret) { dev_err(&pdev->dev, "failed to register mdio-mux bus %s\n", np->full_name); diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 5c81d6faf304..dbd4ecc205dc 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -89,7 +89,8 @@ static int parent_count; int mdio_mux_init(struct device *dev, int (*switch_fn)(int cur, int desired, void *data), void **mux_handle, - void *data) + void *data, + struct mii_bus *mux_bus) { struct device_node *parent_bus_node; struct device_node *child_bus_node; @@ -101,10 +102,21 @@ int mdio_mux_init(struct device *dev, if (!dev->of_node) return -ENODEV; - parent_bus_node = of_parse_phandle(dev->of_node, "mdio-parent-bus", 0); + if (!mux_bus) { + parent_bus_node = of_parse_phandle(dev->of_node, + "mdio-parent-bus", 0); - if (!parent_bus_node) - return -ENODEV; + if (!parent_bus_node) + return -ENODEV; + + parent_bus = of_mdio_find_bus(parent_bus_node); + if (!parent_bus) { + ret_val = -EPROBE_DEFER; + goto err_parent_bus; + } + } else { + parent_bus = mux_bus; + } pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL); if (pb == NULL) { @@ -112,11 +124,6 @@ int mdio_mux_init(struct device *dev, goto err_parent_bus; } - parent_bus = of_mdio_find_bus(parent_bus_node); - if (parent_bus == NULL) { - ret_val = -EPROBE_DEFER; - goto err_parent_bus; - } pb->switch_data = data; pb->switch_fn = switch_fn; @@ -177,7 +184,8 @@ int mdio_mux_init(struct device *dev, put_device(&pb->mii_bus->dev); err_parent_bus: - of_node_put(parent_bus_node); + if (!mux_bus) + of_node_put(parent_bus_node); return ret_val; } EXPORT_SYMBOL_GPL(mdio_mux_init); diff --git a/include/linux/mdio-mux.h b/include/linux/mdio-mux.h index a243dbba8659..61f5b21b31c7 100644 --- a/include/linux/mdio-mux.h +++ b/include/linux/mdio-mux.h @@ -10,11 +10,13 @@ #ifndef __LINUX_MDIO_MUX_H #define __LINUX_MDIO_MUX_H #include +#include int mdio_mux_init(struct device *dev, int (*switch_fn) (int cur, int desired, void *data), void **mux_handle, - void *data); + void *data, + struct mii_bus *mux_bus); void mdio_mux_uninit(void *mux_handle); -- cgit v1.2.3 From 703b5faf22fbddf984a361e6555f3a03fdba63d9 Mon Sep 17 00:00:00 2001 From: George Spelvin Date: Fri, 10 Jun 2016 00:22:12 -0400 Subject: fs/dcache.c: Save one 32-bit multiply in dcache lookup Noe that we're mixing in the parent pointer earlier, we don't need to use hash_32() to mix its bits. Instead, we can just take the msbits of the hash value directly. For those applications which use the partial_name_hash(), move the multiply to end_name_hash. Signed-off-by: George Spelvin Signed-off-by: Linus Torvalds --- fs/dcache.c | 2 +- include/linux/stringhash.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/dcache.c b/fs/dcache.c index 9522b8b63871..03f1a332f677 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -106,7 +106,7 @@ static struct hlist_bl_head *dentry_hashtable __read_mostly; static inline struct hlist_bl_head *d_hash(unsigned int hash) { - return dentry_hashtable + hash_32(hash, d_hash_shift); + return dentry_hashtable + (hash >> (32 - d_hash_shift)); } #define IN_LOOKUP_SHIFT 10 diff --git a/include/linux/stringhash.h b/include/linux/stringhash.h index eb7debb280c0..7c2d95170d01 100644 --- a/include/linux/stringhash.h +++ b/include/linux/stringhash.h @@ -3,6 +3,7 @@ #include /* For __pure */ #include /* For u32, u64 */ +#include /* * Routines for hashing strings of bytes to a 32-bit hash value. @@ -45,11 +46,12 @@ partial_name_hash(unsigned long c, unsigned long prevhash) /* * Finally: cut down the number of bits to a int value (and try to avoid - * losing bits) + * losing bits). This also has the property (wanted by the dcache) + * that the msbits make a good hash table index. */ static inline unsigned long end_name_hash(unsigned long hash) { - return (unsigned int)hash; + return __hash_32((unsigned int)hash); } /* -- cgit v1.2.3 From 14e974a84e831bf9a44495c7256a6846e7f77630 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 6 Jun 2016 23:20:43 +0200 Subject: nvme.h: add RTD3R, RTD3E and OAES fields These have been added in NVMe 1.2 and we'll need at least oaes for the NVMe target driver. Reviewed-by: Sagi Grimberg Reviewed-by: Jay Freyensee Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- include/linux/nvme.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 7d51b2904cb7..ff5ebc378cc3 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -107,7 +107,10 @@ struct nvme_id_ctrl { __u8 mdts; __le16 cntlid; __le32 ver; - __u8 rsvd84[172]; + __le32 rtd3r; + __le32 rtd3e; + __le32 oaes; + __u8 rsvd96[160]; __le16 oacs; __u8 acl; __u8 aerl; -- cgit v1.2.3 From 725b358836ed038d7d8eafef86330b3a0b3f9c2f Mon Sep 17 00:00:00 2001 From: Armen Baloyan Date: Mon, 6 Jun 2016 23:20:44 +0200 Subject: nvme.h: Add get_log_page command strucure Add get_log_page command structure and a corresponding entry in nvme_command union Signed-off-by: Armen Baloyan Reviewed-by: Jay Freyensee Reviewed--by: Sagi Grimberg Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- include/linux/nvme.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'include/linux') diff --git a/include/linux/nvme.h b/include/linux/nvme.h index ff5ebc378cc3..9925b85246d8 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -519,6 +519,24 @@ struct nvme_format_cmd { __u32 rsvd11[5]; }; +struct nvme_get_log_page_command { + __u8 opcode; + __u8 flags; + __u16 command_id; + __le32 nsid; + __u64 rsvd2[2]; + __le64 prp1; + __le64 prp2; + __u8 lid; + __u8 rsvd10; + __le16 numdl; + __le16 numdu; + __u16 rsvd11; + __le32 lpol; + __le32 lpou; + __u32 rsvd14[2]; +}; + struct nvme_command { union { struct nvme_common_command common; @@ -532,6 +550,7 @@ struct nvme_command { struct nvme_format_cmd format; struct nvme_dsm_cmd dsm; struct nvme_abort_cmd abort; + struct nvme_get_log_page_command get_log_page; }; }; -- cgit v1.2.3 From 69cd27e2511616f9b402d1bad4c49f91aa7411a3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 6 Jun 2016 23:20:45 +0200 Subject: nvme.h: add NVM command set SQE/CQE size defines Reviewed-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- include/linux/nvme.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 9925b85246d8..9807d98ca93a 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -50,6 +50,13 @@ enum { #define NVME_CMB_CQS(cmbsz) ((cmbsz) & 0x2) #define NVME_CMB_SQS(cmbsz) ((cmbsz) & 0x1) +/* + * Submission and Completion Queue Entry Sizes for the NVM command set. + * (In bytes and specified as a power of two (2^n)). + */ +#define NVME_NVM_IOSQES 6 +#define NVME_NVM_IOCQES 4 + enum { NVME_CC_ENABLE = 1 << 0, NVME_CC_CSS_NVM = 0 << 4, @@ -61,8 +68,8 @@ enum { NVME_CC_SHN_NORMAL = 1 << 14, NVME_CC_SHN_ABRUPT = 2 << 14, NVME_CC_SHN_MASK = 3 << 14, - NVME_CC_IOSQES = 6 << 16, - NVME_CC_IOCQES = 4 << 20, + NVME_CC_IOSQES = NVME_NVM_IOSQES << 16, + NVME_CC_IOCQES = NVME_NVM_IOCQES << 20, NVME_CSTS_RDY = 1 << 0, NVME_CSTS_CFS = 1 << 1, NVME_CSTS_NSSRO = 1 << 4, -- cgit v1.2.3 From 79f370eac63796a8933b210bca02f006ba32d22e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 6 Jun 2016 23:20:46 +0200 Subject: nvme.h: add AER constants Reviewed-by: Jay Freyensee Reviewed-by: Sagi Grimberg Reviewed-by: Ming Lin Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- include/linux/nvme.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux') diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 9807d98ca93a..a9b8c7bcaf85 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -284,6 +284,12 @@ struct nvme_reservation_status { } regctl_ds[]; }; +enum nvme_async_event_type { + NVME_AER_TYPE_ERROR = 0, + NVME_AER_TYPE_SMART = 1, + NVME_AER_TYPE_NOTICE = 2, +}; + /* I/O commands */ enum nvme_opcode { -- cgit v1.2.3 From 3972be23bd2d2bcfaa44595a260a371cd9218872 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 6 Jun 2016 23:20:47 +0200 Subject: nvme.h: add constants for PSDT and FUSE values Signed-off-by: James Smart Reviewed-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- include/linux/nvme.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'include/linux') diff --git a/include/linux/nvme.h b/include/linux/nvme.h index a9b8c7bcaf85..2b82f05fe4ec 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -306,6 +306,29 @@ enum nvme_opcode { nvme_cmd_resv_release = 0x15, }; +/* + * Lowest two bits of our flags field (FUSE field in the spec): + * + * @NVME_CMD_FUSE_FIRST: Fused Operation, first command + * @NVME_CMD_FUSE_SECOND: Fused Operation, second command + * + * Highest two bits in our flags field (PSDT field in the spec): + * + * @NVME_CMD_PSDT_SGL_METABUF: Use SGLS for this transfer, + * If used, MPTR contains addr of single physical buffer (byte aligned). + * @NVME_CMD_PSDT_SGL_METASEG: Use SGLS for this transfer, + * If used, MPTR contains an address of an SGL segment containing + * exactly 1 SGL descriptor (qword aligned). + */ +enum { + NVME_CMD_FUSE_FIRST = (1 << 0), + NVME_CMD_FUSE_SECOND = (1 << 1), + + NVME_CMD_SGL_METABUF = (1 << 6), + NVME_CMD_SGL_METASEG = (1 << 7), + NVME_CMD_SGL_ALL = NVME_CMD_SGL_METABUF | NVME_CMD_SGL_METASEG, +}; + struct nvme_common_command { __u8 opcode; __u8 flags; -- cgit v1.2.3 From 7a5abb4b48570c3552e33ff4c72ae1e8dac3ba15 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 6 Jun 2016 23:20:49 +0200 Subject: nvme: factor out a add nvme_is_write helper Centralize the check if a given NVMe command reads or writes data. Reviewed-by: Sagi Grimberg Reviewed-by: Jay Freyensee Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- drivers/nvme/host/core.c | 5 ++--- include/linux/nvme.h | 5 +++++ 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 7ded308fd67b..45fd6cca4a27 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -193,10 +193,9 @@ EXPORT_SYMBOL_GPL(nvme_requeue_req); struct request *nvme_alloc_request(struct request_queue *q, struct nvme_command *cmd, unsigned int flags) { - bool write = cmd->common.opcode & 1; struct request *req; - req = blk_mq_alloc_request(q, write, flags); + req = blk_mq_alloc_request(q, nvme_is_write(cmd), flags); if (IS_ERR(req)) return req; @@ -361,7 +360,7 @@ int __nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd, void __user *meta_buffer, unsigned meta_len, u32 meta_seed, u32 *result, unsigned timeout) { - bool write = cmd->common.opcode & 1; + bool write = nvme_is_write(cmd); struct nvme_completion cqe; struct nvme_ns *ns = q->queuedata; struct gendisk *disk = ns ? ns->disk : NULL; diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 2b82f05fe4ec..dc815cc6718d 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -590,6 +590,11 @@ struct nvme_command { }; }; +static inline bool nvme_is_write(struct nvme_command *cmd) +{ + return cmd->common.opcode & 1; +} + enum { NVME_SC_SUCCESS = 0x0, NVME_SC_INVALID_OPCODE = 0x1, -- cgit v1.2.3 From 99860208bc62d8ebd5c57495b84856506fe075bc Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 11 Jun 2016 12:46:04 +0200 Subject: sched: remove NET_XMIT_POLICED sch_atm returns this when TC_ACT_SHOT classification occurs. But all other schedulers that use tc_classify (htb, hfsc, drr, fq_codel ...) return NET_XMIT_SUCCESS | __BYPASS in this case so just do that in atm. BATMAN uses it as an intermediate return value to signal forwarding vs. buffering, but it did not return POLICED to callers outside of BATMAN. Reviewed-by: Sven Eckelmann Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 - net/batman-adv/routing.c | 2 +- net/batman-adv/send.c | 4 ++-- net/core/pktgen.c | 1 - net/sched/sch_api.c | 2 -- net/sched/sch_atm.c | 2 +- 6 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 94eef356a65f..d101e4d904ba 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -90,7 +90,6 @@ void netdev_set_default_ethtool_ops(struct net_device *dev, #define NET_XMIT_SUCCESS 0x00 #define NET_XMIT_DROP 0x01 /* skb dropped */ #define NET_XMIT_CN 0x02 /* congestion notification */ -#define NET_XMIT_POLICED 0x03 /* skb is shot by police */ #define NET_XMIT_MASK 0x0f /* qdisc flags in net/sch_generic.h */ /* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index e3857ed4057f..f75091c983ee 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -653,7 +653,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, len + ETH_HLEN); ret = NET_RX_SUCCESS; - } else if (res == NET_XMIT_POLICED) { + } else if (res == -EINPROGRESS) { /* skb was buffered and consumed */ ret = NET_RX_SUCCESS; } diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index f2f125684ed9..b1a4e8a811c8 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -156,7 +156,7 @@ int batadv_send_unicast_skb(struct sk_buff *skb, * attempted. * * Return: NET_XMIT_SUCCESS on success, NET_XMIT_DROP on failure, or - * NET_XMIT_POLICED if the skb is buffered for later transmit. + * -EINPROGRESS if the skb is buffered for later transmit. */ int batadv_send_skb_to_orig(struct sk_buff *skb, struct batadv_orig_node *orig_node, @@ -188,7 +188,7 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, * network coding fails, then send the packet as usual. */ if (recv_if && batadv_nc_skb_forward(skb, neigh_node)) { - ret = NET_XMIT_POLICED; + ret = -EINPROGRESS; } else { batadv_send_unicast_skb(skb, neigh_node); ret = NET_XMIT_SUCCESS; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 8b02df0d354d..f74ab9c3b38f 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3463,7 +3463,6 @@ xmit_more: break; case NET_XMIT_DROP: case NET_XMIT_CN: - case NET_XMIT_POLICED: /* skb has been consumed */ pkt_dev->errors++; break; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 401eda6de682..12ebde845523 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -95,8 +95,6 @@ static int tclass_notify(struct net *net, struct sk_buff *oskb, Expected action: do not backoff, but wait until queue will clear. NET_XMIT_CN - probably this packet enqueued, but another one dropped. Expected action: backoff or ignore - NET_XMIT_POLICED - dropped by police. - Expected action: backoff or error to real-time apps. Auxiliary routines: diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 7e6c12dfc66a..0785b239ddf9 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -363,7 +363,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) struct atm_flow_data *flow; struct tcf_result res; int result; - int ret = NET_XMIT_POLICED; + int ret = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); result = TC_POLICE_OK; /* be nice to gcc */ -- cgit v1.2.3 From 1e2a7d78499ec8859d2b469051b7b80bad3b08aa Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:28 +0100 Subject: irqdomain: Don't set type when mapping an IRQ Some IRQ chips, such as GPIO controllers or secondary level interrupt controllers, may require require additional runtime power management control to ensure they are accessible. For such IRQ chips, it makes sense to enable the IRQ chip when interrupts are requested and disabled them again once all interrupts have been freed. When mapping an IRQ, the IRQ type settings are read and then programmed. The mapping of the IRQ happens before the IRQ is requested and so the programming of the type settings occurs before the IRQ is requested. This is a problem for IRQ chips that require additional power management control because they may not be accessible yet. Therefore, when mapping the IRQ, don't program the type settings, just save them and then program these saved settings when the IRQ is requested (so long as if they are not overridden via the call to request the IRQ). Add a stub function for irq_domain_free_irqs() to avoid any compilation errors when CONFIG_IRQ_DOMAIN_HIERARCHY is not selected. Signed-off-by: Jon Hunter Reviewed-by: Marc Zyngier Signed-off-by: Marc Zyngier --- include/linux/irqdomain.h | 3 +++ kernel/irq/irqdomain.c | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index f1f36e04d885..317503763314 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -452,6 +452,9 @@ static inline int irq_domain_alloc_irqs(struct irq_domain *domain, return -1; } +static inline void irq_domain_free_irqs(unsigned int virq, + unsigned int nr_irqs) { } + static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) { return false; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index f3ff1eb8dd09..caa6a63d26f0 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -567,6 +567,7 @@ static void of_phandle_args_to_fwspec(struct of_phandle_args *irq_data, unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) { struct irq_domain *domain; + struct irq_data *irq_data; irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; int virq; @@ -614,7 +615,11 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) * it now and return the interrupt number. */ if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) { - irq_set_irq_type(virq, type); + irq_data = irq_get_irq_data(virq); + if (!irq_data) + return 0; + + irqd_set_trigger_type(irq_data, type); return virq; } @@ -634,10 +639,18 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) return virq; } - /* Set type if specified and different than the current one */ - if (type != IRQ_TYPE_NONE && - type != irq_get_trigger_type(virq)) - irq_set_irq_type(virq, type); + irq_data = irq_get_irq_data(virq); + if (!irq_data) { + if (irq_domain_is_hierarchy(domain)) + irq_domain_free_irqs(virq, 1); + else + irq_dispose_mapping(virq); + return 0; + } + + /* Store trigger type */ + irqd_set_trigger_type(irq_data, type); + return virq; } EXPORT_SYMBOL_GPL(irq_create_fwspec_mapping); -- cgit v1.2.3 From be45beb2df6909d42a6b3b0052601b3eef878fc0 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:29 +0100 Subject: genirq: Add runtime power management support for IRQ chips Some IRQ chips may be located in a power domain outside of the CPU subsystem and hence will require device specific runtime power management. In order to support such IRQ chips, add a pointer for a device structure to the irq_chip structure, and if this pointer is populated by the IRQ chip driver and CONFIG_PM is selected in the kernel configuration, then the pm_runtime_get/put APIs for this chip will be called when an IRQ is requested/freed, respectively. Reviewed-by: Kevin Hilman Signed-off-by: Jon Hunter Signed-off-by: Marc Zyngier --- include/linux/irq.h | 4 ++++ kernel/irq/chip.c | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/irq/internals.h | 1 + kernel/irq/manage.c | 31 ++++++++++++++++++++++++++++++- 4 files changed, 75 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 4d758a7c604a..6c92a847394d 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -315,6 +315,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) /** * struct irq_chip - hardware interrupt chip descriptor * + * @parent_device: pointer to parent device for irqchip * @name: name for /proc/interrupts * @irq_startup: start up the interrupt (defaults to ->enable if NULL) * @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL) @@ -354,6 +355,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) * @flags: chip specific flags */ struct irq_chip { + struct device *parent_device; const char *name; unsigned int (*irq_startup)(struct irq_data *data); void (*irq_shutdown)(struct irq_data *data); @@ -488,6 +490,8 @@ extern void handle_bad_irq(struct irq_desc *desc); extern void handle_nested_irq(unsigned int irq); extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg); +extern int irq_chip_pm_get(struct irq_data *data); +extern int irq_chip_pm_put(struct irq_data *data); #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY extern void irq_chip_enable_parent(struct irq_data *data); extern void irq_chip_disable_parent(struct irq_data *data); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 2f9f2b0e79f2..ad8131473774 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -1093,3 +1093,43 @@ int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) return 0; } + +/** + * irq_chip_pm_get - Enable power for an IRQ chip + * @data: Pointer to interrupt specific data + * + * Enable the power to the IRQ chip referenced by the interrupt data + * structure. + */ +int irq_chip_pm_get(struct irq_data *data) +{ + int retval; + + if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) { + retval = pm_runtime_get_sync(data->chip->parent_device); + if (retval < 0) { + pm_runtime_put_noidle(data->chip->parent_device); + return retval; + } + } + + return 0; +} + +/** + * irq_chip_pm_put - Disable power for an IRQ chip + * @data: Pointer to interrupt specific data + * + * Disable the power to the IRQ chip referenced by the interrupt data + * structure, belongs. Note that power will only be disabled, once this + * function has been called for all IRQs that have called irq_chip_pm_get(). + */ +int irq_chip_pm_put(struct irq_data *data) +{ + int retval = 0; + + if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) + retval = pm_runtime_put(data->chip->parent_device); + + return (retval < 0) ? retval : 0; +} diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 09be2c903c6d..d5edcdc9382a 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -7,6 +7,7 @@ */ #include #include +#include #ifdef CONFIG_SPARSE_IRQ # define IRQ_BITMAP_BITS (NR_IRQS + 8196) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index f78b0846afb1..00cfc852cca8 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1416,10 +1416,18 @@ int setup_irq(unsigned int irq, struct irqaction *act) if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc))) return -EINVAL; + + retval = irq_chip_pm_get(&desc->irq_data); + if (retval < 0) + return retval; + chip_bus_lock(desc); retval = __setup_irq(irq, desc, act); chip_bus_sync_unlock(desc); + if (retval) + irq_chip_pm_put(&desc->irq_data); + return retval; } EXPORT_SYMBOL_GPL(setup_irq); @@ -1513,6 +1521,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) } } + irq_chip_pm_put(&desc->irq_data); module_put(desc->owner); kfree(action->secondary); return action; @@ -1655,11 +1664,16 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, action->name = devname; action->dev_id = dev_id; + retval = irq_chip_pm_get(&desc->irq_data); + if (retval < 0) + return retval; + chip_bus_lock(desc); retval = __setup_irq(irq, desc, action); chip_bus_sync_unlock(desc); if (retval) { + irq_chip_pm_put(&desc->irq_data); kfree(action->secondary); kfree(action); } @@ -1836,6 +1850,7 @@ static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_ unregister_handler_proc(irq, action); + irq_chip_pm_put(&desc->irq_data); module_put(desc->owner); return action; @@ -1898,10 +1913,18 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act) if (!desc || !irq_settings_is_per_cpu_devid(desc)) return -EINVAL; + + retval = irq_chip_pm_get(&desc->irq_data); + if (retval < 0) + return retval; + chip_bus_lock(desc); retval = __setup_irq(irq, desc, act); chip_bus_sync_unlock(desc); + if (retval) + irq_chip_pm_put(&desc->irq_data); + return retval; } @@ -1945,12 +1968,18 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler, action->name = devname; action->percpu_dev_id = dev_id; + retval = irq_chip_pm_get(&desc->irq_data); + if (retval < 0) + return retval; + chip_bus_lock(desc); retval = __setup_irq(irq, desc, action); chip_bus_sync_unlock(desc); - if (retval) + if (retval) { + irq_chip_pm_put(&desc->irq_data); kfree(action); + } return retval; } -- cgit v1.2.3 From cdbb813db6925f9dcd352841d8ba28f2edd83ff8 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:32 +0100 Subject: irqchip/gic: Prepare for adding platform driver To support GICs that require runtime power management, it is necessary to add a platform driver, so that the probing of the chip can be deferred if resources, such as a power-domain, is not yet available. To prepare for adding a platform driver: 1. Drop the __init section from the gic_dist_config() so this can be re-used by the platform driver. 2. Add prototypes for functions required by the platform driver to the GIC header file so they can be re-used. Signed-off-by: Jon Hunter Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-common.c | 4 ++-- drivers/irqchip/irq-gic.c | 14 +++++++------- include/linux/irqchip/arm-gic.h | 5 +++++ 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 89e7423f0ebb..9ae71804b5dd 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -90,8 +90,8 @@ int gic_configure_irq(unsigned int irq, unsigned int type, return ret; } -void __init gic_dist_config(void __iomem *base, int gic_irqs, - void (*sync_access)(void)) +void gic_dist_config(void __iomem *base, int gic_irqs, + void (*sync_access)(void)) { unsigned int i; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 94eab6e23124..141ea5801784 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -449,7 +449,7 @@ static void gic_cpu_if_up(struct gic_chip_data *gic) } -static void __init gic_dist_init(struct gic_chip_data *gic) +static void gic_dist_init(struct gic_chip_data *gic) { unsigned int i; u32 cpumask; @@ -535,7 +535,7 @@ int gic_cpu_if_down(unsigned int gic_nr) * this function, no interrupts will be delivered by the GIC, and another * platform-specific wakeup source must be enabled. */ -static void gic_dist_save(struct gic_chip_data *gic) +void gic_dist_save(struct gic_chip_data *gic) { unsigned int gic_irqs; void __iomem *dist_base; @@ -574,7 +574,7 @@ static void gic_dist_save(struct gic_chip_data *gic) * handled normally, but any edge interrupts that occured will not be seen by * the GIC and need to be handled by the platform-specific wakeup source. */ -static void gic_dist_restore(struct gic_chip_data *gic) +void gic_dist_restore(struct gic_chip_data *gic) { unsigned int gic_irqs; unsigned int i; @@ -620,7 +620,7 @@ static void gic_dist_restore(struct gic_chip_data *gic) writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL); } -static void gic_cpu_save(struct gic_chip_data *gic) +void gic_cpu_save(struct gic_chip_data *gic) { int i; u32 *ptr; @@ -650,7 +650,7 @@ static void gic_cpu_save(struct gic_chip_data *gic) } -static void gic_cpu_restore(struct gic_chip_data *gic) +void gic_cpu_restore(struct gic_chip_data *gic) { int i; u32 *ptr; @@ -727,7 +727,7 @@ static struct notifier_block gic_notifier_block = { .notifier_call = gic_notifier, }; -static int __init gic_pm_init(struct gic_chip_data *gic) +static int gic_pm_init(struct gic_chip_data *gic) { gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, sizeof(u32)); @@ -757,7 +757,7 @@ free_ppi_enable: return -ENOMEM; } #else -static int __init gic_pm_init(struct gic_chip_data *gic) +static int gic_pm_init(struct gic_chip_data *gic) { return 0; } diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index fd051855539b..ffcbd8b9a4ff 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -101,9 +101,14 @@ #include struct device_node; +struct gic_chip_data; void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); int gic_cpu_if_down(unsigned int gic_nr); +void gic_cpu_save(struct gic_chip_data *gic); +void gic_cpu_restore(struct gic_chip_data *gic); +void gic_dist_save(struct gic_chip_data *gic); +void gic_dist_restore(struct gic_chip_data *gic); /* * Subdrivers that need some preparatory work can initialize their -- cgit v1.2.3 From 9c8edddfc9924cb473a7570c37ca466db70728f8 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 7 Jun 2016 16:12:34 +0100 Subject: irqchip/gic: Add platform driver for non-root GICs that require RPM Add a platform driver to support non-root GICs that require runtime power-management. Currently, only non-root GICs are supported because the functions, smp_cross_call() and set_handle_irq(), that need to be called for a root controller are located in the __init section and so cannot be called by the platform driver. The GIC platform driver re-uses many functions from the existing GIC driver including some functions to save and restore the GIC context during power transitions. The functions for saving and restoring the GIC context are currently only defined if CONFIG_CPU_PM is enabled and to ensure that these functions are always defined when the platform driver is enabled, a dependency on CONFIG_ARM_GIC_PM (which selects the platform driver) has been added. In order to re-use the private GIC initialisation code, a new public function, gic_of_init_child(), has been added which calls various private functions to initialise the GIC. This is different from the existing gic_of_init() because it only supports non-root GICs (ie. does not call smp_cross_call() is set_handle_irq()) and is not located in the __init section (so can be used by platform drivers). Furthermore, gic_of_init_child() dynamically allocates memory for the GIC chip data which is also different from gic_of_init(). There is no specific suspend handling for GICs registered as platform devices. Non-wakeup interrupts will be disabled by the kernel during late suspend, however, this alone will not power down the GIC if interrupts have been requested and not freed. Therefore, requestors of non-wakeup interrupts will need to free them on entering suspend in order to power-down the GIC. Signed-off-by: Jon Hunter Signed-off-by: Marc Zyngier --- drivers/irqchip/Kconfig | 6 ++ drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-gic-pm.c | 184 ++++++++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic.c | 40 ++++++++- include/linux/irqchip/arm-gic.h | 6 ++ 5 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 drivers/irqchip/irq-gic-pm.c (limited to 'include/linux') diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index fa33c50b0e5a..5495a5ba8039 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -8,6 +8,12 @@ config ARM_GIC select IRQ_DOMAIN_HIERARCHY select MULTI_IRQ_HANDLER +config ARM_GIC_PM + bool + depends on PM + select ARM_GIC + select PM_CLK + config ARM_GIC_MAX_NR int default 2 if ARCH_REALVIEW diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 38853a187607..bd0257e0aab6 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o +obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o obj-$(CONFIG_REALVIEW_DT) += irq-gic-realview.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o diff --git a/drivers/irqchip/irq-gic-pm.c b/drivers/irqchip/irq-gic-pm.c new file mode 100644 index 000000000000..4cbffba3ff13 --- /dev/null +++ b/drivers/irqchip/irq-gic-pm.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2016 NVIDIA CORPORATION, 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 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct gic_clk_data { + unsigned int num_clocks; + const char *const *clocks; +}; + +static int gic_runtime_resume(struct device *dev) +{ + struct gic_chip_data *gic = dev_get_drvdata(dev); + int ret; + + ret = pm_clk_resume(dev); + if (ret) + return ret; + + /* + * On the very first resume, the pointer to the driver data + * will be NULL and this is intentional, because we do not + * want to restore the GIC on the very first resume. So if + * the pointer is not valid just return. + */ + if (!gic) + return 0; + + gic_dist_restore(gic); + gic_cpu_restore(gic); + + return 0; +} + +static int gic_runtime_suspend(struct device *dev) +{ + struct gic_chip_data *gic = dev_get_drvdata(dev); + + gic_dist_save(gic); + gic_cpu_save(gic); + + return pm_clk_suspend(dev); +} + +static int gic_get_clocks(struct device *dev, const struct gic_clk_data *data) +{ + struct clk *clk; + unsigned int i; + int ret; + + if (!dev || !data) + return -EINVAL; + + ret = pm_clk_create(dev); + if (ret) + return ret; + + for (i = 0; i < data->num_clocks; i++) { + clk = of_clk_get_by_name(dev->of_node, data->clocks[i]); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clock %s\n", + data->clocks[i]); + ret = PTR_ERR(clk); + goto error; + } + + ret = pm_clk_add_clk(dev, clk); + if (ret) { + dev_err(dev, "failed to add clock at index %d\n", i); + clk_put(clk); + goto error; + } + } + + return 0; + +error: + pm_clk_destroy(dev); + + return ret; +} + +static int gic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct gic_clk_data *data; + struct gic_chip_data *gic; + int ret, irq; + + data = of_device_get_match_data(&pdev->dev); + if (!data) { + dev_err(&pdev->dev, "no device match found\n"); + return -ENODEV; + } + + irq = irq_of_parse_and_map(dev->of_node, 0); + if (!irq) { + dev_err(dev, "no parent interrupt found!\n"); + return -EINVAL; + } + + ret = gic_get_clocks(dev, data); + if (ret) + goto irq_dispose; + + pm_runtime_enable(dev); + + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto rpm_disable; + + ret = gic_of_init_child(dev, &gic, irq); + if (ret) + goto rpm_put; + + platform_set_drvdata(pdev, gic); + + pm_runtime_put(dev); + + dev_info(dev, "GIC IRQ controller registered\n"); + + return 0; + +rpm_put: + pm_runtime_put_sync(dev); +rpm_disable: + pm_runtime_disable(dev); + pm_clk_destroy(dev); +irq_dispose: + irq_dispose_mapping(irq); + + return ret; +} + +static const struct dev_pm_ops gic_pm_ops = { + SET_RUNTIME_PM_OPS(gic_runtime_suspend, + gic_runtime_resume, NULL) +}; + +static const char * const gic400_clocks[] = { + "clk", +}; + +static const struct gic_clk_data gic400_data = { + .num_clocks = ARRAY_SIZE(gic400_clocks), + .clocks = gic400_clocks, +}; + +static const struct of_device_id gic_match[] = { + { .compatible = "nvidia,tegra210-agic", .data = &gic400_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, gic_match); + +static struct platform_driver gic_driver = { + .probe = gic_probe, + .driver = { + .name = "gic", + .of_match_table = gic_match, + .pm = &gic_pm_ops, + } +}; + +builtin_platform_driver(gic_driver); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 141ea5801784..1de07eb5839c 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -75,7 +75,7 @@ struct gic_chip_data { void __iomem *raw_dist_base; void __iomem *raw_cpu_base; u32 percpu_offset; -#ifdef CONFIG_CPU_PM +#if defined(CONFIG_CPU_PM) || defined(CONFIG_ARM_GIC_PM) u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; u32 saved_spi_active[DIV_ROUND_UP(1020, 32)]; u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; @@ -528,7 +528,7 @@ int gic_cpu_if_down(unsigned int gic_nr) return 0; } -#ifdef CONFIG_CPU_PM +#if defined(CONFIG_CPU_PM) || defined(CONFIG_ARM_GIC_PM) /* * Saves the GIC distributor registers during suspend or idle. Must be called * with interrupts disabled but before powering down the GIC. After calling @@ -1272,7 +1272,7 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base) return true; } -static int __init gic_of_setup(struct gic_chip_data *gic, struct device_node *node) +static int gic_of_setup(struct gic_chip_data *gic, struct device_node *node) { if (!gic || !node) return -EINVAL; @@ -1296,6 +1296,34 @@ error: return -ENOMEM; } +int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq) +{ + int ret; + + if (!dev || !dev->of_node || !gic || !irq) + return -EINVAL; + + *gic = devm_kzalloc(dev, sizeof(**gic), GFP_KERNEL); + if (!*gic) + return -ENOMEM; + + gic_init_chip(*gic, dev, dev->of_node->name, false); + + ret = gic_of_setup(*gic, dev->of_node); + if (ret) + return ret; + + ret = gic_init_bases(*gic, -1, &dev->of_node->fwnode); + if (ret) { + gic_teardown(*gic); + return ret; + } + + irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq, *gic); + + return 0; +} + static void __init gic_of_setup_kvm_info(struct device_node *node) { int ret; @@ -1375,7 +1403,11 @@ IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init); IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init); - +#else +int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq) +{ + return -ENOTSUPP; +} #endif #ifdef CONFIG_ACPI diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index ffcbd8b9a4ff..eafc965b3eb8 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -116,6 +116,12 @@ void gic_dist_restore(struct gic_chip_data *gic); */ int gic_of_init(struct device_node *node, struct device_node *parent); +/* + * Initialises and registers a non-root or child GIC chip. Memory for + * the gic_chip_data structure is dynamically allocated. + */ +int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq); + /* * Legacy platforms not converted to DT yet must use this to init * their GIC -- cgit v1.2.3 From 9347359ad0aeeed16bf8c2d4576a2c40edaa9c85 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 6 Jun 2016 18:17:30 -0500 Subject: irqchip/gicv3-its: Split its_alloc_tables() into two functions The function is getting out of control, it has too many goto statements and would be too complicated for adding a feature two-level device table. So, it is time for us to cleanup and move some of the logic to a separate function without affecting the existing functionality. Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 242 +++++++++++++++++++------------------ include/linux/irqchip/arm-gic-v3.h | 1 + 2 files changed, 127 insertions(+), 116 deletions(-) (limited to 'include/linux') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 5cfa29991eed..146189b1b587 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -56,13 +56,14 @@ struct its_collection { }; /* - * The ITS_BASER structure - contains memory information and cached - * value of BASER register configuration. + * The ITS_BASER structure - contains memory information, cached + * value of BASER register configuration and ITS page size. */ struct its_baser { void *base; u64 val; u32 order; + u32 psz; }; /* @@ -840,6 +841,110 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser, baser->val = its_read_baser(its, baser); } +static int its_setup_baser(struct its_node *its, struct its_baser *baser, + u64 cache, u64 shr, u32 psz, u32 order) +{ + u64 val = its_read_baser(its, baser); + u64 esz = GITS_BASER_ENTRY_SIZE(val); + u64 type = GITS_BASER_TYPE(val); + u32 alloc_pages; + void *base; + u64 tmp; + +retry_alloc_baser: + alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz); + if (alloc_pages > GITS_BASER_PAGES_MAX) { + pr_warn("ITS@%pa: %s too large, reduce ITS pages %u->%u\n", + &its->phys_base, its_base_type_string[type], + alloc_pages, GITS_BASER_PAGES_MAX); + alloc_pages = GITS_BASER_PAGES_MAX; + order = get_order(GITS_BASER_PAGES_MAX * psz); + } + + base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); + if (!base) + return -ENOMEM; + +retry_baser: + val = (virt_to_phys(base) | + (type << GITS_BASER_TYPE_SHIFT) | + ((esz - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) | + ((alloc_pages - 1) << GITS_BASER_PAGES_SHIFT) | + cache | + shr | + GITS_BASER_VALID); + + switch (psz) { + case SZ_4K: + val |= GITS_BASER_PAGE_SIZE_4K; + break; + case SZ_16K: + val |= GITS_BASER_PAGE_SIZE_16K; + break; + case SZ_64K: + val |= GITS_BASER_PAGE_SIZE_64K; + break; + } + + its_write_baser(its, baser, val); + tmp = baser->val; + + if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) { + /* + * Shareability didn't stick. Just use + * whatever the read reported, which is likely + * to be the only thing this redistributor + * supports. If that's zero, make it + * non-cacheable as well. + */ + shr = tmp & GITS_BASER_SHAREABILITY_MASK; + if (!shr) { + cache = GITS_BASER_nC; + __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order)); + } + goto retry_baser; + } + + if ((val ^ tmp) & GITS_BASER_PAGE_SIZE_MASK) { + /* + * Page size didn't stick. Let's try a smaller + * size and retry. If we reach 4K, then + * something is horribly wrong... + */ + free_pages((unsigned long)base, order); + baser->base = NULL; + + switch (psz) { + case SZ_16K: + psz = SZ_4K; + goto retry_alloc_baser; + case SZ_64K: + psz = SZ_16K; + goto retry_alloc_baser; + } + } + + if (val != tmp) { + pr_err("ITS@%pa: %s doesn't stick: %lx %lx\n", + &its->phys_base, its_base_type_string[type], + (unsigned long) val, (unsigned long) tmp); + free_pages((unsigned long)base, order); + return -ENXIO; + } + + baser->order = order; + baser->base = base; + baser->psz = psz; + + pr_info("ITS@%pa: allocated %d %s @%lx (psz %dK, shr %d)\n", + &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / esz), + its_base_type_string[type], + (unsigned long)virt_to_phys(base), + psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); + + return 0; +} + static void its_parse_baser_device(struct its_node *its, struct its_baser *baser, u32 *order) { @@ -879,25 +984,20 @@ static void its_free_tables(struct its_node *its) static int its_alloc_tables(const char *node_name, struct its_node *its) { - int err; - int i; - int psz = SZ_64K; + u64 typer = readq_relaxed(its->base + GITS_TYPER); + u32 ids = GITS_TYPER_DEVBITS(typer); u64 shr = GITS_BASER_InnerShareable; - u64 cache; - u64 typer; - u32 ids; + u64 cache = GITS_BASER_WaWb; + u32 psz = SZ_64K; + int err, i; if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_22375) { /* - * erratum 22375: only alloc 8MB table size - * erratum 24313: ignore memory access type - */ - cache = 0; - ids = 0x14; /* 20 bits, 8MB */ - } else { - cache = GITS_BASER_WaWb; - typer = readq_relaxed(its->base + GITS_TYPER); - ids = GITS_TYPER_DEVBITS(typer); + * erratum 22375: only alloc 8MB table size + * erratum 24313: ignore memory access type + */ + cache = GITS_BASER_nCnB; + ids = 0x14; /* 20 bits, 8MB */ } its->device_ids = ids; @@ -906,11 +1006,7 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) struct its_baser *baser = its->tables + i; u64 val = its_read_baser(its, baser); u64 type = GITS_BASER_TYPE(val); - u64 entry_size = GITS_BASER_ENTRY_SIZE(val); - int order = get_order(psz); - int alloc_pages; - u64 tmp; - void *base; + u32 order = get_order(psz); if (type == GITS_BASER_TYPE_NONE) continue; @@ -918,105 +1014,19 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) if (type == GITS_BASER_TYPE_DEVICE) its_parse_baser_device(its, baser, &order); -retry_alloc_baser: - alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz); - if (alloc_pages > GITS_BASER_PAGES_MAX) { - alloc_pages = GITS_BASER_PAGES_MAX; - order = get_order(GITS_BASER_PAGES_MAX * psz); - pr_warn("%s: Device Table too large, reduce its page order to %u (%u pages)\n", - node_name, order, alloc_pages); - } - - base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); - if (!base) { - err = -ENOMEM; - goto out_free; - } - - its->tables[i].base = base; - its->tables[i].order = order; - -retry_baser: - val = (virt_to_phys(base) | - (type << GITS_BASER_TYPE_SHIFT) | - ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) | - cache | - shr | - GITS_BASER_VALID); - - switch (psz) { - case SZ_4K: - val |= GITS_BASER_PAGE_SIZE_4K; - break; - case SZ_16K: - val |= GITS_BASER_PAGE_SIZE_16K; - break; - case SZ_64K: - val |= GITS_BASER_PAGE_SIZE_64K; - break; - } - - val |= alloc_pages - 1; - - its_write_baser_cache(its, baser, val); - tmp = baser->val; - - if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) { - /* - * Shareability didn't stick. Just use - * whatever the read reported, which is likely - * to be the only thing this redistributor - * supports. If that's zero, make it - * non-cacheable as well. - */ - shr = tmp & GITS_BASER_SHAREABILITY_MASK; - if (!shr) { - cache = GITS_BASER_nC; - __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order)); - } - goto retry_baser; - } - - if ((val ^ tmp) & GITS_BASER_PAGE_SIZE_MASK) { - /* - * Page size didn't stick. Let's try a smaller - * size and retry. If we reach 4K, then - * something is horribly wrong... - */ - free_pages((unsigned long)base, order); - its->tables[i].base = NULL; - - switch (psz) { - case SZ_16K: - psz = SZ_4K; - goto retry_alloc_baser; - case SZ_64K: - psz = SZ_16K; - goto retry_alloc_baser; - } - } - - if (val != tmp) { - pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n", - node_name, i, - (unsigned long) val, (unsigned long) tmp); - err = -ENXIO; - goto out_free; + err = its_setup_baser(its, baser, cache, shr, psz, order); + if (err < 0) { + its_free_tables(its); + return err; } - pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n", - (int)(PAGE_ORDER_TO_SIZE(order) / entry_size), - its_base_type_string[type], - (unsigned long)virt_to_phys(base), - psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); + /* Update settings which will be used for next BASERn */ + psz = baser->psz; + cache = baser->val & GITS_BASER_CACHEABILITY_MASK; + shr = baser->val & GITS_BASER_SHAREABILITY_MASK; } return 0; - -out_free: - its_free_tables(its); - - return err; } static int its_alloc_collections(struct its_node *its) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index dc493e0f0ff7..01cf171ef97d 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -228,6 +228,7 @@ #define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT) #define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT) #define GITS_BASER_PAGES_MAX 256 +#define GITS_BASER_PAGES_SHIFT (0) #define GITS_BASER_TYPE_NONE 0 #define GITS_BASER_TYPE_DEVICE 1 -- cgit v1.2.3 From 3faf24ea894a34887c0ca412f1643540251b9d82 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 6 Jun 2016 18:17:32 -0500 Subject: irqchip/gicv3-its: Implement two-level(indirect) device table support Since device IDs are extremely sparse, the single, a.k.a flat table is not sufficient for the following two reasons. 1) According to ARM-GIC spec, ITS hw can access maximum of 256(pages)* 64K(pageszie) bytes. In the best case, it supports upto DEVid=21 sparse with minimum device table entry size 8bytes. 2) The maximum memory size that is possible without memblock depends on MAX_ORDER. 4MB on 4K page size kernel with default MAX_ORDER, so it supports DEVid range 19bits. The two-level device table feature brings us two advantages, the first is a very high possibility of supporting upto 32bit sparse, and the second one is the best utilization of memory allocation. The feature is enabled automatically during driver probe if the memory requirement is more than 2*ITS-pages and the hardware is capable of two-level table walk. Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 107 +++++++++++++++++++++++++++++++------ include/linux/irqchip/arm-gic-v3.h | 3 ++ 2 files changed, 93 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 7afac33e2f9e..7ceaba81efb4 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -842,7 +842,8 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser, } static int its_setup_baser(struct its_node *its, struct its_baser *baser, - u64 cache, u64 shr, u32 psz, u32 order) + u64 cache, u64 shr, u32 psz, u32 order, + bool indirect) { u64 val = its_read_baser(its, baser); u64 esz = GITS_BASER_ENTRY_SIZE(val); @@ -874,6 +875,8 @@ retry_baser: shr | GITS_BASER_VALID); + val |= indirect ? GITS_BASER_INDIRECT : 0x0; + switch (psz) { case SZ_4K: val |= GITS_BASER_PAGE_SIZE_4K; @@ -935,28 +938,55 @@ retry_baser: baser->order = order; baser->base = base; baser->psz = psz; + tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz; - pr_info("ITS@%pa: allocated %d %s @%lx (psz %dK, shr %d)\n", - &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / esz), + pr_info("ITS@%pa: allocated %d %s @%lx (%s, esz %d, psz %dK, shr %d)\n", + &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / tmp), its_base_type_string[type], (unsigned long)virt_to_phys(base), + indirect ? "indirect" : "flat", (int)esz, psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); return 0; } -static void its_parse_baser_device(struct its_node *its, struct its_baser *baser, - u32 *order) +static bool its_parse_baser_device(struct its_node *its, struct its_baser *baser, + u32 psz, u32 *order) { u64 esz = GITS_BASER_ENTRY_SIZE(its_read_baser(its, baser)); + u64 val = GITS_BASER_InnerShareable | GITS_BASER_WaWb; u32 ids = its->device_ids; u32 new_order = *order; + bool indirect = false; + + /* No need to enable Indirection if memory requirement < (psz*2)bytes */ + if ((esz << ids) > (psz * 2)) { + /* + * Find out whether hw supports a single or two-level table by + * table by reading bit at offset '62' after writing '1' to it. + */ + its_write_baser(its, baser, val | GITS_BASER_INDIRECT); + indirect = !!(baser->val & GITS_BASER_INDIRECT); + + if (indirect) { + /* + * The size of the lvl2 table is equal to ITS page size + * which is 'psz'. For computing lvl1 table size, + * subtract ID bits that sparse lvl2 table from 'ids' + * which is reported by ITS hardware times lvl1 table + * entry size. + */ + ids -= ilog2(psz / esz); + esz = GITS_LVL1_ENTRY_SIZE; + } + } /* * Allocate as many entries as required to fit the * range of device IDs that the ITS can grok... The ID * space being incredibly sparse, this results in a - * massive waste of memory. + * massive waste of memory if two-level device table + * feature is not supported by hardware. */ new_order = max_t(u32, get_order(esz << ids), new_order); if (new_order >= MAX_ORDER) { @@ -967,6 +997,8 @@ static void its_parse_baser_device(struct its_node *its, struct its_baser *baser } *order = new_order; + + return indirect; } static void its_free_tables(struct its_node *its) @@ -1007,14 +1039,15 @@ static int its_alloc_tables(struct its_node *its) u64 val = its_read_baser(its, baser); u64 type = GITS_BASER_TYPE(val); u32 order = get_order(psz); + bool indirect = false; if (type == GITS_BASER_TYPE_NONE) continue; if (type == GITS_BASER_TYPE_DEVICE) - its_parse_baser_device(its, baser, &order); + indirect = its_parse_baser_device(its, baser, psz, &order); - err = its_setup_baser(its, baser, cache, shr, psz, order); + err = its_setup_baser(its, baser, cache, shr, psz, order, indirect); if (err < 0) { its_free_tables(its); return err; @@ -1214,10 +1247,57 @@ static struct its_baser *its_get_baser(struct its_node *its, u32 type) return NULL; } +static bool its_alloc_device_table(struct its_node *its, u32 dev_id) +{ + struct its_baser *baser; + struct page *page; + u32 esz, idx; + __le64 *table; + + baser = its_get_baser(its, GITS_BASER_TYPE_DEVICE); + + /* Don't allow device id that exceeds ITS hardware limit */ + if (!baser) + return (ilog2(dev_id) < its->device_ids); + + /* Don't allow device id that exceeds single, flat table limit */ + esz = GITS_BASER_ENTRY_SIZE(baser->val); + if (!(baser->val & GITS_BASER_INDIRECT)) + return (dev_id < (PAGE_ORDER_TO_SIZE(baser->order) / esz)); + + /* Compute 1st level table index & check if that exceeds table limit */ + idx = dev_id >> ilog2(baser->psz / esz); + if (idx >= (PAGE_ORDER_TO_SIZE(baser->order) / GITS_LVL1_ENTRY_SIZE)) + return false; + + table = baser->base; + + /* Allocate memory for 2nd level table */ + if (!table[idx]) { + page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(baser->psz)); + if (!page) + return false; + + /* Flush Lvl2 table to PoC if hw doesn't support coherency */ + if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) + __flush_dcache_area(page_address(page), baser->psz); + + table[idx] = cpu_to_le64(page_to_phys(page) | GITS_BASER_VALID); + + /* Flush Lvl1 entry to PoC if hw doesn't support coherency */ + if (!(baser->val & GITS_BASER_SHAREABILITY_MASK)) + __flush_dcache_area(table + idx, GITS_LVL1_ENTRY_SIZE); + + /* Ensure updated table contents are visible to ITS hardware */ + dsb(sy); + } + + return true; +} + static struct its_device *its_create_device(struct its_node *its, u32 dev_id, int nvecs) { - struct its_baser *baser; struct its_device *dev; unsigned long *lpi_map; unsigned long flags; @@ -1228,14 +1308,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, int nr_ites; int sz; - baser = its_get_baser(its, GITS_BASER_TYPE_DEVICE); - - /* Don't allow 'dev_id' that exceeds single, flat table limit */ - if (baser) { - if (dev_id >= (PAGE_ORDER_TO_SIZE(baser->order) / - GITS_BASER_ENTRY_SIZE(baser->val))) - return NULL; - } else if (ilog2(dev_id) >= its->device_ids) + if (!its_alloc_device_table(its, dev_id)) return NULL; dev = kzalloc(sizeof(*dev), GFP_KERNEL); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 01cf171ef97d..107eed475b94 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -204,6 +204,7 @@ #define GITS_BASER_NR_REGS 8 #define GITS_BASER_VALID (1UL << 63) +#define GITS_BASER_INDIRECT (1UL << 62) #define GITS_BASER_nCnB (0UL << 59) #define GITS_BASER_nC (1UL << 59) #define GITS_BASER_RaWt (2UL << 59) @@ -239,6 +240,8 @@ #define GITS_BASER_TYPE_RESERVED6 6 #define GITS_BASER_TYPE_RESERVED7 7 +#define GITS_LVL1_ENTRY_SIZE (8UL) + /* * ITS commands */ -- cgit v1.2.3 From 7dd968163f7c12bcb2132792bf873133b397a2d2 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 25 May 2016 09:32:20 +0200 Subject: bitmap: bitmap_equal memcmp optimization The bitmap_equal function has optimized code for small bitmaps with less than BITS_PER_LONG bits. For larger bitmaps the out-of-line function __bitmap_equal is called. For a constant number of bits divisible by BITS_PER_LONG the memcmp function can be used. For s390 gcc knows how to optimize this function, memcmp calls with up to 256 bytes / 2048 bits are translated into a single instruction. Reviewed-by: David Hildenbrand Signed-off-by: Martin Schwidefsky --- include/linux/bitmap.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index e9b0b9ab07e5..27bfc0b631a9 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -267,6 +267,10 @@ static inline int bitmap_equal(const unsigned long *src1, { if (small_const_nbits(nbits)) return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); +#ifdef CONFIG_S390 + else if (__builtin_constant_p(nbits) && (nbits % BITS_PER_LONG) == 0) + return !memcmp(src1, src2, nbits / 8); +#endif else return __bitmap_equal(src1, src2, nbits); } -- cgit v1.2.3 From 9661e783d830699a65f7d42e4b4a76e6923089eb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 7 Jun 2016 20:48:33 +0300 Subject: PCI / PM: Enforce type casting for pci_power_t When casting variables of type pci_power_t, a static analysis tool complains: include/linux/pci.h:119:37: warning: cast from restricted pci_power_t Enforce type casting to make the static analyzer happy. Signed-off-by: Andy Shevchenko Signed-off-by: Bjorn Helgaas --- include/linux/pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index b67e4df20801..8d748345b158 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -116,7 +116,7 @@ extern const char *pci_power_names[]; static inline const char *pci_power_name(pci_power_t state) { - return pci_power_names[1 + (int) state]; + return pci_power_names[1 + (__force int) state]; } #define PCI_PM_D2_DELAY 200 -- cgit v1.2.3 From 42d42a5b0cd263757f8e519debbc744fdaefdaf7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 23 May 2016 09:24:55 -0400 Subject: SUNRPC: Small optimisation of client receive Do not queue the client receive work if we're still processing. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprtsock.h | 1 + net/sunrpc/xprtsock.c | 44 ++++++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h index 0ece4ba06f06..bef3fb0abb8f 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h @@ -80,6 +80,7 @@ struct sock_xprt { #define TCP_RPC_REPLY (1UL << 6) #define XPRT_SOCK_CONNECTING 1U +#define XPRT_SOCK_DATA_READY (2) #endif /* __KERNEL__ */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 2d3e0c42361e..2f2178027761 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -755,11 +755,19 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s sk->sk_error_report = transport->old_error_report; } +static void xs_sock_reset_state_flags(struct rpc_xprt *xprt) +{ + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + + clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); +} + static void xs_sock_reset_connection_flags(struct rpc_xprt *xprt) { smp_mb__before_atomic(); clear_bit(XPRT_CLOSE_WAIT, &xprt->state); clear_bit(XPRT_CLOSING, &xprt->state); + xs_sock_reset_state_flags(xprt); smp_mb__after_atomic(); } @@ -962,10 +970,13 @@ static void xs_local_data_receive(struct sock_xprt *transport) goto out; for (;;) { skb = skb_recv_datagram(sk, 0, 1, &err); - if (skb == NULL) + if (skb != NULL) { + xs_local_data_read_skb(&transport->xprt, sk, skb); + skb_free_datagram(sk, skb); + continue; + } + if (!test_and_clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) break; - xs_local_data_read_skb(&transport->xprt, sk, skb); - skb_free_datagram(sk, skb); } out: mutex_unlock(&transport->recv_mutex); @@ -1043,10 +1054,13 @@ static void xs_udp_data_receive(struct sock_xprt *transport) goto out; for (;;) { skb = skb_recv_datagram(sk, 0, 1, &err); - if (skb == NULL) + if (skb != NULL) { + xs_udp_data_read_skb(&transport->xprt, sk, skb); + skb_free_datagram(sk, skb); + continue; + } + if (!test_and_clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) break; - xs_udp_data_read_skb(&transport->xprt, sk, skb); - skb_free_datagram(sk, skb); } out: mutex_unlock(&transport->recv_mutex); @@ -1074,7 +1088,8 @@ static void xs_data_ready(struct sock *sk) if (xprt != NULL) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - queue_work(rpciod_workqueue, &transport->recv_worker); + if (!test_and_set_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) + queue_work(rpciod_workqueue, &transport->recv_worker); } read_unlock_bh(&sk->sk_callback_lock); } @@ -1474,10 +1489,15 @@ static void xs_tcp_data_receive(struct sock_xprt *transport) for (;;) { lock_sock(sk); read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv); - release_sock(sk); - if (read <= 0) - break; - total += read; + if (read <= 0) { + clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state); + release_sock(sk); + if (!test_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) + break; + } else { + release_sock(sk); + total += read; + } rd_desc.count = 65536; } out: @@ -1508,6 +1528,8 @@ static void xs_tcp_data_ready(struct sock *sk) if (!(xprt = xprt_from_sock(sk))) goto out; transport = container_of(xprt, struct sock_xprt, xprt); + if (test_and_set_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) + goto out; /* Any data means we had a useful conversation, so * the we don't need to delay the next reconnect -- cgit v1.2.3 From 40a5f1b19bacb2de7a051be952dee85e38c9e5f5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 27 May 2016 10:39:50 -0400 Subject: SUNRPC: RPC transport queue must be low latency rpciod can easily get congested due to the long list of queued rpc_tasks. Having the receive queue wait in turn for those tasks to complete can therefore be a bottleneck. Address the problem by separating the workqueues into: - rpciod: manages rpc_tasks - xprtiod: manages transport related work. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 1 + net/sunrpc/sched.c | 24 ++++++++++++++++++++---- net/sunrpc/xprt.c | 8 ++++---- net/sunrpc/xprtsock.c | 6 +++--- 4 files changed, 28 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 05a1809c44d9..ef780b3b5e31 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -247,6 +247,7 @@ void rpc_show_tasks(struct net *); int rpc_init_mempool(void); void rpc_destroy_mempool(void); extern struct workqueue_struct *rpciod_workqueue; +extern struct workqueue_struct *xprtiod_workqueue; void rpc_prepare_task(struct rpc_task *task); static inline int rpc_wait_for_completion_task(struct rpc_task *task) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index fcfd48d263f6..a9f786247ffb 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -54,7 +54,8 @@ static struct rpc_wait_queue delay_queue; /* * rpciod-related stuff */ -struct workqueue_struct *rpciod_workqueue; +struct workqueue_struct *rpciod_workqueue __read_mostly; +struct workqueue_struct *xprtiod_workqueue __read_mostly; /* * Disable the timer for a given RPC task. Should be called with @@ -1071,10 +1072,22 @@ static int rpciod_start(void) * Create the rpciod thread and wait for it to start. */ dprintk("RPC: creating workqueue rpciod\n"); - /* Note: highpri because network receive is latency sensitive */ - wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM, 0); + if (!wq) + goto out_failed; rpciod_workqueue = wq; - return rpciod_workqueue != NULL; + /* Note: highpri because network receive is latency sensitive */ + wq = alloc_workqueue("xprtiod", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + if (!wq) + goto free_rpciod; + xprtiod_workqueue = wq; + return 1; +free_rpciod: + wq = rpciod_workqueue; + rpciod_workqueue = NULL; + destroy_workqueue(wq); +out_failed: + return 0; } static void rpciod_stop(void) @@ -1088,6 +1101,9 @@ static void rpciod_stop(void) wq = rpciod_workqueue; rpciod_workqueue = NULL; destroy_workqueue(wq); + wq = xprtiod_workqueue; + xprtiod_workqueue = NULL; + destroy_workqueue(wq); } void diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 216a1385718a..71df082b84a9 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -220,7 +220,7 @@ static void xprt_clear_locked(struct rpc_xprt *xprt) clear_bit(XPRT_LOCKED, &xprt->state); smp_mb__after_atomic(); } else - queue_work(rpciod_workqueue, &xprt->task_cleanup); + queue_work(xprtiod_workqueue, &xprt->task_cleanup); } /* @@ -645,7 +645,7 @@ void xprt_force_disconnect(struct rpc_xprt *xprt) set_bit(XPRT_CLOSE_WAIT, &xprt->state); /* Try to schedule an autoclose RPC call */ if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) - queue_work(rpciod_workqueue, &xprt->task_cleanup); + queue_work(xprtiod_workqueue, &xprt->task_cleanup); xprt_wake_pending_tasks(xprt, -EAGAIN); spin_unlock_bh(&xprt->transport_lock); } @@ -672,7 +672,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie) set_bit(XPRT_CLOSE_WAIT, &xprt->state); /* Try to schedule an autoclose RPC call */ if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) - queue_work(rpciod_workqueue, &xprt->task_cleanup); + queue_work(xprtiod_workqueue, &xprt->task_cleanup); xprt_wake_pending_tasks(xprt, -EAGAIN); out: spin_unlock_bh(&xprt->transport_lock); @@ -689,7 +689,7 @@ xprt_init_autodisconnect(unsigned long data) if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) goto out_abort; spin_unlock(&xprt->transport_lock); - queue_work(rpciod_workqueue, &xprt->task_cleanup); + queue_work(xprtiod_workqueue, &xprt->task_cleanup); return; out_abort: spin_unlock(&xprt->transport_lock); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 62b4f5a2a331..646170d0cb86 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1095,7 +1095,7 @@ static void xs_data_ready(struct sock *sk) if (xprt->reestablish_timeout) xprt->reestablish_timeout = 0; if (!test_and_set_bit(XPRT_SOCK_DATA_READY, &transport->sock_state)) - queue_work(rpciod_workqueue, &transport->recv_worker); + queue_work(xprtiod_workqueue, &transport->recv_worker); } read_unlock_bh(&sk->sk_callback_lock); } @@ -2378,7 +2378,7 @@ static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task) /* Start by resetting any existing state */ xs_reset_transport(transport); - queue_delayed_work(rpciod_workqueue, + queue_delayed_work(xprtiod_workqueue, &transport->connect_worker, xprt->reestablish_timeout); xprt->reestablish_timeout <<= 1; @@ -2388,7 +2388,7 @@ static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task) xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; } else { dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); - queue_delayed_work(rpciod_workqueue, + queue_delayed_work(xprtiod_workqueue, &transport->connect_worker, 0); } } -- cgit v1.2.3 From f1dc237c60a5fdecc83062a28a702193f881cb19 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 27 May 2016 12:59:33 -0400 Subject: SUNRPC: Reduce latency when send queue is congested Use the low latency transport workqueue to process the task that is next in line on the xprt->sending queue. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 4 ++++ net/sunrpc/sched.c | 43 +++++++++++++++++++++++++++++++++---------- net/sunrpc/xprt.c | 6 ++++-- 3 files changed, 41 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index ef780b3b5e31..817af0b4385e 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -230,6 +230,10 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *, struct rpc_task *); void rpc_wake_up(struct rpc_wait_queue *); struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); +struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq, + struct rpc_wait_queue *, + bool (*)(struct rpc_task *, void *), + void *); struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *, bool (*)(struct rpc_task *, void *), void *); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index a9f786247ffb..9ae588511aaf 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -330,7 +330,8 @@ EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); * lockless RPC_IS_QUEUED() test) before we've had a chance to test * the RPC_TASK_RUNNING flag. */ -static void rpc_make_runnable(struct rpc_task *task) +static void rpc_make_runnable(struct workqueue_struct *wq, + struct rpc_task *task) { bool need_wakeup = !rpc_test_and_set_running(task); @@ -339,7 +340,7 @@ static void rpc_make_runnable(struct rpc_task *task) return; if (RPC_IS_ASYNC(task)) { INIT_WORK(&task->u.tk_work, rpc_async_schedule); - queue_work(rpciod_workqueue, &task->u.tk_work); + queue_work(wq, &task->u.tk_work); } else wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); } @@ -408,13 +409,16 @@ void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task, EXPORT_SYMBOL_GPL(rpc_sleep_on_priority); /** - * __rpc_do_wake_up_task - wake up a single rpc_task + * __rpc_do_wake_up_task_on_wq - wake up a single rpc_task + * @wq: workqueue on which to run task * @queue: wait queue * @task: task to be woken up * * Caller must hold queue->lock, and have cleared the task queued flag. */ -static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task *task) +static void __rpc_do_wake_up_task_on_wq(struct workqueue_struct *wq, + struct rpc_wait_queue *queue, + struct rpc_task *task) { dprintk("RPC: %5u __rpc_wake_up_task (now %lu)\n", task->tk_pid, jiffies); @@ -429,7 +433,7 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task __rpc_remove_wait_queue(queue, task); - rpc_make_runnable(task); + rpc_make_runnable(wq, task); dprintk("RPC: __rpc_wake_up_task done\n"); } @@ -437,15 +441,24 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task /* * Wake up a queued task while the queue lock is being held */ -static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task) +static void rpc_wake_up_task_on_wq_queue_locked(struct workqueue_struct *wq, + struct rpc_wait_queue *queue, struct rpc_task *task) { if (RPC_IS_QUEUED(task)) { smp_rmb(); if (task->tk_waitqueue == queue) - __rpc_do_wake_up_task(queue, task); + __rpc_do_wake_up_task_on_wq(wq, queue, task); } } +/* + * Wake up a queued task while the queue lock is being held + */ +static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task) +{ + rpc_wake_up_task_on_wq_queue_locked(rpciod_workqueue, queue, task); +} + /* * Wake up a task on a specific queue */ @@ -519,7 +532,8 @@ static struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue) /* * Wake up the first task on the wait queue. */ -struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue, +struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq, + struct rpc_wait_queue *queue, bool (*func)(struct rpc_task *, void *), void *data) { struct rpc_task *task = NULL; @@ -530,7 +544,7 @@ struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue, task = __rpc_find_next_queued(queue); if (task != NULL) { if (func(task, data)) - rpc_wake_up_task_queue_locked(queue, task); + rpc_wake_up_task_on_wq_queue_locked(wq, queue, task); else task = NULL; } @@ -538,6 +552,15 @@ struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue, return task; } + +/* + * Wake up the first task on the wait queue. + */ +struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue, + bool (*func)(struct rpc_task *, void *), void *data) +{ + return rpc_wake_up_first_on_wq(rpciod_workqueue, queue, func, data); +} EXPORT_SYMBOL_GPL(rpc_wake_up_first); static bool rpc_wake_up_next_func(struct rpc_task *task, void *data) @@ -815,7 +838,7 @@ void rpc_execute(struct rpc_task *task) bool is_async = RPC_IS_ASYNC(task); rpc_set_active(task); - rpc_make_runnable(task); + rpc_make_runnable(rpciod_workqueue, task); if (!is_async) __rpc_execute(task); } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 71df082b84a9..8313960cac52 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -295,7 +295,8 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) return; - if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_func, xprt)) + if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending, + __xprt_lock_write_func, xprt)) return; xprt_clear_locked(xprt); } @@ -324,7 +325,8 @@ static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) return; if (RPCXPRT_CONGESTED(xprt)) goto out_unlock; - if (rpc_wake_up_first(&xprt->sending, __xprt_lock_write_cong_func, xprt)) + if (rpc_wake_up_first_on_wq(xprtiod_workqueue, &xprt->sending, + __xprt_lock_write_cong_func, xprt)) return; out_unlock: xprt_clear_locked(xprt); -- cgit v1.2.3 From 9d26d3a8f1b0c442339a235f9508bdad8af91043 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 2 Jun 2016 11:17:12 +0300 Subject: PCI: Put PCIe ports into D3 during suspend Currently the Linux PCI core does not touch power state of PCI bridges and PCIe ports when system suspend is entered. Leaving them in D0 consumes power unnecessarily and may prevent the CPU from entering deeper C-states. With recent PCIe hardware we can power down the ports to save power given that we take into account few restrictions: - The PCIe port hardware is recent enough, starting from 2015. - Devices connected to PCIe ports are effectively in D3cold once the port is transitioned to D3 (the config space is not accessible anymore and the link may be powered down). - Devices behind the PCIe port need to be allowed to transition to D3cold and back. There is a way both drivers and userspace can forbid this. - If the device behind the PCIe port is capable of waking the system it needs to be able to do so from D3cold. This patch adds a new flag to struct pci_device called 'bridge_d3'. This flag is set and cleared by the PCI core whenever there is a change in power management state of any of the devices behind the PCIe port. When system later on is suspended we only need to check this flag and if it is true transition the port to D3 otherwise we leave it in D0. Also provide override mechanism via command line parameter "pcie_port_pm=[off|force]" that can be used to disable or enable the feature regardless of the BIOS manufacturing date. Tested-by: Lukas Wunner Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- Documentation/kernel-parameters.txt | 4 + drivers/pci/bus.c | 1 + drivers/pci/pci-driver.c | 5 +- drivers/pci/pci-sysfs.c | 5 ++ drivers/pci/pci.c | 175 ++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 11 +++ drivers/pci/remove.c | 2 + drivers/usb/host/xhci-pci.c | 2 +- include/linux/pci.h | 3 + 9 files changed, 203 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 82b42c958d1c..86edee4cedd4 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3047,6 +3047,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. compat Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe ports driver. + pcie_port_pm= [PCIE] PCIe port power management handling: + off Disable power management of all PCIe ports + force Forcibly enable power management of all PCIe ports + pcie_pme= [PCIE,PM] Native PCIe PME signaling options: nomsi Do not use MSI for native PCIe PME signaling (this makes all PCIe root ports use INTx for all services). diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index dd7cdbee8029..28731360b457 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -291,6 +291,7 @@ void pci_bus_add_device(struct pci_dev *dev) pci_fixup_device(pci_fixup_final, dev); pci_create_sysfs_dev_files(dev); pci_proc_attach_device(dev); + pci_bridge_d3_device_changed(dev); dev->match_driver = true; retval = device_attach(&dev->dev); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d7ffd66814bb..e39a67c8ef39 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -777,7 +777,7 @@ static int pci_pm_suspend_noirq(struct device *dev) if (!pci_dev->state_saved) { pci_save_state(pci_dev); - if (!pci_has_subordinate(pci_dev)) + if (pci_power_manageable(pci_dev)) pci_prepare_to_sleep(pci_dev); } @@ -1144,7 +1144,6 @@ static int pci_pm_runtime_suspend(struct device *dev) return -ENOSYS; pci_dev->state_saved = false; - pci_dev->no_d3cold = false; error = pm->runtime_suspend(dev); if (error) { /* @@ -1161,8 +1160,6 @@ static int pci_pm_runtime_suspend(struct device *dev) return error; } - if (!pci_dev->d3cold_allowed) - pci_dev->no_d3cold = true; pci_fixup_device(pci_fixup_suspend, pci_dev); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index d319a9ca9b7b..bcd10c795284 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -406,6 +406,11 @@ static ssize_t d3cold_allowed_store(struct device *dev, return -EINVAL; pdev->d3cold_allowed = !!val; + if (pdev->d3cold_allowed) + pci_d3cold_enable(pdev); + else + pci_d3cold_disable(pdev); + pm_runtime_resume(dev); return count; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c8b4dbdd1bdd..9ff7183e25a2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -101,6 +102,21 @@ unsigned int pcibios_max_latency = 255; /* If set, the PCIe ARI capability will not be used. */ static bool pcie_ari_disabled; +/* Disable bridge_d3 for all PCIe ports */ +static bool pci_bridge_d3_disable; +/* Force bridge_d3 for all PCIe ports */ +static bool pci_bridge_d3_force; + +static int __init pcie_port_pm_setup(char *str) +{ + if (!strcmp(str, "off")) + pci_bridge_d3_disable = true; + else if (!strcmp(str, "force")) + pci_bridge_d3_force = true; + return 1; +} +__setup("pcie_port_pm=", pcie_port_pm_setup); + /** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search @@ -2155,6 +2171,164 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev) pm_runtime_put_sync(parent); } +/** + * pci_bridge_d3_possible - Is it possible to put the bridge into D3 + * @bridge: Bridge to check + * + * This function checks if it is possible to move the bridge to D3. + * Currently we only allow D3 for recent enough PCIe ports. + */ +static bool pci_bridge_d3_possible(struct pci_dev *bridge) +{ + unsigned int year; + + if (!pci_is_pcie(bridge)) + return false; + + switch (pci_pcie_type(bridge)) { + case PCI_EXP_TYPE_ROOT_PORT: + case PCI_EXP_TYPE_UPSTREAM: + case PCI_EXP_TYPE_DOWNSTREAM: + if (pci_bridge_d3_disable) + return false; + if (pci_bridge_d3_force) + return true; + + /* + * It should be safe to put PCIe ports from 2015 or newer + * to D3. + */ + if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && + year >= 2015) { + return true; + } + break; + } + + return false; +} + +static int pci_dev_check_d3cold(struct pci_dev *dev, void *data) +{ + bool *d3cold_ok = data; + bool no_d3cold; + + /* + * The device needs to be allowed to go D3cold and if it is wake + * capable to do so from D3cold. + */ + no_d3cold = dev->no_d3cold || !dev->d3cold_allowed || + (device_may_wakeup(&dev->dev) && !pci_pme_capable(dev, PCI_D3cold)) || + !pci_power_manageable(dev); + + *d3cold_ok = !no_d3cold; + + return no_d3cold; +} + +/* + * pci_bridge_d3_update - Update bridge D3 capabilities + * @dev: PCI device which is changed + * @remove: Is the device being removed + * + * Update upstream bridge PM capabilities accordingly depending on if the + * device PM configuration was changed or the device is being removed. The + * change is also propagated upstream. + */ +static void pci_bridge_d3_update(struct pci_dev *dev, bool remove) +{ + struct pci_dev *bridge; + bool d3cold_ok = true; + + bridge = pci_upstream_bridge(dev); + if (!bridge || !pci_bridge_d3_possible(bridge)) + return; + + pci_dev_get(bridge); + /* + * If the device is removed we do not care about its D3cold + * capabilities. + */ + if (!remove) + pci_dev_check_d3cold(dev, &d3cold_ok); + + if (d3cold_ok) { + /* + * We need to go through all children to find out if all of + * them can still go to D3cold. + */ + pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold, + &d3cold_ok); + } + + if (bridge->bridge_d3 != d3cold_ok) { + bridge->bridge_d3 = d3cold_ok; + /* Propagate change to upstream bridges */ + pci_bridge_d3_update(bridge, false); + } + + pci_dev_put(bridge); +} + +/** + * pci_bridge_d3_device_changed - Update bridge D3 capabilities on change + * @dev: PCI device that was changed + * + * If a device is added or its PM configuration, such as is it allowed to + * enter D3cold, is changed this function updates upstream bridge PM + * capabilities accordingly. + */ +void pci_bridge_d3_device_changed(struct pci_dev *dev) +{ + pci_bridge_d3_update(dev, false); +} + +/** + * pci_bridge_d3_device_removed - Update bridge D3 capabilities on remove + * @dev: PCI device being removed + * + * Function updates upstream bridge PM capabilities based on other devices + * still left on the bus. + */ +void pci_bridge_d3_device_removed(struct pci_dev *dev) +{ + pci_bridge_d3_update(dev, true); +} + +/** + * pci_d3cold_enable - Enable D3cold for device + * @dev: PCI device to handle + * + * This function can be used in drivers to enable D3cold from the device + * they handle. It also updates upstream PCI bridge PM capabilities + * accordingly. + */ +void pci_d3cold_enable(struct pci_dev *dev) +{ + if (dev->no_d3cold) { + dev->no_d3cold = false; + pci_bridge_d3_device_changed(dev); + } +} +EXPORT_SYMBOL_GPL(pci_d3cold_enable); + +/** + * pci_d3cold_disable - Disable D3cold for device + * @dev: PCI device to handle + * + * This function can be used in drivers to disable D3cold from the device + * they handle. It also updates upstream PCI bridge PM capabilities + * accordingly. + */ +void pci_d3cold_disable(struct pci_dev *dev) +{ + if (!dev->no_d3cold) { + dev->no_d3cold = true; + pci_bridge_d3_device_changed(dev); + } +} +EXPORT_SYMBOL_GPL(pci_d3cold_disable); + /** * pci_pm_init - Initialize PM functions of given PCI device * @dev: PCI device to handle. @@ -2189,6 +2363,7 @@ void pci_pm_init(struct pci_dev *dev) dev->pm_cap = pm; dev->d3_delay = PCI_PM_D3_WAIT; dev->d3cold_delay = PCI_PM_D3COLD_WAIT; + dev->bridge_d3 = pci_bridge_d3_possible(dev); dev->d3cold_allowed = true; dev->d1_support = false; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a814bbb80fcb..9730c474b016 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -82,6 +82,8 @@ void pci_pm_init(struct pci_dev *dev); void pci_ea_init(struct pci_dev *dev); void pci_allocate_cap_save_buffers(struct pci_dev *dev); void pci_free_cap_save_buffers(struct pci_dev *dev); +void pci_bridge_d3_device_changed(struct pci_dev *dev); +void pci_bridge_d3_device_removed(struct pci_dev *dev); static inline void pci_wakeup_event(struct pci_dev *dev) { @@ -94,6 +96,15 @@ static inline bool pci_has_subordinate(struct pci_dev *pci_dev) return !!(pci_dev->subordinate); } +static inline bool pci_power_manageable(struct pci_dev *pci_dev) +{ + /* + * Currently we allow normal PCI devices and PCI bridges transition + * into D3 if their bridge_d3 is set. + */ + return !pci_has_subordinate(pci_dev) || pci_dev->bridge_d3; +} + struct pci_vpd_ops { ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf); ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 8982026637d5..d1ef7acf6930 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -96,6 +96,8 @@ static void pci_remove_bus_device(struct pci_dev *dev) dev->subordinate = NULL; } + pci_bridge_d3_device_removed(dev); + pci_destroy_dev(dev); } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 48672fac7ff3..ac352fe391f4 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -382,7 +382,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) * need to have the registers polled during D3, so avoid D3cold. */ if (xhci->quirks & XHCI_COMP_MODE_QUIRK) - pdev->no_d3cold = true; + pci_d3cold_disable(pdev); if (xhci->quirks & XHCI_PME_STUCK_QUIRK) xhci_pme_quirk(hcd); diff --git a/include/linux/pci.h b/include/linux/pci.h index 8d748345b158..8597b423cb63 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -294,6 +294,7 @@ struct pci_dev { unsigned int d2_support:1; /* Low power state D2 is supported */ unsigned int no_d1d2:1; /* D1 and D2 are forbidden */ unsigned int no_d3cold:1; /* D3cold is forbidden */ + unsigned int bridge_d3:1; /* Allow D3 for bridge */ unsigned int d3cold_allowed:1; /* D3cold is allowed by user */ unsigned int mmio_always_on:1; /* disallow turning off io/mem decoding during bar sizing */ @@ -1083,6 +1084,8 @@ int pci_back_from_sleep(struct pci_dev *dev); bool pci_dev_run_wake(struct pci_dev *dev); bool pci_check_pme_status(struct pci_dev *dev); void pci_pme_wakeup_bus(struct pci_bus *bus); +void pci_d3cold_enable(struct pci_dev *dev); +void pci_d3cold_disable(struct pci_dev *dev); static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable) -- cgit v1.2.3 From 0f614d834bccd3537881c5d0933803b407ce3283 Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Sun, 31 Jan 2016 16:33:00 +0100 Subject: i2c: Add generic support passing secondary devices addresses Some I2C devices have multiple addresses assigned, for example each address corresponding to a different internal register map page of the device. So far drivers which need support for this have handled this with a driver specific and non-generic implementation, e.g. passing the additional address via platform data. This patch provides a new helper function called i2c_new_secondary_device() which is intended to provide a generic way to get the secondary address as well as instantiate a struct i2c_client for the secondary address. The function expects a pointer to the primary i2c_client, a name for the secondary address and an optional default address. The name is used as a handle to specify which secondary address to get. The default address is used as a fallback in case no secondary address was explicitly specified. In case no secondary address and no default address were specified the function returns NULL. For now the function only supports look-up of the secondary address from devicetree, but it can be extended in the future to for example support board files and/or ACPI. Signed-off-by: Jean-Michel Hautbois Acked-by: Rob Herring Acked-by: Mika Westerberg Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c.txt | 7 +++++ drivers/i2c/i2c-core.c | 41 +++++++++++++++++++++++++++ include/linux/i2c.h | 5 ++++ 3 files changed, 53 insertions(+) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index c8d977ed847f..f31b2ad1552b 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -62,6 +62,13 @@ wants to support one of the below features, it should adapt the bindings below. - wakeup-source device can be used as a wakeup source. +- reg + I2C slave addresses + +- reg-names + Names of map programmable addresses. + It can contain any map needing another address than default one. + Binding may contain optional "interrupts" property, describing interrupts used by the device. I2C core will assign "irq" interrupt (or the very first interrupt if not using interrupt names) as primary interrupt for the slave. diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index af11b658984d..952d2f0c02c5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1145,6 +1145,47 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address) } EXPORT_SYMBOL_GPL(i2c_new_dummy); +/** + * i2c_new_secondary_device - Helper to get the instantiated secondary address + * and create the associated device + * @client: Handle to the primary client + * @name: Handle to specify which secondary address to get + * @default_addr: Used as a fallback if no secondary address was specified + * Context: can sleep + * + * I2C clients can be composed of multiple I2C slaves bound together in a single + * component. The I2C client driver then binds to the master I2C slave and needs + * to create I2C dummy clients to communicate with all the other slaves. + * + * This function creates and returns an I2C dummy client whose I2C address is + * retrieved from the platform firmware based on the given slave name. If no + * address is specified by the firmware default_addr is used. + * + * On DT-based platforms the address is retrieved from the "reg" property entry + * cell whose "reg-names" value matches the slave name. + * + * This returns the new i2c client, which should be saved for later use with + * i2c_unregister_device(); or NULL to indicate an error. + */ +struct i2c_client *i2c_new_secondary_device(struct i2c_client *client, + const char *name, + u16 default_addr) +{ + struct device_node *np = client->dev.of_node; + u32 addr = default_addr; + int i; + + if (np) { + i = of_property_match_string(np, "reg-names", name); + if (i >= 0) + of_property_read_u32_index(np, "reg", i, &addr); + } + + dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr); + return i2c_new_dummy(client->adapter, addr); +} +EXPORT_SYMBOL_GPL(i2c_new_secondary_device); + /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 96a25ae14494..6df7bad8c26c 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -349,6 +349,11 @@ extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr); extern struct i2c_client * i2c_new_dummy(struct i2c_adapter *adap, u16 address); +extern struct i2c_client * +i2c_new_secondary_device(struct i2c_client *client, + const char *name, + u16 default_addr); + extern void i2c_unregister_device(struct i2c_client *); #endif /* I2C */ -- cgit v1.2.3 From a5ca66c419410b4a26ab47b120d5424bd1d33700 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 14 Jun 2016 00:26:14 +0200 Subject: drbd: Introduce new disk config option rs-discard-granularity As long as the value is 0 the feature is disabled. With setting it to a positive value, DRBD limits and aligns its resync requests to the rs-discard-granularity setting. If the sync source detects all zeros in such a block, the resync target discards the range on disk. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_nl.c | 32 +++++++++++++++++++++++++++++--- include/linux/drbd_genl.h | 6 +++--- include/linux/drbd_limits.h | 6 ++++++ 3 files changed, 38 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index fad03e4feef6..99339dfe4389 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1348,12 +1348,38 @@ static bool write_ordering_changed(struct disk_conf *a, struct disk_conf *b) a->disk_drain != b->disk_drain; } -static void sanitize_disk_conf(struct disk_conf *disk_conf, struct drbd_backing_dev *nbc) +static void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *disk_conf, + struct drbd_backing_dev *nbc) { + struct request_queue * const q = nbc->backing_bdev->bd_disk->queue; + if (disk_conf->al_extents < DRBD_AL_EXTENTS_MIN) disk_conf->al_extents = DRBD_AL_EXTENTS_MIN; if (disk_conf->al_extents > drbd_al_extents_max(nbc)) disk_conf->al_extents = drbd_al_extents_max(nbc); + + if (!blk_queue_discard(q) || !q->limits.discard_zeroes_data) { + disk_conf->rs_discard_granularity = 0; /* disable feature */ + drbd_info(device, "rs_discard_granularity feature disabled\n"); + } + + if (disk_conf->rs_discard_granularity) { + int orig_value = disk_conf->rs_discard_granularity; + int remainder; + + if (q->limits.discard_granularity > disk_conf->rs_discard_granularity) + disk_conf->rs_discard_granularity = q->limits.discard_granularity; + + remainder = disk_conf->rs_discard_granularity % q->limits.discard_granularity; + disk_conf->rs_discard_granularity += remainder; + + if (disk_conf->rs_discard_granularity > q->limits.max_discard_sectors << 9) + disk_conf->rs_discard_granularity = q->limits.max_discard_sectors << 9; + + if (disk_conf->rs_discard_granularity != orig_value) + drbd_info(device, "rs_discard_granularity changed to %d\n", + disk_conf->rs_discard_granularity); + } } int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) @@ -1403,7 +1429,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) if (!expect(new_disk_conf->resync_rate >= 1)) new_disk_conf->resync_rate = 1; - sanitize_disk_conf(new_disk_conf, device->ldev); + sanitize_disk_conf(device, new_disk_conf, device->ldev); if (new_disk_conf->c_plan_ahead > DRBD_C_PLAN_AHEAD_MAX) new_disk_conf->c_plan_ahead = DRBD_C_PLAN_AHEAD_MAX; @@ -1698,7 +1724,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) if (retcode != NO_ERROR) goto fail; - sanitize_disk_conf(new_disk_conf, nbc); + sanitize_disk_conf(device, new_disk_conf, nbc); if (drbd_get_max_capacity(nbc) < new_disk_conf->disk_size) { drbd_err(device, "max capacity %llu smaller than disk size %llu\n", diff --git a/include/linux/drbd_genl.h b/include/linux/drbd_genl.h index 2d0e5ad5de9d..ab649d8e9ed2 100644 --- a/include/linux/drbd_genl.h +++ b/include/linux/drbd_genl.h @@ -123,14 +123,14 @@ GENL_struct(DRBD_NLA_DISK_CONF, 3, disk_conf, __u32_field_def(13, DRBD_GENLA_F_MANDATORY, c_fill_target, DRBD_C_FILL_TARGET_DEF) __u32_field_def(14, DRBD_GENLA_F_MANDATORY, c_max_rate, DRBD_C_MAX_RATE_DEF) __u32_field_def(15, DRBD_GENLA_F_MANDATORY, c_min_rate, DRBD_C_MIN_RATE_DEF) + __u32_field_def(20, DRBD_GENLA_F_MANDATORY, disk_timeout, DRBD_DISK_TIMEOUT_DEF) + __u32_field_def(21, 0 /* OPTIONAL */, read_balancing, DRBD_READ_BALANCING_DEF) + __u32_field_def(25, 0 /* OPTIONAL */, rs_discard_granularity, DRBD_RS_DISCARD_GRANULARITY_DEF) __flg_field_def(16, DRBD_GENLA_F_MANDATORY, disk_barrier, DRBD_DISK_BARRIER_DEF) __flg_field_def(17, DRBD_GENLA_F_MANDATORY, disk_flushes, DRBD_DISK_FLUSHES_DEF) __flg_field_def(18, DRBD_GENLA_F_MANDATORY, disk_drain, DRBD_DISK_DRAIN_DEF) __flg_field_def(19, DRBD_GENLA_F_MANDATORY, md_flushes, DRBD_MD_FLUSHES_DEF) - __u32_field_def(20, DRBD_GENLA_F_MANDATORY, disk_timeout, DRBD_DISK_TIMEOUT_DEF) - __u32_field_def(21, 0 /* OPTIONAL */, read_balancing, DRBD_READ_BALANCING_DEF) - /* 9: __u32_field_def(22, DRBD_GENLA_F_MANDATORY, unplug_watermark, DRBD_UNPLUG_WATERMARK_DEF) */ __flg_field_def(23, 0 /* OPTIONAL */, al_updates, DRBD_AL_UPDATES_DEF) ) diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h index 8ac8c5d9a3ad..2e4aad8d8ae8 100644 --- a/include/linux/drbd_limits.h +++ b/include/linux/drbd_limits.h @@ -230,4 +230,10 @@ #define DRBD_SOCKET_CHECK_TIMEO_MAX DRBD_PING_TIMEO_MAX #define DRBD_SOCKET_CHECK_TIMEO_DEF 0 #define DRBD_SOCKET_CHECK_TIMEO_SCALE '1' + +#define DRBD_RS_DISCARD_GRANULARITY_MIN 0 +#define DRBD_RS_DISCARD_GRANULARITY_MAX (1<<20) /* 1MiByte */ +#define DRBD_RS_DISCARD_GRANULARITY_DEF 0 /* disabled by default */ +#define DRBD_RS_DISCARD_GRANULARITY_SCALE '1' /* bytes */ + #endif -- cgit v1.2.3 From dd4f699da674010c58d7a2534215b4ca1ff13b13 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 14 Jun 2016 00:26:20 +0200 Subject: drbd: when receiving P_TRIM, zero-out partial unaligned chunks We can avoid spurious data divergence caused by partially-ignored discards on certain backends with discard_zeroes_data=0, if we translate partial unaligned discard requests into explicit zero-out. The relevant use case is LVM/DM thin. If on different nodes, DRBD is backed by devices with differing discard characteristics, discards may lead to data divergence (old data or garbage left over on one backend, zeroes due to unmapped areas on the other backend). Online verify would now potentially report tons of spurious differences. While probably harmless for most use cases (fstrim on a file system), DRBD cannot have that, it would violate our promise to upper layers that our data instances on the nodes are identical. To be correct and play safe (make sure data is identical on both copies), we would have to disable discard support, if our local backend (on a Primary) does not support "discard_zeroes_data=true". We'd also have to translate discards to explicit zero-out on the receiving (typically: Secondary) side, unless the receiving side supports "discard_zeroes_data=true". Which both would allocate those blocks, instead of unmapping them, in contrast with expectations. LVM/DM thin does set discard_zeroes_data=0, because it silently ignores discards to partial chunks. We can work around this by checking the alignment first. For unaligned (wrt. alignment and granularity) or too small discards, we zero-out the initial (and/or) trailing unaligned partial chunks, but discard all the aligned full chunks. At least for LVM/DM thin, the result is effectively "discard_zeroes_data=1". Arguably it should behave this way internally, by default, and we'll try to make that happen. But our workaround is still valid for already deployed setups, and for other devices that may behave this way. Setting discard-zeroes-if-aligned=yes will allow DRBD to use discards, and to announce discard_zeroes_data=true, even on backends that announce discard_zeroes_data=false. Setting discard-zeroes-if-aligned=no will cause DRBD to always fall-back to zero-out on the receiving side, and to not even announce discard capabilities on the Primary, if the respective backend announces discard_zeroes_data=false. We used to ignore the discard_zeroes_data setting completely. To not break established and expected behaviour, and suddenly cause fstrim on thin-provisioned LVs to run out-of-space, instead of freeing up space, the default value is "yes". Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_nl.c | 15 ++-- drivers/block/drbd/drbd_receiver.c | 140 ++++++++++++++++++++++++++++++------- include/linux/drbd_genl.h | 1 + include/linux/drbd_limits.h | 6 ++ 5 files changed, 134 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 9e338ecca7dd..f49ff861bfd8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1488,7 +1488,7 @@ enum determine_dev_size { extern enum determine_dev_size drbd_determine_dev_size(struct drbd_device *, enum dds_flags, struct resize_parms *) __must_hold(local); extern void resync_after_online_grow(struct drbd_device *); -extern void drbd_reconsider_max_bio_size(struct drbd_device *device, struct drbd_backing_dev *bdev); +extern void drbd_reconsider_queue_parameters(struct drbd_device *device, struct drbd_backing_dev *bdev); extern enum drbd_state_rv drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 3643f9ca5a38..8d757d6f21e7 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1161,13 +1161,17 @@ static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backi unsigned int max_hw_sectors = max_bio_size >> 9; unsigned int max_segments = 0; struct request_queue *b = NULL; + struct disk_conf *dc; + bool discard_zeroes_if_aligned = true; if (bdev) { b = bdev->backing_bdev->bd_disk->queue; max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9); rcu_read_lock(); - max_segments = rcu_dereference(device->ldev->disk_conf)->max_bio_bvecs; + dc = rcu_dereference(device->ldev->disk_conf); + max_segments = dc->max_bio_bvecs; + discard_zeroes_if_aligned = dc->discard_zeroes_if_aligned; rcu_read_unlock(); blk_set_stacking_limits(&q->limits); @@ -1185,7 +1189,7 @@ static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backi blk_queue_max_discard_sectors(q, DRBD_MAX_DISCARD_SECTORS); - if (blk_queue_discard(b) && + if (blk_queue_discard(b) && (b->limits.discard_zeroes_data || discard_zeroes_if_aligned) && (connection->cstate < C_CONNECTED || connection->agreed_features & FF_TRIM)) { /* We don't care, stacking below should fix it for the local device. * Whether or not it is a suitable granularity on the remote device @@ -1216,7 +1220,7 @@ static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backi } } -void drbd_reconsider_max_bio_size(struct drbd_device *device, struct drbd_backing_dev *bdev) +void drbd_reconsider_queue_parameters(struct drbd_device *device, struct drbd_backing_dev *bdev) { unsigned int now, new, local, peer; @@ -1488,6 +1492,9 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) if (write_ordering_changed(old_disk_conf, new_disk_conf)) drbd_bump_write_ordering(device->resource, NULL, WO_BDEV_FLUSH); + if (old_disk_conf->discard_zeroes_if_aligned != new_disk_conf->discard_zeroes_if_aligned) + drbd_reconsider_queue_parameters(device, device->ldev); + drbd_md_sync(device); if (device->state.conn >= C_CONNECTED) { @@ -1866,7 +1873,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) device->read_cnt = 0; device->writ_cnt = 0; - drbd_reconsider_max_bio_size(device, device->ldev); + drbd_reconsider_queue_parameters(device, device->ldev); /* If I am currently not R_PRIMARY, * but meta data primary indicator is set, diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 15b2a0dab0e5..cb80fb406361 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1443,6 +1443,108 @@ void drbd_bump_write_ordering(struct drbd_resource *resource, struct drbd_backin drbd_info(resource, "Method to ensure write ordering: %s\n", write_ordering_str[resource->write_ordering]); } +/* + * We *may* ignore the discard-zeroes-data setting, if so configured. + * + * Assumption is that it "discard_zeroes_data=0" is only because the backend + * may ignore partial unaligned discards. + * + * LVM/DM thin as of at least + * LVM version: 2.02.115(2)-RHEL7 (2015-01-28) + * Library version: 1.02.93-RHEL7 (2015-01-28) + * Driver version: 4.29.0 + * still behaves this way. + * + * For unaligned (wrt. alignment and granularity) or too small discards, + * we zero-out the initial (and/or) trailing unaligned partial chunks, + * but discard all the aligned full chunks. + * + * At least for LVM/DM thin, the result is effectively "discard_zeroes_data=1". + */ +int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, unsigned int nr_sectors, bool discard) +{ + struct block_device *bdev = device->ldev->backing_bdev; + struct request_queue *q = bdev_get_queue(bdev); + sector_t tmp, nr; + unsigned int max_discard_sectors, granularity; + int alignment; + int err = 0; + + if (!discard) + goto zero_out; + + /* Zero-sector (unknown) and one-sector granularities are the same. */ + granularity = max(q->limits.discard_granularity >> 9, 1U); + alignment = (bdev_discard_alignment(bdev) >> 9) % granularity; + + max_discard_sectors = min(q->limits.max_discard_sectors, (1U << 22)); + max_discard_sectors -= max_discard_sectors % granularity; + if (unlikely(!max_discard_sectors)) + goto zero_out; + + if (nr_sectors < granularity) + goto zero_out; + + tmp = start; + if (sector_div(tmp, granularity) != alignment) { + if (nr_sectors < 2*granularity) + goto zero_out; + /* start + gran - (start + gran - align) % gran */ + tmp = start + granularity - alignment; + tmp = start + granularity - sector_div(tmp, granularity); + + nr = tmp - start; + err |= blkdev_issue_zeroout(bdev, start, nr, GFP_NOIO, 0); + nr_sectors -= nr; + start = tmp; + } + while (nr_sectors >= granularity) { + nr = min_t(sector_t, nr_sectors, max_discard_sectors); + err |= blkdev_issue_discard(bdev, start, nr, GFP_NOIO, 0); + nr_sectors -= nr; + start += nr; + } + zero_out: + if (nr_sectors) { + err |= blkdev_issue_zeroout(bdev, start, nr_sectors, GFP_NOIO, 0); + } + return err != 0; +} + +static bool can_do_reliable_discards(struct drbd_device *device) +{ + struct request_queue *q = bdev_get_queue(device->ldev->backing_bdev); + struct disk_conf *dc; + bool can_do; + + if (!blk_queue_discard(q)) + return false; + + if (q->limits.discard_zeroes_data) + return true; + + rcu_read_lock(); + dc = rcu_dereference(device->ldev->disk_conf); + can_do = dc->discard_zeroes_if_aligned; + rcu_read_unlock(); + return can_do; +} + +void drbd_issue_peer_discard(struct drbd_device *device, struct drbd_peer_request *peer_req) +{ + /* If the backend cannot discard, or does not guarantee + * read-back zeroes in discarded ranges, we fall back to + * zero-out. Unless configuration specifically requested + * otherwise. */ + if (!can_do_reliable_discards(device)) + peer_req->flags |= EE_IS_TRIM_USE_ZEROOUT; + + if (drbd_issue_discard_or_zero_out(device, peer_req->i.sector, + peer_req->i.size >> 9, !(peer_req->flags & EE_IS_TRIM_USE_ZEROOUT))) + peer_req->flags |= EE_WAS_ERROR; + drbd_endio_write_sec_final(peer_req); +} + /** * drbd_submit_peer_request() * @device: DRBD device. @@ -1474,7 +1576,13 @@ int drbd_submit_peer_request(struct drbd_device *device, unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT; int err = -ENOMEM; - if (peer_req->flags & EE_IS_TRIM_USE_ZEROOUT) { + /* TRIM/DISCARD: for now, always use the helper function + * blkdev_issue_zeroout(..., discard=true). + * It's synchronous, but it does the right thing wrt. bio splitting. + * Correctness first, performance later. Next step is to code an + * asynchronous variant of the same. + */ + if (peer_req->flags & EE_IS_TRIM) { /* wait for all pending IO completions, before we start * zeroing things out. */ conn_wait_active_ee_empty(peer_req->peer_device->connection); @@ -1491,19 +1599,10 @@ int drbd_submit_peer_request(struct drbd_device *device, spin_unlock_irq(&device->resource->req_lock); } - if (blkdev_issue_zeroout(device->ldev->backing_bdev, - sector, data_size >> 9, GFP_NOIO, false)) - peer_req->flags |= EE_WAS_ERROR; - drbd_endio_write_sec_final(peer_req); + drbd_issue_peer_discard(device, peer_req); return 0; } - /* Discards don't have any payload. - * But the scsi layer still expects a bio_vec it can use internally, - * see sd_setup_discard_cmnd() and blk_add_request_payload(). */ - if (peer_req->flags & EE_IS_TRIM) - nr_pages = 1; - /* In most cases, we will only need one bio. But in case the lower * level restrictions happen to be different at this offset on this * side than those of the sending peer, we may need to submit the @@ -1529,11 +1628,6 @@ next_bio: bios = bio; ++n_bios; - if (op == REQ_OP_DISCARD) { - bio->bi_iter.bi_size = data_size; - goto submit; - } - page_chain_for_each(page) { unsigned len = min_t(unsigned, data_size, PAGE_SIZE); if (!bio_add_page(bio, page, len, 0)) { @@ -1555,7 +1649,6 @@ next_bio: --nr_pages; } D_ASSERT(device, data_size == 0); -submit: D_ASSERT(device, page == NULL); atomic_set(&peer_req->pending_bios, n_bios); @@ -2424,10 +2517,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * op = wire_flags_to_bio_op(dp_flags); op_flags = wire_flags_to_bio_flags(dp_flags); if (pi->cmd == P_TRIM) { - struct request_queue *q = bdev_get_queue(device->ldev->backing_bdev); peer_req->flags |= EE_IS_TRIM; - if (!blk_queue_discard(q)) - peer_req->flags |= EE_IS_TRIM_USE_ZEROOUT; D_ASSERT(peer_device, peer_req->i.size > 0); D_ASSERT(peer_device, op == REQ_OP_DISCARD); D_ASSERT(peer_device, peer_req->pages == NULL); @@ -2498,7 +2588,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * * and we wait for all pending requests, respectively wait for * active_ee to become empty in drbd_submit_peer_request(); * better not add ourselves here. */ - if ((peer_req->flags & EE_IS_TRIM_USE_ZEROOUT) == 0) + if ((peer_req->flags & EE_IS_TRIM) == 0) list_add_tail(&peer_req->w.list, &device->active_ee); spin_unlock_irq(&device->resource->req_lock); @@ -3916,14 +4006,14 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info } device->peer_max_bio_size = be32_to_cpu(p->max_bio_size); - /* Leave drbd_reconsider_max_bio_size() before drbd_determine_dev_size(). + /* Leave drbd_reconsider_queue_parameters() before drbd_determine_dev_size(). In case we cleared the QUEUE_FLAG_DISCARD from our queue in - drbd_reconsider_max_bio_size(), we can be sure that after + drbd_reconsider_queue_parameters(), we can be sure that after drbd_determine_dev_size() no REQ_DISCARDs are in the queue. */ ddsf = be16_to_cpu(p->dds_flags); if (get_ldev(device)) { - drbd_reconsider_max_bio_size(device, device->ldev); + drbd_reconsider_queue_parameters(device, device->ldev); dd = drbd_determine_dev_size(device, ddsf, NULL); put_ldev(device); if (dd == DS_ERROR) @@ -3943,7 +4033,7 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info * However, if he sends a zero current size, * take his (user-capped or) backing disk size anyways. */ - drbd_reconsider_max_bio_size(device, NULL); + drbd_reconsider_queue_parameters(device, NULL); drbd_set_my_capacity(device, p_csize ?: p_usize ?: p_size); } diff --git a/include/linux/drbd_genl.h b/include/linux/drbd_genl.h index ab649d8e9ed2..c934d3a96b5e 100644 --- a/include/linux/drbd_genl.h +++ b/include/linux/drbd_genl.h @@ -132,6 +132,7 @@ GENL_struct(DRBD_NLA_DISK_CONF, 3, disk_conf, __flg_field_def(18, DRBD_GENLA_F_MANDATORY, disk_drain, DRBD_DISK_DRAIN_DEF) __flg_field_def(19, DRBD_GENLA_F_MANDATORY, md_flushes, DRBD_MD_FLUSHES_DEF) __flg_field_def(23, 0 /* OPTIONAL */, al_updates, DRBD_AL_UPDATES_DEF) + __flg_field_def(24, 0 /* OPTIONAL */, discard_zeroes_if_aligned, DRBD_DISCARD_ZEROES_IF_ALIGNED) ) GENL_struct(DRBD_NLA_RESOURCE_OPTS, 4, res_opts, diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h index 2e4aad8d8ae8..a351c40087cd 100644 --- a/include/linux/drbd_limits.h +++ b/include/linux/drbd_limits.h @@ -210,6 +210,12 @@ #define DRBD_MD_FLUSHES_DEF 1 #define DRBD_TCP_CORK_DEF 1 #define DRBD_AL_UPDATES_DEF 1 +/* We used to ignore the discard_zeroes_data setting. + * To not change established (and expected) behaviour, + * by default assume that, for discard_zeroes_data=0, + * we can make that an effective discard_zeroes_data=1, + * if we only explicitly zero-out unaligned partial chunks. */ +#define DRBD_DISCARD_ZEROES_IF_ALIGNED 1 #define DRBD_ALLOW_TWO_PRIMARIES_DEF 0 #define DRBD_ALWAYS_ASBP_DEF 0 -- cgit v1.2.3 From 505675f96cf0f169647a18c3dda1f373eca957b1 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 14 Jun 2016 00:26:23 +0200 Subject: drbd: allow larger max_discard_sectors Make sure we have at least 67 (> AL_UPDATES_PER_TRANSACTION) al-extents available, and allow up to half of that to be discarded in one bio. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_actlog.c | 2 +- drivers/block/drbd/drbd_int.h | 8 ++++---- include/linux/drbd_limits.h | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index d524973f94b3..265b2b6ebdec 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -258,7 +258,7 @@ bool drbd_al_begin_io_fastpath(struct drbd_device *device, struct drbd_interval unsigned first = i->sector >> (AL_EXTENT_SHIFT-9); unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9); - D_ASSERT(device, (unsigned)(last - first) <= 1); + D_ASSERT(device, first <= last); D_ASSERT(device, atomic_read(&device->local_cnt) > 0); /* FIXME figure out a fast path for bios crossing AL extent boundaries */ diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 0b5a658882b2..9c68ec54a247 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1347,10 +1347,10 @@ struct bm_extent { #define DRBD_MAX_SIZE_H80_PACKET (1U << 15) /* Header 80 only allows packets up to 32KiB data */ #define DRBD_MAX_BIO_SIZE_P95 (1U << 17) /* Protocol 95 to 99 allows bios up to 128KiB */ -/* For now, don't allow more than one activity log extent worth of data - * to be discarded in one go. We may need to rework drbd_al_begin_io() - * to allow for even larger discard ranges */ -#define DRBD_MAX_DISCARD_SIZE AL_EXTENT_SIZE +/* For now, don't allow more than half of what we can "activate" in one + * activity log transaction to be discarded in one go. We may need to rework + * drbd_al_begin_io() to allow for even larger discard ranges */ +#define DRBD_MAX_DISCARD_SIZE (AL_UPDATES_PER_TRANSACTION/2*AL_EXTENT_SIZE) #define DRBD_MAX_DISCARD_SECTORS (DRBD_MAX_DISCARD_SIZE >> 9) extern int drbd_bm_init(struct drbd_device *device); diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h index a351c40087cd..ddac68422a96 100644 --- a/include/linux/drbd_limits.h +++ b/include/linux/drbd_limits.h @@ -126,8 +126,7 @@ #define DRBD_RESYNC_RATE_DEF 250 #define DRBD_RESYNC_RATE_SCALE 'k' /* kilobytes */ - /* less than 7 would hit performance unnecessarily. */ -#define DRBD_AL_EXTENTS_MIN 7 +#define DRBD_AL_EXTENTS_MIN 67 /* we use u16 as "slot number", (u16)~0 is "FREE". * If you use >= 292 kB on-disk ring buffer, * this is the maximum you can use: */ -- cgit v1.2.3 From 7e5fec31685a5c69b81e9005eaed44318880d881 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 14 Jun 2016 00:26:35 +0200 Subject: drbd: code cleanups without semantic changes This contains various cosmetic fixes ranging from simple typos to const-ifying, and using booleans properly. Original commit messages from Fabian's patch set: drbd: debugfs: constify drbd_version_fops drbd: use seq_put instead of seq_print where possible drbd: include linux/uaccess.h instead of asm/uaccess.h drbd: use const char * const for drbd strings drbd: kerneldoc warning fix in w_e_end_data_req() drbd: use unsigned for one bit fields drbd: use bool for peer is_ states drbd: fix typo drbd: use | for bitmask combination drbd: use true/false for bool drbd: fix drbd_bm_init() comments drbd: introduce peer state union drbd: fix maybe_pull_ahead() locking comments drbd: use bool for growing drbd: remove redundant declarations drbd: replace if/BUG by BUG_ON Signed-off-by: Fabian Frederick Signed-off-by: Roland Kammerer Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_bitmap.c | 6 +++--- drivers/block/drbd/drbd_debugfs.c | 2 +- drivers/block/drbd/drbd_int.h | 4 +--- drivers/block/drbd/drbd_interval.h | 14 +++++++------- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_nl.c | 14 ++++++++------ drivers/block/drbd/drbd_proc.c | 30 +++++++++++++++--------------- drivers/block/drbd/drbd_receiver.c | 8 ++++---- drivers/block/drbd/drbd_req.c | 2 +- drivers/block/drbd/drbd_state.c | 4 +--- drivers/block/drbd/drbd_state.h | 2 +- drivers/block/drbd/drbd_strings.c | 8 ++++---- drivers/block/drbd/drbd_worker.c | 9 ++++----- include/linux/drbd.h | 8 ++++++++ 14 files changed, 59 insertions(+), 54 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index e5d89f623b90..095625beaf98 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -427,8 +427,7 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) } /* - * called on driver init only. TODO call when a device is created. - * allocates the drbd_bitmap, and stores it in device->bitmap. + * allocates the drbd_bitmap and stores it in device->bitmap. */ int drbd_bm_init(struct drbd_device *device) { @@ -633,7 +632,8 @@ int drbd_bm_resize(struct drbd_device *device, sector_t capacity, int set_new_bi unsigned long bits, words, owords, obits; unsigned long want, have, onpages; /* number of pages */ struct page **npages, **opages = NULL; - int err = 0, growing; + int err = 0; + bool growing; if (!expect(b)) return -ENOMEM; diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index 8a9081236f92..be91a8d7c22a 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c @@ -903,7 +903,7 @@ static int drbd_version_open(struct inode *inode, struct file *file) return single_open(file, drbd_version_show, NULL); } -static struct file_operations drbd_version_fops = { +static const struct file_operations drbd_version_fops = { .owner = THIS_MODULE, .open = drbd_version_open, .llseek = seq_lseek, diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 995aa8d25660..2c9194dc2ec2 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1499,7 +1499,7 @@ extern enum drbd_state_rv drbd_set_role(struct drbd_device *device, int force); extern bool conn_try_outdate_peer(struct drbd_connection *connection); extern void conn_try_outdate_peer_async(struct drbd_connection *connection); -extern int conn_khelper(struct drbd_connection *connection, char *cmd); +extern enum drbd_peer_state conn_khelper(struct drbd_connection *connection, char *cmd); extern int drbd_khelper(struct drbd_device *device, char *cmd); /* drbd_worker.c */ @@ -1648,8 +1648,6 @@ void drbd_bump_write_ordering(struct drbd_resource *resource, struct drbd_backin /* drbd_proc.c */ extern struct proc_dir_entry *drbd_proc; extern const struct file_operations drbd_proc_fops; -extern const char *drbd_conn_str(enum drbd_conns s); -extern const char *drbd_role_str(enum drbd_role s); /* drbd_actlog.c */ extern bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *i); diff --git a/drivers/block/drbd/drbd_interval.h b/drivers/block/drbd/drbd_interval.h index f210543f05f4..23c5a94428d2 100644 --- a/drivers/block/drbd/drbd_interval.h +++ b/drivers/block/drbd/drbd_interval.h @@ -6,13 +6,13 @@ struct drbd_interval { struct rb_node rb; - sector_t sector; /* start sector of the interval */ - unsigned int size; /* size in bytes */ - sector_t end; /* highest interval end in subtree */ - int local:1 /* local or remote request? */; - int waiting:1; /* someone is waiting for this to complete */ - int completed:1; /* this has been completed already; - * ignore for conflict detection */ + sector_t sector; /* start sector of the interval */ + unsigned int size; /* size in bytes */ + sector_t end; /* highest interval end in subtree */ + unsigned int local:1 /* local or remote request? */; + unsigned int waiting:1; /* someone is waiting for completion */ + unsigned int completed:1; /* this has been completed already; + * ignore for conflict detection */ }; static inline void drbd_clear_interval(struct drbd_interval *i) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f4ea8d6c50d3..0501ae0c517b 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 9a45c80239ba..f35db29cac76 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -387,7 +387,7 @@ int drbd_khelper(struct drbd_device *device, char *cmd) return ret; } -int conn_khelper(struct drbd_connection *connection, char *cmd) +enum drbd_peer_state conn_khelper(struct drbd_connection *connection, char *cmd) { char *envp[] = { "HOME=/", "TERM=linux", @@ -503,17 +503,17 @@ bool conn_try_outdate_peer(struct drbd_connection *connection) r = conn_khelper(connection, "fence-peer"); switch ((r>>8) & 0xff) { - case 3: /* peer is inconsistent */ + case P_INCONSISTENT: /* peer is inconsistent */ ex_to_string = "peer is inconsistent or worse"; mask.pdsk = D_MASK; val.pdsk = D_INCONSISTENT; break; - case 4: /* peer got outdated, or was already outdated */ + case P_OUTDATED: /* peer got outdated, or was already outdated */ ex_to_string = "peer was fenced"; mask.pdsk = D_MASK; val.pdsk = D_OUTDATED; break; - case 5: /* peer was down */ + case P_DOWN: /* peer was down */ if (conn_highest_disk(connection) == D_UP_TO_DATE) { /* we will(have) create(d) a new UUID anyways... */ ex_to_string = "peer is unreachable, assumed to be dead"; @@ -523,7 +523,7 @@ bool conn_try_outdate_peer(struct drbd_connection *connection) ex_to_string = "peer unreachable, doing nothing since disk != UpToDate"; } break; - case 6: /* Peer is primary, voluntarily outdate myself. + case P_PRIMARY: /* Peer is primary, voluntarily outdate myself. * This is useful when an unconnected R_SECONDARY is asked to * become R_PRIMARY, but finds the other peer being active. */ ex_to_string = "peer is active"; @@ -531,7 +531,9 @@ bool conn_try_outdate_peer(struct drbd_connection *connection) mask.disk = D_MASK; val.disk = D_OUTDATED; break; - case 7: + case P_FENCING: + /* THINK: do we need to handle this + * like case 4, or more like case 5? */ if (fp != FP_STONITH) drbd_err(connection, "fence-peer() = 7 && fencing != Stonith !!!\n"); ex_to_string = "peer was stonithed"; diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 6537b25db9c1..be2b93fd2c11 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -25,7 +25,7 @@ #include -#include +#include #include #include #include @@ -122,18 +122,18 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se x = res/50; y = 20-x; - seq_printf(seq, "\t["); + seq_puts(seq, "\t["); for (i = 1; i < x; i++) - seq_printf(seq, "="); - seq_printf(seq, ">"); + seq_putc(seq, '='); + seq_putc(seq, '>'); for (i = 0; i < y; i++) seq_printf(seq, "."); - seq_printf(seq, "] "); + seq_puts(seq, "] "); if (state.conn == C_VERIFY_S || state.conn == C_VERIFY_T) - seq_printf(seq, "verified:"); + seq_puts(seq, "verified:"); else - seq_printf(seq, "sync'ed:"); + seq_puts(seq, "sync'ed:"); seq_printf(seq, "%3u.%u%% ", res / 10, res % 10); /* if more than a few GB, display in MB */ @@ -146,7 +146,7 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se (unsigned long) Bit2KB(rs_left), (unsigned long) Bit2KB(rs_total)); - seq_printf(seq, "\n\t"); + seq_puts(seq, "\n\t"); /* see drivers/md/md.c * We do not want to overflow, so the order of operands and @@ -175,9 +175,9 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se rt / 3600, (rt % 3600) / 60, rt % 60); dbdt = Bit2KB(db/dt); - seq_printf(seq, " speed: "); + seq_puts(seq, " speed: "); seq_printf_with_thousands_grouping(seq, dbdt); - seq_printf(seq, " ("); + seq_puts(seq, " ("); /* ------------------------- ~3s average ------------------------ */ if (proc_details >= 1) { /* this is what drbd_rs_should_slow_down() uses */ @@ -188,7 +188,7 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se db = device->rs_mark_left[i] - rs_left; dbdt = Bit2KB(db/dt); seq_printf_with_thousands_grouping(seq, dbdt); - seq_printf(seq, " -- "); + seq_puts(seq, " -- "); } /* --------------------- long term average ---------------------- */ @@ -200,11 +200,11 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se db = rs_total - rs_left; dbdt = Bit2KB(db/dt); seq_printf_with_thousands_grouping(seq, dbdt); - seq_printf(seq, ")"); + seq_putc(seq, ')'); if (state.conn == C_SYNC_TARGET || state.conn == C_VERIFY_S) { - seq_printf(seq, " want: "); + seq_puts(seq, " want: "); seq_printf_with_thousands_grouping(seq, device->c_sync_rate); } seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : ""); @@ -231,7 +231,7 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se (unsigned long long)bm_bits * BM_SECT_PER_BIT); if (stop_sector != 0 && stop_sector != ULLONG_MAX) seq_printf(seq, " stop sector: %llu", stop_sector); - seq_printf(seq, "\n"); + seq_putc(seq, '\n'); } } @@ -276,7 +276,7 @@ static int drbd_seq_show(struct seq_file *seq, void *v) rcu_read_lock(); idr_for_each_entry(&drbd_devices, device, i) { if (prev_i != i - 1) - seq_printf(seq, "\n"); + seq_putc(seq, '\n'); prev_i = i; state = device->state; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 577a1872da48..0d74602feca0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -25,7 +25,7 @@ #include -#include +#include #include #include @@ -2289,13 +2289,13 @@ static inline int overlaps(sector_t s1, int l1, sector_t s2, int l2) static bool overlapping_resync_write(struct drbd_device *device, struct drbd_peer_request *peer_req) { struct drbd_peer_request *rs_req; - bool rv = 0; + bool rv = false; spin_lock_irq(&device->resource->req_lock); list_for_each_entry(rs_req, &device->sync_ee, w.list) { if (overlaps(peer_req->i.sector, peer_req->i.size, rs_req->i.sector, rs_req->i.size)) { - rv = 1; + rv = true; break; } } @@ -2678,7 +2678,7 @@ static int receive_Data(struct drbd_connection *connection, struct packet_info * } out_interrupted: - drbd_may_finish_epoch(connection, peer_req->epoch, EV_PUT + EV_CLEANUP); + drbd_may_finish_epoch(connection, peer_req->epoch, EV_PUT | EV_CLEANUP); put_ldev(device); drbd_free_peer_req(device, peer_req); return err; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index a8994875d52b..787536a0ee7c 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1000,7 +1000,7 @@ static void complete_conflicting_writes(struct drbd_request *req) finish_wait(&device->misc_wait, &wait); } -/* called within req_lock and rcu_read_lock() */ +/* called within req_lock */ static void maybe_pull_ahead(struct drbd_device *device) { struct drbd_connection *connection = first_peer_device(device)->connection; diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index a1b5e6c91106..aca68a581b06 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -2196,9 +2196,7 @@ conn_set_state(struct drbd_connection *connection, union drbd_state mask, union ns.disk = os.disk; rv = _drbd_set_state(device, ns, flags, NULL); - if (rv < SS_SUCCESS) - BUG(); - + BUG_ON(rv < SS_SUCCESS); ns.i = device->state.i; ns_max.role = max_role(ns.role, ns_max.role); ns_max.peer = max_role(ns.peer, ns_max.peer); diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h index bd989536f888..6c9d5d4a8a75 100644 --- a/drivers/block/drbd/drbd_state.h +++ b/drivers/block/drbd/drbd_state.h @@ -140,7 +140,7 @@ extern void drbd_resume_al(struct drbd_device *device); extern bool conn_all_vols_unconf(struct drbd_connection *connection); /** - * drbd_request_state() - Reqest a state change + * drbd_request_state() - Request a state change * @device: DRBD device. * @mask: mask of state bits to change. * @val: value of new state bits. diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c index 80b0f63c7075..0eeab14776e9 100644 --- a/drivers/block/drbd/drbd_strings.c +++ b/drivers/block/drbd/drbd_strings.c @@ -26,7 +26,7 @@ #include #include "drbd_strings.h" -static const char *drbd_conn_s_names[] = { +static const char * const drbd_conn_s_names[] = { [C_STANDALONE] = "StandAlone", [C_DISCONNECTING] = "Disconnecting", [C_UNCONNECTED] = "Unconnected", @@ -53,13 +53,13 @@ static const char *drbd_conn_s_names[] = { [C_BEHIND] = "Behind", }; -static const char *drbd_role_s_names[] = { +static const char * const drbd_role_s_names[] = { [R_PRIMARY] = "Primary", [R_SECONDARY] = "Secondary", [R_UNKNOWN] = "Unknown" }; -static const char *drbd_disk_s_names[] = { +static const char * const drbd_disk_s_names[] = { [D_DISKLESS] = "Diskless", [D_ATTACHING] = "Attaching", [D_FAILED] = "Failed", @@ -71,7 +71,7 @@ static const char *drbd_disk_s_names[] = { [D_UP_TO_DATE] = "UpToDate", }; -static const char *drbd_state_sw_errors[] = { +static const char * const drbd_state_sw_errors[] = { [-SS_TWO_PRIMARIES] = "Multiple primaries not allowed by config", [-SS_NO_UP_TO_DATE_DISK] = "Need access to UpToDate data", [-SS_NO_LOCAL_DISK] = "Can not resync without local disk", diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 364fed1e2100..b3fa5575bc0e 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -173,8 +173,8 @@ void drbd_peer_request_endio(struct bio *bio) { struct drbd_peer_request *peer_req = bio->bi_private; struct drbd_device *device = peer_req->peer_device->device; - int is_write = bio_data_dir(bio) == WRITE; - int is_discard = !!(bio_op(bio) == REQ_OP_DISCARD); + bool is_write = bio_data_dir(bio) == WRITE; + bool is_discard = !!(bio_op(bio) == REQ_OP_DISCARD); if (bio->bi_error && __ratelimit(&drbd_ratelimit_state)) drbd_warn(device, "%s: error=%d s=%llus\n", @@ -1039,7 +1039,6 @@ static void move_to_net_ee_or_free(struct drbd_device *device, struct drbd_peer_ /** * w_e_end_data_req() - Worker callback, to send a P_DATA_REPLY packet in response to a P_DATA_REQUEST - * @device: DRBD device. * @w: work object. * @cancel: The connection will be closed anyways */ @@ -1700,7 +1699,7 @@ static bool use_checksum_based_resync(struct drbd_connection *connection, struct rcu_read_unlock(); return connection->agreed_pro_version >= 89 && /* supported? */ connection->csums_tfm && /* configured? */ - (csums_after_crash_only == 0 /* use for each resync? */ + (csums_after_crash_only == false /* use for each resync? */ || test_bit(CRASHED_PRIMARY, &device->flags)); /* or only after Primary crash? */ } @@ -1835,7 +1834,7 @@ void drbd_start_resync(struct drbd_device *device, enum drbd_conns side) device->bm_resync_fo = 0; device->use_csums = use_checksum_based_resync(connection, device); } else { - device->use_csums = 0; + device->use_csums = false; } /* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid diff --git a/include/linux/drbd.h b/include/linux/drbd.h index d6b3c9943a2c..2b26156365ec 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -370,6 +370,14 @@ enum drbd_notification_type { NOTIFY_FLAGS = NOTIFY_CONTINUES, }; +enum drbd_peer_state { + P_INCONSISTENT = 3, + P_OUTDATED = 4, + P_DOWN = 5, + P_PRIMARY = 6, + P_FENCING = 7, +}; + #define UUID_JUST_CREATED ((__u64)4) enum write_ordering_e { -- cgit v1.2.3 From 1b57e66384e2d21150301e68078526fac5680a16 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 14 Jun 2016 00:26:39 +0200 Subject: drbd: correctly handle failed crypto_alloc_hash crypto_alloc_hash returns an ERR_PTR(), not NULL. Also reset peer_integrity_tfm to NULL, to not call crypto_free_hash() on an errno in the cleanup path. Reported-by: Insu Yun Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_receiver.c | 3 ++- include/linux/drbd.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 0d74602feca0..df45713dfbe8 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3681,7 +3681,8 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in */ peer_integrity_tfm = crypto_alloc_ahash(integrity_alg, 0, CRYPTO_ALG_ASYNC); - if (!peer_integrity_tfm) { + if (IS_ERR(peer_integrity_tfm)) { + peer_integrity_tfm = NULL; drbd_err(connection, "peer data-integrity-alg %s not supported\n", integrity_alg); goto disconnect; diff --git a/include/linux/drbd.h b/include/linux/drbd.h index 2b26156365ec..002611c85318 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -51,7 +51,7 @@ #endif extern const char *drbd_buildtag(void); -#define REL_VERSION "8.4.6" +#define REL_VERSION "8.4.7" #define API_VERSION 1 #define PRO_VERSION_MIN 86 #define PRO_VERSION_MAX 101 -- cgit v1.2.3 From 2c95afc1e83d93fac3be6923465e1753c2c53b0a Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 9 Jun 2016 06:14:38 -0700 Subject: perf/x86/intel, watchdog: Switch NMI watchdog to ref cycles on x86 The NMI watchdog uses either the fixed cycles or a generic cycles counter. This causes a lot of conflicts with users of the PMU who want to run a full group including the cycles fixed counter, for example the --topdown support recently added to perf stat. The code needs to fall back to not use groups, which can cause measurement inaccuracy due to multiplexing errors. This patch switches the NMI watchdog to use reference cycles on Intel systems. This is actually more accurate than cycles, because cycles can tick faster than the measured CPU Frequency due to Turbo mode. The ref cycles always tick at their frequency, or slower when the system is idling. That means the NMI watchdog can never expire too early, unlike with cycles. The reference cycles tick roughly at the frequency of the TSC, so the same period computation can be used. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: jolsa@kernel.org Link: http://lkml.kernel.org/r/1465478079-19993-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/hw_nmi.c | 8 ++++++++ include/linux/nmi.h | 1 + kernel/watchdog.c | 7 +++++++ 3 files changed, 16 insertions(+) (limited to 'include/linux') diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 7788ce643bf4..016f4263fad4 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -18,8 +18,16 @@ #include #include #include +#include #ifdef CONFIG_HARDLOCKUP_DETECTOR +int hw_nmi_get_event(void) +{ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + return PERF_COUNT_HW_REF_CPU_CYCLES; + return PERF_COUNT_HW_CPU_CYCLES; +} + u64 hw_nmi_get_sample_period(int watchdog_thresh) { return (u64)(cpu_khz) * 1000 * watchdog_thresh; diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 4630eeae18e0..79858af27209 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -66,6 +66,7 @@ static inline bool trigger_allbutself_cpu_backtrace(void) #ifdef CONFIG_LOCKUP_DETECTOR u64 hw_nmi_get_sample_period(int watchdog_thresh); +int hw_nmi_get_event(void); extern int nmi_watchdog_enabled; extern int soft_watchdog_enabled; extern int watchdog_user_enabled; diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 9acb29f280ec..8dd30fcd91be 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -315,6 +315,12 @@ static int is_softlockup(unsigned long touch_ts) #ifdef CONFIG_HARDLOCKUP_DETECTOR +/* Can be overriden by architecture */ +__weak int hw_nmi_get_event(void) +{ + return PERF_COUNT_HW_CPU_CYCLES; +} + static struct perf_event_attr wd_hw_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, @@ -604,6 +610,7 @@ static int watchdog_nmi_enable(unsigned int cpu) wd_attr = &wd_hw_attr; wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh); + wd_attr->config = hw_nmi_get_event(); /* Try to register using hardware perf events */ event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); -- cgit v1.2.3 From 1f03e8d2919270bd6ef64f39a45ce8df8a9f012a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 4 Apr 2016 10:57:12 +0200 Subject: locking/barriers: Replace smp_cond_acquire() with smp_cond_load_acquire() This new form allows using hardware assisted waiting. Some hardware (ARM64 and x86) allow monitoring an address for changes, so by providing a pointer we can use this to replace the cpu_relax() with hardware optimized methods in the future. Requested-by: Will Deacon Suggested-by: Linus Torvalds Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Signed-off-by: Ingo Molnar --- include/linux/compiler.h | 25 +++++++++++++++++++------ kernel/locking/qspinlock.c | 12 ++++++------ kernel/sched/core.c | 8 ++++---- kernel/sched/sched.h | 2 +- kernel/smp.c | 2 +- 5 files changed, 31 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 06f27fd9d760..2bcaedc0f032 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -305,21 +305,34 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s }) /** - * smp_cond_acquire() - Spin wait for cond with ACQUIRE ordering + * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering + * @ptr: pointer to the variable to wait on * @cond: boolean expression to wait for * * Equivalent to using smp_load_acquire() on the condition variable but employs * the control dependency of the wait to reduce the barrier on many platforms. * + * Due to C lacking lambda expressions we load the value of *ptr into a + * pre-named variable @VAL to be used in @cond. + * * The control dependency provides a LOAD->STORE order, the additional RMB * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, * aka. ACQUIRE. */ -#define smp_cond_acquire(cond) do { \ - while (!(cond)) \ - cpu_relax(); \ - smp_rmb(); /* ctrl + rmb := acquire */ \ -} while (0) +#ifndef smp_cond_load_acquire +#define smp_cond_load_acquire(ptr, cond_expr) ({ \ + typeof(ptr) __PTR = (ptr); \ + typeof(*ptr) VAL; \ + for (;;) { \ + VAL = READ_ONCE(*__PTR); \ + if (cond_expr) \ + break; \ + cpu_relax(); \ + } \ + smp_rmb(); /* ctrl + rmb := acquire */ \ + VAL; \ +}) +#endif #endif /* __KERNEL__ */ diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index 2f9153b183c9..1b8dda90ebfa 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c @@ -475,7 +475,7 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) * sequentiality; this is because not all clear_pending_set_locked() * implementations imply full barriers. */ - smp_cond_acquire(!(atomic_read(&lock->val) & _Q_LOCKED_MASK)); + smp_cond_load_acquire(&lock->val.counter, !(VAL & _Q_LOCKED_MASK)); /* * take ownership and clear the pending bit. @@ -562,7 +562,7 @@ queue: * * The PV pv_wait_head_or_lock function, if active, will acquire * the lock and return a non-zero value. So we have to skip the - * smp_cond_acquire() call. As the next PV queue head hasn't been + * smp_cond_load_acquire() call. As the next PV queue head hasn't been * designated yet, there is no way for the locked value to become * _Q_SLOW_VAL. So both the set_locked() and the * atomic_cmpxchg_relaxed() calls will be safe. @@ -573,7 +573,7 @@ queue: if ((val = pv_wait_head_or_lock(lock, node))) goto locked; - smp_cond_acquire(!((val = atomic_read(&lock->val)) & _Q_LOCKED_PENDING_MASK)); + val = smp_cond_load_acquire(&lock->val.counter, !(VAL & _Q_LOCKED_PENDING_MASK)); locked: /* @@ -593,9 +593,9 @@ locked: break; } /* - * The smp_cond_acquire() call above has provided the necessary - * acquire semantics required for locking. At most two - * iterations of this loop may be ran. + * The smp_cond_load_acquire() call above has provided the + * necessary acquire semantics required for locking. At most + * two iterations of this loop may be ran. */ old = atomic_cmpxchg_relaxed(&lock->val, val, _Q_LOCKED_VAL); if (old == val) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 017d5394f5dc..5cd6931cb2cb 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1935,7 +1935,7 @@ static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) * chain to provide order. Instead we do: * * 1) smp_store_release(X->on_cpu, 0) - * 2) smp_cond_acquire(!X->on_cpu) + * 2) smp_cond_load_acquire(!X->on_cpu) * * Example: * @@ -1946,7 +1946,7 @@ static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) * sched-out X * smp_store_release(X->on_cpu, 0); * - * smp_cond_acquire(!X->on_cpu); + * smp_cond_load_acquire(&X->on_cpu, !VAL); * X->state = WAKING * set_task_cpu(X,2) * @@ -1972,7 +1972,7 @@ static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) * This means that any means of doing remote wakeups must order the CPU doing * the wakeup against the CPU the task is going to end up running on. This, * however, is already required for the regular Program-Order guarantee above, - * since the waking CPU is the one issueing the ACQUIRE (smp_cond_acquire). + * since the waking CPU is the one issueing the ACQUIRE (smp_cond_load_acquire). * */ @@ -2045,7 +2045,7 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) * This ensures that tasks getting woken will be fully ordered against * their previous state and preserve Program Order. */ - smp_cond_acquire(!p->on_cpu); + smp_cond_load_acquire(&p->on_cpu, !VAL); p->sched_contributes_to_load = !!task_contributes_to_load(p); p->state = TASK_WAKING; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 72f1f3087b04..425bf5ddaa5a 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1113,7 +1113,7 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) * In particular, the load of prev->state in finish_task_switch() must * happen before this. * - * Pairs with the smp_cond_acquire() in try_to_wake_up(). + * Pairs with the smp_cond_load_acquire() in try_to_wake_up(). */ smp_store_release(&prev->on_cpu, 0); #endif diff --git a/kernel/smp.c b/kernel/smp.c index 74165443c240..36552beed397 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -107,7 +107,7 @@ void __init call_function_init(void) */ static __always_inline void csd_lock_wait(struct call_single_data *csd) { - smp_cond_acquire(!(csd->flags & CSD_FLAG_LOCK)); + smp_cond_load_acquire(&csd->flags, !(VAL & CSD_FLAG_LOCK)); } static __always_inline void csd_lock(struct call_single_data *csd) -- cgit v1.2.3 From 33ac279677dcc2441cb93d8cb9cf7a74df62814d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 24 May 2016 13:17:12 +0200 Subject: locking/barriers: Introduce smp_acquire__after_ctrl_dep() Introduce smp_acquire__after_ctrl_dep(), this construct is not uncommon, but the lack of this barrier is. Use it to better express smp_rmb() uses in WRITE_ONCE(), the IPC semaphore code and the qspinlock code. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- include/linux/compiler.h | 17 ++++++++++++----- ipc/sem.c | 14 ++------------ kernel/locking/qspinlock.c | 2 +- 3 files changed, 15 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 2bcaedc0f032..59a7004fc7dd 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -304,6 +304,17 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s __u.__val; \ }) +/** + * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency + * + * A control dependency provides a LOAD->STORE order, the additional RMB + * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, + * aka. (load)-ACQUIRE. + * + * Architectures that do not do load speculation can have this be barrier(). + */ +#define smp_acquire__after_ctrl_dep() smp_rmb() + /** * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering * @ptr: pointer to the variable to wait on @@ -314,10 +325,6 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s * * Due to C lacking lambda expressions we load the value of *ptr into a * pre-named variable @VAL to be used in @cond. - * - * The control dependency provides a LOAD->STORE order, the additional RMB - * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, - * aka. ACQUIRE. */ #ifndef smp_cond_load_acquire #define smp_cond_load_acquire(ptr, cond_expr) ({ \ @@ -329,7 +336,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s break; \ cpu_relax(); \ } \ - smp_rmb(); /* ctrl + rmb := acquire */ \ + smp_acquire__after_ctrl_dep(); \ VAL; \ }) #endif diff --git a/ipc/sem.c b/ipc/sem.c index b3757ea0694b..84dff3df11a4 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -259,16 +259,6 @@ static void sem_rcu_free(struct rcu_head *head) ipc_rcu_free(head); } -/* - * spin_unlock_wait() and !spin_is_locked() are not memory barriers, they - * are only control barriers. - * The code must pair with spin_unlock(&sem->lock) or - * spin_unlock(&sem_perm.lock), thus just the control barrier is insufficient. - * - * smp_rmb() is sufficient, as writes cannot pass the control barrier. - */ -#define ipc_smp_acquire__after_spin_is_unlocked() smp_rmb() - /* * Wait until all currently ongoing simple ops have completed. * Caller must own sem_perm.lock. @@ -292,7 +282,7 @@ static void sem_wait_array(struct sem_array *sma) sem = sma->sem_base + i; spin_unlock_wait(&sem->lock); } - ipc_smp_acquire__after_spin_is_unlocked(); + smp_acquire__after_ctrl_dep(); } /* @@ -350,7 +340,7 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops, * complex_count++; * spin_unlock(sem_perm.lock); */ - ipc_smp_acquire__after_spin_is_unlocked(); + smp_acquire__after_ctrl_dep(); /* * Now repeat the test of complex_count: diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index 1b8dda90ebfa..730655533440 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c @@ -379,7 +379,7 @@ void queued_spin_unlock_wait(struct qspinlock *lock) cpu_relax(); done: - smp_rmb(); /* CTRL + RMB -> ACQUIRE */ + smp_acquire__after_ctrl_dep(); } EXPORT_SYMBOL(queued_spin_unlock_wait); #endif -- cgit v1.2.3 From 7cb45c0fe9858f92cc264f6bf9d2f6a0e7d3b249 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 1 Jun 2016 19:23:54 +0200 Subject: locking/barriers: Move smp_cond_load_acquire() to asm-generic/barrier.h Since all asm/barrier.h should/must include asm-generic/barrier.h the latter is a good place for generic infrastructure like this. This also allows archs to override the new smp_acquire__after_ctrl_dep(). Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Signed-off-by: Ingo Molnar --- include/asm-generic/barrier.h | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/compiler.h | 37 ------------------------------------- 2 files changed, 39 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h index 1cceca146905..ab7b0bd7d4dd 100644 --- a/include/asm-generic/barrier.h +++ b/include/asm-generic/barrier.h @@ -207,5 +207,44 @@ do { \ #define virt_store_release(p, v) __smp_store_release(p, v) #define virt_load_acquire(p) __smp_load_acquire(p) +/** + * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency + * + * A control dependency provides a LOAD->STORE order, the additional RMB + * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, + * aka. (load)-ACQUIRE. + * + * Architectures that do not do load speculation can have this be barrier(). + */ +#ifndef smp_acquire__after_ctrl_dep +#define smp_acquire__after_ctrl_dep() smp_rmb() +#endif + +/** + * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering + * @ptr: pointer to the variable to wait on + * @cond: boolean expression to wait for + * + * Equivalent to using smp_load_acquire() on the condition variable but employs + * the control dependency of the wait to reduce the barrier on many platforms. + * + * Due to C lacking lambda expressions we load the value of *ptr into a + * pre-named variable @VAL to be used in @cond. + */ +#ifndef smp_cond_load_acquire +#define smp_cond_load_acquire(ptr, cond_expr) ({ \ + typeof(ptr) __PTR = (ptr); \ + typeof(*ptr) VAL; \ + for (;;) { \ + VAL = READ_ONCE(*__PTR); \ + if (cond_expr) \ + break; \ + cpu_relax(); \ + } \ + smp_acquire__after_ctrl_dep(); \ + VAL; \ +}) +#endif + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_GENERIC_BARRIER_H */ diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 59a7004fc7dd..2e853b679a5d 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -304,43 +304,6 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s __u.__val; \ }) -/** - * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency - * - * A control dependency provides a LOAD->STORE order, the additional RMB - * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, - * aka. (load)-ACQUIRE. - * - * Architectures that do not do load speculation can have this be barrier(). - */ -#define smp_acquire__after_ctrl_dep() smp_rmb() - -/** - * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering - * @ptr: pointer to the variable to wait on - * @cond: boolean expression to wait for - * - * Equivalent to using smp_load_acquire() on the condition variable but employs - * the control dependency of the wait to reduce the barrier on many platforms. - * - * Due to C lacking lambda expressions we load the value of *ptr into a - * pre-named variable @VAL to be used in @cond. - */ -#ifndef smp_cond_load_acquire -#define smp_cond_load_acquire(ptr, cond_expr) ({ \ - typeof(ptr) __PTR = (ptr); \ - typeof(*ptr) VAL; \ - for (;;) { \ - VAL = READ_ONCE(*__PTR); \ - if (cond_expr) \ - break; \ - cpu_relax(); \ - } \ - smp_acquire__after_ctrl_dep(); \ - VAL; \ -}) -#endif - #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ -- cgit v1.2.3 From 726328d92a42b6d4b76078e2659f43067f82c4e8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 26 May 2016 10:35:03 +0200 Subject: locking/spinlock, arch: Update and fix spin_unlock_wait() implementations This patch updates/fixes all spin_unlock_wait() implementations. The update is in semantics; where it previously was only a control dependency, we now upgrade to a full load-acquire to match the store-release from the spin_unlock() we waited on. This ensures that when spin_unlock_wait() returns, we're guaranteed to observe the full critical section we waited on. This fixes a number of spin_unlock_wait() users that (not unreasonably) rely on this. I also fixed a number of ticket lock versions to only wait on the current lock holder, instead of for a full unlock, as this is sufficient. Furthermore; again for ticket locks; I added an smp_rmb() in between the initial ticket load and the spin loop testing the current value because I could not convince myself the address dependency is sufficient, esp. if the loads are of different sizes. I'm more than happy to remove this smp_rmb() again if people are certain the address dependency does indeed work as expected. Note: PPC32 will be fixed independently Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: chris@zankel.net Cc: cmetcalf@mellanox.com Cc: davem@davemloft.net Cc: dhowells@redhat.com Cc: james.hogan@imgtec.com Cc: jejb@parisc-linux.org Cc: linux@armlinux.org.uk Cc: mpe@ellerman.id.au Cc: ralf@linux-mips.org Cc: realmz6@gmail.com Cc: rkuo@codeaurora.org Cc: rth@twiddle.net Cc: schwidefsky@de.ibm.com Cc: tony.luck@intel.com Cc: vgupta@synopsys.com Cc: ysato@users.sourceforge.jp Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- arch/alpha/include/asm/spinlock.h | 9 +++++++-- arch/arc/include/asm/spinlock.h | 7 +++++-- arch/arm/include/asm/spinlock.h | 19 +++++++++++++++++-- arch/blackfin/include/asm/spinlock.h | 5 +++-- arch/hexagon/include/asm/spinlock.h | 10 ++++++++-- arch/ia64/include/asm/spinlock.h | 4 ++++ arch/m32r/include/asm/spinlock.h | 9 +++++++-- arch/metag/include/asm/spinlock.h | 14 ++++++++++++-- arch/mips/include/asm/spinlock.h | 19 +++++++++++++++++-- arch/mn10300/include/asm/spinlock.h | 8 +++++++- arch/parisc/include/asm/spinlock.h | 9 +++++++-- arch/s390/include/asm/spinlock.h | 3 +++ arch/sh/include/asm/spinlock.h | 10 ++++++++-- arch/sparc/include/asm/spinlock_32.h | 7 +++++-- arch/sparc/include/asm/spinlock_64.h | 10 +++++++--- arch/tile/lib/spinlock_32.c | 6 ++++++ arch/tile/lib/spinlock_64.c | 6 ++++++ arch/xtensa/include/asm/spinlock.h | 10 ++++++++-- include/asm-generic/barrier.h | 2 +- include/linux/spinlock_up.h | 10 +++++++--- 20 files changed, 145 insertions(+), 32 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/include/asm/spinlock.h b/arch/alpha/include/asm/spinlock.h index fed9c6f44c19..a40b9fc0c6c3 100644 --- a/arch/alpha/include/asm/spinlock.h +++ b/arch/alpha/include/asm/spinlock.h @@ -3,6 +3,8 @@ #include #include +#include +#include /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -13,8 +15,11 @@ #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) #define arch_spin_is_locked(x) ((x)->lock != 0) -#define arch_spin_unlock_wait(x) \ - do { cpu_relax(); } while ((x)->lock) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} static inline int arch_spin_value_unlocked(arch_spinlock_t lock) { diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h index cded4a9b5438..233d5ffe6ec7 100644 --- a/arch/arc/include/asm/spinlock.h +++ b/arch/arc/include/asm/spinlock.h @@ -15,8 +15,11 @@ #define arch_spin_is_locked(x) ((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__) #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(x) \ - do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, !VAL); +} #ifdef CONFIG_ARC_HAS_LLSC diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h index 0fa418463f49..4bec45442072 100644 --- a/arch/arm/include/asm/spinlock.h +++ b/arch/arm/include/asm/spinlock.h @@ -6,6 +6,8 @@ #endif #include +#include +#include /* * sev and wfe are ARMv6K extensions. Uniprocessor ARMv6 may not have the K @@ -50,8 +52,21 @@ static inline void dsb_sev(void) * memory. */ -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + u16 owner = READ_ONCE(lock->tickets.owner); + + for (;;) { + arch_spinlock_t tmp = READ_ONCE(*lock); + + if (tmp.tickets.owner == tmp.tickets.next || + tmp.tickets.owner != owner) + break; + + wfe(); + } + smp_acquire__after_ctrl_dep(); +} #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h index 490c7caa02d9..c58f4a83ed6f 100644 --- a/arch/blackfin/include/asm/spinlock.h +++ b/arch/blackfin/include/asm/spinlock.h @@ -12,6 +12,8 @@ #else #include +#include +#include asmlinkage int __raw_spin_is_locked_asm(volatile int *ptr); asmlinkage void __raw_spin_lock_asm(volatile int *ptr); @@ -48,8 +50,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) { - while (arch_spin_is_locked(lock)) - cpu_relax(); + smp_cond_load_acquire(&lock->lock, !VAL); } static inline int arch_read_can_lock(arch_rwlock_t *rw) diff --git a/arch/hexagon/include/asm/spinlock.h b/arch/hexagon/include/asm/spinlock.h index 12ca4ebc0338..a1c55788c5d6 100644 --- a/arch/hexagon/include/asm/spinlock.h +++ b/arch/hexagon/include/asm/spinlock.h @@ -23,6 +23,8 @@ #define _ASM_SPINLOCK_H #include +#include +#include /* * This file is pulled in for SMP builds. @@ -176,8 +178,12 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock) * SMP spinlocks are intended to allow only a single CPU at the lock */ #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(lock) \ - do {while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} + #define arch_spin_is_locked(x) ((x)->lock != 0) #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h index 45698cd15b7b..ca9e76149a4a 100644 --- a/arch/ia64/include/asm/spinlock.h +++ b/arch/ia64/include/asm/spinlock.h @@ -15,6 +15,8 @@ #include #include +#include +#include #define arch_spin_lock_init(x) ((x)->lock = 0) @@ -86,6 +88,8 @@ static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock) return; cpu_relax(); } + + smp_acquire__after_ctrl_dep(); } static inline int __ticket_spin_is_locked(arch_spinlock_t *lock) diff --git a/arch/m32r/include/asm/spinlock.h b/arch/m32r/include/asm/spinlock.h index fa13694eaae3..323c7fc953cd 100644 --- a/arch/m32r/include/asm/spinlock.h +++ b/arch/m32r/include/asm/spinlock.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include /* * Your basic SMP spinlocks, allowing only a single CPU anywhere @@ -27,8 +29,11 @@ #define arch_spin_is_locked(x) (*(volatile int *)(&(x)->slock) <= 0) #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(x) \ - do { cpu_relax(); } while (arch_spin_is_locked(x)) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, VAL > 0); +} /** * arch_spin_trylock - Try spin lock and return a result diff --git a/arch/metag/include/asm/spinlock.h b/arch/metag/include/asm/spinlock.h index 86a7cf3d1386..c0c7a22be1ae 100644 --- a/arch/metag/include/asm/spinlock.h +++ b/arch/metag/include/asm/spinlock.h @@ -1,14 +1,24 @@ #ifndef __ASM_SPINLOCK_H #define __ASM_SPINLOCK_H +#include +#include + #ifdef CONFIG_METAG_ATOMICITY_LOCK1 #include #else #include #endif -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) +/* + * both lock1 and lnkget are test-and-set spinlocks with 0 unlocked and 1 + * locked. + */ + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h index 40196bebe849..f485afe51514 100644 --- a/arch/mips/include/asm/spinlock.h +++ b/arch/mips/include/asm/spinlock.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -48,8 +49,22 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock) } #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(x) \ - while (arch_spin_is_locked(x)) { cpu_relax(); } + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + u16 owner = READ_ONCE(lock->h.serving_now); + smp_rmb(); + for (;;) { + arch_spinlock_t tmp = READ_ONCE(*lock); + + if (tmp.h.serving_now == tmp.h.ticket || + tmp.h.serving_now != owner) + break; + + cpu_relax(); + } + smp_acquire__after_ctrl_dep(); +} static inline int arch_spin_is_contended(arch_spinlock_t *lock) { diff --git a/arch/mn10300/include/asm/spinlock.h b/arch/mn10300/include/asm/spinlock.h index 1ae580f38933..9c7b8f7942d8 100644 --- a/arch/mn10300/include/asm/spinlock.h +++ b/arch/mn10300/include/asm/spinlock.h @@ -12,6 +12,8 @@ #define _ASM_SPINLOCK_H #include +#include +#include #include #include @@ -23,7 +25,11 @@ */ #define arch_spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) != 0) -#define arch_spin_unlock_wait(x) do { barrier(); } while (arch_spin_is_locked(x)) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, !VAL); +} static inline void arch_spin_unlock(arch_spinlock_t *lock) { diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h index 64f2992e439f..e32936cd7f10 100644 --- a/arch/parisc/include/asm/spinlock.h +++ b/arch/parisc/include/asm/spinlock.h @@ -13,8 +13,13 @@ static inline int arch_spin_is_locked(arch_spinlock_t *x) } #define arch_spin_lock(lock) arch_spin_lock_flags(lock, 0) -#define arch_spin_unlock_wait(x) \ - do { cpu_relax(); } while (arch_spin_is_locked(x)) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *x) +{ + volatile unsigned int *a = __ldcw_align(x); + + smp_cond_load_acquire(a, VAL); +} static inline void arch_spin_lock_flags(arch_spinlock_t *x, unsigned long flags) diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index 63ebf37d3143..7e9e09f600fa 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -10,6 +10,8 @@ #define __ASM_SPINLOCK_H #include +#include +#include #define SPINLOCK_LOCKVAL (S390_lowcore.spinlock_lockval) @@ -97,6 +99,7 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) { while (arch_spin_is_locked(lock)) arch_spin_relax(lock); + smp_acquire__after_ctrl_dep(); } /* diff --git a/arch/sh/include/asm/spinlock.h b/arch/sh/include/asm/spinlock.h index bdc0f3b6c56a..416834b60ad0 100644 --- a/arch/sh/include/asm/spinlock.h +++ b/arch/sh/include/asm/spinlock.h @@ -19,14 +19,20 @@ #error "Need movli.l/movco.l for spinlocks" #endif +#include +#include + /* * Your basic SMP spinlocks, allowing only a single CPU anywhere */ #define arch_spin_is_locked(x) ((x)->lock <= 0) #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) -#define arch_spin_unlock_wait(x) \ - do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, VAL > 0); +} /* * Simple spin lock operations. There are two variants, one clears IRQ's diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h index bcc98fc35281..d9c5876c6121 100644 --- a/arch/sparc/include/asm/spinlock_32.h +++ b/arch/sparc/include/asm/spinlock_32.h @@ -9,12 +9,15 @@ #ifndef __ASSEMBLY__ #include +#include #include /* for cpu_relax */ #define arch_spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} static inline void arch_spin_lock(arch_spinlock_t *lock) { diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h index 968917694978..87990b7c6b0d 100644 --- a/arch/sparc/include/asm/spinlock_64.h +++ b/arch/sparc/include/asm/spinlock_64.h @@ -8,6 +8,9 @@ #ifndef __ASSEMBLY__ +#include +#include + /* To get debugging spinlocks which detect and catch * deadlock situations, set CONFIG_DEBUG_SPINLOCK * and rebuild your kernel. @@ -23,9 +26,10 @@ #define arch_spin_is_locked(lp) ((lp)->lock != 0) -#define arch_spin_unlock_wait(lp) \ - do { rmb(); \ - } while((lp)->lock) +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->lock, !VAL); +} static inline void arch_spin_lock(arch_spinlock_t *lock) { diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c index 88c2a53362e7..076c6cc43113 100644 --- a/arch/tile/lib/spinlock_32.c +++ b/arch/tile/lib/spinlock_32.c @@ -76,6 +76,12 @@ void arch_spin_unlock_wait(arch_spinlock_t *lock) do { delay_backoff(iterations++); } while (READ_ONCE(lock->current_ticket) == curr); + + /* + * The TILE architecture doesn't do read speculation; therefore + * a control dependency guarantees a LOAD->{LOAD,STORE} order. + */ + barrier(); } EXPORT_SYMBOL(arch_spin_unlock_wait); diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c index c8d1f94ff1fe..a4b5b2cbce93 100644 --- a/arch/tile/lib/spinlock_64.c +++ b/arch/tile/lib/spinlock_64.c @@ -76,6 +76,12 @@ void arch_spin_unlock_wait(arch_spinlock_t *lock) do { delay_backoff(iterations++); } while (arch_spin_current(READ_ONCE(lock->lock)) == curr); + + /* + * The TILE architecture doesn't do read speculation; therefore + * a control dependency guarantees a LOAD->{LOAD,STORE} order. + */ + barrier(); } EXPORT_SYMBOL(arch_spin_unlock_wait); diff --git a/arch/xtensa/include/asm/spinlock.h b/arch/xtensa/include/asm/spinlock.h index 1d95fa5dcd10..a36221cf6363 100644 --- a/arch/xtensa/include/asm/spinlock.h +++ b/arch/xtensa/include/asm/spinlock.h @@ -11,6 +11,9 @@ #ifndef _XTENSA_SPINLOCK_H #define _XTENSA_SPINLOCK_H +#include +#include + /* * spinlock * @@ -29,8 +32,11 @@ */ #define arch_spin_is_locked(x) ((x)->slock != 0) -#define arch_spin_unlock_wait(lock) \ - do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) + +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, !VAL); +} #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h index ab7b0bd7d4dd..fe297b599b0a 100644 --- a/include/asm-generic/barrier.h +++ b/include/asm-generic/barrier.h @@ -194,7 +194,7 @@ do { \ }) #endif -#endif +#endif /* CONFIG_SMP */ /* Barriers for virtual machine guests when talking to an SMP host */ #define virt_mb() __smp_mb() diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h index 8b3ac0d718eb..0d9848de677d 100644 --- a/include/linux/spinlock_up.h +++ b/include/linux/spinlock_up.h @@ -6,6 +6,7 @@ #endif #include /* for cpu_relax() */ +#include /* * include/linux/spinlock_up.h - UP-debug version of spinlocks. @@ -25,6 +26,11 @@ #ifdef CONFIG_DEBUG_SPINLOCK #define arch_spin_is_locked(x) ((x)->slock == 0) +static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) +{ + smp_cond_load_acquire(&lock->slock, VAL); +} + static inline void arch_spin_lock(arch_spinlock_t *lock) { lock->slock = 0; @@ -67,6 +73,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) #else /* DEBUG_SPINLOCK */ #define arch_spin_is_locked(lock) ((void)(lock), 0) +#define arch_spin_unlock_wait(lock) do { barrier(); (void)(lock); } while (0) /* for sched/core.c and kernel_lock.c: */ # define arch_spin_lock(lock) do { barrier(); (void)(lock); } while (0) # define arch_spin_lock_flags(lock, flags) do { barrier(); (void)(lock); } while (0) @@ -79,7 +86,4 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) #define arch_read_can_lock(lock) (((void)(lock), 1)) #define arch_write_can_lock(lock) (((void)(lock), 1)) -#define arch_spin_unlock_wait(lock) \ - do { cpu_relax(); } while (arch_spin_is_locked(lock)) - #endif /* __LINUX_SPINLOCK_UP_H */ -- cgit v1.2.3 From 2f275de5d1ed7269913ef9b4c64a13952c0a38e8 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 27 May 2016 12:57:02 -0700 Subject: seccomp: Add a seccomp_data parameter secure_computing() Currently, if arch code wants to supply seccomp_data directly to seccomp (which is generally much faster than having seccomp do it using the syscall_get_xyz() API), it has to use the two-phase seccomp hooks. Add it to the easy hooks, too. Cc: linux-arch@vger.kernel.org Signed-off-by: Andy Lutomirski Signed-off-by: Kees Cook --- arch/arm/kernel/ptrace.c | 2 +- arch/arm64/kernel/ptrace.c | 2 +- arch/mips/kernel/ptrace.c | 2 +- arch/parisc/kernel/ptrace.c | 2 +- arch/powerpc/kernel/ptrace.c | 2 +- arch/s390/kernel/ptrace.c | 2 +- arch/tile/kernel/ptrace.c | 2 +- arch/um/kernel/skas/syscall.c | 2 +- arch/x86/entry/vsyscall/vsyscall_64.c | 2 +- include/linux/seccomp.h | 8 ++++---- kernel/seccomp.c | 4 ++-- 11 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 4d9375814b53..1027d3b54541 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -934,7 +934,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) /* Do the secure computing check first; failures should be fast. */ #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; #else /* XXX: remove this once OABI gets fixed */ diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 3f6cd5c5234f..6e2cf046615d 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -1247,7 +1247,7 @@ static void tracehook_report_syscall(struct pt_regs *regs, asmlinkage int syscall_trace_enter(struct pt_regs *regs) { /* Do the secure computing check first; failures should be fast. */ - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; if (test_thread_flag(TIF_SYSCALL_TRACE)) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 0dcf69194473..c50af846ecf9 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -893,7 +893,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall) current_thread_info()->syscall = syscall; - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; if (test_thread_flag(TIF_SYSCALL_TRACE) && diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index b5458b37fc5b..8edc47c0b98e 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -312,7 +312,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, long do_syscall_trace_enter(struct pt_regs *regs) { /* Do the secure computing check first. */ - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; if (test_thread_flag(TIF_SYSCALL_TRACE) && diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 30a03c03fe73..ed799e994773 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1783,7 +1783,7 @@ static int do_seccomp(struct pt_regs *regs) * have already loaded -ENOSYS into r3, or seccomp has put * something else in r3 (via SECCOMP_RET_ERRNO/TRACE). */ - if (__secure_computing()) + if (__secure_computing(NULL)) return -1; /* diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 49b1c13bf6c9..c238e9958c2a 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -824,7 +824,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) long ret = 0; /* Do the secure computing check first. */ - if (secure_computing()) { + if (secure_computing(NULL)) { /* seccomp failures shouldn't expose any additional code. */ ret = -1; goto out; diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index 54e7b723db99..8c6d2f2fefa3 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c @@ -255,7 +255,7 @@ int do_syscall_trace_enter(struct pt_regs *regs) { u32 work = ACCESS_ONCE(current_thread_info()->flags); - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; if (work & _TIF_SYSCALL_TRACE) { diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 48b0dcbd87be..9c5570f0f397 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -21,7 +21,7 @@ void handle_syscall(struct uml_pt_regs *r) PT_REGS_SET_SYSCALL_RETURN(regs, -ENOSYS); /* Do the secure computing check first; failures should be fast. */ - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return; if (syscall_trace_enter(regs)) diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 174c2549939d..85acde5fa442 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -207,7 +207,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) */ regs->orig_ax = syscall_nr; regs->ax = -ENOSYS; - tmp = secure_computing(); + tmp = secure_computing(NULL); if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) { warn_bad_vsyscall(KERN_DEBUG, regs, "seccomp tried to change syscall nr or ip"); diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 2296e6b2f690..9eaa7b34d6da 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -28,11 +28,11 @@ struct seccomp { }; #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER -extern int __secure_computing(void); -static inline int secure_computing(void) +extern int __secure_computing(const struct seccomp_data *sd); +static inline int secure_computing(const struct seccomp_data *sd) { if (unlikely(test_thread_flag(TIF_SECCOMP))) - return __secure_computing(); + return __secure_computing(sd); return 0; } @@ -61,7 +61,7 @@ struct seccomp { }; struct seccomp_filter { }; #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER -static inline int secure_computing(void) { return 0; } +static inline int secure_computing(struct seccomp_data *sd) { return 0; } #else static inline void secure_computing_strict(int this_syscall) { return; } #endif diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 7002796f14a4..06816290a212 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -554,9 +554,9 @@ void secure_computing_strict(int this_syscall) BUG(); } #else -int __secure_computing(void) +int __secure_computing(const struct seccomp_data *sd) { - u32 phase1_result = seccomp_phase1(NULL); + u32 phase1_result = seccomp_phase1(sd); if (likely(phase1_result == SECCOMP_PHASE1_OK)) return 0; -- cgit v1.2.3 From 8112c4f140fa03f9ee68aad2cc79afa7df5418d3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 1 Jun 2016 16:02:17 -0700 Subject: seccomp: remove 2-phase API Since nothing is using the 2-phase API, and it adds more complexity than benefit, remove it. Signed-off-by: Kees Cook Cc: Andy Lutomirski --- include/linux/seccomp.h | 6 --- kernel/seccomp.c | 129 +++++++++++++++--------------------------------- 2 files changed, 41 insertions(+), 94 deletions(-) (limited to 'include/linux') diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 9eaa7b34d6da..ecc296c137cd 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -35,12 +35,6 @@ static inline int secure_computing(const struct seccomp_data *sd) return __secure_computing(sd); return 0; } - -#define SECCOMP_PHASE1_OK 0 -#define SECCOMP_PHASE1_SKIP 1 - -extern u32 seccomp_phase1(struct seccomp_data *sd); -int seccomp_phase2(u32 phase1_result); #else extern void secure_computing_strict(int this_syscall); #endif diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 06816290a212..14a37d71b612 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -173,7 +173,7 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) * * Returns valid seccomp BPF response codes. */ -static u32 seccomp_run_filters(struct seccomp_data *sd) +static u32 seccomp_run_filters(const struct seccomp_data *sd) { struct seccomp_data sd_local; u32 ret = SECCOMP_RET_ALLOW; @@ -554,20 +554,9 @@ void secure_computing_strict(int this_syscall) BUG(); } #else -int __secure_computing(const struct seccomp_data *sd) -{ - u32 phase1_result = seccomp_phase1(sd); - - if (likely(phase1_result == SECCOMP_PHASE1_OK)) - return 0; - else if (likely(phase1_result == SECCOMP_PHASE1_SKIP)) - return -1; - else - return seccomp_phase2(phase1_result); -} #ifdef CONFIG_SECCOMP_FILTER -static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd) +static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) { u32 filter_ret, action; int data; @@ -599,10 +588,33 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd) goto skip; case SECCOMP_RET_TRACE: - return filter_ret; /* Save the rest for phase 2. */ + /* ENOSYS these calls if there is no tracer attached. */ + if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { + syscall_set_return_value(current, + task_pt_regs(current), + -ENOSYS, 0); + goto skip; + } + + /* Allow the BPF to provide the event message */ + ptrace_event(PTRACE_EVENT_SECCOMP, data); + /* + * The delivery of a fatal signal during event + * notification may silently skip tracer notification. + * Terminating the task now avoids executing a system + * call that may not be intended. + */ + if (fatal_signal_pending(current)) + do_exit(SIGSYS); + /* Check if the tracer forced the syscall to be skipped. */ + this_syscall = syscall_get_nr(current, task_pt_regs(current)); + if (this_syscall < 0) + goto skip; + + return 0; case SECCOMP_RET_ALLOW: - return SECCOMP_PHASE1_OK; + return 0; case SECCOMP_RET_KILL: default: @@ -614,96 +626,37 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd) skip: audit_seccomp(this_syscall, 0, action); - return SECCOMP_PHASE1_SKIP; + return -1; +} +#else +static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) +{ + BUG(); } #endif -/** - * seccomp_phase1() - run fast path seccomp checks on the current syscall - * @arg sd: The seccomp_data or NULL - * - * This only reads pt_regs via the syscall_xyz helpers. The only change - * it will make to pt_regs is via syscall_set_return_value, and it will - * only do that if it returns SECCOMP_PHASE1_SKIP. - * - * If sd is provided, it will not read pt_regs at all. - * - * It may also call do_exit or force a signal; these actions must be - * safe. - * - * If it returns SECCOMP_PHASE1_OK, the syscall passes checks and should - * be processed normally. - * - * If it returns SECCOMP_PHASE1_SKIP, then the syscall should not be - * invoked. In this case, seccomp_phase1 will have set the return value - * using syscall_set_return_value. - * - * If it returns anything else, then the return value should be passed - * to seccomp_phase2 from a context in which ptrace hooks are safe. - */ -u32 seccomp_phase1(struct seccomp_data *sd) +int __secure_computing(const struct seccomp_data *sd) { int mode = current->seccomp.mode; - int this_syscall = sd ? sd->nr : - syscall_get_nr(current, task_pt_regs(current)); + int this_syscall; if (config_enabled(CONFIG_CHECKPOINT_RESTORE) && unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) - return SECCOMP_PHASE1_OK; + return 0; + + this_syscall = sd ? sd->nr : + syscall_get_nr(current, task_pt_regs(current)); switch (mode) { case SECCOMP_MODE_STRICT: __secure_computing_strict(this_syscall); /* may call do_exit */ - return SECCOMP_PHASE1_OK; -#ifdef CONFIG_SECCOMP_FILTER + return 0; case SECCOMP_MODE_FILTER: - return __seccomp_phase1_filter(this_syscall, sd); -#endif + return __seccomp_filter(this_syscall, sd); default: BUG(); } } - -/** - * seccomp_phase2() - finish slow path seccomp work for the current syscall - * @phase1_result: The return value from seccomp_phase1() - * - * This must be called from a context in which ptrace hooks can be used. - * - * Returns 0 if the syscall should be processed or -1 to skip the syscall. - */ -int seccomp_phase2(u32 phase1_result) -{ - struct pt_regs *regs = task_pt_regs(current); - u32 action = phase1_result & SECCOMP_RET_ACTION; - int data = phase1_result & SECCOMP_RET_DATA; - - BUG_ON(action != SECCOMP_RET_TRACE); - - audit_seccomp(syscall_get_nr(current, regs), 0, action); - - /* Skip these calls if there is no tracer. */ - if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { - syscall_set_return_value(current, regs, - -ENOSYS, 0); - return -1; - } - - /* Allow the BPF to provide the event message */ - ptrace_event(PTRACE_EVENT_SECCOMP, data); - /* - * The delivery of a fatal signal during event - * notification may silently skip tracer notification. - * Terminating the task now avoids executing a system - * call that may not be intended. - */ - if (fatal_signal_pending(current)) - do_exit(SIGSYS); - if (syscall_get_nr(current, regs) < 0) - return -1; /* Explicit request to skip. */ - - return 0; -} #endif /* CONFIG_HAVE_ARCH_SECCOMP_FILTER */ long prctl_get_seccomp(void) -- cgit v1.2.3 From 810ce8b5df1c8338065f2ae1d2ec08cc566fbb8b Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 20 Apr 2016 09:22:15 -0700 Subject: rcu: Document RCU_NONIDLE() restrictions in comment header Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 5f1533e3d032..c61b6b9506e7 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -379,12 +379,13 @@ static inline void rcu_init_nohz(void) * in the inner idle loop. * * This macro provides the way out: RCU_NONIDLE(do_something_with_RCU()) - * will tell RCU that it needs to pay attending, invoke its argument - * (in this example, a call to the do_something_with_RCU() function), + * will tell RCU that it needs to pay attention, invoke its argument + * (in this example, calling the do_something_with_RCU() function), * and then tell RCU to go back to ignoring this CPU. It is permissible - * to nest RCU_NONIDLE() wrappers, but the nesting level is currently - * quite limited. If deeper nesting is required, it will be necessary - * to adjust DYNTICK_TASK_NESTING_VALUE accordingly. + * to nest RCU_NONIDLE() wrappers, but not indefinitely (but the limit is + * on the order of a million or so, even on 32-bit systems). It is + * not legal to block within RCU_NONIDLE(), nor is it permissible to + * transfer control either into or out of RCU_NONIDLE()'s statement. */ #define RCU_NONIDLE(a) \ do { \ -- cgit v1.2.3 From d95f5ba90fa6043a366958897fdef705af968b70 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 20 Apr 2016 17:18:41 -0700 Subject: torture: Break online and offline functions out of torture_onoff() This commit breaks torture_online() and torture_offline() out of torture_onoff() in preparation for allowing waketorture finer-grained control of its CPU-hotplug workload. Signed-off-by: Paul E. McKenney --- include/linux/torture.h | 4 ++ kernel/torture.c | 168 ++++++++++++++++++++++++++++++------------------ 2 files changed, 108 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/include/linux/torture.h b/include/linux/torture.h index 7759fc3c622d..6685a73736a2 100644 --- a/include/linux/torture.h +++ b/include/linux/torture.h @@ -50,6 +50,10 @@ do { if (verbose) pr_alert("%s" TORTURE_FLAG "!!! %s\n", torture_type, s); } while (0) /* Definitions for online/offline exerciser. */ +bool torture_offline(int cpu, long *n_onl_attempts, long *n_onl_successes, + unsigned long *sum_offl, int *min_onl, int *max_onl); +bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes, + unsigned long *sum_onl, int *min_onl, int *max_onl); int torture_onoff_init(long ooholdoff, long oointerval); void torture_onoff_stats(void); bool torture_onoff_failures(void); diff --git a/kernel/torture.c b/kernel/torture.c index fa0bdeee17ac..fb39a06bbef5 100644 --- a/kernel/torture.c +++ b/kernel/torture.c @@ -81,6 +81,104 @@ static unsigned long sum_online; static int min_online = -1; static int max_online; +/* + * Attempt to take a CPU offline. Return false if the CPU is already + * offline or if it is not subject to CPU-hotplug operations. The + * caller can detect other failures by looking at the statistics. + */ +bool torture_offline(int cpu, long *n_offl_attempts, long *n_offl_successes, + unsigned long *sum_offl, int *min_offl, int *max_offl) +{ + unsigned long delta; + int ret; + unsigned long starttime; + + if (!cpu_online(cpu) || !cpu_is_hotpluggable(cpu)) + return false; + + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offlining %d\n", + torture_type, cpu); + starttime = jiffies; + (*n_offl_attempts)++; + ret = cpu_down(cpu); + if (ret) { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offline %d failed: errno %d\n", + torture_type, cpu, ret); + } else { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: offlined %d\n", + torture_type, cpu); + (*n_offl_successes)++; + delta = jiffies - starttime; + sum_offl += delta; + if (*min_offl < 0) { + *min_offl = delta; + *max_offl = delta; + } + if (*min_offl > delta) + *min_offl = delta; + if (*max_offl < delta) + *max_offl = delta; + } + + return true; +} +EXPORT_SYMBOL_GPL(torture_offline); + +/* + * Attempt to bring a CPU online. Return false if the CPU is already + * online or if it is not subject to CPU-hotplug operations. The + * caller can detect other failures by looking at the statistics. + */ +bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes, + unsigned long *sum_onl, int *min_onl, int *max_onl) +{ + unsigned long delta; + int ret; + unsigned long starttime; + + if (cpu_online(cpu) || !cpu_is_hotpluggable(cpu)) + return false; + + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: onlining %d\n", + torture_type, cpu); + starttime = jiffies; + (*n_onl_attempts)++; + ret = cpu_up(cpu); + if (ret) { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: online %d failed: errno %d\n", + torture_type, cpu, ret); + } else { + if (verbose) + pr_alert("%s" TORTURE_FLAG + "torture_onoff task: onlined %d\n", + torture_type, cpu); + (*n_onl_successes)++; + delta = jiffies - starttime; + *sum_onl += delta; + if (*min_onl < 0) { + *min_onl = delta; + *max_onl = delta; + } + if (*min_onl > delta) + *min_onl = delta; + if (*max_onl < delta) + *max_onl = delta; + } + + return true; +} +EXPORT_SYMBOL_GPL(torture_online); + /* * Execute random CPU-hotplug operations at the interval specified * by the onoff_interval. @@ -89,11 +187,8 @@ static int torture_onoff(void *arg) { int cpu; - unsigned long delta; int maxcpu = -1; DEFINE_TORTURE_RANDOM(rand); - int ret; - unsigned long starttime; VERBOSE_TOROUT_STRING("torture_onoff task started"); for_each_online_cpu(cpu) @@ -106,67 +201,12 @@ torture_onoff(void *arg) } while (!torture_must_stop()) { cpu = (torture_random(&rand) >> 4) % (maxcpu + 1); - if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: offlining %d\n", - torture_type, cpu); - starttime = jiffies; - n_offline_attempts++; - ret = cpu_down(cpu); - if (ret) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: offline %d failed: errno %d\n", - torture_type, cpu, ret); - } else { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: offlined %d\n", - torture_type, cpu); - n_offline_successes++; - delta = jiffies - starttime; - sum_offline += delta; - if (min_offline < 0) { - min_offline = delta; - max_offline = delta; - } - if (min_offline > delta) - min_offline = delta; - if (max_offline < delta) - max_offline = delta; - } - } else if (cpu_is_hotpluggable(cpu)) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: onlining %d\n", - torture_type, cpu); - starttime = jiffies; - n_online_attempts++; - ret = cpu_up(cpu); - if (ret) { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: online %d failed: errno %d\n", - torture_type, cpu, ret); - } else { - if (verbose) - pr_alert("%s" TORTURE_FLAG - "torture_onoff task: onlined %d\n", - torture_type, cpu); - n_online_successes++; - delta = jiffies - starttime; - sum_online += delta; - if (min_online < 0) { - min_online = delta; - max_online = delta; - } - if (min_online > delta) - min_online = delta; - if (max_online < delta) - max_online = delta; - } - } + if (!torture_offline(cpu, + &n_offline_attempts, &n_offline_successes, + &sum_offline, &min_offline, &max_offline)) + torture_online(cpu, + &n_online_attempts, &n_online_successes, + &sum_online, &min_online, &max_online); schedule_timeout_interruptible(onoff_interval); } torture_kthread_stopping("torture_onoff"); -- cgit v1.2.3 From ca5f2b4c4fb7bb7397317ee2ead83485aa295a3e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 14 Jun 2016 16:23:22 +0200 Subject: PM / sleep: Make pm_prepare_console() return void Nothing is using its return value so change it to return void. No functionality change. Signed-off-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- include/linux/suspend.h | 5 ++--- kernel/power/console.c | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 8b6ec7ef0854..7693e39b14fe 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -18,12 +18,11 @@ static inline void pm_set_vt_switch(int do_switch) #endif #ifdef CONFIG_VT_CONSOLE_SLEEP -extern int pm_prepare_console(void); +extern void pm_prepare_console(void); extern void pm_restore_console(void); #else -static inline int pm_prepare_console(void) +static inline void pm_prepare_console(void) { - return 0; } static inline void pm_restore_console(void) diff --git a/kernel/power/console.c b/kernel/power/console.c index aba9c545a0e3..0e781798b0b3 100644 --- a/kernel/power/console.c +++ b/kernel/power/console.c @@ -126,17 +126,17 @@ out: return ret; } -int pm_prepare_console(void) +void pm_prepare_console(void) { if (!pm_vt_switch()) - return 0; + return; orig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1); if (orig_fgconsole < 0) - return 1; + return; orig_kmsg = vt_kmsg_redirect(SUSPEND_CONSOLE); - return 0; + return; } void pm_restore_console(void) -- cgit v1.2.3 From 2e0ab8ca83c122f275b21ea917d52fee506910bf Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 13 Jun 2016 23:54:31 +0300 Subject: ptr_ring: array based FIFO for pointers A simple array based FIFO of pointers. Intended for net stack which commonly has a single consumer/producer. Signed-off-by: Michael S. Tsirkin Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- include/linux/ptr_ring.h | 264 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 include/linux/ptr_ring.h (limited to 'include/linux') diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h new file mode 100644 index 000000000000..633406f9af8e --- /dev/null +++ b/include/linux/ptr_ring.h @@ -0,0 +1,264 @@ +/* + * Definitions for the 'struct ptr_ring' datastructure. + * + * Author: + * Michael S. Tsirkin + * + * Copyright (C) 2016 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This is a limited-size FIFO maintaining pointers in FIFO order, with + * one CPU producing entries and another consuming entries from a FIFO. + * + * This implementation tries to minimize cache-contention when there is a + * single producer and a single consumer CPU. + */ + +#ifndef _LINUX_PTR_RING_H +#define _LINUX_PTR_RING_H 1 + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#endif + +struct ptr_ring { + int producer ____cacheline_aligned_in_smp; + spinlock_t producer_lock; + int consumer ____cacheline_aligned_in_smp; + spinlock_t consumer_lock; + /* Shared consumer/producer data */ + /* Read-only by both the producer and the consumer */ + int size ____cacheline_aligned_in_smp; /* max entries in queue */ + void **queue; +}; + +/* Note: callers invoking this in a loop must use a compiler barrier, + * for example cpu_relax(). + * Callers don't need to take producer lock - if they don't + * the next call to __ptr_ring_produce may fail. + */ +static inline bool __ptr_ring_full(struct ptr_ring *r) +{ + return r->queue[r->producer]; +} + +static inline bool ptr_ring_full(struct ptr_ring *r) +{ + barrier(); + return __ptr_ring_full(r); +} + +/* Note: callers invoking this in a loop must use a compiler barrier, + * for example cpu_relax(). + */ +static inline int __ptr_ring_produce(struct ptr_ring *r, void *ptr) +{ + if (__ptr_ring_full(r)) + return -ENOSPC; + + r->queue[r->producer++] = ptr; + if (unlikely(r->producer >= r->size)) + r->producer = 0; + return 0; +} + +static inline int ptr_ring_produce(struct ptr_ring *r, void *ptr) +{ + int ret; + + spin_lock(&r->producer_lock); + ret = __ptr_ring_produce(r, ptr); + spin_unlock(&r->producer_lock); + + return ret; +} + +static inline int ptr_ring_produce_irq(struct ptr_ring *r, void *ptr) +{ + int ret; + + spin_lock_irq(&r->producer_lock); + ret = __ptr_ring_produce(r, ptr); + spin_unlock_irq(&r->producer_lock); + + return ret; +} + +static inline int ptr_ring_produce_any(struct ptr_ring *r, void *ptr) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&r->producer_lock, flags); + ret = __ptr_ring_produce(r, ptr); + spin_unlock_irqrestore(&r->producer_lock, flags); + + return ret; +} + +static inline int ptr_ring_produce_bh(struct ptr_ring *r, void *ptr) +{ + int ret; + + spin_lock_bh(&r->producer_lock); + ret = __ptr_ring_produce(r, ptr); + spin_unlock_bh(&r->producer_lock); + + return ret; +} + +/* Note: callers invoking this in a loop must use a compiler barrier, + * for example cpu_relax(). Callers must take consumer_lock + * if they dereference the pointer - see e.g. PTR_RING_PEEK_CALL. + * There's no need for a lock if pointer is merely tested - see e.g. + * ptr_ring_empty. + */ +static inline void *__ptr_ring_peek(struct ptr_ring *r) +{ + return r->queue[r->consumer]; +} + +static inline bool ptr_ring_empty(struct ptr_ring *r) +{ + barrier(); + return !__ptr_ring_peek(r); +} + +/* Must only be called after __ptr_ring_peek returned !NULL */ +static inline void __ptr_ring_discard_one(struct ptr_ring *r) +{ + r->queue[r->consumer++] = NULL; + if (unlikely(r->consumer >= r->size)) + r->consumer = 0; +} + +static inline void *__ptr_ring_consume(struct ptr_ring *r) +{ + void *ptr; + + ptr = __ptr_ring_peek(r); + if (ptr) + __ptr_ring_discard_one(r); + + return ptr; +} + +static inline void *ptr_ring_consume(struct ptr_ring *r) +{ + void *ptr; + + spin_lock(&r->consumer_lock); + ptr = __ptr_ring_consume(r); + spin_unlock(&r->consumer_lock); + + return ptr; +} + +static inline void *ptr_ring_consume_irq(struct ptr_ring *r) +{ + void *ptr; + + spin_lock_irq(&r->consumer_lock); + ptr = __ptr_ring_consume(r); + spin_unlock_irq(&r->consumer_lock); + + return ptr; +} + +static inline void *ptr_ring_consume_any(struct ptr_ring *r) +{ + unsigned long flags; + void *ptr; + + spin_lock_irqsave(&r->consumer_lock, flags); + ptr = __ptr_ring_consume(r); + spin_unlock_irqrestore(&r->consumer_lock, flags); + + return ptr; +} + +static inline void *ptr_ring_consume_bh(struct ptr_ring *r) +{ + void *ptr; + + spin_lock_bh(&r->consumer_lock); + ptr = __ptr_ring_consume(r); + spin_unlock_bh(&r->consumer_lock); + + return ptr; +} + +/* Cast to structure type and call a function without discarding from FIFO. + * Function must return a value. + * Callers must take consumer_lock. + */ +#define __PTR_RING_PEEK_CALL(r, f) ((f)(__ptr_ring_peek(r))) + +#define PTR_RING_PEEK_CALL(r, f) ({ \ + typeof((f)(NULL)) __PTR_RING_PEEK_CALL_v; \ + \ + spin_lock(&(r)->consumer_lock); \ + __PTR_RING_PEEK_CALL_v = __PTR_RING_PEEK_CALL(r, f); \ + spin_unlock(&(r)->consumer_lock); \ + __PTR_RING_PEEK_CALL_v; \ +}) + +#define PTR_RING_PEEK_CALL_IRQ(r, f) ({ \ + typeof((f)(NULL)) __PTR_RING_PEEK_CALL_v; \ + \ + spin_lock_irq(&(r)->consumer_lock); \ + __PTR_RING_PEEK_CALL_v = __PTR_RING_PEEK_CALL(r, f); \ + spin_unlock_irq(&(r)->consumer_lock); \ + __PTR_RING_PEEK_CALL_v; \ +}) + +#define PTR_RING_PEEK_CALL_BH(r, f) ({ \ + typeof((f)(NULL)) __PTR_RING_PEEK_CALL_v; \ + \ + spin_lock_bh(&(r)->consumer_lock); \ + __PTR_RING_PEEK_CALL_v = __PTR_RING_PEEK_CALL(r, f); \ + spin_unlock_bh(&(r)->consumer_lock); \ + __PTR_RING_PEEK_CALL_v; \ +}) + +#define PTR_RING_PEEK_CALL_ANY(r, f) ({ \ + typeof((f)(NULL)) __PTR_RING_PEEK_CALL_v; \ + unsigned long __PTR_RING_PEEK_CALL_f;\ + \ + spin_lock_irqsave(&(r)->consumer_lock, __PTR_RING_PEEK_CALL_f); \ + __PTR_RING_PEEK_CALL_v = __PTR_RING_PEEK_CALL(r, f); \ + spin_unlock_irqrestore(&(r)->consumer_lock, __PTR_RING_PEEK_CALL_f); \ + __PTR_RING_PEEK_CALL_v; \ +}) + +static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp) +{ + r->queue = kzalloc(ALIGN(size * sizeof *(r->queue), SMP_CACHE_BYTES), + gfp); + if (!r->queue) + return -ENOMEM; + + r->size = size; + r->producer = r->consumer = 0; + spin_lock_init(&r->producer_lock); + spin_lock_init(&r->consumer_lock); + + return 0; +} + +static inline void ptr_ring_cleanup(struct ptr_ring *r) +{ + kfree(r->queue); +} + +#endif /* _LINUX_PTR_RING_H */ -- cgit v1.2.3 From ad69f35d1dc0a79f86627ca56e01f86512602a49 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 13 Jun 2016 23:54:41 +0300 Subject: skb_array: array based FIFO for skbs A simple array based FIFO of pointers. Intended for net stack so uses skbs for type safety. Implemented as a set of wrappers around ptr_ring. Signed-off-by: Michael S. Tsirkin Acked-by: Jesper Dangaard Brouer Tested-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- include/linux/skb_array.h | 144 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 include/linux/skb_array.h (limited to 'include/linux') diff --git a/include/linux/skb_array.h b/include/linux/skb_array.h new file mode 100644 index 000000000000..c4c090223333 --- /dev/null +++ b/include/linux/skb_array.h @@ -0,0 +1,144 @@ +/* + * Definitions for the 'struct skb_array' datastructure. + * + * Author: + * Michael S. Tsirkin + * + * Copyright (C) 2016 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Limited-size FIFO of skbs. Can be used more or less whenever + * sk_buff_head can be used, except you need to know the queue size in + * advance. + * Implemented as a type-safe wrapper around ptr_ring. + */ + +#ifndef _LINUX_SKB_ARRAY_H +#define _LINUX_SKB_ARRAY_H 1 + +#ifdef __KERNEL__ +#include +#include +#include +#endif + +struct skb_array { + struct ptr_ring ring; +}; + +/* Might be slightly faster than skb_array_full below, but callers invoking + * this in a loop must use a compiler barrier, for example cpu_relax(). + */ +static inline bool __skb_array_full(struct skb_array *a) +{ + return __ptr_ring_full(&a->ring); +} + +static inline bool skb_array_full(struct skb_array *a) +{ + return ptr_ring_full(&a->ring); +} + +static inline int skb_array_produce(struct skb_array *a, struct sk_buff *skb) +{ + return ptr_ring_produce(&a->ring, skb); +} + +static inline int skb_array_produce_irq(struct skb_array *a, struct sk_buff *skb) +{ + return ptr_ring_produce_irq(&a->ring, skb); +} + +static inline int skb_array_produce_bh(struct skb_array *a, struct sk_buff *skb) +{ + return ptr_ring_produce_bh(&a->ring, skb); +} + +static inline int skb_array_produce_any(struct skb_array *a, struct sk_buff *skb) +{ + return ptr_ring_produce_any(&a->ring, skb); +} + +/* Might be slightly faster than skb_array_empty below, but callers invoking + * this in a loop must take care to use a compiler barrier, for example + * cpu_relax(). + */ +static inline bool __skb_array_empty(struct skb_array *a) +{ + return !__ptr_ring_peek(&a->ring); +} + +static inline bool skb_array_empty(struct skb_array *a) +{ + return ptr_ring_empty(&a->ring); +} + +static inline struct sk_buff *skb_array_consume(struct skb_array *a) +{ + return ptr_ring_consume(&a->ring); +} + +static inline struct sk_buff *skb_array_consume_irq(struct skb_array *a) +{ + return ptr_ring_consume_irq(&a->ring); +} + +static inline struct sk_buff *skb_array_consume_any(struct skb_array *a) +{ + return ptr_ring_consume_any(&a->ring); +} + +static inline struct sk_buff *skb_array_consume_bh(struct skb_array *a) +{ + return ptr_ring_consume_bh(&a->ring); +} + +static inline int __skb_array_len_with_tag(struct sk_buff *skb) +{ + if (likely(skb)) { + int len = skb->len; + + if (skb_vlan_tag_present(skb)) + len += VLAN_HLEN; + + return len; + } else { + return 0; + } +} + +static inline int skb_array_peek_len(struct skb_array *a) +{ + return PTR_RING_PEEK_CALL(&a->ring, __skb_array_len_with_tag); +} + +static inline int skb_array_peek_len_irq(struct skb_array *a) +{ + return PTR_RING_PEEK_CALL_IRQ(&a->ring, __skb_array_len_with_tag); +} + +static inline int skb_array_peek_len_bh(struct skb_array *a) +{ + return PTR_RING_PEEK_CALL_BH(&a->ring, __skb_array_len_with_tag); +} + +static inline int skb_array_peek_len_any(struct skb_array *a) +{ + return PTR_RING_PEEK_CALL_ANY(&a->ring, __skb_array_len_with_tag); +} + +static inline int skb_array_init(struct skb_array *a, int size, gfp_t gfp) +{ + return ptr_ring_init(&a->ring, size, gfp); +} + +static inline void skb_array_cleanup(struct skb_array *a) +{ + ptr_ring_cleanup(&a->ring); +} + +#endif /* _LINUX_SKB_ARRAY_H */ -- cgit v1.2.3 From 5d49de532002f02755decd1758aac53063a68625 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 13 Jun 2016 23:54:45 +0300 Subject: ptr_ring: resize support This adds ring resize support. Seems to be necessary as users such as tun allow userspace control over queue size. If resize is used, this costs us ability to peek at queue without consumer lock - should not be a big deal as peek and consumer are usually run on the same CPU. If ring is made bigger, ring contents is preserved. If ring is made smaller, extra pointers are passed to an optional destructor callback. Cleanup function also gains destructor callback such that all pointers in queue can be cleaned up. This changes some APIs but we don't have any users yet, so it won't break bisect. Signed-off-by: Michael S. Tsirkin Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- include/linux/ptr_ring.h | 157 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h index 633406f9af8e..562a65e8bcc0 100644 --- a/include/linux/ptr_ring.h +++ b/include/linux/ptr_ring.h @@ -43,9 +43,9 @@ struct ptr_ring { }; /* Note: callers invoking this in a loop must use a compiler barrier, - * for example cpu_relax(). - * Callers don't need to take producer lock - if they don't - * the next call to __ptr_ring_produce may fail. + * for example cpu_relax(). If ring is ever resized, callers must hold + * producer_lock - see e.g. ptr_ring_full. Otherwise, if callers don't hold + * producer_lock, the next call to __ptr_ring_produce may fail. */ static inline bool __ptr_ring_full(struct ptr_ring *r) { @@ -54,16 +54,55 @@ static inline bool __ptr_ring_full(struct ptr_ring *r) static inline bool ptr_ring_full(struct ptr_ring *r) { - barrier(); - return __ptr_ring_full(r); + bool ret; + + spin_lock(&r->producer_lock); + ret = __ptr_ring_full(r); + spin_unlock(&r->producer_lock); + + return ret; +} + +static inline bool ptr_ring_full_irq(struct ptr_ring *r) +{ + bool ret; + + spin_lock_irq(&r->producer_lock); + ret = __ptr_ring_full(r); + spin_unlock_irq(&r->producer_lock); + + return ret; +} + +static inline bool ptr_ring_full_any(struct ptr_ring *r) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&r->producer_lock, flags); + ret = __ptr_ring_full(r); + spin_unlock_irqrestore(&r->producer_lock, flags); + + return ret; +} + +static inline bool ptr_ring_full_bh(struct ptr_ring *r) +{ + bool ret; + + spin_lock_bh(&r->producer_lock); + ret = __ptr_ring_full(r); + spin_unlock_bh(&r->producer_lock); + + return ret; } /* Note: callers invoking this in a loop must use a compiler barrier, - * for example cpu_relax(). + * for example cpu_relax(). Callers must hold producer_lock. */ static inline int __ptr_ring_produce(struct ptr_ring *r, void *ptr) { - if (__ptr_ring_full(r)) + if (r->queue[r->producer]) return -ENOSPC; r->queue[r->producer++] = ptr; @@ -120,20 +159,68 @@ static inline int ptr_ring_produce_bh(struct ptr_ring *r, void *ptr) /* Note: callers invoking this in a loop must use a compiler barrier, * for example cpu_relax(). Callers must take consumer_lock * if they dereference the pointer - see e.g. PTR_RING_PEEK_CALL. - * There's no need for a lock if pointer is merely tested - see e.g. - * ptr_ring_empty. + * If ring is never resized, and if the pointer is merely + * tested, there's no need to take the lock - see e.g. __ptr_ring_empty. */ static inline void *__ptr_ring_peek(struct ptr_ring *r) { return r->queue[r->consumer]; } -static inline bool ptr_ring_empty(struct ptr_ring *r) +/* Note: callers invoking this in a loop must use a compiler barrier, + * for example cpu_relax(). Callers must take consumer_lock + * if the ring is ever resized - see e.g. ptr_ring_empty. + */ +static inline bool __ptr_ring_empty(struct ptr_ring *r) { - barrier(); return !__ptr_ring_peek(r); } +static inline bool ptr_ring_empty(struct ptr_ring *r) +{ + bool ret; + + spin_lock(&r->consumer_lock); + ret = __ptr_ring_empty(r); + spin_unlock(&r->consumer_lock); + + return ret; +} + +static inline bool ptr_ring_empty_irq(struct ptr_ring *r) +{ + bool ret; + + spin_lock_irq(&r->consumer_lock); + ret = __ptr_ring_empty(r); + spin_unlock_irq(&r->consumer_lock); + + return ret; +} + +static inline bool ptr_ring_empty_any(struct ptr_ring *r) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&r->consumer_lock, flags); + ret = __ptr_ring_empty(r); + spin_unlock_irqrestore(&r->consumer_lock, flags); + + return ret; +} + +static inline bool ptr_ring_empty_bh(struct ptr_ring *r) +{ + bool ret; + + spin_lock_bh(&r->consumer_lock); + ret = __ptr_ring_empty(r); + spin_unlock_bh(&r->consumer_lock); + + return ret; +} + /* Must only be called after __ptr_ring_peek returned !NULL */ static inline void __ptr_ring_discard_one(struct ptr_ring *r) { @@ -241,10 +328,14 @@ static inline void *ptr_ring_consume_bh(struct ptr_ring *r) __PTR_RING_PEEK_CALL_v; \ }) +static inline void **__ptr_ring_init_queue_alloc(int size, gfp_t gfp) +{ + return kzalloc(ALIGN(size * sizeof(void *), SMP_CACHE_BYTES), gfp); +} + static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp) { - r->queue = kzalloc(ALIGN(size * sizeof *(r->queue), SMP_CACHE_BYTES), - gfp); + r->queue = __ptr_ring_init_queue_alloc(size, gfp); if (!r->queue) return -ENOMEM; @@ -256,8 +347,46 @@ static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp) return 0; } -static inline void ptr_ring_cleanup(struct ptr_ring *r) +static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp, + void (*destroy)(void *)) +{ + unsigned long flags; + int producer = 0; + void **queue = __ptr_ring_init_queue_alloc(size, gfp); + void **old; + void *ptr; + + if (!queue) + return -ENOMEM; + + spin_lock_irqsave(&(r)->producer_lock, flags); + + while ((ptr = ptr_ring_consume(r))) + if (producer < size) + queue[producer++] = ptr; + else if (destroy) + destroy(ptr); + + r->size = size; + r->producer = producer; + r->consumer = 0; + old = r->queue; + r->queue = queue; + + spin_unlock_irqrestore(&(r)->producer_lock, flags); + + kfree(old); + + return 0; +} + +static inline void ptr_ring_cleanup(struct ptr_ring *r, void (*destroy)(void *)) { + void *ptr; + + if (destroy) + while ((ptr = ptr_ring_consume(r))) + destroy(ptr); kfree(r->queue); } -- cgit v1.2.3 From 7d7072e3bad5569f636d3c54a36da40976bfd505 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 13 Jun 2016 23:54:50 +0300 Subject: skb_array: resize support Update skb_array after ptr_ring API changes. Signed-off-by: Michael S. Tsirkin Acked-by: Jesper Dangaard Brouer Tested-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- include/linux/skb_array.h | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skb_array.h b/include/linux/skb_array.h index c4c090223333..678bfbf78ac4 100644 --- a/include/linux/skb_array.h +++ b/include/linux/skb_array.h @@ -63,9 +63,9 @@ static inline int skb_array_produce_any(struct skb_array *a, struct sk_buff *skb return ptr_ring_produce_any(&a->ring, skb); } -/* Might be slightly faster than skb_array_empty below, but callers invoking - * this in a loop must take care to use a compiler barrier, for example - * cpu_relax(). +/* Might be slightly faster than skb_array_empty below, but only safe if the + * array is never resized. Also, callers invoking this in a loop must take care + * to use a compiler barrier, for example cpu_relax(). */ static inline bool __skb_array_empty(struct skb_array *a) { @@ -77,6 +77,21 @@ static inline bool skb_array_empty(struct skb_array *a) return ptr_ring_empty(&a->ring); } +static inline bool skb_array_empty_bh(struct skb_array *a) +{ + return ptr_ring_empty_bh(&a->ring); +} + +static inline bool skb_array_empty_irq(struct skb_array *a) +{ + return ptr_ring_empty_irq(&a->ring); +} + +static inline bool skb_array_empty_any(struct skb_array *a) +{ + return ptr_ring_empty_any(&a->ring); +} + static inline struct sk_buff *skb_array_consume(struct skb_array *a) { return ptr_ring_consume(&a->ring); @@ -136,9 +151,19 @@ static inline int skb_array_init(struct skb_array *a, int size, gfp_t gfp) return ptr_ring_init(&a->ring, size, gfp); } +void __skb_array_destroy_skb(void *ptr) +{ + kfree_skb(ptr); +} + +int skb_array_resize(struct skb_array *a, int size, gfp_t gfp) +{ + return ptr_ring_resize(&a->ring, size, gfp, __skb_array_destroy_skb); +} + static inline void skb_array_cleanup(struct skb_array *a) { - ptr_ring_cleanup(&a->ring); + ptr_ring_cleanup(&a->ring, __skb_array_destroy_skb); } #endif /* _LINUX_SKB_ARRAY_H */ -- cgit v1.2.3 From 1b5c5493e3e68181be344cb51bf9df192d05ffc2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 13 Jun 2016 20:21:50 -0700 Subject: net_sched: add the ability to defer skb freeing qdisc are changed under RTNL protection and often while blocking BH and root qdisc spinlock. When lots of skbs need to be dropped, we free them under these locks causing TX/RX freezes, and more generally latency spikes. This commit adds rtnl_kfree_skbs(), used to queue skbs for deferred freeing. Actual freeing happens right after RTNL is released, with appropriate scheduling points. rtnl_qdisc_drop() can also be used in place of disc_drop() when RTNL is held. qdisc_reset_queue() and __qdisc_reset_queue() get the new behavior, so standard qdiscs like pfifo, pfifo_fast... have their ->reset() method automatically handled. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 5 +++-- include/net/sch_generic.h | 16 ++++++++++++---- net/core/rtnetlink.c | 22 ++++++++++++++++++++++ net/sched/sch_generic.c | 2 +- 4 files changed, 38 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index c006cc900c44..2daece8979f7 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -89,8 +89,9 @@ void net_inc_egress_queue(void); void net_dec_egress_queue(void); #endif -extern void rtnetlink_init(void); -extern void __rtnl_unlock(void); +void rtnetlink_init(void); +void __rtnl_unlock(void); +void rtnl_kfree_skbs(struct sk_buff *head, struct sk_buff *tail); #define ASSERT_RTNL() do { \ if (unlikely(!rtnl_is_locked())) { \ diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 9a0d177884c6..4f7cee8344c4 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -683,19 +683,21 @@ static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch) return skb; } -static inline void __qdisc_reset_queue(struct Qdisc *sch, - struct sk_buff_head *list) +static inline void __qdisc_reset_queue(struct sk_buff_head *list) { /* * We do not know the backlog in bytes of this list, it * is up to the caller to correct it */ - __skb_queue_purge(list); + if (!skb_queue_empty(list)) { + rtnl_kfree_skbs(list->next, list->prev); + __skb_queue_head_init(list); + } } static inline void qdisc_reset_queue(struct Qdisc *sch) { - __qdisc_reset_queue(sch, &sch->q); + __qdisc_reset_queue(&sch->q); sch->qstats.backlog = 0; } @@ -716,6 +718,12 @@ static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new, return old; } +static inline void rtnl_qdisc_drop(struct sk_buff *skb, struct Qdisc *sch) +{ + rtnl_kfree_skbs(skb, skb); + qdisc_qstats_drop(sch); +} + static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch) { kfree_skb(skb); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index d69c4644f8f2..eb49ca24274a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -71,9 +71,31 @@ void rtnl_lock(void) } EXPORT_SYMBOL(rtnl_lock); +static struct sk_buff *defer_kfree_skb_list; +void rtnl_kfree_skbs(struct sk_buff *head, struct sk_buff *tail) +{ + if (head && tail) { + tail->next = defer_kfree_skb_list; + defer_kfree_skb_list = head; + } +} +EXPORT_SYMBOL(rtnl_kfree_skbs); + void __rtnl_unlock(void) { + struct sk_buff *head = defer_kfree_skb_list; + + defer_kfree_skb_list = NULL; + mutex_unlock(&rtnl_mutex); + + while (head) { + struct sk_buff *next = head->next; + + kfree_skb(head); + cond_resched(); + head = next; + } } void rtnl_unlock(void) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 0c9cb516f2e3..773b632e1e33 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -493,7 +493,7 @@ static void pfifo_fast_reset(struct Qdisc *qdisc) struct pfifo_fast_priv *priv = qdisc_priv(qdisc); for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) - __qdisc_reset_queue(qdisc, band2list(priv, prio)); + __qdisc_reset_queue(band2list(priv, prio)); priv->bitmap = 0; qdisc->qstats.backlog = 0; -- cgit v1.2.3 From 6c7caebc26c5f0b618f0ef6b851e9f5f27c3812f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 13 Jun 2016 14:48:25 +0200 Subject: KVM: introduce kvm->created_vcpus The race between creating the irqchip and the first VCPU is currently fixed by checking the presence of an irqchip before updating kvm->online_vcpus, and undoing the whole VCPU creation if someone created the irqchip in the meanwhile. Instead, introduce a new field in struct kvm that will count VCPUs under a mutex, without the atomic access and memory ordering that we need elsewhere to protect the vcpus array. This also plugs the race and is more easily applicable in all similar circumstances. Reviewed-by: Cornelia Huck Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 8 ++++++++ virt/kvm/kvm_main.c | 23 +++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 1c9c973a7dd9..63c6ab30bc81 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -371,7 +371,15 @@ struct kvm { struct srcu_struct srcu; struct srcu_struct irq_srcu; struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; + + /* + * created_vcpus is protected by kvm->lock, and is incremented + * at the beginning of KVM_CREATE_VCPU. online_vcpus is only + * incremented after storing the kvm_vcpu pointer in vcpus, + * and is accessed atomically. + */ atomic_t online_vcpus; + int created_vcpus; int last_boosted_vcpu; struct list_head vm_list; struct mutex lock; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 02e98f3131bd..15b757ae64e1 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2346,9 +2346,20 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) if (id >= KVM_MAX_VCPU_ID) return -EINVAL; + mutex_lock(&kvm->lock); + if (kvm->created_vcpus == KVM_MAX_VCPUS) { + mutex_unlock(&kvm->lock); + return -EINVAL; + } + + kvm->created_vcpus++; + mutex_unlock(&kvm->lock); + vcpu = kvm_arch_vcpu_create(kvm, id); - if (IS_ERR(vcpu)) - return PTR_ERR(vcpu); + if (IS_ERR(vcpu)) { + r = PTR_ERR(vcpu); + goto vcpu_decrement; + } preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); @@ -2361,10 +2372,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) r = -EINVAL; goto unlock_vcpu_destroy; } - if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) { - r = -EINVAL; - goto unlock_vcpu_destroy; - } if (kvm_get_vcpu_by_id(kvm, id)) { r = -EEXIST; goto unlock_vcpu_destroy; @@ -2397,6 +2404,10 @@ unlock_vcpu_destroy: mutex_unlock(&kvm->lock); vcpu_destroy: kvm_arch_vcpu_destroy(vcpu); +vcpu_decrement: + mutex_lock(&kvm->lock); + kvm->created_vcpus--; + mutex_unlock(&kvm->lock); return r; } -- cgit v1.2.3 From 557abc40d121358883d2da8bc8bf976d6e8ec332 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 13 Jun 2016 14:50:04 +0200 Subject: KVM: remove kvm_vcpu_compatible The new created_vcpus field makes it possible to avoid the race between irqchip and VCPU creation in a much nicer way; just check under kvm->lock whether a VCPU has already been created. We can then remove KVM_APIC_ARCHITECTURE too, because at this point the symbol is only governing the default definition of kvm_vcpu_compatible. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/Kconfig | 1 - arch/x86/kvm/x86.c | 11 +++-------- include/linux/kvm_host.h | 6 ------ virt/kvm/Kconfig | 3 --- virt/kvm/kvm_main.c | 4 ---- 5 files changed, 3 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 639a6e34500c..ab8e32f7b9a8 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -32,7 +32,6 @@ config KVM select HAVE_KVM_IRQ_BYPASS select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_EVENTFD - select KVM_APIC_ARCHITECTURE select KVM_ASYNC_PF select USER_RETURN_NOTIFIER select KVM_MMIO diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bf227212aebb..ab2f45a50bb5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3774,7 +3774,7 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, r = -EEXIST; if (irqchip_in_kernel(kvm)) goto split_irqchip_unlock; - if (atomic_read(&kvm->online_vcpus)) + if (kvm->created_vcpus) goto split_irqchip_unlock; r = kvm_setup_empty_irq_routing(kvm); if (r) @@ -3839,7 +3839,7 @@ long kvm_arch_vm_ioctl(struct file *filp, if (kvm->arch.vpic) goto create_irqchip_unlock; r = -EINVAL; - if (atomic_read(&kvm->online_vcpus)) + if (kvm->created_vcpus) goto create_irqchip_unlock; r = -ENOMEM; vpic = kvm_create_pic(kvm); @@ -3995,7 +3995,7 @@ long kvm_arch_vm_ioctl(struct file *filp, case KVM_SET_BOOT_CPU_ID: r = 0; mutex_lock(&kvm->lock); - if (atomic_read(&kvm->online_vcpus) != 0) + if (kvm->created_vcpus) r = -EBUSY; else kvm->arch.bsp_vcpu_id = arg; @@ -7639,11 +7639,6 @@ bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu) return (vcpu->arch.apic_base & MSR_IA32_APICBASE_BSP) != 0; } -bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) -{ - return irqchip_in_kernel(vcpu->kvm) == lapic_in_kernel(vcpu); -} - struct static_key kvm_no_apic_vcpu __read_mostly; EXPORT_SYMBOL_GPL(kvm_no_apic_vcpu); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 63c6ab30bc81..0640ee92b978 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1105,12 +1105,6 @@ static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) #endif /* CONFIG_HAVE_KVM_EVENTFD */ -#ifdef CONFIG_KVM_APIC_ARCHITECTURE -bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu); -#else -static inline bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) { return true; } -#endif - static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu) { /* diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index e5d6108f5e85..b0cc1a34db27 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -16,9 +16,6 @@ config HAVE_KVM_EVENTFD bool select EVENTFD -config KVM_APIC_ARCHITECTURE - bool - config KVM_MMIO bool diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 15b757ae64e1..ef54b4c31792 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2368,10 +2368,6 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) goto vcpu_destroy; mutex_lock(&kvm->lock); - if (!kvm_vcpu_compatible(vcpu)) { - r = -EINVAL; - goto unlock_vcpu_destroy; - } if (kvm_get_vcpu_by_id(kvm, id)) { r = -EEXIST; goto unlock_vcpu_destroy; -- cgit v1.2.3 From 3a37f7275cda5ad25c1fe9be8f20c76c60d175fa Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sun, 1 May 2016 18:46:54 -0700 Subject: rcu: No ordering for rcu_assign_pointer() of NULL This commit does a compile-time check for rcu_assign_pointer() of NULL, and uses WRITE_ONCE() rather than smp_store_release() in that case. Reported-by: Christoph Hellwig Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index c61b6b9506e7..a8af79738a0e 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -650,7 +650,16 @@ static inline void rcu_preempt_sleep_check(void) * please be careful when making changes to rcu_assign_pointer() and the * other macros that it invokes. */ -#define rcu_assign_pointer(p, v) smp_store_release(&p, RCU_INITIALIZER(v)) +#define rcu_assign_pointer(p, v) \ +({ \ + uintptr_t _r_a_p__v = (uintptr_t)(v); \ + \ + if (__builtin_constant_p(v) && (_r_a_p__v) == (uintptr_t)NULL) \ + WRITE_ONCE((p), (typeof(p))(_r_a_p__v)); \ + else \ + smp_store_release(&p, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \ + _r_a_p__v; \ +}) /** * rcu_access_pointer() - fetch RCU pointer with no dereferencing -- cgit v1.2.3 From 4929c913bda505dbe44bb42c00da06011fee6c9d Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 2 May 2016 11:58:56 -0700 Subject: rcu: Make call_rcu_tasks() tolerate first call with irqs disabled Currently, if the very first call to call_rcu_tasks() has irqs disabled, it will create the rcu_tasks_kthread with irqs disabled, which will result in a splat in the memory allocator, which kthread_run() invokes with the expectation that irqs are enabled. This commit fixes this problem by deferring kthread creation if called with irqs disabled. The first call to call_rcu_tasks() that has irqs enabled will create the kthread. This bug was detected by rcutorture changes that were motivated by Iftekhar Ahmed's mutation-testing efforts. Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 1 + kernel/rcu/update.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index a8af79738a0e..3bc5de08c0b7 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -45,6 +45,7 @@ #include #include #include +#include #include diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index 3e888cd5a594..f0d8322bc3ec 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -528,6 +528,7 @@ static int rcu_task_stall_timeout __read_mostly = HZ * 60 * 10; module_param(rcu_task_stall_timeout, int, 0644); static void rcu_spawn_tasks_kthread(void); +static struct task_struct *rcu_tasks_kthread_ptr; /* * Post an RCU-tasks callback. First call must be from process context @@ -537,6 +538,7 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func) { unsigned long flags; bool needwake; + bool havetask = READ_ONCE(rcu_tasks_kthread_ptr); rhp->next = NULL; rhp->func = func; @@ -545,7 +547,9 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func) *rcu_tasks_cbs_tail = rhp; rcu_tasks_cbs_tail = &rhp->next; raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags); - if (needwake) { + /* We can't create the thread unless interrupts are enabled. */ + if ((needwake && havetask) || + (!havetask && !irqs_disabled_flags(flags))) { rcu_spawn_tasks_kthread(); wake_up(&rcu_tasks_cbs_wq); } @@ -790,7 +794,6 @@ static int __noreturn rcu_tasks_kthread(void *arg) static void rcu_spawn_tasks_kthread(void) { static DEFINE_MUTEX(rcu_tasks_kthread_mutex); - static struct task_struct *rcu_tasks_kthread_ptr; struct task_struct *t; if (READ_ONCE(rcu_tasks_kthread_ptr)) { -- cgit v1.2.3 From 088e9d253d3a4ab7e058dd84bb532c32dadf1882 Mon Sep 17 00:00:00 2001 From: Daniel Bristot de Oliveira Date: Thu, 2 Jun 2016 13:51:41 -0300 Subject: rcu: sysctl: Panic on RCU Stall It is not always easy to determine the cause of an RCU stall just by analysing the RCU stall messages, mainly when the problem is caused by the indirect starvation of rcu threads. For example, when preempt_rcu is not awakened due to the starvation of a timer softirq. We have been hard coding panic() in the RCU stall functions for some time while testing the kernel-rt. But this is not possible in some scenarios, like when supporting customers. This patch implements the sysctl kernel.panic_on_rcu_stall. If set to 1, the system will panic() when an RCU stall takes place, enabling the capture of a vmcore. The vmcore provides a way to analyze all kernel/tasks states, helping out to point to the culprit and the solution for the stall. The kernel.panic_on_rcu_stall sysctl is disabled by default. Changes from v1: - Fixed a typo in the git log - The if(sysctl_panic_on_rcu_stall) panic() is in a static function - Fixed the CONFIG_TINY_RCU compilation issue - The var sysctl_panic_on_rcu_stall is now __read_mostly Cc: Jonathan Corbet Cc: "Paul E. McKenney" Cc: Josh Triplett Cc: Steven Rostedt Cc: Mathieu Desnoyers Cc: Lai Jiangshan Acked-by: Christian Borntraeger Reviewed-by: Josh Triplett Reviewed-by: Arnaldo Carvalho de Melo Tested-by: "Luis Claudio R. Goncalves" Signed-off-by: Daniel Bristot de Oliveira Signed-off-by: Paul E. McKenney --- Documentation/sysctl/kernel.txt | 12 ++++++++++++ include/linux/kernel.h | 1 + kernel/rcu/tree.c | 12 ++++++++++++ kernel/sysctl.c | 11 +++++++++++ 4 files changed, 36 insertions(+) (limited to 'include/linux') diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index a3683ce2a2f3..33204604de6c 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -58,6 +58,7 @@ show up in /proc/sys/kernel: - panic_on_stackoverflow - panic_on_unrecovered_nmi - panic_on_warn +- panic_on_rcu_stall - perf_cpu_time_max_percent - perf_event_paranoid - perf_event_max_stack @@ -618,6 +619,17 @@ a kernel rebuild when attempting to kdump at the location of a WARN(). ============================================================== +panic_on_rcu_stall: + +When set to 1, calls panic() after RCU stall detection messages. This +is useful to define the root cause of RCU stalls using a vmcore. + +0: do not panic() when RCU stall takes place, default behavior. + +1: panic() after printing RCU stall messages. + +============================================================== + perf_cpu_time_max_percent: Hints to the kernel how much CPU time it should be allowed to diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 94aa10ffe156..c42082112ec8 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -451,6 +451,7 @@ extern int panic_on_oops; extern int panic_on_unrecovered_nmi; extern int panic_on_io_nmi; extern int panic_on_warn; +extern int sysctl_panic_on_rcu_stall; extern int sysctl_panic_on_stackoverflow; extern bool crash_kexec_post_notifiers; diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index c844b6142a86..e5ca15a461b9 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -125,6 +125,8 @@ int rcu_num_lvls __read_mostly = RCU_NUM_LVLS; /* Number of rcu_nodes at specified level. */ static int num_rcu_lvl[] = NUM_RCU_LVL_INIT; int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */ +/* panic() on RCU Stall sysctl. */ +int sysctl_panic_on_rcu_stall __read_mostly; /* * The rcu_scheduler_active variable transitions from zero to one just @@ -1312,6 +1314,12 @@ static void rcu_stall_kick_kthreads(struct rcu_state *rsp) } } +static inline void panic_on_rcu_stall(void) +{ + if (sysctl_panic_on_rcu_stall) + panic("RCU Stall\n"); +} + static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) { int cpu; @@ -1391,6 +1399,8 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum) rcu_check_gp_kthread_starvation(rsp); + panic_on_rcu_stall(); + force_quiescent_state(rsp); /* Kick them all. */ } @@ -1431,6 +1441,8 @@ static void print_cpu_stall(struct rcu_state *rsp) jiffies + 3 * rcu_jiffies_till_stall_check() + 3); raw_spin_unlock_irqrestore_rcu_node(rnp, flags); + panic_on_rcu_stall(); + /* * Attempt to revive the RCU machinery by forcing a context switch. * diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 87b2fc38398b..35f0dcb1cb4f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1204,6 +1204,17 @@ static struct ctl_table kern_table[] = { .extra1 = &one, .extra2 = &one, }, +#endif +#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) + { + .procname = "panic_on_rcu_stall", + .data = &sysctl_panic_on_rcu_stall, + .maxlen = sizeof(sysctl_panic_on_rcu_stall), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, #endif { } }; -- cgit v1.2.3 From e63a46bef01ff3064f44dba145833284fb6adeec Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 15 Jun 2016 18:17:27 -0700 Subject: block: introduce device_add_disk() In preparation for removing the ->driverfs_dev member of a gendisk, add an api that takes the parent device as a parameter to add_disk(). For now this maintains the status quo of WARN()ing on failure, but not return a error code. Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Bart Van Assche Signed-off-by: Dan Williams --- block/genhd.c | 17 +++++++++++------ include/linux/genhd.h | 8 +++++++- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/block/genhd.c b/block/genhd.c index 9f42526b4d62..fb2d9aeb75a5 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -506,7 +506,7 @@ static int exact_lock(dev_t devt, void *data) return 0; } -static void register_disk(struct gendisk *disk) +static void register_disk(struct device *parent, struct gendisk *disk) { struct device *ddev = disk_to_dev(disk); struct block_device *bdev; @@ -514,7 +514,7 @@ static void register_disk(struct gendisk *disk) struct hd_struct *part; int err; - ddev->parent = disk->driverfs_dev; + ddev->parent = parent; dev_set_name(ddev, "%s", disk->disk_name); @@ -573,7 +573,8 @@ exit: } /** - * add_disk - add partitioning information to kernel list + * device_add_disk - add partitioning information to kernel list + * @parent: parent device for the disk * @disk: per-device partitioning information * * This function registers the partitioning information in @disk @@ -581,7 +582,7 @@ exit: * * FIXME: error handling */ -void add_disk(struct gendisk *disk) +void device_add_disk(struct device *parent, struct gendisk *disk) { struct backing_dev_info *bdi; dev_t devt; @@ -617,7 +618,11 @@ void add_disk(struct gendisk *disk) blk_register_region(disk_devt(disk), disk->minors, NULL, exact_match, exact_lock, disk); - register_disk(disk); + + /* temporary while we convert usages to use disk_to_dev(disk)->parent */ + disk->driverfs_dev = parent; + + register_disk(parent, disk); blk_register_queue(disk); /* @@ -633,7 +638,7 @@ void add_disk(struct gendisk *disk) disk_add_events(disk); blk_integrity_add(disk); } -EXPORT_SYMBOL(add_disk); +EXPORT_SYMBOL(device_add_disk); void del_gendisk(struct gendisk *disk) { diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 359a8e4bd44d..df1dabbfd388 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -414,7 +414,13 @@ static inline void free_part_info(struct hd_struct *part) extern void part_round_stats(int cpu, struct hd_struct *part); /* block/genhd.c */ -extern void add_disk(struct gendisk *disk); +extern void device_add_disk(struct device *parent, struct gendisk *disk); +static inline void add_disk(struct gendisk *disk) +{ + /* temporary while we convert callers to device_add_disk */ + device_add_disk(disk->driverfs_dev, disk); +} + extern void del_gendisk(struct gendisk *gp); extern struct gendisk *get_gendisk(dev_t dev, int *partno); extern struct block_device *bdget_disk(struct gendisk *disk, int partno); -- cgit v1.2.3 From 8626a0c83b0d471d859bcd908d016874df951fc3 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 15 Jun 2016 21:20:16 +0200 Subject: 6lowpan: add private neighbour data This patch will introduce a 6lowpan neighbour private data. Like the interface private data we handle private data for generic 6lowpan and for link-layer specific 6lowpan. The current first use case if to save the short address for a 802.15.4 6lowpan neighbour. Cc: David S. Miller Reviewed-by: Stefan Schmidt Acked-by: YOSHIFUJI Hideaki Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +-- include/net/6lowpan.h | 10 ++++++++++ net/ieee802154/6lowpan/core.c | 12 ++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d101e4d904ba..36e43bd422f8 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1483,8 +1483,7 @@ enum netdev_priv_flags { * @perm_addr: Permanent hw address * @addr_assign_type: Hw address assignment type * @addr_len: Hardware address length - * @neigh_priv_len; Used in neigh_alloc(), - * initialized only in atm/clip.c + * @neigh_priv_len: Used in neigh_alloc() * @dev_id: Used to differentiate devices that share * the same link layer address * @dev_port: Used to differentiate devices that share diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h index da84cf920b78..2d9b9d39221e 100644 --- a/include/net/6lowpan.h +++ b/include/net/6lowpan.h @@ -141,6 +141,16 @@ struct lowpan_dev { u8 priv[0] __aligned(sizeof(void *)); }; +struct lowpan_802154_neigh { + __le16 short_addr; +}; + +static inline +struct lowpan_802154_neigh *lowpan_802154_neigh(void *neigh_priv) +{ + return neigh_priv; +} + static inline struct lowpan_dev *lowpan_dev(const struct net_device *dev) { diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index 4e2b30894224..8c004a0c8d64 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -81,11 +81,21 @@ static int lowpan_stop(struct net_device *dev) return 0; } +static int lowpan_neigh_construct(struct neighbour *n) +{ + struct lowpan_802154_neigh *neigh = lowpan_802154_neigh(neighbour_priv(n)); + + /* default no short_addr is available for a neighbour */ + neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC); + return 0; +} + static const struct net_device_ops lowpan_netdev_ops = { .ndo_init = lowpan_dev_init, .ndo_start_xmit = lowpan_xmit, .ndo_open = lowpan_open, .ndo_stop = lowpan_stop, + .ndo_neigh_construct = lowpan_neigh_construct, }; static void lowpan_setup(struct net_device *ldev) @@ -150,6 +160,8 @@ static int lowpan_newlink(struct net *src_net, struct net_device *ldev, wdev->needed_headroom; ldev->needed_tailroom = wdev->needed_tailroom; + ldev->neigh_priv_len = sizeof(struct lowpan_802154_neigh); + ret = lowpan_register_netdevice(ldev, LOWPAN_LLTYPE_IEEE802154); if (ret < 0) { dev_put(wdev); -- cgit v1.2.3 From f997c55c1dc8841b3ee4df0493d0ac7966d42165 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 15 Jun 2016 21:20:23 +0200 Subject: ipv6: introduce neighbour discovery ops This patch introduces neighbour discovery ops callback structure. The idea is to separate the handling for 6LoWPAN into the 6lowpan module. These callback offers 6lowpan different handling, such as 802.15.4 short address handling or RFC6775 (Neighbor Discovery Optimization for IPv6 over 6LoWPANs). Cc: David S. Miller Cc: Alexey Kuznetsov Cc: James Morris Cc: Hideaki YOSHIFUJI Cc: Patrick McHardy Acked-by: YOSHIFUJI Hideaki Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/linux/netdevice.h | 5 ++ include/net/ndisc.h | 197 +++++++++++++++++++++++++++++++++++++++++++++- net/ipv6/addrconf.c | 13 ++- net/ipv6/ndisc.c | 101 ++++++++++++++++-------- net/ipv6/route.c | 8 +- 5 files changed, 284 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 36e43bd422f8..890158e99159 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1456,6 +1456,8 @@ enum netdev_priv_flags { * @netdev_ops: Includes several pointers to callbacks, * if one wants to override the ndo_*() functions * @ethtool_ops: Management operations + * @ndisc_ops: Includes callbacks for different IPv6 neighbour + * discovery handling. Necessary for e.g. 6LoWPAN. * @header_ops: Includes callbacks for creating,parsing,caching,etc * of Layer 2 headers. * @@ -1672,6 +1674,9 @@ struct net_device { #ifdef CONFIG_NET_L3_MASTER_DEV const struct l3mdev_ops *l3mdev_ops; #endif +#if IS_ENABLED(CONFIG_IPV6) + const struct ndisc_ops *ndisc_ops; +#endif const struct header_ops *header_ops; diff --git a/include/net/ndisc.h b/include/net/ndisc.h index c8962adf24d0..a5e276703cb3 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -58,6 +58,7 @@ struct inet6_dev; struct net_device; struct net_proto_family; struct sk_buff; +struct prefix_info; extern struct neigh_table nd_tbl; @@ -110,9 +111,182 @@ struct ndisc_options { #define NDISC_OPT_SPACE(len) (((len)+2+7)&~7) -struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, +struct ndisc_options *ndisc_parse_options(const struct net_device *dev, + u8 *opt, int opt_len, struct ndisc_options *ndopts); +#define NDISC_OPS_REDIRECT_DATA_SPACE 2 + +/* + * This structure defines the hooks for IPv6 neighbour discovery. + * The following hooks can be defined; unless noted otherwise, they are + * optional and can be filled with a null pointer. + * + * int (*is_useropt)(u8 nd_opt_type): + * This function is called when IPv6 decide RA userspace options. if + * this function returns 1 then the option given by nd_opt_type will + * be handled as userspace option additional to the IPv6 options. + * + * int (*parse_options)(const struct net_device *dev, + * struct nd_opt_hdr *nd_opt, + * struct ndisc_options *ndopts): + * This function is called while parsing ndisc ops and put each position + * as pointer into ndopts. If this function return unequal 0, then this + * function took care about the ndisc option, if 0 then the IPv6 ndisc + * option parser will take care about that option. + * + * void (*update)(const struct net_device *dev, struct neighbour *n, + * u32 flags, u8 icmp6_type, + * const struct ndisc_options *ndopts): + * This function is called when IPv6 ndisc updates the neighbour cache + * entry. Additional options which can be updated may be previously + * parsed by parse_opts callback and accessible over ndopts parameter. + * + * int (*opt_addr_space)(const struct net_device *dev, u8 icmp6_type, + * struct neighbour *neigh, u8 *ha_buf, + * u8 **ha): + * This function is called when the necessary option space will be + * calculated before allocating a skb. The parameters neigh, ha_buf + * abd ha are available on NDISC_REDIRECT messages only. + * + * void (*fill_addr_option)(const struct net_device *dev, + * struct sk_buff *skb, u8 icmp6_type, + * const u8 *ha): + * This function is called when the skb will finally fill the option + * fields inside skb. NOTE: this callback should fill the option + * fields to the skb which are previously indicated by opt_space + * parameter. That means the decision to add such option should + * not lost between these two callbacks, e.g. protected by interface + * up state. + * + * void (*prefix_rcv_add_addr)(struct net *net, struct net_device *dev, + * const struct prefix_info *pinfo, + * struct inet6_dev *in6_dev, + * struct in6_addr *addr, + * int addr_type, u32 addr_flags, + * bool sllao, bool tokenized, + * __u32 valid_lft, u32 prefered_lft, + * bool dev_addr_generated): + * This function is called when a RA messages is received with valid + * PIO option fields and an IPv6 address will be added to the interface + * for autoconfiguration. The parameter dev_addr_generated reports about + * if the address was based on dev->dev_addr or not. This can be used + * to add a second address if link-layer operates with two link layer + * addresses. E.g. 802.15.4 6LoWPAN. + */ +struct ndisc_ops { + int (*is_useropt)(u8 nd_opt_type); + int (*parse_options)(const struct net_device *dev, + struct nd_opt_hdr *nd_opt, + struct ndisc_options *ndopts); + void (*update)(const struct net_device *dev, struct neighbour *n, + u32 flags, u8 icmp6_type, + const struct ndisc_options *ndopts); + int (*opt_addr_space)(const struct net_device *dev, u8 icmp6_type, + struct neighbour *neigh, u8 *ha_buf, + u8 **ha); + void (*fill_addr_option)(const struct net_device *dev, + struct sk_buff *skb, u8 icmp6_type, + const u8 *ha); + void (*prefix_rcv_add_addr)(struct net *net, struct net_device *dev, + const struct prefix_info *pinfo, + struct inet6_dev *in6_dev, + struct in6_addr *addr, + int addr_type, u32 addr_flags, + bool sllao, bool tokenized, + __u32 valid_lft, u32 prefered_lft, + bool dev_addr_generated); +}; + +#if IS_ENABLED(CONFIG_IPV6) +static inline int ndisc_ops_is_useropt(const struct net_device *dev, + u8 nd_opt_type) +{ + if (dev->ndisc_ops && dev->ndisc_ops->is_useropt) + return dev->ndisc_ops->is_useropt(nd_opt_type); + else + return 0; +} + +static inline int ndisc_ops_parse_options(const struct net_device *dev, + struct nd_opt_hdr *nd_opt, + struct ndisc_options *ndopts) +{ + if (dev->ndisc_ops && dev->ndisc_ops->parse_options) + return dev->ndisc_ops->parse_options(dev, nd_opt, ndopts); + else + return 0; +} + +static inline void ndisc_ops_update(const struct net_device *dev, + struct neighbour *n, u32 flags, + u8 icmp6_type, + const struct ndisc_options *ndopts) +{ + if (dev->ndisc_ops && dev->ndisc_ops->update) + dev->ndisc_ops->update(dev, n, flags, icmp6_type, ndopts); +} + +static inline int ndisc_ops_opt_addr_space(const struct net_device *dev, + u8 icmp6_type) +{ + if (dev->ndisc_ops && dev->ndisc_ops->opt_addr_space && + icmp6_type != NDISC_REDIRECT) + return dev->ndisc_ops->opt_addr_space(dev, icmp6_type, NULL, + NULL, NULL); + else + return 0; +} + +static inline int ndisc_ops_redirect_opt_addr_space(const struct net_device *dev, + struct neighbour *neigh, + u8 *ha_buf, u8 **ha) +{ + if (dev->ndisc_ops && dev->ndisc_ops->opt_addr_space) + return dev->ndisc_ops->opt_addr_space(dev, NDISC_REDIRECT, + neigh, ha_buf, ha); + else + return 0; +} + +static inline void ndisc_ops_fill_addr_option(const struct net_device *dev, + struct sk_buff *skb, + u8 icmp6_type) +{ + if (dev->ndisc_ops && dev->ndisc_ops->fill_addr_option && + icmp6_type != NDISC_REDIRECT) + dev->ndisc_ops->fill_addr_option(dev, skb, icmp6_type, NULL); +} + +static inline void ndisc_ops_fill_redirect_addr_option(const struct net_device *dev, + struct sk_buff *skb, + const u8 *ha) +{ + if (dev->ndisc_ops && dev->ndisc_ops->fill_addr_option) + dev->ndisc_ops->fill_addr_option(dev, skb, NDISC_REDIRECT, ha); +} + +static inline void ndisc_ops_prefix_rcv_add_addr(struct net *net, + struct net_device *dev, + const struct prefix_info *pinfo, + struct inet6_dev *in6_dev, + struct in6_addr *addr, + int addr_type, u32 addr_flags, + bool sllao, bool tokenized, + __u32 valid_lft, + u32 prefered_lft, + bool dev_addr_generated) +{ + if (dev->ndisc_ops && dev->ndisc_ops->prefix_rcv_add_addr) + dev->ndisc_ops->prefix_rcv_add_addr(net, dev, pinfo, in6_dev, + addr, addr_type, + addr_flags, sllao, + tokenized, valid_lft, + prefered_lft, + dev_addr_generated); +} +#endif + /* * Return the padding between the option length and the start of the * link addr. Currently only IP-over-InfiniBand needs this, although @@ -132,11 +306,25 @@ static inline int __ndisc_opt_addr_space(unsigned char addr_len, int pad) return NDISC_OPT_SPACE(addr_len + pad); } -static inline int ndisc_opt_addr_space(struct net_device *dev) +#if IS_ENABLED(CONFIG_IPV6) +static inline int ndisc_opt_addr_space(struct net_device *dev, u8 icmp6_type) +{ + return __ndisc_opt_addr_space(dev->addr_len, + ndisc_addr_option_pad(dev->type)) + + ndisc_ops_opt_addr_space(dev, icmp6_type); +} + +static inline int ndisc_redirect_opt_addr_space(struct net_device *dev, + struct neighbour *neigh, + u8 *ops_data_buf, + u8 **ops_data) { return __ndisc_opt_addr_space(dev->addr_len, - ndisc_addr_option_pad(dev->type)); + ndisc_addr_option_pad(dev->type)) + + ndisc_ops_redirect_opt_addr_space(dev, neigh, ops_data_buf, + ops_data); } +#endif static inline u8 *__ndisc_opt_addr_data(struct nd_opt_hdr *p, unsigned char addr_len, int prepad) @@ -205,6 +393,9 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target); int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir); +void ndisc_update(const struct net_device *dev, struct neighbour *neigh, + const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type, + struct ndisc_options *ndopts); /* * IGMP diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 44c1cefdb299..b6e9bdc610f2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2531,7 +2531,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) if (pinfo->autoconf && in6_dev->cnf.autoconf) { struct in6_addr addr; - bool tokenized = false; + bool tokenized = false, dev_addr_generated = false; if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); @@ -2550,6 +2550,8 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { goto put; + } else { + dev_addr_generated = true; } goto ok; } @@ -2565,6 +2567,15 @@ ok: prefered_lft); if (err) goto put; + + /* Ignore error case here because previous prefix add addr was + * successful which will be notified. + */ + ndisc_ops_prefix_rcv_add_addr(net, dev, pinfo, in6_dev, &addr, + addr_type, addr_flags, sllao, + tokenized, valid_lft, + prefered_lft, + dev_addr_generated); } inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo); put: diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index a7b9468e684a..2f4afd17954b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -172,10 +172,19 @@ static void __ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data, } static inline void ndisc_fill_addr_option(struct sk_buff *skb, int type, - void *data) + void *data, u8 icmp6_type) { __ndisc_fill_addr_option(skb, type, data, skb->dev->addr_len, ndisc_addr_option_pad(skb->dev->type)); + ndisc_ops_fill_addr_option(skb->dev, skb, icmp6_type); +} + +static inline void ndisc_fill_redirect_addr_option(struct sk_buff *skb, + void *ha, + const u8 *ops_data) +{ + ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha, NDISC_REDIRECT); + ndisc_ops_fill_redirect_addr_option(skb->dev, skb, ops_data); } static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, @@ -191,24 +200,28 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, return cur <= end && cur->nd_opt_type == type ? cur : NULL; } -static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) +static inline int ndisc_is_useropt(const struct net_device *dev, + struct nd_opt_hdr *opt) { return opt->nd_opt_type == ND_OPT_RDNSS || - opt->nd_opt_type == ND_OPT_DNSSL; + opt->nd_opt_type == ND_OPT_DNSSL || + ndisc_ops_is_useropt(dev, opt->nd_opt_type); } -static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, +static struct nd_opt_hdr *ndisc_next_useropt(const struct net_device *dev, + struct nd_opt_hdr *cur, struct nd_opt_hdr *end) { if (!cur || !end || cur >= end) return NULL; do { cur = ((void *)cur) + (cur->nd_opt_len << 3); - } while (cur < end && !ndisc_is_useropt(cur)); - return cur <= end && ndisc_is_useropt(cur) ? cur : NULL; + } while (cur < end && !ndisc_is_useropt(dev, cur)); + return cur <= end && ndisc_is_useropt(dev, cur) ? cur : NULL; } -struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, +struct ndisc_options *ndisc_parse_options(const struct net_device *dev, + u8 *opt, int opt_len, struct ndisc_options *ndopts) { struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt; @@ -223,6 +236,8 @@ struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, l = nd_opt->nd_opt_len << 3; if (opt_len < l || l == 0) return NULL; + if (ndisc_ops_parse_options(dev, nd_opt, ndopts)) + goto next_opt; switch (nd_opt->nd_opt_type) { case ND_OPT_SOURCE_LL_ADDR: case ND_OPT_TARGET_LL_ADDR: @@ -249,7 +264,7 @@ struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, break; #endif default: - if (ndisc_is_useropt(nd_opt)) { + if (ndisc_is_useropt(dev, nd_opt)) { ndopts->nd_useropts_end = nd_opt; if (!ndopts->nd_useropts) ndopts->nd_useropts = nd_opt; @@ -266,6 +281,7 @@ struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, nd_opt->nd_opt_len); } } +next_opt: opt_len -= l; nd_opt = ((void *)nd_opt) + l; } @@ -515,7 +531,8 @@ void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr, if (!dev->addr_len) inc_opt = 0; if (inc_opt) - optlen += ndisc_opt_addr_space(dev); + optlen += ndisc_opt_addr_space(dev, + NDISC_NEIGHBOUR_ADVERTISEMENT); skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); if (!skb) @@ -534,8 +551,8 @@ void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr, if (inc_opt) ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, - dev->dev_addr); - + dev->dev_addr, + NDISC_NEIGHBOUR_ADVERTISEMENT); ndisc_send_skb(skb, daddr, src_addr); } @@ -580,7 +597,8 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, if (ipv6_addr_any(saddr)) inc_opt = false; if (inc_opt) - optlen += ndisc_opt_addr_space(dev); + optlen += ndisc_opt_addr_space(dev, + NDISC_NEIGHBOUR_SOLICITATION); skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); if (!skb) @@ -596,7 +614,8 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, if (inc_opt) ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, - dev->dev_addr); + dev->dev_addr, + NDISC_NEIGHBOUR_SOLICITATION); ndisc_send_skb(skb, daddr, saddr); } @@ -632,7 +651,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, } #endif if (send_sllao) - optlen += ndisc_opt_addr_space(dev); + optlen += ndisc_opt_addr_space(dev, NDISC_ROUTER_SOLICITATION); skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); if (!skb) @@ -647,7 +666,8 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, if (send_sllao) ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, - dev->dev_addr); + dev->dev_addr, + NDISC_ROUTER_SOLICITATION); ndisc_send_skb(skb, daddr, saddr); } @@ -708,6 +728,15 @@ static int pndisc_is_router(const void *pkey, return ret; } +void ndisc_update(const struct net_device *dev, struct neighbour *neigh, + const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type, + struct ndisc_options *ndopts) +{ + neigh_update(neigh, lladdr, new, flags); + /* report ndisc ops about neighbour update */ + ndisc_ops_update(dev, neigh, flags, icmp6_type, ndopts); +} + static void ndisc_recv_ns(struct sk_buff *skb) { struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); @@ -744,7 +773,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) return; } - if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) { + if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) { ND_PRINTK(2, warn, "NS: invalid ND options\n"); return; } @@ -862,9 +891,10 @@ have_ifp: neigh = __neigh_lookup(&nd_tbl, saddr, dev, !inc || lladdr || !dev->addr_len); if (neigh) - neigh_update(neigh, lladdr, NUD_STALE, + ndisc_update(dev, neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| - NEIGH_UPDATE_F_OVERRIDE); + NEIGH_UPDATE_F_OVERRIDE, + NDISC_NEIGHBOUR_SOLICITATION, &ndopts); if (neigh || !dev->header_ops) { ndisc_send_na(dev, saddr, &msg->target, !!is_router, true, (ifp != NULL && inc), inc); @@ -917,7 +947,7 @@ static void ndisc_recv_na(struct sk_buff *skb) idev->cnf.drop_unsolicited_na) return; - if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) { + if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) { ND_PRINTK(2, warn, "NS: invalid ND option\n"); return; } @@ -973,12 +1003,13 @@ static void ndisc_recv_na(struct sk_buff *skb) goto out; } - neigh_update(neigh, lladdr, + ndisc_update(dev, neigh, lladdr, msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)| NEIGH_UPDATE_F_OVERRIDE_ISROUTER| - (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0)); + (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0), + NDISC_NEIGHBOUR_ADVERTISEMENT, &ndopts); if ((old_flags & ~neigh->flags) & NTF_ROUTER) { /* @@ -1023,7 +1054,7 @@ static void ndisc_recv_rs(struct sk_buff *skb) goto out; /* Parse ND options */ - if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) { + if (!ndisc_parse_options(skb->dev, rs_msg->opt, ndoptlen, &ndopts)) { ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n"); goto out; } @@ -1037,10 +1068,11 @@ static void ndisc_recv_rs(struct sk_buff *skb) neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1); if (neigh) { - neigh_update(neigh, lladdr, NUD_STALE, + ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE| - NEIGH_UPDATE_F_OVERRIDE_ISROUTER); + NEIGH_UPDATE_F_OVERRIDE_ISROUTER, + NDISC_ROUTER_SOLICITATION, &ndopts); neigh_release(neigh); } out: @@ -1141,7 +1173,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } - if (!ndisc_parse_options(opt, optlen, &ndopts)) { + if (!ndisc_parse_options(skb->dev, opt, optlen, &ndopts)) { ND_PRINTK(2, warn, "RA: invalid ND options\n"); return; } @@ -1335,11 +1367,12 @@ skip_linkparms: goto out; } } - neigh_update(neigh, lladdr, NUD_STALE, + ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE_ISROUTER| - NEIGH_UPDATE_F_ISROUTER); + NEIGH_UPDATE_F_ISROUTER, + NDISC_ROUTER_ADVERTISEMENT, &ndopts); } if (!ipv6_accept_ra(in6_dev)) { @@ -1427,7 +1460,8 @@ skip_routeinfo: struct nd_opt_hdr *p; for (p = ndopts.nd_useropts; p; - p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) { + p = ndisc_next_useropt(skb->dev, p, + ndopts.nd_useropts_end)) { ndisc_ra_useropt(skb, p); } } @@ -1465,7 +1499,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) return; } - if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) + if (!ndisc_parse_options(skb->dev, msg->opt, ndoptlen, &ndopts)) return; if (!ndopts.nd_opts_rh) { @@ -1510,7 +1544,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) struct dst_entry *dst; struct flowi6 fl6; int rd_len; - u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; + u8 ha_buf[MAX_ADDR_LEN], *ha = NULL, + ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL; int oif = l3mdev_fib_oif(dev); bool ret; @@ -1569,7 +1604,9 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) memcpy(ha_buf, neigh->ha, dev->addr_len); read_unlock_bh(&neigh->lock); ha = ha_buf; - optlen += ndisc_opt_addr_space(dev); + optlen += ndisc_redirect_opt_addr_space(dev, neigh, + ops_data_buf, + &ops_data); } else read_unlock_bh(&neigh->lock); @@ -1600,7 +1637,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) */ if (ha) - ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha); + ndisc_fill_redirect_addr_option(buff, ha, ops_data); /* * build redirect option and copy skb over to the new packet. diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d51a1a48b839..9e1516785dac 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2201,7 +2201,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu * first-hop router for the specified ICMP Destination Address. */ - if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) { + if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) { net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); return; } @@ -2236,12 +2236,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu * We have finally decided to accept it. */ - neigh_update(neigh, lladdr, NUD_STALE, + ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE| (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER| - NEIGH_UPDATE_F_ISROUTER)) - ); + NEIGH_UPDATE_F_ISROUTER)), + NDISC_REDIRECT, &ndopts); nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL); if (!nrt) -- cgit v1.2.3 From 61d1b6a42fec61c5065f54cc62cef02b483c69fb Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 15 Jun 2016 22:47:12 +0200 Subject: bpf, maps: add release callback Add a release callback for maps that is invoked when the last reference to its struct file is gone and the struct file about to be released by vfs. The handler will be used by fd array maps. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/bpf.h | 3 ++- kernel/bpf/syscall.c | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1bcae82c6cb1..29b5a1ae22cb 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -19,7 +19,8 @@ struct bpf_map; struct bpf_map_ops { /* funcs callable from userspace (via syscall) */ struct bpf_map *(*map_alloc)(union bpf_attr *attr); - void (*map_free)(struct bpf_map *); + void (*map_release)(struct bpf_map *map, struct file *map_file); + void (*map_free)(struct bpf_map *map); int (*map_get_next_key)(struct bpf_map *map, void *key, void *next_key); /* funcs callable from userspace and from eBPF programs */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 46ecce4b79ed..fc3adcd064b1 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -124,7 +124,12 @@ void bpf_map_put_with_uref(struct bpf_map *map) static int bpf_map_release(struct inode *inode, struct file *filp) { - bpf_map_put_with_uref(filp->private_data); + struct bpf_map *map = filp->private_data; + + if (map->ops->map_release) + map->ops->map_release(map, filp); + + bpf_map_put_with_uref(map); return 0; } -- cgit v1.2.3 From d056a788765e67773124f520159185bc89f5d1ad Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 15 Jun 2016 22:47:13 +0200 Subject: bpf, maps: extend map_fd_get_ptr arguments This patch extends map_fd_get_ptr() callback that is used by fd array maps, so that struct file pointer from the related map can be passed in. It's safe to remove map_update_elem() callback for the two maps since this is only allowed from syscall side, but not from eBPF programs for these two map types. Like in per-cpu map case, bpf_fd_array_map_update_elem() needs to be called directly here due to the extra argument. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/bpf.h | 12 +++++++++--- kernel/bpf/arraymap.c | 16 +++++++++------- kernel/bpf/syscall.c | 6 ++++++ 3 files changed, 24 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 29b5a1ae22cb..d7b43e73fe87 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -29,8 +29,9 @@ struct bpf_map_ops { int (*map_delete_elem)(struct bpf_map *map, void *key); /* funcs called by prog_array and perf_event_array map */ - void *(*map_fd_get_ptr) (struct bpf_map *map, int fd); - void (*map_fd_put_ptr) (void *ptr); + void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file, + int fd); + void (*map_fd_put_ptr)(void *ptr); }; struct bpf_map { @@ -169,7 +170,7 @@ struct bpf_array { u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5); u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); -void bpf_fd_array_map_clear(struct bpf_map *map); + bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp); const struct bpf_func_proto *bpf_get_trace_printk_proto(void); @@ -207,8 +208,13 @@ int bpf_percpu_hash_update(struct bpf_map *map, void *key, void *value, u64 flags); int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value, u64 flags); + int bpf_stackmap_copy(struct bpf_map *map, void *key, void *value); +int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file, + void *key, void *value, u64 map_flags); +void bpf_fd_array_map_clear(struct bpf_map *map); + /* memcpy that is used with 8-byte aligned pointers, power-of-8 size and * forced to use 'long' read/writes to try to atomically copy long counters. * Best-effort only. No barriers here, since it _will_ race with concurrent diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 76d5a794e426..bfedcbdb4d84 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -328,8 +328,8 @@ static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key) } /* only called from syscall */ -static int fd_array_map_update_elem(struct bpf_map *map, void *key, - void *value, u64 map_flags) +int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file, + void *key, void *value, u64 map_flags) { struct bpf_array *array = container_of(map, struct bpf_array, map); void *new_ptr, *old_ptr; @@ -342,7 +342,7 @@ static int fd_array_map_update_elem(struct bpf_map *map, void *key, return -E2BIG; ufd = *(u32 *)value; - new_ptr = map->ops->map_fd_get_ptr(map, ufd); + new_ptr = map->ops->map_fd_get_ptr(map, map_file, ufd); if (IS_ERR(new_ptr)) return PTR_ERR(new_ptr); @@ -371,10 +371,12 @@ static int fd_array_map_delete_elem(struct bpf_map *map, void *key) } } -static void *prog_fd_array_get_ptr(struct bpf_map *map, int fd) +static void *prog_fd_array_get_ptr(struct bpf_map *map, + struct file *map_file, int fd) { struct bpf_array *array = container_of(map, struct bpf_array, map); struct bpf_prog *prog = bpf_prog_get(fd); + if (IS_ERR(prog)) return prog; @@ -382,6 +384,7 @@ static void *prog_fd_array_get_ptr(struct bpf_map *map, int fd) bpf_prog_put(prog); return ERR_PTR(-EINVAL); } + return prog; } @@ -407,7 +410,6 @@ static const struct bpf_map_ops prog_array_ops = { .map_free = fd_array_map_free, .map_get_next_key = array_map_get_next_key, .map_lookup_elem = fd_array_map_lookup_elem, - .map_update_elem = fd_array_map_update_elem, .map_delete_elem = fd_array_map_delete_elem, .map_fd_get_ptr = prog_fd_array_get_ptr, .map_fd_put_ptr = prog_fd_array_put_ptr, @@ -431,7 +433,8 @@ static void perf_event_array_map_free(struct bpf_map *map) fd_array_map_free(map); } -static void *perf_event_fd_array_get_ptr(struct bpf_map *map, int fd) +static void *perf_event_fd_array_get_ptr(struct bpf_map *map, + struct file *map_file, int fd) { struct perf_event *event; const struct perf_event_attr *attr; @@ -474,7 +477,6 @@ static const struct bpf_map_ops perf_event_array_ops = { .map_free = perf_event_array_map_free, .map_get_next_key = array_map_get_next_key, .map_lookup_elem = fd_array_map_lookup_elem, - .map_update_elem = fd_array_map_update_elem, .map_delete_elem = fd_array_map_delete_elem, .map_fd_get_ptr = perf_event_fd_array_get_ptr, .map_fd_put_ptr = perf_event_fd_array_put_ptr, diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index fc3adcd064b1..c23a4e9311b3 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -392,6 +392,12 @@ static int map_update_elem(union bpf_attr *attr) err = bpf_percpu_hash_update(map, key, value, attr->flags); } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { err = bpf_percpu_array_update(map, key, value, attr->flags); + } else if (map->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || + map->map_type == BPF_MAP_TYPE_PROG_ARRAY) { + rcu_read_lock(); + err = bpf_fd_array_map_update_elem(map, f.file, key, value, + attr->flags); + rcu_read_unlock(); } else { rcu_read_lock(); err = map->ops->map_update_elem(map, key, value, attr->flags); -- cgit v1.2.3 From 3b1efb196eee45b2f0c4994e0c43edb5e367f620 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 15 Jun 2016 22:47:14 +0200 Subject: bpf, maps: flush own entries on perf map release The behavior of perf event arrays are quite different from all others as they are tightly coupled to perf event fds, f.e. shown recently by commit e03e7ee34fdd ("perf/bpf: Convert perf_event_array to use struct file") to make refcounting on perf event more robust. A remaining issue that the current code still has is that since additions to the perf event array take a reference on the struct file via perf_event_get() and are only released via fput() (that cleans up the perf event eventually via perf_event_release_kernel()) when the element is either manually removed from the map from user space or automatically when the last reference on the perf event map is dropped. However, this leads us to dangling struct file's when the map gets pinned after the application owning the perf event descriptor exits, and since the struct file reference will in such case only be manually dropped or via pinned file removal, it leads to the perf event living longer than necessary, consuming needlessly resources for that time. Relations between perf event fds and bpf perf event map fds can be rather complex. F.e. maps can act as demuxers among different perf event fds that can possibly be owned by different threads and based on the index selection from the program, events get dispatched to one of the per-cpu fd endpoints. One perf event fd (or, rather a per-cpu set of them) can also live in multiple perf event maps at the same time, listening for events. Also, another requirement is that perf event fds can get closed from application side after they have been attached to the perf event map, so that on exit perf event map will take care of dropping their references eventually. Likewise, when such maps are pinned, the intended behavior is that a user application does bpf_obj_get(), puts its fds in there and on exit when fd is released, they are dropped from the map again, so the map acts rather as connector endpoint. This also makes perf event maps inherently different from program arrays as described in more detail in commit c9da161c6517 ("bpf: fix clearing on persistent program array maps"). To tackle this, map entries are marked by the map struct file that added the element to the map. And when the last reference to that map struct file is released from user space, then the tracked entries are purged from the map. This is okay, because new map struct files instances resp. frontends to the anon inode are provided via bpf_map_new_fd() that is called when we invoke bpf_obj_get_user() for retrieving a pinned map, but also when an initial instance is created via map_create(). The rest is resolved by the vfs layer automatically for us by keeping reference count on the map's struct file. Any concurrent updates on the map slot are fine as well, it just means that perf_event_fd_array_release() needs to delete less of its own entires. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/bpf.h | 9 +++++ kernel/bpf/arraymap.c | 102 ++++++++++++++++++++++++++++++++++------------- kernel/trace/bpf_trace.c | 18 ++++----- 3 files changed, 91 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index d7b43e73fe87..9adfef694a25 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -13,6 +13,7 @@ #include #include +struct perf_event; struct bpf_map; /* map is generic key/value storage optionally accesible by eBPF programs */ @@ -166,8 +167,16 @@ struct bpf_array { void __percpu *pptrs[0] __aligned(8); }; }; + #define MAX_TAIL_CALL_CNT 32 +struct bpf_event_entry { + struct perf_event *event; + struct file *perf_file; + struct file *map_file; + struct rcu_head rcu; +}; + u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5); u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index bfedcbdb4d84..5af30732697b 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -427,59 +427,105 @@ static int __init register_prog_array_map(void) } late_initcall(register_prog_array_map); -static void perf_event_array_map_free(struct bpf_map *map) +static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file, + struct file *map_file) { - bpf_fd_array_map_clear(map); - fd_array_map_free(map); + struct bpf_event_entry *ee; + + ee = kzalloc(sizeof(*ee), GFP_KERNEL); + if (ee) { + ee->event = perf_file->private_data; + ee->perf_file = perf_file; + ee->map_file = map_file; + } + + return ee; +} + +static void __bpf_event_entry_free(struct rcu_head *rcu) +{ + struct bpf_event_entry *ee; + + ee = container_of(rcu, struct bpf_event_entry, rcu); + fput(ee->perf_file); + kfree(ee); +} + +static void bpf_event_entry_free_rcu(struct bpf_event_entry *ee) +{ + call_rcu(&ee->rcu, __bpf_event_entry_free); } static void *perf_event_fd_array_get_ptr(struct bpf_map *map, struct file *map_file, int fd) { - struct perf_event *event; const struct perf_event_attr *attr; - struct file *file; + struct bpf_event_entry *ee; + struct perf_event *event; + struct file *perf_file; - file = perf_event_get(fd); - if (IS_ERR(file)) - return file; + perf_file = perf_event_get(fd); + if (IS_ERR(perf_file)) + return perf_file; - event = file->private_data; + event = perf_file->private_data; + ee = ERR_PTR(-EINVAL); attr = perf_event_attrs(event); - if (IS_ERR(attr)) - goto err; - - if (attr->inherit) - goto err; - - if (attr->type == PERF_TYPE_RAW) - return file; - - if (attr->type == PERF_TYPE_HARDWARE) - return file; + if (IS_ERR(attr) || attr->inherit) + goto err_out; + + switch (attr->type) { + case PERF_TYPE_SOFTWARE: + if (attr->config != PERF_COUNT_SW_BPF_OUTPUT) + goto err_out; + /* fall-through */ + case PERF_TYPE_RAW: + case PERF_TYPE_HARDWARE: + ee = bpf_event_entry_gen(perf_file, map_file); + if (ee) + return ee; + ee = ERR_PTR(-ENOMEM); + /* fall-through */ + default: + break; + } - if (attr->type == PERF_TYPE_SOFTWARE && - attr->config == PERF_COUNT_SW_BPF_OUTPUT) - return file; -err: - fput(file); - return ERR_PTR(-EINVAL); +err_out: + fput(perf_file); + return ee; } static void perf_event_fd_array_put_ptr(void *ptr) { - fput((struct file *)ptr); + bpf_event_entry_free_rcu(ptr); +} + +static void perf_event_fd_array_release(struct bpf_map *map, + struct file *map_file) +{ + struct bpf_array *array = container_of(map, struct bpf_array, map); + struct bpf_event_entry *ee; + int i; + + rcu_read_lock(); + for (i = 0; i < array->map.max_entries; i++) { + ee = READ_ONCE(array->ptrs[i]); + if (ee && ee->map_file == map_file) + fd_array_map_delete_elem(map, &i); + } + rcu_read_unlock(); } static const struct bpf_map_ops perf_event_array_ops = { .map_alloc = fd_array_map_alloc, - .map_free = perf_event_array_map_free, + .map_free = fd_array_map_free, .map_get_next_key = array_map_get_next_key, .map_lookup_elem = fd_array_map_lookup_elem, .map_delete_elem = fd_array_map_delete_elem, .map_fd_get_ptr = perf_event_fd_array_get_ptr, .map_fd_put_ptr = perf_event_fd_array_put_ptr, + .map_release = perf_event_fd_array_release, }; static struct bpf_map_type_list perf_event_array_type __read_mostly = { diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 720b7bb01d43..037ea6ea3cb2 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -192,18 +192,17 @@ static u64 bpf_perf_event_read(u64 r1, u64 index, u64 r3, u64 r4, u64 r5) { struct bpf_map *map = (struct bpf_map *) (unsigned long) r1; struct bpf_array *array = container_of(map, struct bpf_array, map); + struct bpf_event_entry *ee; struct perf_event *event; - struct file *file; if (unlikely(index >= array->map.max_entries)) return -E2BIG; - file = READ_ONCE(array->ptrs[index]); - if (unlikely(!file)) + ee = READ_ONCE(array->ptrs[index]); + if (unlikely(!ee)) return -ENOENT; - event = file->private_data; - + event = ee->event; /* make sure event is local and doesn't have pmu::count */ if (event->oncpu != smp_processor_id() || event->pmu->count) @@ -233,8 +232,8 @@ static u64 bpf_perf_event_output(u64 r1, u64 r2, u64 flags, u64 r4, u64 size) u64 index = flags & BPF_F_INDEX_MASK; void *data = (void *) (long) r4; struct perf_sample_data sample_data; + struct bpf_event_entry *ee; struct perf_event *event; - struct file *file; struct perf_raw_record raw = { .size = size, .data = data, @@ -247,12 +246,11 @@ static u64 bpf_perf_event_output(u64 r1, u64 r2, u64 flags, u64 r4, u64 size) if (unlikely(index >= array->map.max_entries)) return -E2BIG; - file = READ_ONCE(array->ptrs[index]); - if (unlikely(!file)) + ee = READ_ONCE(array->ptrs[index]); + if (unlikely(!ee)) return -ENOENT; - event = file->private_data; - + event = ee->event; if (unlikely(event->attr.type != PERF_TYPE_SOFTWARE || event->attr.config != PERF_COUNT_SW_BPF_OUTPUT)) return -EINVAL; -- cgit v1.2.3 From e12133324b7daaa176bb687c1eb59e1a6b203da4 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 00:52:13 +0200 Subject: locking/atomic: Fix atomic64_relaxed() bits We should only expand the atomic64 relaxed bits once we've included all relevant headers. So move it down until after we potentially include asm-generic/atomic64.h. In practise this will not have made a difference so far, since the generic bits will not define _relaxed versions. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Davidlohr Bueso Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- include/linux/atomic.h | 306 ++++++++++++++++++++++++------------------------- 1 file changed, 153 insertions(+), 153 deletions(-) (limited to 'include/linux') diff --git a/include/linux/atomic.h b/include/linux/atomic.h index e451534fe54d..351f89e1d15c 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -211,159 +211,6 @@ #endif #endif /* atomic_cmpxchg_relaxed */ -#ifndef atomic64_read_acquire -#define atomic64_read_acquire(v) smp_load_acquire(&(v)->counter) -#endif - -#ifndef atomic64_set_release -#define atomic64_set_release(v, i) smp_store_release(&(v)->counter, (i)) -#endif - -/* atomic64_add_return_relaxed */ -#ifndef atomic64_add_return_relaxed -#define atomic64_add_return_relaxed atomic64_add_return -#define atomic64_add_return_acquire atomic64_add_return -#define atomic64_add_return_release atomic64_add_return - -#else /* atomic64_add_return_relaxed */ - -#ifndef atomic64_add_return_acquire -#define atomic64_add_return_acquire(...) \ - __atomic_op_acquire(atomic64_add_return, __VA_ARGS__) -#endif - -#ifndef atomic64_add_return_release -#define atomic64_add_return_release(...) \ - __atomic_op_release(atomic64_add_return, __VA_ARGS__) -#endif - -#ifndef atomic64_add_return -#define atomic64_add_return(...) \ - __atomic_op_fence(atomic64_add_return, __VA_ARGS__) -#endif -#endif /* atomic64_add_return_relaxed */ - -/* atomic64_inc_return_relaxed */ -#ifndef atomic64_inc_return_relaxed -#define atomic64_inc_return_relaxed atomic64_inc_return -#define atomic64_inc_return_acquire atomic64_inc_return -#define atomic64_inc_return_release atomic64_inc_return - -#else /* atomic64_inc_return_relaxed */ - -#ifndef atomic64_inc_return_acquire -#define atomic64_inc_return_acquire(...) \ - __atomic_op_acquire(atomic64_inc_return, __VA_ARGS__) -#endif - -#ifndef atomic64_inc_return_release -#define atomic64_inc_return_release(...) \ - __atomic_op_release(atomic64_inc_return, __VA_ARGS__) -#endif - -#ifndef atomic64_inc_return -#define atomic64_inc_return(...) \ - __atomic_op_fence(atomic64_inc_return, __VA_ARGS__) -#endif -#endif /* atomic64_inc_return_relaxed */ - - -/* atomic64_sub_return_relaxed */ -#ifndef atomic64_sub_return_relaxed -#define atomic64_sub_return_relaxed atomic64_sub_return -#define atomic64_sub_return_acquire atomic64_sub_return -#define atomic64_sub_return_release atomic64_sub_return - -#else /* atomic64_sub_return_relaxed */ - -#ifndef atomic64_sub_return_acquire -#define atomic64_sub_return_acquire(...) \ - __atomic_op_acquire(atomic64_sub_return, __VA_ARGS__) -#endif - -#ifndef atomic64_sub_return_release -#define atomic64_sub_return_release(...) \ - __atomic_op_release(atomic64_sub_return, __VA_ARGS__) -#endif - -#ifndef atomic64_sub_return -#define atomic64_sub_return(...) \ - __atomic_op_fence(atomic64_sub_return, __VA_ARGS__) -#endif -#endif /* atomic64_sub_return_relaxed */ - -/* atomic64_dec_return_relaxed */ -#ifndef atomic64_dec_return_relaxed -#define atomic64_dec_return_relaxed atomic64_dec_return -#define atomic64_dec_return_acquire atomic64_dec_return -#define atomic64_dec_return_release atomic64_dec_return - -#else /* atomic64_dec_return_relaxed */ - -#ifndef atomic64_dec_return_acquire -#define atomic64_dec_return_acquire(...) \ - __atomic_op_acquire(atomic64_dec_return, __VA_ARGS__) -#endif - -#ifndef atomic64_dec_return_release -#define atomic64_dec_return_release(...) \ - __atomic_op_release(atomic64_dec_return, __VA_ARGS__) -#endif - -#ifndef atomic64_dec_return -#define atomic64_dec_return(...) \ - __atomic_op_fence(atomic64_dec_return, __VA_ARGS__) -#endif -#endif /* atomic64_dec_return_relaxed */ - -/* atomic64_xchg_relaxed */ -#ifndef atomic64_xchg_relaxed -#define atomic64_xchg_relaxed atomic64_xchg -#define atomic64_xchg_acquire atomic64_xchg -#define atomic64_xchg_release atomic64_xchg - -#else /* atomic64_xchg_relaxed */ - -#ifndef atomic64_xchg_acquire -#define atomic64_xchg_acquire(...) \ - __atomic_op_acquire(atomic64_xchg, __VA_ARGS__) -#endif - -#ifndef atomic64_xchg_release -#define atomic64_xchg_release(...) \ - __atomic_op_release(atomic64_xchg, __VA_ARGS__) -#endif - -#ifndef atomic64_xchg -#define atomic64_xchg(...) \ - __atomic_op_fence(atomic64_xchg, __VA_ARGS__) -#endif -#endif /* atomic64_xchg_relaxed */ - -/* atomic64_cmpxchg_relaxed */ -#ifndef atomic64_cmpxchg_relaxed -#define atomic64_cmpxchg_relaxed atomic64_cmpxchg -#define atomic64_cmpxchg_acquire atomic64_cmpxchg -#define atomic64_cmpxchg_release atomic64_cmpxchg - -#else /* atomic64_cmpxchg_relaxed */ - -#ifndef atomic64_cmpxchg_acquire -#define atomic64_cmpxchg_acquire(...) \ - __atomic_op_acquire(atomic64_cmpxchg, __VA_ARGS__) -#endif - -#ifndef atomic64_cmpxchg_release -#define atomic64_cmpxchg_release(...) \ - __atomic_op_release(atomic64_cmpxchg, __VA_ARGS__) -#endif - -#ifndef atomic64_cmpxchg -#define atomic64_cmpxchg(...) \ - __atomic_op_fence(atomic64_cmpxchg, __VA_ARGS__) -#endif -#endif /* atomic64_cmpxchg_relaxed */ - /* cmpxchg_relaxed */ #ifndef cmpxchg_relaxed #define cmpxchg_relaxed cmpxchg @@ -583,6 +430,159 @@ static inline int atomic_fetch_or(int mask, atomic_t *p) #include #endif +#ifndef atomic64_read_acquire +#define atomic64_read_acquire(v) smp_load_acquire(&(v)->counter) +#endif + +#ifndef atomic64_set_release +#define atomic64_set_release(v, i) smp_store_release(&(v)->counter, (i)) +#endif + +/* atomic64_add_return_relaxed */ +#ifndef atomic64_add_return_relaxed +#define atomic64_add_return_relaxed atomic64_add_return +#define atomic64_add_return_acquire atomic64_add_return +#define atomic64_add_return_release atomic64_add_return + +#else /* atomic64_add_return_relaxed */ + +#ifndef atomic64_add_return_acquire +#define atomic64_add_return_acquire(...) \ + __atomic_op_acquire(atomic64_add_return, __VA_ARGS__) +#endif + +#ifndef atomic64_add_return_release +#define atomic64_add_return_release(...) \ + __atomic_op_release(atomic64_add_return, __VA_ARGS__) +#endif + +#ifndef atomic64_add_return +#define atomic64_add_return(...) \ + __atomic_op_fence(atomic64_add_return, __VA_ARGS__) +#endif +#endif /* atomic64_add_return_relaxed */ + +/* atomic64_inc_return_relaxed */ +#ifndef atomic64_inc_return_relaxed +#define atomic64_inc_return_relaxed atomic64_inc_return +#define atomic64_inc_return_acquire atomic64_inc_return +#define atomic64_inc_return_release atomic64_inc_return + +#else /* atomic64_inc_return_relaxed */ + +#ifndef atomic64_inc_return_acquire +#define atomic64_inc_return_acquire(...) \ + __atomic_op_acquire(atomic64_inc_return, __VA_ARGS__) +#endif + +#ifndef atomic64_inc_return_release +#define atomic64_inc_return_release(...) \ + __atomic_op_release(atomic64_inc_return, __VA_ARGS__) +#endif + +#ifndef atomic64_inc_return +#define atomic64_inc_return(...) \ + __atomic_op_fence(atomic64_inc_return, __VA_ARGS__) +#endif +#endif /* atomic64_inc_return_relaxed */ + + +/* atomic64_sub_return_relaxed */ +#ifndef atomic64_sub_return_relaxed +#define atomic64_sub_return_relaxed atomic64_sub_return +#define atomic64_sub_return_acquire atomic64_sub_return +#define atomic64_sub_return_release atomic64_sub_return + +#else /* atomic64_sub_return_relaxed */ + +#ifndef atomic64_sub_return_acquire +#define atomic64_sub_return_acquire(...) \ + __atomic_op_acquire(atomic64_sub_return, __VA_ARGS__) +#endif + +#ifndef atomic64_sub_return_release +#define atomic64_sub_return_release(...) \ + __atomic_op_release(atomic64_sub_return, __VA_ARGS__) +#endif + +#ifndef atomic64_sub_return +#define atomic64_sub_return(...) \ + __atomic_op_fence(atomic64_sub_return, __VA_ARGS__) +#endif +#endif /* atomic64_sub_return_relaxed */ + +/* atomic64_dec_return_relaxed */ +#ifndef atomic64_dec_return_relaxed +#define atomic64_dec_return_relaxed atomic64_dec_return +#define atomic64_dec_return_acquire atomic64_dec_return +#define atomic64_dec_return_release atomic64_dec_return + +#else /* atomic64_dec_return_relaxed */ + +#ifndef atomic64_dec_return_acquire +#define atomic64_dec_return_acquire(...) \ + __atomic_op_acquire(atomic64_dec_return, __VA_ARGS__) +#endif + +#ifndef atomic64_dec_return_release +#define atomic64_dec_return_release(...) \ + __atomic_op_release(atomic64_dec_return, __VA_ARGS__) +#endif + +#ifndef atomic64_dec_return +#define atomic64_dec_return(...) \ + __atomic_op_fence(atomic64_dec_return, __VA_ARGS__) +#endif +#endif /* atomic64_dec_return_relaxed */ + +/* atomic64_xchg_relaxed */ +#ifndef atomic64_xchg_relaxed +#define atomic64_xchg_relaxed atomic64_xchg +#define atomic64_xchg_acquire atomic64_xchg +#define atomic64_xchg_release atomic64_xchg + +#else /* atomic64_xchg_relaxed */ + +#ifndef atomic64_xchg_acquire +#define atomic64_xchg_acquire(...) \ + __atomic_op_acquire(atomic64_xchg, __VA_ARGS__) +#endif + +#ifndef atomic64_xchg_release +#define atomic64_xchg_release(...) \ + __atomic_op_release(atomic64_xchg, __VA_ARGS__) +#endif + +#ifndef atomic64_xchg +#define atomic64_xchg(...) \ + __atomic_op_fence(atomic64_xchg, __VA_ARGS__) +#endif +#endif /* atomic64_xchg_relaxed */ + +/* atomic64_cmpxchg_relaxed */ +#ifndef atomic64_cmpxchg_relaxed +#define atomic64_cmpxchg_relaxed atomic64_cmpxchg +#define atomic64_cmpxchg_acquire atomic64_cmpxchg +#define atomic64_cmpxchg_release atomic64_cmpxchg + +#else /* atomic64_cmpxchg_relaxed */ + +#ifndef atomic64_cmpxchg_acquire +#define atomic64_cmpxchg_acquire(...) \ + __atomic_op_acquire(atomic64_cmpxchg, __VA_ARGS__) +#endif + +#ifndef atomic64_cmpxchg_release +#define atomic64_cmpxchg_release(...) \ + __atomic_op_release(atomic64_cmpxchg, __VA_ARGS__) +#endif + +#ifndef atomic64_cmpxchg +#define atomic64_cmpxchg(...) \ + __atomic_op_fence(atomic64_cmpxchg, __VA_ARGS__) +#endif +#endif /* atomic64_cmpxchg_relaxed */ + #ifndef atomic64_andnot static inline void atomic64_andnot(long long i, atomic64_t *v) { -- cgit v1.2.3 From 28aa2bda2211f4327d83b44a4f917b4a061b1c56 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 00:54:38 +0200 Subject: locking/atomic: Implement atomic{,64,_long}_fetch_{add,sub,and,andnot,or,xor}{,_relaxed,_acquire,_release}() Now that all the architectures have implemented support for these new atomic primitives add on the generic infrastructure to expose and use it. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Arnd Bergmann Cc: Boqun Feng Cc: Borislav Petkov Cc: Davidlohr Bueso Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- include/asm-generic/atomic-long.h | 36 +++- include/asm-generic/atomic.h | 49 ++++++ include/asm-generic/atomic64.h | 15 +- include/linux/atomic.h | 336 ++++++++++++++++++++++++++++++++++++++ lib/atomic64.c | 32 +++- lib/atomic64_test.c | 34 ++++ 6 files changed, 493 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h index 5e1f345b58dd..2d0d3cf791ab 100644 --- a/include/asm-generic/atomic-long.h +++ b/include/asm-generic/atomic-long.h @@ -112,6 +112,40 @@ static __always_inline void atomic_long_dec(atomic_long_t *l) ATOMIC_LONG_PFX(_dec)(v); } +#define ATOMIC_LONG_FETCH_OP(op, mo) \ +static inline long \ +atomic_long_fetch_##op##mo(long i, atomic_long_t *l) \ +{ \ + ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ + \ + return (long)ATOMIC_LONG_PFX(_fetch_##op##mo)(i, v); \ +} + +ATOMIC_LONG_FETCH_OP(add, ) +ATOMIC_LONG_FETCH_OP(add, _relaxed) +ATOMIC_LONG_FETCH_OP(add, _acquire) +ATOMIC_LONG_FETCH_OP(add, _release) +ATOMIC_LONG_FETCH_OP(sub, ) +ATOMIC_LONG_FETCH_OP(sub, _relaxed) +ATOMIC_LONG_FETCH_OP(sub, _acquire) +ATOMIC_LONG_FETCH_OP(sub, _release) +ATOMIC_LONG_FETCH_OP(and, ) +ATOMIC_LONG_FETCH_OP(and, _relaxed) +ATOMIC_LONG_FETCH_OP(and, _acquire) +ATOMIC_LONG_FETCH_OP(and, _release) +ATOMIC_LONG_FETCH_OP(andnot, ) +ATOMIC_LONG_FETCH_OP(andnot, _relaxed) +ATOMIC_LONG_FETCH_OP(andnot, _acquire) +ATOMIC_LONG_FETCH_OP(andnot, _release) +ATOMIC_LONG_FETCH_OP(or, ) +ATOMIC_LONG_FETCH_OP(or, _relaxed) +ATOMIC_LONG_FETCH_OP(or, _acquire) +ATOMIC_LONG_FETCH_OP(or, _release) +ATOMIC_LONG_FETCH_OP(xor, ) +ATOMIC_LONG_FETCH_OP(xor, _relaxed) +ATOMIC_LONG_FETCH_OP(xor, _acquire) +ATOMIC_LONG_FETCH_OP(xor, _release) + #define ATOMIC_LONG_OP(op) \ static __always_inline void \ atomic_long_##op(long i, atomic_long_t *l) \ @@ -124,9 +158,9 @@ atomic_long_##op(long i, atomic_long_t *l) \ ATOMIC_LONG_OP(add) ATOMIC_LONG_OP(sub) ATOMIC_LONG_OP(and) +ATOMIC_LONG_OP(andnot) ATOMIC_LONG_OP(or) ATOMIC_LONG_OP(xor) -ATOMIC_LONG_OP(andnot) #undef ATOMIC_LONG_OP diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 74f1a3704d7a..a2304ccf4ed0 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -61,6 +61,18 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return c c_op i; \ } +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + int c, old; \ + \ + c = v->counter; \ + while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ + c = old; \ + \ + return c; \ +} + #else #include @@ -88,6 +100,20 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return ret; \ } +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + int ret; \ + \ + raw_local_irq_save(flags); \ + ret = v->counter; \ + v->counter = v->counter c_op i; \ + raw_local_irq_restore(flags); \ + \ + return ret; \ +} + #endif /* CONFIG_SMP */ #ifndef atomic_add_return @@ -98,6 +124,28 @@ ATOMIC_OP_RETURN(add, +) ATOMIC_OP_RETURN(sub, -) #endif +#ifndef atomic_fetch_add +ATOMIC_FETCH_OP(add, +) +#endif + +#ifndef atomic_fetch_sub +ATOMIC_FETCH_OP(sub, -) +#endif + +#ifndef atomic_fetch_and +ATOMIC_FETCH_OP(and, &) +#endif + +#ifndef atomic_fetch_or +#define atomic_fetch_or atomic_fetch_or + +ATOMIC_FETCH_OP(or, |) +#endif + +#ifndef atomic_fetch_xor +ATOMIC_FETCH_OP(xor, ^) +#endif + #ifndef atomic_and ATOMIC_OP(and, &) #endif @@ -110,6 +158,7 @@ ATOMIC_OP(or, |) ATOMIC_OP(xor, ^) #endif +#undef ATOMIC_FETCH_OP #undef ATOMIC_OP_RETURN #undef ATOMIC_OP diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h index d48e78ccad3d..dad68bf46c77 100644 --- a/include/asm-generic/atomic64.h +++ b/include/asm-generic/atomic64.h @@ -27,16 +27,23 @@ extern void atomic64_##op(long long a, atomic64_t *v); #define ATOMIC64_OP_RETURN(op) \ extern long long atomic64_##op##_return(long long a, atomic64_t *v); -#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) +#define ATOMIC64_FETCH_OP(op) \ +extern long long atomic64_fetch_##op(long long a, atomic64_t *v); + +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op) ATOMIC64_OPS(add) ATOMIC64_OPS(sub) -ATOMIC64_OP(and) -ATOMIC64_OP(or) -ATOMIC64_OP(xor) +#undef ATOMIC64_OPS +#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_FETCH_OP(op) + +ATOMIC64_OPS(and) +ATOMIC64_OPS(or) +ATOMIC64_OPS(xor) #undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 351f89e1d15c..2e6c013ac5a4 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -163,6 +163,154 @@ #endif #endif /* atomic_dec_return_relaxed */ + +/* atomic_fetch_add_relaxed */ +#ifndef atomic_fetch_add_relaxed +#define atomic_fetch_add_relaxed atomic_fetch_add +#define atomic_fetch_add_acquire atomic_fetch_add +#define atomic_fetch_add_release atomic_fetch_add + +#else /* atomic_fetch_add_relaxed */ + +#ifndef atomic_fetch_add_acquire +#define atomic_fetch_add_acquire(...) \ + __atomic_op_acquire(atomic_fetch_add, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_add_release +#define atomic_fetch_add_release(...) \ + __atomic_op_release(atomic_fetch_add, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_add +#define atomic_fetch_add(...) \ + __atomic_op_fence(atomic_fetch_add, __VA_ARGS__) +#endif +#endif /* atomic_fetch_add_relaxed */ + +/* atomic_fetch_sub_relaxed */ +#ifndef atomic_fetch_sub_relaxed +#define atomic_fetch_sub_relaxed atomic_fetch_sub +#define atomic_fetch_sub_acquire atomic_fetch_sub +#define atomic_fetch_sub_release atomic_fetch_sub + +#else /* atomic_fetch_sub_relaxed */ + +#ifndef atomic_fetch_sub_acquire +#define atomic_fetch_sub_acquire(...) \ + __atomic_op_acquire(atomic_fetch_sub, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_sub_release +#define atomic_fetch_sub_release(...) \ + __atomic_op_release(atomic_fetch_sub, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_sub +#define atomic_fetch_sub(...) \ + __atomic_op_fence(atomic_fetch_sub, __VA_ARGS__) +#endif +#endif /* atomic_fetch_sub_relaxed */ + +/* atomic_fetch_or_relaxed */ +#ifndef atomic_fetch_or_relaxed +#define atomic_fetch_or_relaxed atomic_fetch_or +#define atomic_fetch_or_acquire atomic_fetch_or +#define atomic_fetch_or_release atomic_fetch_or + +#else /* atomic_fetch_or_relaxed */ + +#ifndef atomic_fetch_or_acquire +#define atomic_fetch_or_acquire(...) \ + __atomic_op_acquire(atomic_fetch_or, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_or_release +#define atomic_fetch_or_release(...) \ + __atomic_op_release(atomic_fetch_or, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_or +#define atomic_fetch_or(...) \ + __atomic_op_fence(atomic_fetch_or, __VA_ARGS__) +#endif +#endif /* atomic_fetch_or_relaxed */ + +/* atomic_fetch_and_relaxed */ +#ifndef atomic_fetch_and_relaxed +#define atomic_fetch_and_relaxed atomic_fetch_and +#define atomic_fetch_and_acquire atomic_fetch_and +#define atomic_fetch_and_release atomic_fetch_and + +#else /* atomic_fetch_and_relaxed */ + +#ifndef atomic_fetch_and_acquire +#define atomic_fetch_and_acquire(...) \ + __atomic_op_acquire(atomic_fetch_and, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_and_release +#define atomic_fetch_and_release(...) \ + __atomic_op_release(atomic_fetch_and, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_and +#define atomic_fetch_and(...) \ + __atomic_op_fence(atomic_fetch_and, __VA_ARGS__) +#endif +#endif /* atomic_fetch_and_relaxed */ + +#ifdef atomic_andnot +/* atomic_fetch_andnot_relaxed */ +#ifndef atomic_fetch_andnot_relaxed +#define atomic_fetch_andnot_relaxed atomic_fetch_andnot +#define atomic_fetch_andnot_acquire atomic_fetch_andnot +#define atomic_fetch_andnot_release atomic_fetch_andnot + +#else /* atomic_fetch_andnot_relaxed */ + +#ifndef atomic_fetch_andnot_acquire +#define atomic_fetch_andnot_acquire(...) \ + __atomic_op_acquire(atomic_fetch_andnot, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_andnot_release +#define atomic_fetch_andnot_release(...) \ + __atomic_op_release(atomic_fetch_andnot, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_andnot +#define atomic_fetch_andnot(...) \ + __atomic_op_fence(atomic_fetch_andnot, __VA_ARGS__) +#endif +#endif /* atomic_fetch_andnot_relaxed */ +#endif /* atomic_andnot */ + +/* atomic_fetch_xor_relaxed */ +#ifndef atomic_fetch_xor_relaxed +#define atomic_fetch_xor_relaxed atomic_fetch_xor +#define atomic_fetch_xor_acquire atomic_fetch_xor +#define atomic_fetch_xor_release atomic_fetch_xor + +#else /* atomic_fetch_xor_relaxed */ + +#ifndef atomic_fetch_xor_acquire +#define atomic_fetch_xor_acquire(...) \ + __atomic_op_acquire(atomic_fetch_xor, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_xor_release +#define atomic_fetch_xor_release(...) \ + __atomic_op_release(atomic_fetch_xor, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_xor +#define atomic_fetch_xor(...) \ + __atomic_op_fence(atomic_fetch_xor, __VA_ARGS__) +#endif +#endif /* atomic_fetch_xor_relaxed */ + + /* atomic_xchg_relaxed */ #ifndef atomic_xchg_relaxed #define atomic_xchg_relaxed atomic_xchg @@ -310,6 +458,26 @@ static inline void atomic_andnot(int i, atomic_t *v) { atomic_and(~i, v); } + +static inline int atomic_fetch_andnot(int i, atomic_t *v) +{ + return atomic_fetch_and(~i, v); +} + +static inline int atomic_fetch_andnot_relaxed(int i, atomic_t *v) +{ + return atomic_fetch_and_relaxed(~i, v); +} + +static inline int atomic_fetch_andnot_acquire(int i, atomic_t *v) +{ + return atomic_fetch_and_acquire(~i, v); +} + +static inline int atomic_fetch_andnot_release(int i, atomic_t *v) +{ + return atomic_fetch_and_release(~i, v); +} #endif static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) @@ -535,6 +703,154 @@ static inline int atomic_fetch_or(int mask, atomic_t *p) #endif #endif /* atomic64_dec_return_relaxed */ + +/* atomic64_fetch_add_relaxed */ +#ifndef atomic64_fetch_add_relaxed +#define atomic64_fetch_add_relaxed atomic64_fetch_add +#define atomic64_fetch_add_acquire atomic64_fetch_add +#define atomic64_fetch_add_release atomic64_fetch_add + +#else /* atomic64_fetch_add_relaxed */ + +#ifndef atomic64_fetch_add_acquire +#define atomic64_fetch_add_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_add, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_add_release +#define atomic64_fetch_add_release(...) \ + __atomic_op_release(atomic64_fetch_add, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_add +#define atomic64_fetch_add(...) \ + __atomic_op_fence(atomic64_fetch_add, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_add_relaxed */ + +/* atomic64_fetch_sub_relaxed */ +#ifndef atomic64_fetch_sub_relaxed +#define atomic64_fetch_sub_relaxed atomic64_fetch_sub +#define atomic64_fetch_sub_acquire atomic64_fetch_sub +#define atomic64_fetch_sub_release atomic64_fetch_sub + +#else /* atomic64_fetch_sub_relaxed */ + +#ifndef atomic64_fetch_sub_acquire +#define atomic64_fetch_sub_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_sub, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_sub_release +#define atomic64_fetch_sub_release(...) \ + __atomic_op_release(atomic64_fetch_sub, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_sub +#define atomic64_fetch_sub(...) \ + __atomic_op_fence(atomic64_fetch_sub, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_sub_relaxed */ + +/* atomic64_fetch_or_relaxed */ +#ifndef atomic64_fetch_or_relaxed +#define atomic64_fetch_or_relaxed atomic64_fetch_or +#define atomic64_fetch_or_acquire atomic64_fetch_or +#define atomic64_fetch_or_release atomic64_fetch_or + +#else /* atomic64_fetch_or_relaxed */ + +#ifndef atomic64_fetch_or_acquire +#define atomic64_fetch_or_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_or, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_or_release +#define atomic64_fetch_or_release(...) \ + __atomic_op_release(atomic64_fetch_or, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_or +#define atomic64_fetch_or(...) \ + __atomic_op_fence(atomic64_fetch_or, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_or_relaxed */ + +/* atomic64_fetch_and_relaxed */ +#ifndef atomic64_fetch_and_relaxed +#define atomic64_fetch_and_relaxed atomic64_fetch_and +#define atomic64_fetch_and_acquire atomic64_fetch_and +#define atomic64_fetch_and_release atomic64_fetch_and + +#else /* atomic64_fetch_and_relaxed */ + +#ifndef atomic64_fetch_and_acquire +#define atomic64_fetch_and_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_and, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_and_release +#define atomic64_fetch_and_release(...) \ + __atomic_op_release(atomic64_fetch_and, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_and +#define atomic64_fetch_and(...) \ + __atomic_op_fence(atomic64_fetch_and, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_and_relaxed */ + +#ifdef atomic64_andnot +/* atomic64_fetch_andnot_relaxed */ +#ifndef atomic64_fetch_andnot_relaxed +#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot +#define atomic64_fetch_andnot_acquire atomic64_fetch_andnot +#define atomic64_fetch_andnot_release atomic64_fetch_andnot + +#else /* atomic64_fetch_andnot_relaxed */ + +#ifndef atomic64_fetch_andnot_acquire +#define atomic64_fetch_andnot_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_andnot, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_andnot_release +#define atomic64_fetch_andnot_release(...) \ + __atomic_op_release(atomic64_fetch_andnot, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_andnot +#define atomic64_fetch_andnot(...) \ + __atomic_op_fence(atomic64_fetch_andnot, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_andnot_relaxed */ +#endif /* atomic64_andnot */ + +/* atomic64_fetch_xor_relaxed */ +#ifndef atomic64_fetch_xor_relaxed +#define atomic64_fetch_xor_relaxed atomic64_fetch_xor +#define atomic64_fetch_xor_acquire atomic64_fetch_xor +#define atomic64_fetch_xor_release atomic64_fetch_xor + +#else /* atomic64_fetch_xor_relaxed */ + +#ifndef atomic64_fetch_xor_acquire +#define atomic64_fetch_xor_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_xor, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_xor_release +#define atomic64_fetch_xor_release(...) \ + __atomic_op_release(atomic64_fetch_xor, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_xor +#define atomic64_fetch_xor(...) \ + __atomic_op_fence(atomic64_fetch_xor, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_xor_relaxed */ + + /* atomic64_xchg_relaxed */ #ifndef atomic64_xchg_relaxed #define atomic64_xchg_relaxed atomic64_xchg @@ -588,6 +904,26 @@ static inline void atomic64_andnot(long long i, atomic64_t *v) { atomic64_and(~i, v); } + +static inline long long atomic64_fetch_andnot(long long i, atomic64_t *v) +{ + return atomic64_fetch_and(~i, v); +} + +static inline long long atomic64_fetch_andnot_relaxed(long long i, atomic64_t *v) +{ + return atomic64_fetch_and_relaxed(~i, v); +} + +static inline long long atomic64_fetch_andnot_acquire(long long i, atomic64_t *v) +{ + return atomic64_fetch_and_acquire(~i, v); +} + +static inline long long atomic64_fetch_andnot_release(long long i, atomic64_t *v) +{ + return atomic64_fetch_and_release(~i, v); +} #endif #include diff --git a/lib/atomic64.c b/lib/atomic64.c index 2886ebac6567..53c2d5edc826 100644 --- a/lib/atomic64.c +++ b/lib/atomic64.c @@ -96,17 +96,41 @@ long long atomic64_##op##_return(long long a, atomic64_t *v) \ } \ EXPORT_SYMBOL(atomic64_##op##_return); +#define ATOMIC64_FETCH_OP(op, c_op) \ +long long atomic64_fetch_##op(long long a, atomic64_t *v) \ +{ \ + unsigned long flags; \ + raw_spinlock_t *lock = lock_addr(v); \ + long long val; \ + \ + raw_spin_lock_irqsave(lock, flags); \ + val = v->counter; \ + v->counter c_op a; \ + raw_spin_unlock_irqrestore(lock, flags); \ + return val; \ +} \ +EXPORT_SYMBOL(atomic64_fetch_##op); + #define ATOMIC64_OPS(op, c_op) \ ATOMIC64_OP(op, c_op) \ - ATOMIC64_OP_RETURN(op, c_op) + ATOMIC64_OP_RETURN(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) ATOMIC64_OPS(add, +=) ATOMIC64_OPS(sub, -=) -ATOMIC64_OP(and, &=) -ATOMIC64_OP(or, |=) -ATOMIC64_OP(xor, ^=) #undef ATOMIC64_OPS +#define ATOMIC64_OPS(op, c_op) \ + ATOMIC64_OP(op, c_op) \ + ATOMIC64_OP_RETURN(op, c_op) \ + ATOMIC64_FETCH_OP(op, c_op) + +ATOMIC64_OPS(and, &=) +ATOMIC64_OPS(or, |=) +ATOMIC64_OPS(xor, ^=) + +#undef ATOMIC64_OPS +#undef ATOMIC64_FETCH_OP #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c index 123481814320..dbb369145dda 100644 --- a/lib/atomic64_test.c +++ b/lib/atomic64_test.c @@ -53,11 +53,25 @@ do { \ BUG_ON(atomic##bit##_read(&v) != r); \ } while (0) +#define TEST_FETCH(bit, op, c_op, val) \ +do { \ + atomic##bit##_set(&v, v0); \ + r = v0; \ + r c_op val; \ + BUG_ON(atomic##bit##_##op(val, &v) != v0); \ + BUG_ON(atomic##bit##_read(&v) != r); \ +} while (0) + #define RETURN_FAMILY_TEST(bit, op, c_op, val) \ do { \ FAMILY_TEST(TEST_RETURN, bit, op, c_op, val); \ } while (0) +#define FETCH_FAMILY_TEST(bit, op, c_op, val) \ +do { \ + FAMILY_TEST(TEST_FETCH, bit, op, c_op, val); \ +} while (0) + #define TEST_ARGS(bit, op, init, ret, expect, args...) \ do { \ atomic##bit##_set(&v, init); \ @@ -114,6 +128,16 @@ static __init void test_atomic(void) RETURN_FAMILY_TEST(, sub_return, -=, onestwos); RETURN_FAMILY_TEST(, sub_return, -=, -one); + FETCH_FAMILY_TEST(, fetch_add, +=, onestwos); + FETCH_FAMILY_TEST(, fetch_add, +=, -one); + FETCH_FAMILY_TEST(, fetch_sub, -=, onestwos); + FETCH_FAMILY_TEST(, fetch_sub, -=, -one); + + FETCH_FAMILY_TEST(, fetch_or, |=, v1); + FETCH_FAMILY_TEST(, fetch_and, &=, v1); + FETCH_FAMILY_TEST(, fetch_andnot, &= ~, v1); + FETCH_FAMILY_TEST(, fetch_xor, ^=, v1); + INC_RETURN_FAMILY_TEST(, v0); DEC_RETURN_FAMILY_TEST(, v0); @@ -154,6 +178,16 @@ static __init void test_atomic64(void) RETURN_FAMILY_TEST(64, sub_return, -=, onestwos); RETURN_FAMILY_TEST(64, sub_return, -=, -one); + FETCH_FAMILY_TEST(64, fetch_add, +=, onestwos); + FETCH_FAMILY_TEST(64, fetch_add, +=, -one); + FETCH_FAMILY_TEST(64, fetch_sub, -=, onestwos); + FETCH_FAMILY_TEST(64, fetch_sub, -=, -one); + + FETCH_FAMILY_TEST(64, fetch_or, |=, v1); + FETCH_FAMILY_TEST(64, fetch_and, &=, v1); + FETCH_FAMILY_TEST(64, fetch_andnot, &= ~, v1); + FETCH_FAMILY_TEST(64, fetch_xor, ^=, v1); + INIT(v0); atomic64_inc(&v); r += one; -- cgit v1.2.3 From b53d6bedbe781974097fd8c38263f6cc78ff9ea7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 00:58:25 +0200 Subject: locking/atomic: Remove linux/atomic.h:atomic_fetch_or() Since all architectures have this implemented now natively, remove this dead code. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- arch/alpha/include/asm/atomic.h | 2 -- arch/arc/include/asm/atomic.h | 2 -- arch/arm/include/asm/atomic.h | 2 -- arch/arm64/include/asm/atomic.h | 2 -- arch/avr32/include/asm/atomic.h | 2 -- arch/frv/include/asm/atomic.h | 2 -- arch/h8300/include/asm/atomic.h | 2 -- arch/hexagon/include/asm/atomic.h | 2 -- arch/m32r/include/asm/atomic.h | 2 -- arch/m68k/include/asm/atomic.h | 2 -- arch/metag/include/asm/atomic.h | 2 -- arch/mips/include/asm/atomic.h | 2 -- arch/mn10300/include/asm/atomic.h | 2 -- arch/parisc/include/asm/atomic.h | 2 -- arch/s390/include/asm/atomic.h | 2 -- arch/sh/include/asm/atomic.h | 2 -- arch/sparc/include/asm/atomic.h | 1 - arch/sparc/include/asm/atomic_32.h | 2 -- arch/tile/include/asm/atomic.h | 2 -- arch/x86/include/asm/atomic.h | 2 -- arch/xtensa/include/asm/atomic.h | 2 -- include/asm-generic/atomic.h | 2 -- include/linux/atomic.h | 21 --------------------- 23 files changed, 64 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 8243f17999e3..5377ca8bb503 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -153,8 +153,6 @@ ATOMIC_OPS(sub) #define atomic_andnot atomic_andnot #define atomic64_andnot atomic64_andnot -#define atomic_fetch_or atomic_fetch_or - #undef ATOMIC_OPS #define ATOMIC_OPS(op, asm) \ ATOMIC_OP(op, asm) \ diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index c066a21caaaf..bd9c51cb2bfd 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -189,8 +189,6 @@ ATOMIC_OPS(sub, -=, sub) #define atomic_andnot atomic_andnot -#define atomic_fetch_or atomic_fetch_or - #undef ATOMIC_OPS #define ATOMIC_OPS(op, c_op, asm_op) \ ATOMIC_OP(op, c_op, asm_op) \ diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 0feb110ec542..66d0e215a773 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -201,8 +201,6 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ return val; \ } -#define atomic_fetch_or atomic_fetch_or - static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { int ret; diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 3128c3d7c1ff..c0235e0ff849 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -128,8 +128,6 @@ #define __atomic_add_unless(v, a, u) ___atomic_add_unless(v, a, u,) #define atomic_andnot atomic_andnot -#define atomic_fetch_or atomic_fetch_or - /* * 64-bit atomic operations. */ diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index b8681fd495ef..3d5ce38a6f0b 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h @@ -66,8 +66,6 @@ ATOMIC_OP_RETURN(add, add, r) ATOMIC_FETCH_OP (sub, sub, rKs21) ATOMIC_FETCH_OP (add, add, r) -#define atomic_fetch_or atomic_fetch_or - #define ATOMIC_OPS(op, asm_op) \ ATOMIC_OP_RETURN(op, asm_op, r) \ static inline void atomic_##op(int i, atomic_t *v) \ diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index e3e06da0cd59..1c2a5e264fc7 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -74,8 +74,6 @@ static inline void atomic_dec(atomic_t *v) #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) #define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) -#define atomic_fetch_or atomic_fetch_or - /* * 64-bit atomic ops */ diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h index 0961b618bdde..349a47a918db 100644 --- a/arch/h8300/include/asm/atomic.h +++ b/arch/h8300/include/asm/atomic.h @@ -54,8 +54,6 @@ static inline void atomic_##op(int i, atomic_t *v) \ ATOMIC_OP_RETURN(add, +=) ATOMIC_OP_RETURN(sub, -=) -#define atomic_fetch_or atomic_fetch_or - #define ATOMIC_OPS(op, c_op) \ ATOMIC_OP(op, c_op) \ ATOMIC_FETCH_OP(op, c_op) diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index 07dbb3332b4a..a62ba368b27d 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -152,8 +152,6 @@ ATOMIC_OPS(sub) #undef ATOMIC_OPS #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and) ATOMIC_OPS(or) ATOMIC_OPS(xor) diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index 8ba8a0ab5d5d..640cc1c7099f 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -121,8 +121,6 @@ ATOMIC_OPS(sub) #undef ATOMIC_OPS #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and) ATOMIC_OPS(or) ATOMIC_OPS(xor) diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index 5cf9b3b1b6ac..3e03de7ae33b 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -119,8 +119,6 @@ ATOMIC_OPS(sub, -=, sub) ATOMIC_OP(op, c_op, asm_op) \ ATOMIC_FETCH_OP(op, c_op, asm_op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, &=, and) ATOMIC_OPS(or, |=, or) ATOMIC_OPS(xor, ^=, eor) diff --git a/arch/metag/include/asm/atomic.h b/arch/metag/include/asm/atomic.h index 6ca210de8a7d..470e365f04ea 100644 --- a/arch/metag/include/asm/atomic.h +++ b/arch/metag/include/asm/atomic.h @@ -17,8 +17,6 @@ #include #endif -#define atomic_fetch_or atomic_fetch_or - #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1, (v)) diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 431079f8e483..387ce288334e 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -194,8 +194,6 @@ ATOMIC_OPS(sub, -=, subu) ATOMIC_OP(op, c_op, asm_op) \ ATOMIC_FETCH_OP(op, c_op, asm_op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, &=, and) ATOMIC_OPS(or, |=, or) ATOMIC_OPS(xor, ^=, xor) diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index 3580f789f3a6..36389efd45e8 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -113,8 +113,6 @@ ATOMIC_OPS(sub) #undef ATOMIC_OPS #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and) ATOMIC_OPS(or) ATOMIC_OPS(xor) diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 29df1f871910..5394b9c5f914 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -148,8 +148,6 @@ ATOMIC_OPS(sub, -=) ATOMIC_OP(op, c_op) \ ATOMIC_FETCH_OP(op, c_op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, &=) ATOMIC_OPS(or, |=) ATOMIC_OPS(xor, ^=) diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index 2324e759b544..d28cc2f5b7b2 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -135,8 +135,6 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ return __ATOMIC_LOOP(v, i, __ATOMIC_##OP, __ATOMIC_BARRIER); \ } -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, AND) ATOMIC_OPS(or, OR) ATOMIC_OPS(xor, XOR) diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index d93ed7ce1b2f..c399e1c55685 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h @@ -25,8 +25,6 @@ #include #endif -#define atomic_fetch_or atomic_fetch_or - #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) diff --git a/arch/sparc/include/asm/atomic.h b/arch/sparc/include/asm/atomic.h index 1f741bcc73b7..8ff83d8cc33f 100644 --- a/arch/sparc/include/asm/atomic.h +++ b/arch/sparc/include/asm/atomic.h @@ -5,5 +5,4 @@ #else #include #endif -#define atomic_fetch_or atomic_fetch_or #endif diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 5cfb20a599d9..ee3f11c43cda 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -36,8 +36,6 @@ void atomic_set(atomic_t *, int); #define atomic_inc(v) ((void)atomic_add_return( 1, (v))) #define atomic_dec(v) ((void)atomic_add_return( -1, (v))) -#define atomic_fetch_or atomic_fetch_or - #define atomic_and(i, v) ((void)atomic_fetch_and((i), (v))) #define atomic_or(i, v) ((void)atomic_fetch_or((i), (v))) #define atomic_xor(i, v) ((void)atomic_fetch_xor((i), (v))) diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h index 9807030557c4..8dda3c8ff5ab 100644 --- a/arch/tile/include/asm/atomic.h +++ b/arch/tile/include/asm/atomic.h @@ -48,8 +48,6 @@ static inline int atomic_read(const atomic_t *v) #define atomic_fetch_sub(i, v) atomic_fetch_add(-(int)(i), (v)) -#define atomic_fetch_or atomic_fetch_or - /** * atomic_sub - subtract integer from atomic variable * @i: integer value to subtract diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 73b8463b89e9..a58b99811105 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -217,8 +217,6 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ ATOMIC_OP(op) \ ATOMIC_FETCH_OP(op, c_op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and, &) ATOMIC_OPS(or , |) ATOMIC_OPS(xor, ^) diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index d95a8aa1a6d3..e7a23f2a519a 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -188,8 +188,6 @@ ATOMIC_OPS(sub) #undef ATOMIC_OPS #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) -#define atomic_fetch_or atomic_fetch_or - ATOMIC_OPS(and) ATOMIC_OPS(or) ATOMIC_OPS(xor) diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index a2304ccf4ed0..9ed8b987185b 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -137,8 +137,6 @@ ATOMIC_FETCH_OP(and, &) #endif #ifndef atomic_fetch_or -#define atomic_fetch_or atomic_fetch_or - ATOMIC_FETCH_OP(or, |) #endif diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 2e6c013ac5a4..0b3802d33125 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -573,27 +573,6 @@ static inline int atomic_dec_if_positive(atomic_t *v) } #endif -/** - * atomic_fetch_or - perform *p |= mask and return old value of *p - * @mask: mask to OR on the atomic_t - * @p: pointer to atomic_t - */ -#ifndef atomic_fetch_or -static inline int atomic_fetch_or(int mask, atomic_t *p) -{ - int old, val = atomic_read(p); - - for (;;) { - old = atomic_cmpxchg(p, val, val | mask); - if (old == val) - break; - val = old; - } - - return old; -} -#endif - #ifdef CONFIG_GENERIC_ATOMIC64 #include #endif -- cgit v1.2.3 From e37837fb62f95a81bdcefa86ceea043df84937d7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 18 Apr 2016 01:01:27 +0200 Subject: locking/atomic: Remove the deprecated atomic_{set,clear}_mask() functions These functions have been deprecated for a while and there is only the one user left, convert and kill. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Boqun Feng Cc: Davidlohr Bueso Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- include/linux/atomic.h | 10 ---------- kernel/locking/qspinlock_paravirt.h | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 0b3802d33125..12d910d61b83 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -480,16 +480,6 @@ static inline int atomic_fetch_andnot_release(int i, atomic_t *v) } #endif -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_andnot(mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - /** * atomic_inc_not_zero_hint - increment if not null * @v: pointer of type atomic_t diff --git a/kernel/locking/qspinlock_paravirt.h b/kernel/locking/qspinlock_paravirt.h index 21ede57f68b3..37649e69056c 100644 --- a/kernel/locking/qspinlock_paravirt.h +++ b/kernel/locking/qspinlock_paravirt.h @@ -112,12 +112,12 @@ static __always_inline int trylock_clear_pending(struct qspinlock *lock) #else /* _Q_PENDING_BITS == 8 */ static __always_inline void set_pending(struct qspinlock *lock) { - atomic_set_mask(_Q_PENDING_VAL, &lock->val); + atomic_or(_Q_PENDING_VAL, &lock->val); } static __always_inline void clear_pending(struct qspinlock *lock) { - atomic_clear_mask(_Q_PENDING_VAL, &lock->val); + atomic_andnot(_Q_PENDING_VAL, &lock->val); } static __always_inline int trylock_clear_pending(struct qspinlock *lock) -- cgit v1.2.3 From 39dd0f234fc37da071dadbd9b49fe800d62139b4 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 30 May 2016 11:43:07 +0200 Subject: PM / Domains: Allow genpd to power on during system PM phases If a PM domain is powered off when the first device starts its system PM prepare phase, genpd prevents any further attempts to power on the PM domain during the following system PM phases. Not until the system PM complete phase is finalized for all devices in the PM domain, genpd again allows it to be powered on. This behaviour needs to be changed, as a subsystem/driver for a device in the same PM domain may still need to be able to serve requests in some of the system PM phases. Accordingly, it may need to runtime resume its device and thus also request the corresponding PM domain to be powered on. To deal with these scenarios, let's make the device operational in the system PM prepare phase by runtime resuming it, no matter if the PM domain is powered on or off. Changing this also enables us to remove genpd's suspend_power_off flag, as it's being used to track this condition. Additionally, we must allow the PM domain to be powered on via runtime PM during the system PM phases. This change also requires a fix in the AMD ACP (Audio CoProcessor) drm driver. It registers a genpd to model the ACP as a PM domain, but unfortunately it's also abuses genpd's "internal" suspend_power_off flag to deal with a corner case at system PM resume. More precisely, the so called SMU block powers on the ACP at system PM resume, unconditionally if it's being used or not. This may lead to that genpd's internal status of the power state, may not correctly reflect the power state of the HW after a system PM resume. Because of changing the behaviour of genpd, by runtime resuming devices in the prepare phase, the AMD ACP drm driver no longer have to deal with this corner case. So let's just drop the related code in this driver. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Acked-by: Maruthi Bayyavarapu Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 84 ++++++++++++--------------------- drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 23 --------- include/linux/pm_domain.h | 1 - 3 files changed, 31 insertions(+), 77 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index de23b648fce3..a608f521e6fc 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -187,8 +187,7 @@ static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth) struct gpd_link *link; int ret = 0; - if (genpd->status == GPD_STATE_ACTIVE - || (genpd->prepared_count > 0 && genpd->suspend_power_off)) + if (genpd->status == GPD_STATE_ACTIVE) return 0; /* @@ -735,21 +734,22 @@ static int pm_genpd_prepare(struct device *dev) mutex_lock(&genpd->lock); - if (genpd->prepared_count++ == 0) { + if (genpd->prepared_count++ == 0) genpd->suspended_count = 0; - genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF; - } mutex_unlock(&genpd->lock); - if (genpd->suspend_power_off) - return 0; - /* - * The PM domain must be in the GPD_STATE_ACTIVE state at this point, - * so genpd_poweron() will return immediately, but if the device - * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need - * to make it operational. + * Even if the PM domain is powered off at this point, we can't expect + * it to remain in that state during the entire system PM suspend + * phase. Any subsystem/driver for a device in the PM domain, may still + * need to serve a request which may require the device to be runtime + * resumed and its PM domain to be powered. + * + * As we are disabling runtime PM at this point, we are preventing the + * subsystem/driver to decide themselves. For that reason, we need to + * make sure the device is operational as it may be required in some + * cases. */ pm_runtime_resume(dev); __pm_runtime_disable(dev, false); @@ -758,8 +758,7 @@ static int pm_genpd_prepare(struct device *dev) if (ret) { mutex_lock(&genpd->lock); - if (--genpd->prepared_count == 0) - genpd->suspend_power_off = false; + genpd->prepared_count--; mutex_unlock(&genpd->lock); pm_runtime_enable(dev); @@ -786,7 +785,7 @@ static int pm_genpd_suspend(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev); + return pm_generic_suspend(dev); } /** @@ -807,7 +806,7 @@ static int pm_genpd_suspend_late(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : pm_generic_suspend_late(dev); + return pm_generic_suspend_late(dev); } /** @@ -827,8 +826,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->suspend_power_off - || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) + if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) return 0; genpd_stop_dev(genpd, dev); @@ -860,8 +858,7 @@ static int pm_genpd_resume_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->suspend_power_off - || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) + if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) return 0; /* @@ -894,7 +891,7 @@ static int pm_genpd_resume_early(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : pm_generic_resume_early(dev); + return pm_generic_resume_early(dev); } /** @@ -915,7 +912,7 @@ static int pm_genpd_resume(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : pm_generic_resume(dev); + return pm_generic_resume(dev); } /** @@ -936,7 +933,7 @@ static int pm_genpd_freeze(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev); + return pm_generic_freeze(dev); } /** @@ -958,7 +955,7 @@ static int pm_genpd_freeze_late(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : pm_generic_freeze_late(dev); + return pm_generic_freeze_late(dev); } /** @@ -980,7 +977,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev); + return genpd_stop_dev(genpd, dev); } /** @@ -1000,8 +997,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? - 0 : genpd_start_dev(genpd, dev); + return genpd_start_dev(genpd, dev); } /** @@ -1023,7 +1019,7 @@ static int pm_genpd_thaw_early(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : pm_generic_thaw_early(dev); + return pm_generic_thaw_early(dev); } /** @@ -1044,7 +1040,7 @@ static int pm_genpd_thaw(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev); + return pm_generic_thaw(dev); } /** @@ -1072,26 +1068,13 @@ static int pm_genpd_restore_noirq(struct device *dev) * At this point suspended_count == 0 means we are being run for the * first time for the given domain in the present cycle. */ - if (genpd->suspended_count++ == 0) { + if (genpd->suspended_count++ == 0) /* * The boot kernel might put the domain into arbitrary state, * so make it appear as powered off to pm_genpd_sync_poweron(), * so that it tries to power it on in case it was really off. */ genpd->status = GPD_STATE_POWER_OFF; - if (genpd->suspend_power_off) { - /* - * If the domain was off before the hibernation, make - * sure it will be off going forward. - */ - genpd_power_off(genpd, true); - - return 0; - } - } - - if (genpd->suspend_power_off) - return 0; pm_genpd_sync_poweron(genpd, true); @@ -1110,7 +1093,6 @@ static int pm_genpd_restore_noirq(struct device *dev) static void pm_genpd_complete(struct device *dev) { struct generic_pm_domain *genpd; - bool run_complete; dev_dbg(dev, "%s()\n", __func__); @@ -1120,18 +1102,14 @@ static void pm_genpd_complete(struct device *dev) mutex_lock(&genpd->lock); - run_complete = !genpd->suspend_power_off; - if (--genpd->prepared_count == 0) - genpd->suspend_power_off = false; + genpd->prepared_count--; mutex_unlock(&genpd->lock); - if (run_complete) { - pm_generic_complete(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_request_idle(dev); - } + pm_generic_complete(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_request_idle(dev); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index 252edba16e36..892d60fb225b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c @@ -421,29 +421,6 @@ static int acp_suspend(void *handle) static int acp_resume(void *handle) { - int i, ret; - struct acp_pm_domain *apd; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - /* return early if no ACP */ - if (!adev->acp.acp_genpd) - return 0; - - /* SMU block will power on ACP irrespective of ACP runtime status. - * Power off explicitly based on genpd ACP runtime status so that ACP - * hw and ACP-genpd status are in sync. - * 'suspend_power_off' represents "Power status before system suspend" - */ - if (adev->acp.acp_genpd->gpd.suspend_power_off == true) { - apd = container_of(&adev->acp.acp_genpd->gpd, - struct acp_pm_domain, gpd); - - for (i = 4; i >= 0 ; i--) { - ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_P1 + i); - if (ret) - pr_err("ACP tile %d tile suspend failed\n", i); - } - } return 0; } diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 39285c7bd3f5..dd5b0447d572 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -57,7 +57,6 @@ struct generic_pm_domain { unsigned int device_count; /* Number of devices */ unsigned int suspended_count; /* System suspend device counter */ unsigned int prepared_count; /* Suspend counter of prepared devices */ - bool suspend_power_off; /* Power status before system suspend */ int (*power_off)(struct generic_pm_domain *domain); int (*power_on)(struct generic_pm_domain *domain); struct gpd_dev_ops dev_ops; -- cgit v1.2.3 From cecbc5563a02289164fa6379130243cbe08b2dd6 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Wed, 15 Jun 2016 11:32:21 -0700 Subject: net: stmmac: allow to split suspend/resume from init/exit callbacks Let the stmmac platform drivers provide dedicated suspend and resume callbacks rather than always re-using the init and exits callbacks. If the driver does not provide the suspend or resume callback, we fall back to the old behavior trying to use exit or init. This allows a specific platform to perform only a partial power-down on suspend if Wake-on-Lan is enabled but always perform the full shutdown sequence if the module is unloaded. Signed-off-by: Vincent Palatin Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 8 ++++++-- include/linux/stmmac.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 409db913b117..a96714d34560 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -411,7 +411,9 @@ static int stmmac_pltfr_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); ret = stmmac_suspend(dev); - if (priv->plat->exit) + if (priv->plat->suspend) + priv->plat->suspend(pdev, priv->plat->bsp_priv); + else if (priv->plat->exit) priv->plat->exit(pdev, priv->plat->bsp_priv); return ret; @@ -430,7 +432,9 @@ static int stmmac_pltfr_resume(struct device *dev) struct stmmac_priv *priv = netdev_priv(ndev); struct platform_device *pdev = to_platform_device(dev); - if (priv->plat->init) + if (priv->plat->resume) + priv->plat->resume(pdev, priv->plat->bsp_priv); + else if (priv->plat->init) priv->plat->init(pdev, priv->plat->bsp_priv); return stmmac_resume(dev); diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index ffdaca9c01af..0507dbfbf63c 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -135,6 +135,8 @@ struct plat_stmmacenet_data { void (*bus_setup)(void __iomem *ioaddr); int (*init)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv); + void (*suspend)(struct platform_device *pdev, void *priv); + void (*resume)(struct platform_device *pdev, void *priv); void *bsp_priv; struct stmmac_axi *axi; int has_gmac4; -- cgit v1.2.3 From b4f210541fc319bd643ad9a4fdbfe2ce31be6cfc Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 9 Jun 2016 16:53:47 +0200 Subject: i2c: add a protocol parameter to the alert callback .alert() is meant to be generic, but there is currently no way for the device driver to know which protocol generated the alert. Add a parameter in .alert() to help the device driver to understand what is given in data. This patch is required to have the support of SMBus Host Notify protocol through .alert(). Tested-by: Andrew Duggan For hwmon: Acked-by: Guenter Roeck For IPMI: Acked-by: Corey Minyard Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/char/ipmi/ipmi_ssif.c | 6 +++++- drivers/hwmon/lm90.c | 6 +++++- drivers/i2c/i2c-smbus.c | 3 ++- include/linux/i2c.h | 7 ++++++- 4 files changed, 18 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 097c86898608..5673ffff00be 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -568,12 +568,16 @@ static void retry_timeout(unsigned long data) } -static void ssif_alert(struct i2c_client *client, unsigned int data) +static void ssif_alert(struct i2c_client *client, enum i2c_alert_protocol type, + unsigned int data) { struct ssif_info *ssif_info = i2c_get_clientdata(client); unsigned long oflags, *flags; bool do_get = false; + if (type != I2C_PROTOCOL_SMBUS_ALERT) + return; + ssif_inc_stat(ssif_info, alerts); flags = ipmi_ssif_lock_cond(ssif_info, &oflags); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index e30a5939dc0d..5b62c57e8bfc 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1624,10 +1624,14 @@ static int lm90_remove(struct i2c_client *client) return 0; } -static void lm90_alert(struct i2c_client *client, unsigned int flag) +static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, + unsigned int flag) { u16 alarms; + if (type != I2C_PROTOCOL_SMBUS_ALERT) + return; + if (lm90_is_tripped(client, &alarms)) { /* * Disable ALERT# output, because these chips don't implement diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index abb55d3e76f3..3b6765a4ebe9 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -56,7 +56,8 @@ static int smbus_do_alert(struct device *dev, void *addrp) if (client->dev.driver) { driver = to_i2c_driver(client->dev.driver); if (driver->alert) - driver->alert(client, data->flag); + driver->alert(client, I2C_PROTOCOL_SMBUS_ALERT, + data->flag); else dev_warn(&client->dev, "no driver alert()!\n"); } else diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 6df7bad8c26c..37a45dcd6592 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -126,6 +126,10 @@ i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, u8 command, u8 length, u8 *values); #endif /* I2C */ +enum i2c_alert_protocol { + I2C_PROTOCOL_SMBUS_ALERT, +}; + /** * struct i2c_driver - represent an I2C device driver * @class: What kind of i2c device we instantiate (for detect) @@ -181,7 +185,8 @@ struct i2c_driver { * For the SMBus alert protocol, there is a single bit of data passed * as the alert response's low bit ("event flag"). */ - void (*alert)(struct i2c_client *, unsigned int data); + void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol, + unsigned int data); /* a ioctl like command that can be used to perform specific functions * with the device. -- cgit v1.2.3 From e456cd37bc28abe47dc65189df916ac0510ac1d4 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 9 Jun 2016 16:53:48 +0200 Subject: i2c: smbus: add SMBus Host Notify support SMBus Host Notify allows a slave device to act as a master on a bus to notify the host of an interrupt. On Intel chipsets, the functionality is directly implemented in the firmware. We just need to export a function to call .alert() on the proper device driver. i2c_handle_smbus_host_notify() behaves like i2c_handle_smbus_alert(). When called, it schedules a task that will be able to sleep to go through the list of devices attached to the adapter. The current implementation allows one Host Notification to be scheduled while an other is running. Tested-by: Andrew Duggan Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- Documentation/i2c/smbus-protocol | 6 +++ drivers/i2c/i2c-smbus.c | 113 +++++++++++++++++++++++++++++++++++++-- include/linux/i2c-smbus.h | 44 +++++++++++++++ include/linux/i2c.h | 3 ++ include/uapi/linux/i2c.h | 1 + 5 files changed, 162 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol index 6012b12b3510..14d4ec1be245 100644 --- a/Documentation/i2c/smbus-protocol +++ b/Documentation/i2c/smbus-protocol @@ -199,6 +199,12 @@ alerting device's address. [S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P] +This is implemented in the following way in the Linux kernel: +* I2C bus drivers which support SMBus Host Notify should call + i2c_setup_smbus_host_notify() to setup SMBus Host Notify support. +* I2C drivers for devices which can trigger SMBus Host Notify should implement + the optional alert() callback. + Packet Error Checking (PEC) =========================== diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 3b6765a4ebe9..f574995b41c1 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -33,7 +33,8 @@ struct i2c_smbus_alert { struct alert_data { unsigned short addr; - u8 flag:1; + enum i2c_alert_protocol type; + unsigned int data; }; /* If this is the alerting device, notify its driver */ @@ -56,8 +57,7 @@ static int smbus_do_alert(struct device *dev, void *addrp) if (client->dev.driver) { driver = to_i2c_driver(client->dev.driver); if (driver->alert) - driver->alert(client, I2C_PROTOCOL_SMBUS_ALERT, - data->flag); + driver->alert(client, data->type, data->data); else dev_warn(&client->dev, "no driver alert()!\n"); } else @@ -97,8 +97,9 @@ static void smbus_alert(struct work_struct *work) if (status < 0) break; - data.flag = status & 1; + data.data = status & 1; data.addr = status >> 1; + data.type = I2C_PROTOCOL_SMBUS_ALERT; if (data.addr == prev_addr) { dev_warn(&ara->dev, "Duplicate SMBALERT# from dev " @@ -106,7 +107,7 @@ static void smbus_alert(struct work_struct *work) break; } dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n", - data.addr, data.flag); + data.addr, data.data); /* Notify driver for the device which issued the alert */ device_for_each_child(&ara->adapter->dev, &data, @@ -240,6 +241,108 @@ int i2c_handle_smbus_alert(struct i2c_client *ara) } EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert); +static void smbus_host_notify_work(struct work_struct *work) +{ + struct alert_data alert; + struct i2c_adapter *adapter; + unsigned long flags; + u16 payload; + u8 addr; + struct smbus_host_notify *data; + + data = container_of(work, struct smbus_host_notify, work); + + spin_lock_irqsave(&data->lock, flags); + payload = data->payload; + addr = data->addr; + adapter = data->adapter; + + /* clear the pending bit and release the spinlock */ + data->pending = false; + spin_unlock_irqrestore(&data->lock, flags); + + if (!adapter || !addr) + return; + + alert.type = I2C_PROTOCOL_SMBUS_HOST_NOTIFY; + alert.addr = addr; + alert.data = payload; + + device_for_each_child(&adapter->dev, &alert, smbus_do_alert); +} + +/** + * i2c_setup_smbus_host_notify - Allocate a new smbus_host_notify for the given + * I2C adapter. + * @adapter: the adapter we want to associate a Host Notify function + * + * Returns a struct smbus_host_notify pointer on success, and NULL on failure. + * The resulting smbus_host_notify must not be freed afterwards, it is a + * managed resource already. + */ +struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap) +{ + struct smbus_host_notify *host_notify; + + host_notify = devm_kzalloc(&adap->dev, sizeof(struct smbus_host_notify), + GFP_KERNEL); + if (!host_notify) + return NULL; + + host_notify->adapter = adap; + + spin_lock_init(&host_notify->lock); + INIT_WORK(&host_notify->work, smbus_host_notify_work); + + return host_notify; +} +EXPORT_SYMBOL_GPL(i2c_setup_smbus_host_notify); + +/** + * i2c_handle_smbus_host_notify - Forward a Host Notify event to the correct + * I2C client. + * @host_notify: the struct host_notify attached to the relevant adapter + * @data: the Host Notify data which contains the payload and address of the + * client + * Context: can't sleep + * + * Helper function to be called from an I2C bus driver's interrupt + * handler. It will schedule the Host Notify work, in turn calling the + * corresponding I2C device driver's alert function. + * + * host_notify should be a valid pointer previously returned by + * i2c_setup_smbus_host_notify(). + */ +int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, + unsigned short addr, unsigned int data) +{ + unsigned long flags; + struct i2c_adapter *adapter; + + if (!host_notify || !host_notify->adapter) + return -EINVAL; + + adapter = host_notify->adapter; + + spin_lock_irqsave(&host_notify->lock, flags); + + if (host_notify->pending) { + spin_unlock_irqrestore(&host_notify->lock, flags); + dev_warn(&adapter->dev, "Host Notify already scheduled.\n"); + return -EBUSY; + } + + host_notify->payload = data; + host_notify->addr = addr; + + /* Mark that there is a pending notification and release the lock */ + host_notify->pending = true; + spin_unlock_irqrestore(&host_notify->lock, flags); + + return schedule_work(&host_notify->work); +} +EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify); + module_i2c_driver(smbalert_driver); MODULE_AUTHOR("Jean Delvare "); diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h index 8f1b086ca5bc..4ac95bbe53ef 100644 --- a/include/linux/i2c-smbus.h +++ b/include/linux/i2c-smbus.h @@ -23,6 +23,8 @@ #define _LINUX_I2C_SMBUS_H #include +#include +#include /** @@ -48,4 +50,46 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, struct i2c_smbus_alert_setup *setup); int i2c_handle_smbus_alert(struct i2c_client *ara); +/** + * smbus_host_notify - internal structure used by the Host Notify mechanism. + * @adapter: the I2C adapter associated with this struct + * @work: worker used to schedule the IRQ in the slave device + * @lock: spinlock to check if a notification is already pending + * @pending: flag set when a notification is pending (any new notification will + * be rejected if pending is true) + * @payload: the actual payload of the Host Notify event + * @addr: the address of the slave device which raised the notification + * + * This struct needs to be allocated by i2c_setup_smbus_host_notify() and does + * not need to be freed. Internally, i2c_setup_smbus_host_notify() uses a + * managed resource to clean this up when the adapter get released. + */ +struct smbus_host_notify { + struct i2c_adapter *adapter; + struct work_struct work; + spinlock_t lock; + bool pending; + u16 payload; + u8 addr; +}; + +#if IS_ENABLED(CONFIG_I2C_SMBUS) +struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap); +int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, + unsigned short addr, unsigned int data); +#else +static inline struct smbus_host_notify * +i2c_setup_smbus_host_notify(struct i2c_adapter *adap) +{ + return NULL; +} + +static inline int +i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, + unsigned short addr, unsigned int data) +{ + return 0; +} +#endif /* I2C_SMBUS */ + #endif /* _LINUX_I2C_SMBUS_H */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 37a45dcd6592..fffdc270ca18 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -128,6 +128,7 @@ i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, enum i2c_alert_protocol { I2C_PROTOCOL_SMBUS_ALERT, + I2C_PROTOCOL_SMBUS_HOST_NOTIFY, }; /** @@ -184,6 +185,8 @@ struct i2c_driver { * The format and meaning of the data value depends on the protocol. * For the SMBus alert protocol, there is a single bit of data passed * as the alert response's low bit ("event flag"). + * For the SMBus Host Notify protocol, the data corresponds to the + * 16-bit payload data reported by the slave device acting as master. */ void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol, unsigned int data); diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h index adcbef4bff61..009e27bb9abe 100644 --- a/include/uapi/linux/i2c.h +++ b/include/uapi/linux/i2c.h @@ -102,6 +102,7 @@ struct i2c_msg { #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 #define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ +#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000 #define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ I2C_FUNC_SMBUS_WRITE_BYTE) -- cgit v1.2.3 From 8221a013528597edc18d371b22667e8eefca599b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 17 Jun 2016 14:43:34 -0500 Subject: PCI: Unify pci_resource_to_user() declarations Replace the pci_resource_to_user() declarations in each arch that defines HAVE_ARCH_PCI_RESOURCE_TO_USER with a single one in linux/pci.h. Change the MIPS static inline implementation to a non-inline version so the static inline doesn't conflict with the new non-static linux/pci.h declaration. No functional change intended. Signed-off-by: Bjorn Helgaas --- arch/microblaze/include/asm/pci.h | 3 --- arch/mips/include/asm/pci.h | 10 ---------- arch/mips/pci/pci.c | 10 ++++++++++ arch/powerpc/include/asm/pci.h | 3 --- arch/sparc/include/asm/pci_64.h | 3 --- include/linux/pci.h | 6 +++++- 6 files changed, 15 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h index fc3ecb55f1b2..2a120bb70e54 100644 --- a/arch/microblaze/include/asm/pci.h +++ b/arch/microblaze/include/asm/pci.h @@ -82,9 +82,6 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, pgprot_t prot); #define HAVE_ARCH_PCI_RESOURCE_TO_USER -extern void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - resource_size_t *start, resource_size_t *end); extern void pcibios_setup_bus_devices(struct pci_bus *bus); extern void pcibios_setup_bus_self(struct pci_bus *bus); diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 86b239d9d75d..9b63cd41213d 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -80,16 +80,6 @@ extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, #define HAVE_ARCH_PCI_RESOURCE_TO_USER -static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, resource_size_t *start, - resource_size_t *end) -{ - phys_addr_t size = resource_size(rsrc); - - *start = fixup_bigphys_addr(rsrc->start, size); - *end = rsrc->start + size; -} - /* * Dynamic DMA mapping stuff. * MIPS has everything mapped statically. diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index f1b11f0dea2d..5717384a986d 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -319,6 +319,16 @@ void pcibios_fixup_bus(struct pci_bus *bus) EXPORT_SYMBOL(PCIBIOS_MIN_IO); EXPORT_SYMBOL(PCIBIOS_MIN_MEM); +void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, resource_size_t *start, + resource_size_t *end) +{ + phys_addr_t size = resource_size(rsrc); + + *start = fixup_bigphys_addr(rsrc->start, size); + *end = rsrc->start + size; +} + int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine) { diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index a6f3ac0d4602..e9bd6cf0212f 100644 --- a/arch/powerpc/include/asm/pci.h +++ b/arch/powerpc/include/asm/pci.h @@ -136,9 +136,6 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, pgprot_t prot); #define HAVE_ARCH_PCI_RESOURCE_TO_USER -extern void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - resource_size_t *start, resource_size_t *end); extern resource_size_t pcibios_io_space_offset(struct pci_controller *hose); extern void pcibios_setup_bus_devices(struct pci_bus *bus); diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h index 022d16008a00..2303635158f5 100644 --- a/arch/sparc/include/asm/pci_64.h +++ b/arch/sparc/include/asm/pci_64.h @@ -55,9 +55,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) } #define HAVE_ARCH_PCI_RESOURCE_TO_USER -void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - resource_size_t *start, resource_size_t *end); #endif /* __KERNEL__ */ #endif /* __SPARC64_PCI_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index b67e4df20801..9c201d4dbd51 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1554,7 +1554,11 @@ static inline const char *pci_name(const struct pci_dev *pdev) /* Some archs don't want to expose struct resource to userland as-is * in sysfs and /proc */ -#ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER +#ifdef HAVE_ARCH_PCI_RESOURCE_TO_USER +void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, + resource_size_t *start, resource_size_t *end); +#else static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, const struct resource *rsrc, resource_size_t *start, resource_size_t *end) -- cgit v1.2.3 From 224abb67e6eb5ac062de9239163136d5ec3155c8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 17 Jun 2016 15:23:52 -0500 Subject: PCI: Document connection between pci_power_t and hardware PM capability The dev.pme_support field, pci_pm_init(), pci_pme_capable(), and pci_raw_set_power_state() depend on the fact that the pci_power_t values (PCI_D0, PCI_D1, etc.) match the definition of the Capabilities PME_Support and the Control/Status PowerState fields in the Power Management capability (see PCI Bus Power Management spec r1.2, sec 3.2.3). Add a note to this effect at the pci_power_t typedef. Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko Reviewed-by: Mika Westerberg --- include/linux/pci.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 8597b423cb63..0a1a9e30359c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -101,6 +101,10 @@ enum { DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES, }; +/* + * pci_power_t values must match the bits in the Capabilities PME_Support + * and Control/Status PowerState fields in the Power Management capability. + */ typedef int __bitwise pci_power_t; #define PCI_D0 ((pci_power_t __force) 0) -- cgit v1.2.3 From 70f4f9352317ed8bc70cd7fe2bf34a3f9f7f21e3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 17 Jun 2016 16:48:17 +0200 Subject: ia64: efi: use timespec64 for persistent clock We have a generic read_persistent_clock64 interface now, and can change the ia64 implementation to provide that instead of read_persistent_clock. The main point of this is to avoid the use of struct timespec in the global efi.h, which would cause build errors as soon as we want to build a kernel without 'struct timespec' defined on 32-bit architectures. Aside from this, we get a little closer to removing the __weak read_persistent_clock() definition, which relies on converting all architectures to provide read_persistent_clock64 instead. Signed-off-by: Arnd Bergmann Signed-off-by: Tony Luck --- arch/ia64/kernel/efi.c | 4 ++-- arch/ia64/kernel/time.c | 2 +- include/linux/efi.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 3b7a60e40e8a..121295637d0d 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -236,7 +236,7 @@ STUB_GET_NEXT_HIGH_MONO_COUNT(virt, id) STUB_RESET_SYSTEM(virt, id) void -efi_gettimeofday (struct timespec *ts) +efi_gettimeofday (struct timespec64 *ts) { efi_time_t tm; @@ -245,7 +245,7 @@ efi_gettimeofday (struct timespec *ts) return; } - ts->tv_sec = mktime(tm.year, tm.month, tm.day, + ts->tv_sec = mktime64(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); ts->tv_nsec = tm.nanosecond; } diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index c8dbe2acd735..6f892b94e906 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -355,7 +355,7 @@ static struct irqaction timer_irqaction = { .name = "timer" }; -void read_persistent_clock(struct timespec *ts) +void read_persistent_clock64(struct timespec64 *ts) { efi_gettimeofday(ts); } diff --git a/include/linux/efi.h b/include/linux/efi.h index f196dd0b0f2f..acb6adace01e 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -937,7 +937,7 @@ extern void efi_init (void); extern void *efi_get_pal_addr (void); extern void efi_map_pal_code (void); extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); -extern void efi_gettimeofday (struct timespec *ts); +extern void efi_gettimeofday (struct timespec64 *ts); extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ #ifdef CONFIG_X86 extern void efi_late_init(void); -- cgit v1.2.3 From 7c46a640de6fcc4f35d0702710356a024eadf68f Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 16 Jun 2016 12:21:00 -0700 Subject: net: Merge VXLAN and GENEVE push notifiers into a single notifier This patch merges the notifiers for VXLAN and GENEVE into a single UDP tunnel notifier. The idea is that we will want to only have to make one notifier call to receive the list of ports for VXLAN and GENEVE tunnels that need to be offloaded. In addition we add a new set of ndo functions named ndo_udp_tunnel_add and ndo_udp_tunnel_del that are meant to allow us to track the tunnel meta-data such as port and address family as tunnels are added and removed. The tunnel meta-data is now transported in a structure named udp_tunnel_info which for now carries the type, address family, and port number. In the future this could be updated so that we can include a tuple of values including things such as the destination IP address and other fields. I also ended up going with a naming scheme that consisted of using the prefix udp_tunnel on function names. I applied this to the notifier and ndo ops as well so that it hopefully points to the fact that these are primarily used in the udp_tunnel functions. Signed-off-by: Alexander Duyck Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- drivers/net/geneve.c | 2 +- drivers/net/vxlan.c | 2 +- include/linux/netdevice.h | 22 ++++++++++++++++++++-- include/net/geneve.h | 3 +-- include/net/udp_tunnel.h | 6 ++++++ include/net/vxlan.h | 4 ++-- net/ipv4/udp_tunnel.c | 10 ++++++++++ 7 files changed, 41 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index af6f676ca444..aa61708bea69 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1497,7 +1497,7 @@ static int geneve_netdevice_event(struct notifier_block *unused, { struct net_device *dev = netdev_notifier_info_to_dev(ptr); - if (event == NETDEV_OFFLOAD_PUSH_GENEVE) + if (event == NETDEV_UDP_TUNNEL_PUSH_INFO) geneve_push_rx_ports(dev); return NOTIFY_DONE; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index adbd979da22d..31aeec967175 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3239,7 +3239,7 @@ static int vxlan_netdevice_event(struct notifier_block *unused, if (event == NETDEV_UNREGISTER) vxlan_handle_lowerdev_unregister(vn, dev); - else if (event == NETDEV_OFFLOAD_PUSH_VXLAN) + else if (event == NETDEV_UDP_TUNNEL_PUSH_INFO) vxlan_push_rx_ports(dev); return NOTIFY_DONE; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 890158e99159..577d2a1814b1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -61,6 +61,8 @@ struct wireless_dev; /* 802.15.4 specific */ struct wpan_dev; struct mpls_dev; +/* UDP Tunnel offloads */ +struct udp_tunnel_info; void netdev_set_default_ethtool_ops(struct net_device *dev, const struct ethtool_ops *ops); @@ -1050,6 +1052,19 @@ struct tc_to_netdev { * address family that vxlan is not listening to anymore. The operation * is protected by the vxlan_net->sock_lock. * + * void (*ndo_udp_tunnel_add)(struct net_device *dev, + * struct udp_tunnel_info *ti); + * Called by UDP tunnel to notify a driver about the UDP port and socket + * address family that a UDP tunnel is listnening to. It is called only + * when a new port starts listening. The operation is protected by the + * RTNL. + * + * void (*ndo_udp_tunnel_del)(struct net_device *dev, + * struct udp_tunnel_info *ti); + * Called by UDP tunnel to notify the driver about a UDP port and socket + * address family that the UDP tunnel is not listening to anymore. The + * operation is protected by the RTNL. + * * void* (*ndo_dfwd_add_station)(struct net_device *pdev, * struct net_device *dev) * Called by upper layer devices to accelerate switching or other @@ -1269,6 +1284,10 @@ struct net_device_ops { void (*ndo_del_geneve_port)(struct net_device *dev, sa_family_t sa_family, __be16 port); + void (*ndo_udp_tunnel_add)(struct net_device *dev, + struct udp_tunnel_info *ti); + void (*ndo_udp_tunnel_del)(struct net_device *dev, + struct udp_tunnel_info *ti); void* (*ndo_dfwd_add_station)(struct net_device *pdev, struct net_device *dev); void (*ndo_dfwd_del_station)(struct net_device *pdev, @@ -2255,8 +2274,7 @@ struct netdev_lag_lower_state_info { #define NETDEV_BONDING_INFO 0x0019 #define NETDEV_PRECHANGEUPPER 0x001A #define NETDEV_CHANGELOWERSTATE 0x001B -#define NETDEV_OFFLOAD_PUSH_VXLAN 0x001C -#define NETDEV_OFFLOAD_PUSH_GENEVE 0x001D +#define NETDEV_UDP_TUNNEL_PUSH_INFO 0x001C int register_netdevice_notifier(struct notifier_block *nb); int unregister_netdevice_notifier(struct notifier_block *nb); diff --git a/include/net/geneve.h b/include/net/geneve.h index f8aff18d6702..3410c4b5a382 100644 --- a/include/net/geneve.h +++ b/include/net/geneve.h @@ -61,8 +61,7 @@ struct genevehdr { static inline void geneve_get_rx_port(struct net_device *netdev) { - ASSERT_RTNL(); - call_netdevice_notifiers(NETDEV_OFFLOAD_PUSH_GENEVE, netdev); + udp_tunnel_get_rx_info(netdev); } #ifdef CONFIG_INET diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index 71afbea873a0..1c9408a04213 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -117,6 +117,12 @@ void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock, void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type); void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type); +static inline void udp_tunnel_get_rx_info(struct net_device *dev) +{ + ASSERT_RTNL(); + call_netdevice_notifiers(NETDEV_UDP_TUNNEL_PUSH_INFO, dev); +} + /* Transmit the skb using UDP encapsulation. */ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 7d944941f32f..c62e2ed1c3af 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -4,6 +4,7 @@ #include #include #include +#include /* VXLAN protocol (RFC 7348) header: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -390,8 +391,7 @@ static inline __be32 vxlan_compute_rco(unsigned int start, unsigned int offset) static inline void vxlan_get_rx_port(struct net_device *netdev) { - ASSERT_RTNL(); - call_netdevice_notifiers(NETDEV_OFFLOAD_PUSH_VXLAN, netdev); + udp_tunnel_get_rx_info(netdev); } static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs) diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c index 8174753e6494..683e494d9000 100644 --- a/net/ipv4/udp_tunnel.c +++ b/net/ipv4/udp_tunnel.c @@ -79,6 +79,11 @@ EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); static void __udp_tunnel_push_rx_port(struct net_device *dev, struct udp_tunnel_info *ti) { + if (dev->netdev_ops->ndo_udp_tunnel_add) { + dev->netdev_ops->ndo_udp_tunnel_add(dev, ti); + return; + } + switch (ti->type) { case UDP_TUNNEL_TYPE_VXLAN: if (!dev->netdev_ops->ndo_add_vxlan_port) @@ -137,6 +142,11 @@ EXPORT_SYMBOL_GPL(udp_tunnel_notify_add_rx_port); static void __udp_tunnel_pull_rx_port(struct net_device *dev, struct udp_tunnel_info *ti) { + if (dev->netdev_ops->ndo_udp_tunnel_del) { + dev->netdev_ops->ndo_udp_tunnel_del(dev, ti); + return; + } + switch (ti->type) { case UDP_TUNNEL_TYPE_VXLAN: if (!dev->netdev_ops->ndo_del_vxlan_port) -- cgit v1.2.3 From 1938ee1fd3de74d761a60806b048df652666afec Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 16 Jun 2016 12:23:12 -0700 Subject: net: Remove deprecated tunnel specific UDP offload functions Now that we have all the drivers using udp_tunnel_get_rx_ports, ndo_add_udp_enc_rx_port, and ndo_del_udp_enc_rx_port we can drop the function calls that were specific to VXLAN and GENEVE. Signed-off-by: Alexander Duyck Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/netdevice.h | 38 ----------------------- include/net/geneve.h | 5 --- include/net/vxlan.h | 5 --- net/ipv4/udp_tunnel.c | 79 +++++++++-------------------------------------- 4 files changed, 14 insertions(+), 113 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 577d2a1814b1..e84d9d23c2d5 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1026,32 +1026,6 @@ struct tc_to_netdev { * not implement this, it is assumed that the hw is not able to have * multiple net devices on single physical port. * - * void (*ndo_add_vxlan_port)(struct net_device *dev, - * sa_family_t sa_family, __be16 port); - * Called by vxlan to notify a driver about the UDP port and socket - * address family that vxlan is listening to. It is called only when - * a new port starts listening. The operation is protected by the - * vxlan_net->sock_lock. - * - * void (*ndo_add_geneve_port)(struct net_device *dev, - * sa_family_t sa_family, __be16 port); - * Called by geneve to notify a driver about the UDP port and socket - * address family that geneve is listnening to. It is called only when - * a new port starts listening. The operation is protected by the - * geneve_net->sock_lock. - * - * void (*ndo_del_geneve_port)(struct net_device *dev, - * sa_family_t sa_family, __be16 port); - * Called by geneve to notify the driver about a UDP port and socket - * address family that geneve is not listening to anymore. The operation - * is protected by the geneve_net->sock_lock. - * - * void (*ndo_del_vxlan_port)(struct net_device *dev, - * sa_family_t sa_family, __be16 port); - * Called by vxlan to notify the driver about a UDP port and socket - * address family that vxlan is not listening to anymore. The operation - * is protected by the vxlan_net->sock_lock. - * * void (*ndo_udp_tunnel_add)(struct net_device *dev, * struct udp_tunnel_info *ti); * Called by UDP tunnel to notify a driver about the UDP port and socket @@ -1272,18 +1246,6 @@ struct net_device_ops { struct netdev_phys_item_id *ppid); int (*ndo_get_phys_port_name)(struct net_device *dev, char *name, size_t len); - void (*ndo_add_vxlan_port)(struct net_device *dev, - sa_family_t sa_family, - __be16 port); - void (*ndo_del_vxlan_port)(struct net_device *dev, - sa_family_t sa_family, - __be16 port); - void (*ndo_add_geneve_port)(struct net_device *dev, - sa_family_t sa_family, - __be16 port); - void (*ndo_del_geneve_port)(struct net_device *dev, - sa_family_t sa_family, - __be16 port); void (*ndo_udp_tunnel_add)(struct net_device *dev, struct udp_tunnel_info *ti); void (*ndo_udp_tunnel_del)(struct net_device *dev, diff --git a/include/net/geneve.h b/include/net/geneve.h index 3410c4b5a382..ec0327d4331b 100644 --- a/include/net/geneve.h +++ b/include/net/geneve.h @@ -59,11 +59,6 @@ struct genevehdr { struct geneve_opt options[]; }; -static inline void geneve_get_rx_port(struct net_device *netdev) -{ - udp_tunnel_get_rx_info(netdev); -} - #ifdef CONFIG_INET struct net_device *geneve_dev_create_fb(struct net *net, const char *name, u8 name_assign_type, u16 dst_port); diff --git a/include/net/vxlan.h b/include/net/vxlan.h index c62e2ed1c3af..b96d0360c095 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -389,11 +389,6 @@ static inline __be32 vxlan_compute_rco(unsigned int start, unsigned int offset) return vni_field; } -static inline void vxlan_get_rx_port(struct net_device *netdev) -{ - udp_tunnel_get_rx_info(netdev); -} - static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs) { return vs->sock->sk->sk_family; diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c index 683e494d9000..58bd39fb14b4 100644 --- a/net/ipv4/udp_tunnel.c +++ b/net/ipv4/udp_tunnel.c @@ -76,47 +76,20 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock, } EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); -static void __udp_tunnel_push_rx_port(struct net_device *dev, - struct udp_tunnel_info *ti) -{ - if (dev->netdev_ops->ndo_udp_tunnel_add) { - dev->netdev_ops->ndo_udp_tunnel_add(dev, ti); - return; - } - - switch (ti->type) { - case UDP_TUNNEL_TYPE_VXLAN: - if (!dev->netdev_ops->ndo_add_vxlan_port) - break; - - dev->netdev_ops->ndo_add_vxlan_port(dev, - ti->sa_family, - ti->port); - break; - case UDP_TUNNEL_TYPE_GENEVE: - if (!dev->netdev_ops->ndo_add_geneve_port) - break; - - dev->netdev_ops->ndo_add_geneve_port(dev, - ti->sa_family, - ti->port); - break; - default: - break; - } -} - void udp_tunnel_push_rx_port(struct net_device *dev, struct socket *sock, unsigned short type) { struct sock *sk = sock->sk; struct udp_tunnel_info ti; + if (!dev->netdev_ops->ndo_udp_tunnel_add) + return; + ti.type = type; ti.sa_family = sk->sk_family; ti.port = inet_sk(sk)->inet_sport; - __udp_tunnel_push_rx_port(dev, &ti); + dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti); } EXPORT_SYMBOL_GPL(udp_tunnel_push_rx_port); @@ -133,42 +106,15 @@ void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type) ti.port = inet_sk(sk)->inet_sport; rcu_read_lock(); - for_each_netdev_rcu(net, dev) - __udp_tunnel_push_rx_port(dev, &ti); + for_each_netdev_rcu(net, dev) { + if (!dev->netdev_ops->ndo_udp_tunnel_add) + continue; + dev->netdev_ops->ndo_udp_tunnel_add(dev, &ti); + } rcu_read_unlock(); } EXPORT_SYMBOL_GPL(udp_tunnel_notify_add_rx_port); -static void __udp_tunnel_pull_rx_port(struct net_device *dev, - struct udp_tunnel_info *ti) -{ - if (dev->netdev_ops->ndo_udp_tunnel_del) { - dev->netdev_ops->ndo_udp_tunnel_del(dev, ti); - return; - } - - switch (ti->type) { - case UDP_TUNNEL_TYPE_VXLAN: - if (!dev->netdev_ops->ndo_del_vxlan_port) - break; - - dev->netdev_ops->ndo_del_vxlan_port(dev, - ti->sa_family, - ti->port); - break; - case UDP_TUNNEL_TYPE_GENEVE: - if (!dev->netdev_ops->ndo_del_geneve_port) - break; - - dev->netdev_ops->ndo_del_geneve_port(dev, - ti->sa_family, - ti->port); - break; - default: - break; - } -} - /* Notify netdevs that UDP port is no more listening */ void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type) { @@ -182,8 +128,11 @@ void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type) ti.port = inet_sk(sk)->inet_sport; rcu_read_lock(); - for_each_netdev_rcu(net, dev) - __udp_tunnel_pull_rx_port(dev, &ti); + for_each_netdev_rcu(net, dev) { + if (!dev->netdev_ops->ndo_udp_tunnel_del) + continue; + dev->netdev_ops->ndo_udp_tunnel_del(dev, &ti); + } rcu_read_unlock(); } EXPORT_SYMBOL_GPL(udp_tunnel_notify_del_rx_port); -- cgit v1.2.3 From 0431b9065f28ecf6c320fefebe0241620049984f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 31 May 2016 16:59:04 -0300 Subject: staging/android: bring struct sync_pt back Move the list_head members from sync_pt to struct fence was a mistake, they will not be used by struct fence as planned before, so here we create sync_pt again to bring the list heads back. Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter Reviewed-by: Sumit Semwal Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/sync.c | 40 ++++++++++++++++++------------------ drivers/staging/android/sync.h | 29 ++++++++++++++++++++++---- drivers/staging/android/sync_debug.c | 16 +++++++-------- include/linux/fence.h | 2 -- 4 files changed, 53 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index c83a599e2221..aab80ec7bce6 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -28,8 +28,6 @@ #define CREATE_TRACE_POINTS #include "trace/sync.h" -static const struct fence_ops timeline_fence_ops; - struct sync_timeline *sync_timeline_create(const char *drv_name, const char *name) { @@ -90,7 +88,7 @@ EXPORT_SYMBOL(sync_timeline_destroy); void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) { unsigned long flags; - struct fence *fence, *next; + struct sync_pt *pt, *next; trace_sync_timeline(obj); @@ -98,37 +96,37 @@ void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) obj->value += inc; - list_for_each_entry_safe(fence, next, &obj->active_list_head, + list_for_each_entry_safe(pt, next, &obj->active_list_head, active_list) { - if (fence_is_signaled_locked(fence)) - list_del_init(&fence->active_list); + if (fence_is_signaled_locked(&pt->base)) + list_del_init(&pt->active_list); } spin_unlock_irqrestore(&obj->child_list_lock, flags); } EXPORT_SYMBOL(sync_timeline_signal); -struct fence *sync_pt_create(struct sync_timeline *obj, int size, +struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size, unsigned int value) { unsigned long flags; - struct fence *fence; + struct sync_pt *pt; - if (size < sizeof(*fence)) + if (size < sizeof(*pt)) return NULL; - fence = kzalloc(size, GFP_KERNEL); - if (!fence) + pt = kzalloc(size, GFP_KERNEL); + if (!pt) return NULL; spin_lock_irqsave(&obj->child_list_lock, flags); sync_timeline_get(obj); - fence_init(fence, &timeline_fence_ops, &obj->child_list_lock, + fence_init(&pt->base, &timeline_fence_ops, &obj->child_list_lock, obj->context, value); - list_add_tail(&fence->child_list, &obj->child_list_head); - INIT_LIST_HEAD(&fence->active_list); + list_add_tail(&pt->child_list, &obj->child_list_head); + INIT_LIST_HEAD(&pt->active_list); spin_unlock_irqrestore(&obj->child_list_lock, flags); - return fence; + return pt; } EXPORT_SYMBOL(sync_pt_create); @@ -148,13 +146,14 @@ static const char *timeline_fence_get_timeline_name(struct fence *fence) static void timeline_fence_release(struct fence *fence) { + struct sync_pt *pt = fence_to_sync_pt(fence); struct sync_timeline *parent = fence_parent(fence); unsigned long flags; spin_lock_irqsave(fence->lock, flags); - list_del(&fence->child_list); - if (WARN_ON_ONCE(!list_empty(&fence->active_list))) - list_del(&fence->active_list); + list_del(&pt->child_list); + if (WARN_ON_ONCE(!list_empty(&pt->active_list))) + list_del(&pt->active_list); spin_unlock_irqrestore(fence->lock, flags); sync_timeline_put(parent); @@ -170,12 +169,13 @@ static bool timeline_fence_signaled(struct fence *fence) static bool timeline_fence_enable_signaling(struct fence *fence) { + struct sync_pt *pt = fence_to_sync_pt(fence); struct sync_timeline *parent = fence_parent(fence); if (timeline_fence_signaled(fence)) return false; - list_add_tail(&fence->active_list, &parent->active_list_head); + list_add_tail(&pt->active_list, &parent->active_list_head); return true; } @@ -193,7 +193,7 @@ static void timeline_fence_timeline_value_str(struct fence *fence, snprintf(str, size, "%d", parent->value); } -static const struct fence_ops timeline_fence_ops = { +const struct fence_ops timeline_fence_ops = { .get_driver_name = timeline_fence_get_driver_name, .get_timeline_name = timeline_fence_get_timeline_name, .enable_signaling = timeline_fence_enable_signaling, diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index f2fbf984ec6b..14b61cb18824 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -60,6 +60,27 @@ static inline struct sync_timeline *fence_parent(struct fence *fence) child_list_lock); } +/** + * struct sync_pt - sync_pt object + * @base: base fence object + * @child_list: sync timeline child's list + * @active_list: sync timeline active child's list + */ +struct sync_pt { + struct fence base; + struct list_head child_list; + struct list_head active_list; +}; + +extern const struct fence_ops timeline_fence_ops; + +static inline struct sync_pt *fence_to_sync_pt(struct fence *fence) +{ + if (fence->ops != &timeline_fence_ops) + return NULL; + return container_of(fence, struct sync_pt, base); +} + /* * API for sync_timeline implementers */ @@ -101,13 +122,13 @@ void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc); * @size: size to allocate for this pt * @inc: value of the fence * - * Creates a new fence as a child of @parent. @size bytes will be + * Creates a new sync_pt as a child of @parent. @size bytes will be * allocated allowing for implementation specific data to be kept after - * the generic sync_timeline struct. Returns the fence object or + * the generic sync_timeline struct. Returns the sync_pt object or * NULL in case of error. */ -struct fence *sync_pt_create(struct sync_timeline *parent, int size, - unsigned int inc); +struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size, + unsigned int inc); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c index cb0f8883cdb3..703f198abe5a 100644 --- a/drivers/staging/android/sync_debug.c +++ b/drivers/staging/android/sync_debug.c @@ -140,9 +140,9 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj) spin_lock_irqsave(&obj->child_list_lock, flags); list_for_each(pos, &obj->child_list_head) { - struct fence *fence = - container_of(pos, struct fence, child_list); - sync_print_fence(s, fence, false); + struct sync_pt *pt = + container_of(pos, struct sync_pt, child_list); + sync_print_fence(s, &pt->base, false); } spin_unlock_irqrestore(&obj->child_list_lock, flags); } @@ -240,7 +240,7 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, { int fd = get_unused_fd_flags(O_CLOEXEC); int err; - struct fence *fence; + struct sync_pt *pt; struct sync_file *sync_file; struct sw_sync_create_fence_data data; @@ -252,15 +252,15 @@ static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, goto err; } - fence = sync_pt_create(obj, sizeof(*fence), data.value); - if (!fence) { + pt = sync_pt_create(obj, sizeof(*pt), data.value); + if (!pt) { err = -ENOMEM; goto err; } - sync_file = sync_file_create(fence); + sync_file = sync_file_create(&pt->base); if (!sync_file) { - fence_put(fence); + fence_put(&pt->base); err = -ENOMEM; goto err; } diff --git a/include/linux/fence.h b/include/linux/fence.h index 2056e9fd0138..1de1b3f6fb76 100644 --- a/include/linux/fence.h +++ b/include/linux/fence.h @@ -81,8 +81,6 @@ struct fence { unsigned long flags; ktime_t timestamp; int status; - struct list_head child_list; - struct list_head active_list; }; enum fence_flag_bits { -- cgit v1.2.3 From edd14cfebc4404698544d407ecf8eda6e19aa19e Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 17 Jun 2016 16:00:20 -0600 Subject: genirq: Add untracked irq handler This adds a software irq handler for controllers that multiplex interrupts from multiple devices, but don't know which device generated the interrupt. For these devices, the irq handler that demuxes must check every action for every software irq using the same h/w irq in order to find out which device generated the interrupt. This will inevitably trigger spurious interrupt detection if we are noting the irq. The new irq handler does not track the handling for spurious interrupt detection. An irq that uses this also won't get stats tracked since it didn't generate the interrupt, nor added to randomness since they are not random. Signed-off-by: Keith Busch Cc: Bjorn Helgaas Cc: linux-pci@vger.kernel.org Cc: Jon Derrick Link: http://lkml.kernel.org/r/1466200821-29159-1-git-send-email-keith.busch@intel.com Signed-off-by: Thomas Gleixner --- include/linux/irq.h | 1 + kernel/irq/chip.c | 43 +++++++++++++++++++++++++++++++++++++++++++ kernel/irq/handle.c | 18 ++++++++++++++---- kernel/irq/internals.h | 1 + 4 files changed, 59 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 6c92a847394d..562cef010aa8 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -484,6 +484,7 @@ extern void handle_fasteoi_irq(struct irq_desc *desc); extern void handle_edge_irq(struct irq_desc *desc); extern void handle_edge_eoi_irq(struct irq_desc *desc); extern void handle_simple_irq(struct irq_desc *desc); +extern void handle_untracked_irq(struct irq_desc *desc); extern void handle_percpu_irq(struct irq_desc *desc); extern void handle_percpu_devid_irq(struct irq_desc *desc); extern void handle_bad_irq(struct irq_desc *desc); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index ad8131473774..b4c1bc7c9ca2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -426,6 +426,49 @@ out_unlock: } EXPORT_SYMBOL_GPL(handle_simple_irq); +/** + * handle_untracked_irq - Simple and software-decoded IRQs. + * @desc: the interrupt description structure for this irq + * + * Untracked interrupts are sent from a demultiplexing interrupt + * handler when the demultiplexer does not know which device it its + * multiplexed irq domain generated the interrupt. IRQ's handled + * through here are not subjected to stats tracking, randomness, or + * spurious interrupt detection. + * + * Note: Like handle_simple_irq, the caller is expected to handle + * the ack, clear, mask and unmask issues if necessary. + */ +void handle_untracked_irq(struct irq_desc *desc) +{ + unsigned int flags = 0; + + raw_spin_lock(&desc->lock); + + if (!irq_may_run(desc)) + goto out_unlock; + + desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); + + if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { + desc->istate |= IRQS_PENDING; + goto out_unlock; + } + + desc->istate &= ~IRQS_PENDING; + irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); + raw_spin_unlock(&desc->lock); + + __handle_irq_event_percpu(desc, &flags); + + raw_spin_lock(&desc->lock); + irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); + +out_unlock: + raw_spin_unlock(&desc->lock); +} +EXPORT_SYMBOL_GPL(handle_untracked_irq); + /* * Called unconditionally from handle_level_irq() and only for oneshot * interrupts from handle_fasteoi_irq() diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index a15b5485b446..d3f24905852c 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -132,10 +132,10 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action) wake_up_process(action->thread); } -irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) +irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags) { irqreturn_t retval = IRQ_NONE; - unsigned int flags = 0, irq = desc->irq_data.irq; + unsigned int irq = desc->irq_data.irq; struct irqaction *action; for_each_action_of_desc(desc, action) { @@ -164,7 +164,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) /* Fall through to add to randomness */ case IRQ_HANDLED: - flags |= action->flags; + *flags |= action->flags; break; default: @@ -174,7 +174,17 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) retval |= res; } - add_interrupt_randomness(irq, flags); + return retval; +} + +irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) +{ + irqreturn_t retval; + unsigned int flags = 0; + + retval = __handle_irq_event_percpu(desc, &flags); + + add_interrupt_randomness(desc->irq_data.irq, flags); if (!noirqdebug) note_interrupt(desc, retval); diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index d5edcdc9382a..0c6f35ba9cc0 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -84,6 +84,7 @@ extern void irq_mark_irq(unsigned int irq); extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); +irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags); irqreturn_t handle_irq_event_percpu(struct irq_desc *desc); irqreturn_t handle_irq_event(struct irq_desc *desc); -- cgit v1.2.3 From b1cadc1a0949c82ff7fcb15603e3caf2d32ff9f6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 18 Jun 2016 21:52:02 -0700 Subject: ipv6: icmp: add a force_saddr param to icmp6_send() SIT or GRE tunnels might want to translate an IPV4 address into a v4mapped one when translating ICMP to ICMPv6. This patch adds the parameter to icmp6_send() but does not change icmpv6_send() signature. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 3 ++- net/ipv6/icmp.c | 7 +++++-- net/ipv6/ip6_icmp.c | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 630f45335c73..432611a297fb 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -14,7 +14,8 @@ static inline struct icmp6hdr *icmp6_hdr(const struct sk_buff *skb) #if IS_ENABLED(CONFIG_IPV6) extern void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info); -typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info); +typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info, + const struct in6_addr *force_saddr); extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn); extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index e32a72fb9982..6c57e6e90301 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -388,7 +388,8 @@ relookup_failed: /* * Send an ICMP message in response to a packet in error */ -static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) +static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + const struct in6_addr *force_saddr) { struct net *net = dev_net(skb->dev); struct inet6_dev *idev = NULL; @@ -475,6 +476,8 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_proto = IPPROTO_ICMPV6; fl6.daddr = hdr->saddr; + if (force_saddr) + saddr = force_saddr; if (saddr) fl6.saddr = *saddr; fl6.flowi6_mark = mark; @@ -551,7 +554,7 @@ out: */ void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) { - icmp6_send(skb, ICMPV6_PARAMPROB, code, pos); + icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL); kfree_skb(skb); } diff --git a/net/ipv6/ip6_icmp.c b/net/ipv6/ip6_icmp.c index 14dacc544c3e..713676f14a0e 100644 --- a/net/ipv6/ip6_icmp.c +++ b/net/ipv6/ip6_icmp.c @@ -39,7 +39,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) if (!send) goto out; - send(skb, type, code, info); + send(skb, type, code, info, NULL); out: rcu_read_unlock(); } -- cgit v1.2.3 From 5fbba8ac9358f1e796c8aedcccc3487364643723 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 18 Jun 2016 21:52:03 -0700 Subject: ip6: move ipip6_err_gen_icmpv6_unreach() We want to use this helper from GRE as well, so this is the time to move it in net/ipv6/icmp.c Also add a @nhs parameter, since SIT and GRE have different values for the header(s) to skip. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 1 + net/ipv6/icmp.c | 39 +++++++++++++++++++++++++++++++++++++++ net/ipv6/sit.c | 38 +------------------------------------- 3 files changed, 41 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 432611a297fb..9796481edbdb 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -18,6 +18,7 @@ typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info, const struct in6_addr *force_saddr); extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn); extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn); +int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs); #else diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 6c57e6e90301..07bc63c23712 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -558,6 +558,45 @@ void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) kfree_skb(skb); } +/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH + * if sufficient data bytes are available + * @nhs is the size of the tunnel header(s) : + * Either an IPv4 header for SIT encap + * an IPv4 header + GRE header for GRE encap + */ +int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs) +{ + struct rt6_info *rt; + struct sk_buff *skb2; + + if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8)) + return 1; + + skb2 = skb_clone(skb, GFP_ATOMIC); + + if (!skb2) + return 1; + + skb_dst_drop(skb2); + skb_pull(skb2, nhs); + skb_reset_network_header(skb2); + + rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0); + + if (rt && rt->dst.dev) + skb2->dev = rt->dst.dev; + + icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); + + if (rt) + ip6_rt_put(rt); + + kfree_skb(skb2); + + return 0; +} +EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach); + static void icmpv6_echo_reply(struct sk_buff *skb) { struct net *net = dev_net(skb->dev); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d9f2bd6ef72d..78e84d6793ee 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -479,42 +479,6 @@ static void ipip6_tunnel_uninit(struct net_device *dev) dev_put(dev); } -/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH - * if sufficient data bytes are available - */ -static int ipip6_err_gen_icmpv6_unreach(struct sk_buff *skb) -{ - int ihl = ((const struct iphdr *)skb->data)->ihl*4; - struct rt6_info *rt; - struct sk_buff *skb2; - - if (!pskb_may_pull(skb, ihl + sizeof(struct ipv6hdr) + 8)) - return 1; - - skb2 = skb_clone(skb, GFP_ATOMIC); - - if (!skb2) - return 1; - - skb_dst_drop(skb2); - skb_pull(skb2, ihl); - skb_reset_network_header(skb2); - - rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0); - - if (rt && rt->dst.dev) - skb2->dev = rt->dst.dev; - - icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); - - if (rt) - ip6_rt_put(rt); - - kfree_skb(skb2); - - return 0; -} - static int ipip6_err(struct sk_buff *skb, u32 info) { const struct iphdr *iph = (const struct iphdr *)skb->data; @@ -575,7 +539,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) goto out; err = 0; - if (!ipip6_err_gen_icmpv6_unreach(skb)) + if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4)) goto out; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) -- cgit v1.2.3 From 2d7a3b276be2d032a6c1a48ced87a474327ee3d3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 18 Jun 2016 21:52:04 -0700 Subject: ipv6: translate ICMP_TIME_EXCEEDED to ICMPV6_TIME_EXCEED For better traceroute/mtr support for SIT and GRE tunnels, we translate IPV4 ICMP ICMP_TIME_EXCEEDED to ICMPV6_TIME_EXCEED We also have to translate the IPv4 source IP address of ICMP message to IPv6 v4mapped. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 2 +- net/ipv6/icmp.c | 12 +++++++++--- net/ipv6/sit.c | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 9796481edbdb..97ae98071a03 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -18,7 +18,7 @@ typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info, const struct in6_addr *force_saddr); extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn); extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn); -int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs); +int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type); #else diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 07bc63c23712..867aebc34248 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -564,8 +564,9 @@ void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) * Either an IPv4 header for SIT encap * an IPv4 header + GRE header for GRE encap */ -int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs) +int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type) { + struct in6_addr temp_saddr; struct rt6_info *rt; struct sk_buff *skb2; @@ -586,8 +587,13 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs) if (rt && rt->dst.dev) skb2->dev = rt->dst.dev; - icmpv6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); - + ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr); + if (type == ICMP_TIME_EXCEEDED) + icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, + 0, &temp_saddr); + else + icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, + 0, &temp_saddr); if (rt) ip6_rt_put(rt); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 78e84d6793ee..d7a36114eb50 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -535,11 +535,11 @@ static int ipip6_err(struct sk_buff *skb, u32 info) goto out; } - if (t->parms.iph.daddr == 0) + err = 0; + if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type)) goto out; - err = 0; - if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4)) + if (t->parms.iph.daddr == 0) goto out; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) -- cgit v1.2.3 From 20e1954fe238dbe5f8d3a979e593fe352bd703cf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 18 Jun 2016 21:52:06 -0700 Subject: ipv6: RFC 4884 partial support for SIT/GRE tunnels When receiving an ICMPv4 message containing extensions as defined in RFC 4884, and translating it to ICMPv6 at SIT or GRE tunnel, we need some extra manipulation in order to properly forward the extensions. This patch only takes care of Time Exceeded messages as they are the ones that typically carry information from various routers in a fabric during a traceroute session. It also avoids complex skb logic if the data_len is not a multiple of 8. RFC states : The "original datagram" field MUST contain at least 128 octets. If the original datagram did not contain 128 octets, the "original datagram" field MUST be zero padded to 128 octets. In practice routers use 128 bytes of original datagram, not more. Initial translation was added in commit ca15a078bd90 ("sit: generate icmpv6 error when receiving icmpv4 error") Signed-off-by: Eric Dumazet Cc: Oussama Ghorbel Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 3 ++- include/uapi/linux/icmp.h | 1 + net/ipv4/ip_gre.c | 5 ++++- net/ipv6/icmp.c | 28 ++++++++++++++++++++++++---- net/ipv6/sit.c | 4 +++- 5 files changed, 34 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 97ae98071a03..57086e9fc64c 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -18,7 +18,8 @@ typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info, const struct in6_addr *force_saddr); extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn); extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn); -int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type); +int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type, + unsigned int data_len); #else diff --git a/include/uapi/linux/icmp.h b/include/uapi/linux/icmp.h index 16fff055f734..fddd9d736284 100644 --- a/include/uapi/linux/icmp.h +++ b/include/uapi/linux/icmp.h @@ -79,6 +79,7 @@ struct icmphdr { __be16 __unused; __be16 mtu; } frag; + __u8 reserved[4]; } un; }; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index ab4cff8e563d..8eec78f53f9e 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -144,6 +144,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info, const struct iphdr *iph; const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; + unsigned int data_len = 0; struct ip_tunnel *t; switch (type) { @@ -169,6 +170,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info, case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) return; + data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ break; case ICMP_REDIRECT: @@ -189,7 +191,8 @@ static void ipgre_err(struct sk_buff *skb, u32 info, #if IS_ENABLED(CONFIG_IPV6) if (tpi->proto == htons(ETH_P_IPV6) && - !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, type)) + !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, + type, data_len)) return; #endif diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 867aebc34248..fd11f5856ce8 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -564,16 +564,22 @@ void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) * Either an IPv4 header for SIT encap * an IPv4 header + GRE header for GRE encap */ -int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type) +int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type, + unsigned int data_len) { struct in6_addr temp_saddr; struct rt6_info *rt; struct sk_buff *skb2; + u32 info = 0; if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8)) return 1; - skb2 = skb_clone(skb, GFP_ATOMIC); + /* RFC 4884 (partial) support for ICMP extensions */ + if (data_len < 128 || (data_len & 7) || skb->len < data_len) + data_len = 0; + + skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC); if (!skb2) return 1; @@ -588,12 +594,26 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type) skb2->dev = rt->dst.dev; ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr); + + if (data_len) { + /* RFC 4884 (partial) support : + * insert 0 padding at the end, before the extensions + */ + __skb_push(skb2, nhs); + skb_reset_network_header(skb2); + memmove(skb2->data, skb2->data + nhs, data_len - nhs); + memset(skb2->data + data_len - nhs, 0, nhs); + /* RFC 4884 4.5 : Length is measured in 64-bit words, + * and stored in reserved[0] + */ + info = (data_len/8) << 24; + } if (type == ICMP_TIME_EXCEEDED) icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, - 0, &temp_saddr); + info, &temp_saddr); else icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, - 0, &temp_saddr); + info, &temp_saddr); if (rt) ip6_rt_put(rt); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d7a36114eb50..cdd714690f95 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -484,6 +484,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) const struct iphdr *iph = (const struct iphdr *)skb->data; const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; + unsigned int data_len = 0; struct ip_tunnel *t; int err; @@ -508,6 +509,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) return 0; + data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ break; case ICMP_REDIRECT: break; @@ -536,7 +538,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) } err = 0; - if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type)) + if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len)) goto out; if (t->parms.iph.daddr == 0) -- cgit v1.2.3 From e008bb6134a6e68fd2c827a46b27d017d920de8f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 17 Jun 2016 22:03:16 +0200 Subject: quota: use time64_t internally The quota subsystem has two formats, the old v1 format using architecture specific time_t values on the on-disk format, while the v2 format (introduced in Linux 2.5.16 and 2.4.22) uses fixed 64-bit little-endian. While there is no future for the v1 format beyond y2038, the v2 format is almost there on 32-bit architectures, as both the user interface and the on-disk format use 64-bit timestamps, just not the time_t inbetween. This changes the internal representation to use time64_t, which will end up doing the right thing everywhere for v2 format. Signed-off-by: Arnd Bergmann Signed-off-by: Jan Kara --- fs/ocfs2/quota_global.c | 2 +- fs/quota/dquot.c | 16 ++++++++-------- include/linux/quota.h | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index ab6a6cdcf91c..87e577a49b0d 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c @@ -483,7 +483,7 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing) struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv; struct ocfs2_global_disk_dqblk dqblk; s64 spacechange, inodechange; - time_t olditime, oldbtime; + time64_t olditime, oldbtime; err = sb->s_op->quota_read(sb, type, (char *)&dqblk, sizeof(struct ocfs2_global_disk_dqblk), diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index ff21980d0119..b1322dd9d136 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -1133,7 +1133,7 @@ static void dquot_decr_inodes(struct dquot *dquot, qsize_t number) else dquot->dq_dqb.dqb_curinodes = 0; if (dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit) - dquot->dq_dqb.dqb_itime = (time_t) 0; + dquot->dq_dqb.dqb_itime = (time64_t) 0; clear_bit(DQ_INODES_B, &dquot->dq_flags); } @@ -1145,7 +1145,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number) else dquot->dq_dqb.dqb_curspace = 0; if (dquot->dq_dqb.dqb_curspace <= dquot->dq_dqb.dqb_bsoftlimit) - dquot->dq_dqb.dqb_btime = (time_t) 0; + dquot->dq_dqb.dqb_btime = (time64_t) 0; clear_bit(DQ_BLKS_B, &dquot->dq_flags); } @@ -1292,7 +1292,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, if (dquot->dq_dqb.dqb_isoftlimit && newinodes > dquot->dq_dqb.dqb_isoftlimit && dquot->dq_dqb.dqb_itime && - get_seconds() >= dquot->dq_dqb.dqb_itime && + ktime_get_real_seconds() >= dquot->dq_dqb.dqb_itime && !ignore_hardlimit(dquot)) { prepare_warning(warn, dquot, QUOTA_NL_ISOFTLONGWARN); return -EDQUOT; @@ -1302,7 +1302,7 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, newinodes > dquot->dq_dqb.dqb_isoftlimit && dquot->dq_dqb.dqb_itime == 0) { prepare_warning(warn, dquot, QUOTA_NL_ISOFTWARN); - dquot->dq_dqb.dqb_itime = get_seconds() + + dquot->dq_dqb.dqb_itime = ktime_get_real_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type].dqi_igrace; } @@ -1334,7 +1334,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, if (dquot->dq_dqb.dqb_bsoftlimit && tspace > dquot->dq_dqb.dqb_bsoftlimit && dquot->dq_dqb.dqb_btime && - get_seconds() >= dquot->dq_dqb.dqb_btime && + ktime_get_real_seconds() >= dquot->dq_dqb.dqb_btime && !ignore_hardlimit(dquot)) { if (!prealloc) prepare_warning(warn, dquot, QUOTA_NL_BSOFTLONGWARN); @@ -1346,7 +1346,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, dquot->dq_dqb.dqb_btime == 0) { if (!prealloc) { prepare_warning(warn, dquot, QUOTA_NL_BSOFTWARN); - dquot->dq_dqb.dqb_btime = get_seconds() + + dquot->dq_dqb.dqb_btime = ktime_get_real_seconds() + sb_dqopt(sb)->info[dquot->dq_id.type].dqi_bgrace; } else @@ -2695,7 +2695,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di) clear_bit(DQ_BLKS_B, &dquot->dq_flags); } else if (!(di->d_fieldmask & QC_SPC_TIMER)) /* Set grace only if user hasn't provided his own... */ - dm->dqb_btime = get_seconds() + dqi->dqi_bgrace; + dm->dqb_btime = ktime_get_real_seconds() + dqi->dqi_bgrace; } if (check_ilim) { if (!dm->dqb_isoftlimit || @@ -2704,7 +2704,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di) clear_bit(DQ_INODES_B, &dquot->dq_flags); } else if (!(di->d_fieldmask & QC_INO_TIMER)) /* Set grace only if user hasn't provided his own... */ - dm->dqb_itime = get_seconds() + dqi->dqi_igrace; + dm->dqb_itime = ktime_get_real_seconds() + dqi->dqi_igrace; } if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit) diff --git a/include/linux/quota.h b/include/linux/quota.h index 9dfb6bce8c9e..8486d27cf360 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -200,8 +200,8 @@ struct mem_dqblk { qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */ qsize_t dqb_isoftlimit; /* preferred inode limit */ qsize_t dqb_curinodes; /* current # allocated inodes */ - time_t dqb_btime; /* time limit for excessive disk use */ - time_t dqb_itime; /* time limit for excessive inode use */ + time64_t dqb_btime; /* time limit for excessive disk use */ + time64_t dqb_itime; /* time limit for excessive inode use */ }; /* -- cgit v1.2.3 From fa4191a609f219262a18dd8b02ab7dc30896b707 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Tue, 14 Jun 2016 15:36:17 +0800 Subject: leds: pca9532: Add device tree support This patch adds basic device tree support for the pca9532 LEDs. Signed-off-by: Phil Reid Signed-off-by: Jacek Anaszewski --- .../devicetree/bindings/leds/leds-pca9532.txt | 39 +++++++++++ drivers/leds/leds-pca9532.c | 75 ++++++++++++++++++++-- include/dt-bindings/leds/leds-pca9532.h | 18 ++++++ include/linux/leds-pca9532.h | 9 ++- 4 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 Documentation/devicetree/bindings/leds/leds-pca9532.txt create mode 100644 include/dt-bindings/leds/leds-pca9532.h (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/leds/leds-pca9532.txt b/Documentation/devicetree/bindings/leds/leds-pca9532.txt new file mode 100644 index 000000000000..198f3ba0e01f --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-pca9532.txt @@ -0,0 +1,39 @@ +*NXP - pca9532 PWM LED Driver + +The PCA9532 family is SMBus I/O expander optimized for dimming LEDs. +The PWM support 256 steps. + +Required properties: + - compatible: + "nxp,pca9530" + "nxp,pca9531" + "nxp,pca9532" + "nxp,pca9533" + - reg - I2C slave address + +Each led is represented as a sub-node of the nxp,pca9530. + +Optional sub-node properties: + - label: see Documentation/devicetree/bindings/leds/common.txt + - type: Output configuration, see dt-bindings/leds/leds-pca9532.h (default NONE) + - linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt + +Example: + #include + + leds: pca9530@60 { + compatible = "nxp,pca9530"; + reg = <0x60>; + + red-power { + label = "pca:red:power"; + type = ; + }; + green-power { + label = "pca:green:power"; + type = ; + }; + }; + +For more product information please see the link below: +http://nxp.com/documents/data_sheet/PCA9532.pdf diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index e3d3b1aaa9e0..09a7cffbc46f 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include /* m = num_leds*/ #define PCA9532_REG_INPUT(i) ((i) >> 3) @@ -86,9 +88,22 @@ static const struct pca9532_chip_info pca9532_chip_info_tbl[] = { }, }; +#ifdef CONFIG_OF +static const struct of_device_id of_pca9532_leds_match[] = { + { .compatible = "nxp,pca9530", .data = (void *)pca9530 }, + { .compatible = "nxp,pca9531", .data = (void *)pca9531 }, + { .compatible = "nxp,pca9532", .data = (void *)pca9532 }, + { .compatible = "nxp,pca9533", .data = (void *)pca9533 }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_pca9532_leds_match); +#endif + static struct i2c_driver pca9532_driver = { .driver = { .name = "leds-pca953x", + .of_match_table = of_match_ptr(of_pca9532_leds_match), }, .probe = pca9532_probe, .remove = pca9532_remove, @@ -354,6 +369,7 @@ static int pca9532_configure(struct i2c_client *client, led->state = pled->state; led->name = pled->name; led->ldev.name = led->name; + led->ldev.default_trigger = led->default_trigger; led->ldev.brightness = LED_OFF; led->ldev.brightness_set_blocking = pca9532_set_brightness; @@ -432,15 +448,66 @@ exit: return err; } +static struct pca9532_platform_data * +pca9532_of_populate_pdata(struct device *dev, struct device_node *np) +{ + struct pca9532_platform_data *pdata; + struct device_node *child; + const struct of_device_id *match; + int devid, maxleds; + int i = 0; + + match = of_match_device(of_pca9532_leds_match, dev); + if (!match) + return ERR_PTR(-ENODEV); + + devid = (int)(uintptr_t)match->data; + maxleds = pca9532_chip_info_tbl[devid].num_leds; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + for_each_child_of_node(np, child) { + if (of_property_read_string(child, "label", + &pdata->leds[i].name)) + pdata->leds[i].name = child->name; + of_property_read_u32(child, "type", &pdata->leds[i].type); + of_property_read_string(child, "linux,default-trigger", + &pdata->leds[i].default_trigger); + if (++i >= maxleds) { + of_node_put(child); + break; + } + } + + return pdata; +} + static int pca9532_probe(struct i2c_client *client, const struct i2c_device_id *id) { + int devid; struct pca9532_data *data = i2c_get_clientdata(client); struct pca9532_platform_data *pca9532_pdata = dev_get_platdata(&client->dev); - - if (!pca9532_pdata) - return -EIO; + struct device_node *np = client->dev.of_node; + + if (!pca9532_pdata) { + if (np) { + pca9532_pdata = + pca9532_of_populate_pdata(&client->dev, np); + if (IS_ERR(pca9532_pdata)) + return PTR_ERR(pca9532_pdata); + } else { + dev_err(&client->dev, "no platform data\n"); + return -EINVAL; + } + devid = (int)(uintptr_t)of_match_device( + of_pca9532_leds_match, &client->dev)->data; + } else { + devid = id->driver_data; + } if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -450,7 +517,7 @@ static int pca9532_probe(struct i2c_client *client, if (!data) return -ENOMEM; - data->chip_info = &pca9532_chip_info_tbl[id->driver_data]; + data->chip_info = &pca9532_chip_info_tbl[devid]; dev_info(&client->dev, "setting platform data\n"); i2c_set_clientdata(client, data); diff --git a/include/dt-bindings/leds/leds-pca9532.h b/include/dt-bindings/leds/leds-pca9532.h new file mode 100644 index 000000000000..4d917aab7e1e --- /dev/null +++ b/include/dt-bindings/leds/leds-pca9532.h @@ -0,0 +1,18 @@ +/* + * This header provides constants for pca9532 LED bindings. + * + * 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. + */ + +#ifndef _DT_BINDINGS_LEDS_PCA9532_H +#define _DT_BINDINGS_LEDS_PCA9532_H + +#define PCA9532_TYPE_NONE 0 +#define PCA9532_TYPE_LED 1 +#define PCA9532_TYPE_N2100_BEEP 2 +#define PCA9532_TYPE_GPIO 3 +#define PCA9532_LED_TIMER2 4 + +#endif /* _DT_BINDINGS_LEDS_PCA9532_H */ diff --git a/include/linux/leds-pca9532.h b/include/linux/leds-pca9532.h index b8d6fffed4d8..d215b4561180 100644 --- a/include/linux/leds-pca9532.h +++ b/include/linux/leds-pca9532.h @@ -16,6 +16,7 @@ #include #include +#include enum pca9532_state { PCA9532_OFF = 0x0, @@ -24,16 +25,14 @@ enum pca9532_state { PCA9532_PWM1 = 0x3 }; -enum pca9532_type { PCA9532_TYPE_NONE, PCA9532_TYPE_LED, - PCA9532_TYPE_N2100_BEEP, PCA9532_TYPE_GPIO }; - struct pca9532_led { u8 id; struct i2c_client *client; - char *name; + const char *name; + const char *default_trigger; struct led_classdev ldev; struct work_struct work; - enum pca9532_type type; + u32 type; enum pca9532_state state; }; -- cgit v1.2.3 From eb25cb9956cc9384b7fa0d75dec908c9fac8c444 Mon Sep 17 00:00:00 2001 From: Stephan Linz Date: Fri, 10 Jun 2016 07:59:56 +0200 Subject: leds: convert IDE trigger to common disk trigger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch converts the IDE specific LED trigger to a generic disk activity LED trigger. The libata core is now a trigger source just like before the IDE disk driver. It's merely a replacement of the string ide by disk. The patch is taken from http://dev.gentoo.org/~josejx/ata.patch and is widely used by any ibook/powerbook owners with great satisfaction. Likewise, it is very often used successfully on different ARM platforms. Unlike the original patch, the existing 'ide-disk' trigger is still available for backward compatibility. That reduce the amount of patches in affected device trees out of the mainline kernel. For further development, the new name 'disk-activity' should be used. Cc: Joseph Jezak Cc: Jörg Sommer Cc: Richard Purdie Signed-off-by: Stephan Linz Signed-off-by: Jacek Anaszewski --- drivers/ata/libata-core.c | 4 ++++ drivers/ide/ide-disk.c | 2 +- drivers/leds/leds-hp6xx.c | 2 +- drivers/leds/trigger/Kconfig | 8 +++---- drivers/leds/trigger/Makefile | 2 +- drivers/leds/trigger/ledtrig-disk.c | 41 +++++++++++++++++++++++++++++++++ drivers/leds/trigger/ledtrig-ide-disk.c | 36 ----------------------------- include/linux/leds.h | 6 ++--- 8 files changed, 55 insertions(+), 46 deletions(-) create mode 100644 drivers/leds/trigger/ledtrig-disk.c delete mode 100644 drivers/leds/trigger/ledtrig-ide-disk.c (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 6be7770f68e9..2eca572f4df6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -5072,6 +5073,9 @@ void ata_qc_complete(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + /* Trigger the LED (if available) */ + ledtrig_disk_activity(); + /* XXX: New EH and old EH use different mechanisms to * synchronize EH with regular execution path. * diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 05dbcce70b0e..5ceb176dc148 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -186,7 +186,7 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); BUG_ON(rq->cmd_type != REQ_TYPE_FS); - ledtrig_ide_activity(); + ledtrig_disk_activity(); pr_debug("%s: %sing: block=%llu, sectors=%u\n", drive->name, rq_data_dir(rq) == READ ? "read" : "writ", diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c index a6b8db0e27f1..137969fcecbb 100644 --- a/drivers/leds/leds-hp6xx.c +++ b/drivers/leds/leds-hp6xx.c @@ -50,7 +50,7 @@ static struct led_classdev hp6xx_red_led = { static struct led_classdev hp6xx_green_led = { .name = "hp6xx:green", - .default_trigger = "ide-disk", + .default_trigger = "disk-activity", .brightness_set = hp6xxled_green_set, .flags = LED_CORE_SUSPENDRESUME, }; diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index 9893d911390d..3f9ddb9fafa7 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -33,12 +33,12 @@ config LEDS_TRIGGER_ONESHOT If unsure, say Y. -config LEDS_TRIGGER_IDE_DISK - bool "LED IDE Disk Trigger" - depends on IDE_GD_ATA +config LEDS_TRIGGER_DISK + bool "LED Disk Trigger" + depends on IDE_GD_ATA || ATA depends on LEDS_TRIGGERS help - This allows LEDs to be controlled by IDE disk activity. + This allows LEDs to be controlled by disk activity. If unsure, say Y. config LEDS_TRIGGER_MTD diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile index 8cc64a4f4e25..a72c43cffebf 100644 --- a/drivers/leds/trigger/Makefile +++ b/drivers/leds/trigger/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o obj-$(CONFIG_LEDS_TRIGGER_ONESHOT) += ledtrig-oneshot.o -obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o +obj-$(CONFIG_LEDS_TRIGGER_DISK) += ledtrig-disk.o obj-$(CONFIG_LEDS_TRIGGER_MTD) += ledtrig-mtd.o obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o diff --git a/drivers/leds/trigger/ledtrig-disk.c b/drivers/leds/trigger/ledtrig-disk.c new file mode 100644 index 000000000000..cd525b4125eb --- /dev/null +++ b/drivers/leds/trigger/ledtrig-disk.c @@ -0,0 +1,41 @@ +/* + * LED Disk Activity Trigger + * + * Copyright 2006 Openedhand Ltd. + * + * Author: Richard Purdie + * + * 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 + +#define BLINK_DELAY 30 + +DEFINE_LED_TRIGGER(ledtrig_disk); +DEFINE_LED_TRIGGER(ledtrig_ide); + +void ledtrig_disk_activity(void) +{ + unsigned long blink_delay = BLINK_DELAY; + + led_trigger_blink_oneshot(ledtrig_disk, + &blink_delay, &blink_delay, 0); + led_trigger_blink_oneshot(ledtrig_ide, + &blink_delay, &blink_delay, 0); +} +EXPORT_SYMBOL(ledtrig_disk_activity); + +static int __init ledtrig_disk_init(void) +{ + led_trigger_register_simple("disk-activity", &ledtrig_disk); + led_trigger_register_simple("ide-disk", &ledtrig_ide); + + return 0; +} +device_initcall(ledtrig_disk_init); diff --git a/drivers/leds/trigger/ledtrig-ide-disk.c b/drivers/leds/trigger/ledtrig-ide-disk.c deleted file mode 100644 index 15123d389240..000000000000 --- a/drivers/leds/trigger/ledtrig-ide-disk.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * LED IDE-Disk Activity Trigger - * - * Copyright 2006 Openedhand Ltd. - * - * Author: Richard Purdie - * - * 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 - -#define BLINK_DELAY 30 - -DEFINE_LED_TRIGGER(ledtrig_ide); - -void ledtrig_ide_activity(void) -{ - unsigned long ide_blink_delay = BLINK_DELAY; - - led_trigger_blink_oneshot(ledtrig_ide, - &ide_blink_delay, &ide_blink_delay, 0); -} -EXPORT_SYMBOL(ledtrig_ide_activity); - -static int __init ledtrig_ide_init(void) -{ - led_trigger_register_simple("ide-disk", &ledtrig_ide); - return 0; -} -device_initcall(ledtrig_ide_init); diff --git a/include/linux/leds.h b/include/linux/leds.h index e5e7f2e80a54..0aa3701f2bf4 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -325,10 +325,10 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) #endif /* CONFIG_LEDS_TRIGGERS */ /* Trigger specific functions */ -#ifdef CONFIG_LEDS_TRIGGER_IDE_DISK -extern void ledtrig_ide_activity(void); +#ifdef CONFIG_LEDS_TRIGGER_DISK +extern void ledtrig_disk_activity(void); #else -static inline void ledtrig_ide_activity(void) {} +static inline void ledtrig_disk_activity(void) {} #endif #ifdef CONFIG_LEDS_TRIGGER_MTD -- cgit v1.2.3 From af4afb40085f04f8b2ea8d28df878f7f0be02f89 Mon Sep 17 00:00:00 2001 From: Pratyush Patel Date: Tue, 14 Jun 2016 11:00:42 +0200 Subject: alarmtimer: Fix comments describing structure fields Updated struct alarm and struct alarm_timer descriptions. Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Pratyush Patel Signed-off-by: John Stultz --- include/linux/alarmtimer.h | 6 +++--- kernel/time/alarmtimer.c | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h index 52f3b7da4f2d..9d8031257a90 100644 --- a/include/linux/alarmtimer.h +++ b/include/linux/alarmtimer.h @@ -26,10 +26,10 @@ enum alarmtimer_restart { * struct alarm - Alarm timer structure * @node: timerqueue node for adding to the event list this value * also includes the expiration time. - * @period: Period for recuring alarms + * @timer: hrtimer used to schedule events while running * @function: Function pointer to be executed when the timer fires. - * @type: Alarm type (BOOTTIME/REALTIME) - * @enabled: Flag that represents if the alarm is set to fire or not + * @type: Alarm type (BOOTTIME/REALTIME). + * @state: Flag that represents if the alarm is set to fire or not. * @data: Internal data value. */ struct alarm { diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index e840ed867a5d..c3aad685bbc0 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -30,7 +30,6 @@ * struct alarm_base - Alarm timer bases * @lock: Lock for syncrhonized access to the base * @timerqueue: Timerqueue head managing the list of events - * @timer: hrtimer used to schedule events while running * @gettime: Function to read the time correlating to the base * @base_clockid: clockid for the base */ -- cgit v1.2.3 From e6c2682a1da36a2e79d9bab470412374434ce89e Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Wed, 8 Jun 2016 22:04:59 -0700 Subject: time: Add time64_to_tm() time_to_tm() takes time_t as an argument. time_t is not y2038 safe. Add time64_to_tm() that takes time64_t as an argument which is y2038 safe. The plan is to eventually replace all calls to time_to_tm() by time64_to_tm(). Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Signed-off-by: Deepa Dinamani Signed-off-by: John Stultz --- include/linux/time.h | 15 ++++++++++++++- kernel/time/timeconv.c | 11 ++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/time.h b/include/linux/time.h index 297f09f23896..4cea09d94208 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -205,7 +205,20 @@ struct tm { int tm_yday; }; -void time_to_tm(time_t totalsecs, int offset, struct tm *result); +void time64_to_tm(time64_t totalsecs, int offset, struct tm *result); + +/** + * time_to_tm - converts the calendar time to local broken-down time + * + * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, + * Coordinated Universal Time (UTC). + * @offset offset seconds adding to totalsecs. + * @result pointer to struct tm variable to receive broken-down time + */ +static inline void time_to_tm(time_t totalsecs, int offset, struct tm *result) +{ + time64_to_tm(totalsecs, offset, result); +} /** * timespec_to_ns - Convert timespec to nanoseconds diff --git a/kernel/time/timeconv.c b/kernel/time/timeconv.c index 86628e755f38..7142580ad94f 100644 --- a/kernel/time/timeconv.c +++ b/kernel/time/timeconv.c @@ -67,20 +67,21 @@ static const unsigned short __mon_yday[2][13] = { #define SECS_PER_DAY (SECS_PER_HOUR * 24) /** - * time_to_tm - converts the calendar time to local broken-down time + * time64_to_tm - converts the calendar time to local broken-down time * * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, * Coordinated Universal Time (UTC). * @offset offset seconds adding to totalsecs. * @result pointer to struct tm variable to receive broken-down time */ -void time_to_tm(time_t totalsecs, int offset, struct tm *result) +void time64_to_tm(time64_t totalsecs, int offset, struct tm *result) { long days, rem, y; + int remainder; const unsigned short *ip; - days = totalsecs / SECS_PER_DAY; - rem = totalsecs % SECS_PER_DAY; + days = div_s64_rem(totalsecs, SECS_PER_DAY, &remainder); + rem = remainder; rem += offset; while (rem < 0) { rem += SECS_PER_DAY; @@ -124,4 +125,4 @@ void time_to_tm(time_t totalsecs, int offset, struct tm *result) result->tm_mon = y; result->tm_mday = days + 1; } -EXPORT_SYMBOL(time_to_tm); +EXPORT_SYMBOL(time64_to_tm); -- cgit v1.2.3 From 4f920843d248946545415c1bf6120942048708ed Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jun 2016 14:58:54 +0900 Subject: kconfig.h: use __is_defined() to check if MODULE is defined The macro MODULE is not a config option, it is a per-file build option. So, config_enabled(MODULE) is not sensible. (There is another case in include/linux/export.h, where config_enabled() is used against a non-config option.) This commit renames some macros in include/linux/kconfig.h for the use for non-config macros and replaces config_enabled(MODULE) with __is_defined(MODULE). I am keeping config_enabled() because it is still referenced from some places, but I expect it would be deprecated in the future. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- include/linux/kconfig.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index b33c7797eb57..a94b5bf57f51 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -17,10 +17,11 @@ * the last step cherry picks the 2nd arg, we get a zero. */ #define __ARG_PLACEHOLDER_1 0, -#define config_enabled(cfg) _config_enabled(cfg) -#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value) -#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0) -#define ___config_enabled(__ignored, val, ...) val +#define config_enabled(cfg) ___is_defined(cfg) +#define __is_defined(x) ___is_defined(x) +#define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) +#define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0) +#define __take_second_arg(__ignored, val, ...) val /* * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0 @@ -42,7 +43,7 @@ * built-in code when CONFIG_FOO is set to 'm'. */ #define IS_REACHABLE(option) (config_enabled(option) || \ - (config_enabled(option##_MODULE) && config_enabled(MODULE))) + (config_enabled(option##_MODULE) && __is_defined(MODULE))) /* * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm', -- cgit v1.2.3 From 6023d2369ba7b82b0588fd6fcdd558a6fef200ae Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jun 2016 14:58:55 +0900 Subject: export.h: use __is_defined() to check if __KSYM_* is defined Here the need is for a macro that checks whether the given symbol is defined or not, which has nothing to do with config. The new macro __is_defined() is a better fit for this case. Signed-off-by: Masahiro Yamada Acked-by: Nicolas Pitre Signed-off-by: Michal Marek --- include/linux/export.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/export.h b/include/linux/export.h index 2f9ccbe6a639..c565f87f005e 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -82,7 +82,7 @@ extern struct module __this_module; #include #define __EXPORT_SYMBOL(sym, sec) \ - __cond_export_sym(sym, sec, config_enabled(__KSYM_##sym)) + __cond_export_sym(sym, sec, __is_defined(__KSYM_##sym)) #define __cond_export_sym(sym, sec, conf) \ ___cond_export_sym(sym, sec, conf) #define ___cond_export_sym(sym, sec, enabled) \ -- cgit v1.2.3 From 05a25c8e2c593914c18faf91dfb5ee471b79ce58 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jun 2016 14:58:56 +0900 Subject: kconfig.h: use already defined macros for IS_REACHABLE() define For the same reason as commit 02d699f1f464 ("include/linux/kconfig.h: ese macros which are already defined"), it is better to use macros IS_BUILTIN() and IS_MODULE() for defining IS_REACHABLE(). Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- include/linux/kconfig.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index a94b5bf57f51..722c7d2c48d6 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -42,8 +42,8 @@ * This is similar to IS_ENABLED(), but returns false when invoked from * built-in code when CONFIG_FOO is set to 'm'. */ -#define IS_REACHABLE(option) (config_enabled(option) || \ - (config_enabled(option##_MODULE) && __is_defined(MODULE))) +#define IS_REACHABLE(option) (IS_BUILTIN(option) || \ + (IS_MODULE(option) && __is_defined(MODULE))) /* * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm', -- cgit v1.2.3 From 5e8754fd80b0a594f720f44d32bf28c7b06ba5a6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jun 2016 14:58:57 +0900 Subject: kconfig.h: allow to use IS_{ENABLE,REACHABLE} in macro expansion The typical usage of IS_ENABLED() is if (IS_ENABLED(CONFIG_FOO)) { ... } or #if IS_ENABLED(CONFIG_FOO) ... #endif The current implementation of IS_ENABLED() includes "||" operator, which works well in those expressions like above. However, there is a case where we want to evaluate a config option beyond those use cases. For example, the OF_TABLE() in include/asm-generic/vmlinux.lds.h needs to evaluate a config option in macro expansion: #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) #define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name) #define OF_TABLE(cfg, name) __OF_TABLE(config_enabled(cfg), name) #define _OF_TABLE_0(name) #define _OF_TABLE_1(name) \ ... Here, we can not use IS_ENABLED() because of the "||" operator in its define. It is true config_enabled() works well, but it is a bit ambiguous to be used against config options. This commit makes IS_ENABLED() available in more generic context by calculating "or" with macro expansion only. Do likewise for IS_REACHABLE(). Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- include/linux/kconfig.h | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index 722c7d2c48d6..15ec117ec537 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -3,6 +3,21 @@ #include +#define __ARG_PLACEHOLDER_1 0, +#define __take_second_arg(__ignored, val, ...) val + +/* + * The use of "&&" / "||" is limited in certain expressions. + * The followings enable to calculate "and" / "or" with macro expansion only. + */ +#define __and(x, y) ___and(x, y) +#define ___and(x, y) ____and(__ARG_PLACEHOLDER_##x, y) +#define ____and(arg1_or_junk, y) __take_second_arg(arg1_or_junk y, 0) + +#define __or(x, y) ___or(x, y) +#define ___or(x, y) ____or(__ARG_PLACEHOLDER_##x, y) +#define ____or(arg1_or_junk, y) __take_second_arg(arg1_or_junk 1, y) + /* * Helper macros to use CONFIG_ options in C/CPP expressions. Note that * these only work with boolean and tristate options. @@ -16,12 +31,10 @@ * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when * the last step cherry picks the 2nd arg, we get a zero. */ -#define __ARG_PLACEHOLDER_1 0, #define config_enabled(cfg) ___is_defined(cfg) #define __is_defined(x) ___is_defined(x) #define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) #define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0) -#define __take_second_arg(__ignored, val, ...) val /* * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0 @@ -42,14 +55,13 @@ * This is similar to IS_ENABLED(), but returns false when invoked from * built-in code when CONFIG_FOO is set to 'm'. */ -#define IS_REACHABLE(option) (IS_BUILTIN(option) || \ - (IS_MODULE(option) && __is_defined(MODULE))) +#define IS_REACHABLE(option) __or(IS_BUILTIN(option), \ + __and(IS_MODULE(option), __is_defined(MODULE))) /* * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm', * 0 otherwise. */ -#define IS_ENABLED(option) \ - (IS_BUILTIN(option) || IS_MODULE(option)) +#define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option)) #endif /* __LINUX_KCONFIG_H */ -- cgit v1.2.3 From 199a31c6d93ba9dc6f831fa1e77d9926f34f4e8a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2016 09:22:39 +1000 Subject: fs: move struct iomap from exportfs.h to a separate header Signed-off-by: Christoph Hellwig Reviewed-by: Bob Peterson Signed-off-by: Dave Chinner --- fs/nfsd/blocklayout.c | 1 + fs/nfsd/blocklayoutxdr.c | 1 + fs/xfs/xfs_pnfs.c | 1 + include/linux/exportfs.h | 16 +--------------- include/linux/iomap.h | 21 +++++++++++++++++++++ 5 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 include/linux/iomap.h (limited to 'include/linux') diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index e55b5242614d..4df16ae1633a 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -2,6 +2,7 @@ * Copyright (c) 2014-2016 Christoph Hellwig. */ #include +#include #include #include #include diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c index 6c3b316f932e..4ebaaf4b8d8a 100644 --- a/fs/nfsd/blocklayoutxdr.c +++ b/fs/nfsd/blocklayoutxdr.c @@ -3,6 +3,7 @@ */ #include #include +#include #include #include "nfsd.h" diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index d5b756669fb5..db3c7df52e30 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2014 Christoph Hellwig. */ +#include #include "xfs.h" #include "xfs_format.h" #include "xfs_log_format.h" diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index d8414502edb4..b03c0625fa6e 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h @@ -6,6 +6,7 @@ struct dentry; struct iattr; struct inode; +struct iomap; struct super_block; struct vfsmount; @@ -187,21 +188,6 @@ struct fid { * get_name is not (which is possibly inconsistent) */ -/* types of block ranges for multipage write mappings. */ -#define IOMAP_HOLE 0x01 /* no blocks allocated, need allocation */ -#define IOMAP_DELALLOC 0x02 /* delayed allocation blocks */ -#define IOMAP_MAPPED 0x03 /* blocks allocated @blkno */ -#define IOMAP_UNWRITTEN 0x04 /* blocks allocated @blkno in unwritten state */ - -#define IOMAP_NULL_BLOCK -1LL /* blkno is not valid */ - -struct iomap { - sector_t blkno; /* first sector of mapping */ - loff_t offset; /* file offset of mapping, bytes */ - u64 length; /* length of mapping, bytes */ - int type; /* type of mapping */ -}; - struct export_operations { int (*encode_fh)(struct inode *inode, __u32 *fh, int *max_len, struct inode *parent); diff --git a/include/linux/iomap.h b/include/linux/iomap.h new file mode 100644 index 000000000000..1b22197bcf01 --- /dev/null +++ b/include/linux/iomap.h @@ -0,0 +1,21 @@ +#ifndef LINUX_IOMAP_H +#define LINUX_IOMAP_H 1 + +#include + +/* types of block ranges for multipage write mappings. */ +#define IOMAP_HOLE 0x01 /* no blocks allocated, need allocation */ +#define IOMAP_DELALLOC 0x02 /* delayed allocation blocks */ +#define IOMAP_MAPPED 0x03 /* blocks allocated @blkno */ +#define IOMAP_UNWRITTEN 0x04 /* blocks allocated @blkno in unwritten state */ + +#define IOMAP_NULL_BLOCK -1LL /* blkno is not valid */ + +struct iomap { + sector_t blkno; /* first sector of mapping */ + loff_t offset; /* file offset of mapping, bytes */ + u64 length; /* length of mapping, bytes */ + int type; /* type of mapping */ +}; + +#endif /* LINUX_IOMAP_H */ -- cgit v1.2.3 From ae259a9c8593f98aa60d045df978a5482a67c53f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2016 09:23:11 +1000 Subject: fs: introduce iomap infrastructure Add infrastructure for multipage buffered writes. This is implemented using an main iterator that applies an actor function to a range that can be written. This infrastucture is used to implement a buffered write helper, one to zero file ranges and one to implement the ->page_mkwrite VM operations. All of them borrow a fair amount of code from fs/buffers. for now by using an internal version of __block_write_begin that gets passed an iomap and builds the corresponding buffer head. The file system is gets a set of paired ->iomap_begin and ->iomap_end calls which allow it to map/reserve a range and get a notification once the write code is finished with it. Based on earlier code from Dave Chinner. Signed-off-by: Christoph Hellwig Reviewed-by: Bob Peterson Signed-off-by: Dave Chinner --- fs/Kconfig | 3 + fs/Makefile | 1 + fs/buffer.c | 76 +++++++++- fs/internal.h | 3 + fs/iomap.c | 394 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/iomap.h | 56 ++++++- 6 files changed, 523 insertions(+), 10 deletions(-) create mode 100644 fs/iomap.c (limited to 'include/linux') diff --git a/fs/Kconfig b/fs/Kconfig index b8fcb416be72..4524916fa200 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -10,6 +10,9 @@ config DCACHE_WORD_ACCESS if BLOCK +config FS_IOMAP + bool + source "fs/ext2/Kconfig" source "fs/ext4/Kconfig" source "fs/jbd2/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index 85b6e13b62d3..ed2b63257ba9 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_COREDUMP) += coredump.o obj-$(CONFIG_SYSCTL) += drop_caches.o obj-$(CONFIG_FHANDLE) += fhandle.o +obj-$(CONFIG_FS_IOMAP) += iomap.o obj-y += quota/ diff --git a/fs/buffer.c b/fs/buffer.c index 754813a6962b..228288a7de38 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1891,8 +1892,62 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to) } EXPORT_SYMBOL(page_zero_new_buffers); -int __block_write_begin(struct page *page, loff_t pos, unsigned len, - get_block_t *get_block) +static void +iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh, + struct iomap *iomap) +{ + loff_t offset = block << inode->i_blkbits; + + bh->b_bdev = iomap->bdev; + + /* + * Block points to offset in file we need to map, iomap contains + * the offset at which the map starts. If the map ends before the + * current block, then do not map the buffer and let the caller + * handle it. + */ + BUG_ON(offset >= iomap->offset + iomap->length); + + switch (iomap->type) { + case IOMAP_HOLE: + /* + * If the buffer is not up to date or beyond the current EOF, + * we need to mark it as new to ensure sub-block zeroing is + * executed if necessary. + */ + if (!buffer_uptodate(bh) || + (offset >= i_size_read(inode))) + set_buffer_new(bh); + break; + case IOMAP_DELALLOC: + if (!buffer_uptodate(bh) || + (offset >= i_size_read(inode))) + set_buffer_new(bh); + set_buffer_uptodate(bh); + set_buffer_mapped(bh); + set_buffer_delay(bh); + break; + case IOMAP_UNWRITTEN: + /* + * For unwritten regions, we always need to ensure that + * sub-block writes cause the regions in the block we are not + * writing to are zeroed. Set the buffer as new to ensure this. + */ + set_buffer_new(bh); + set_buffer_unwritten(bh); + /* FALLTHRU */ + case IOMAP_MAPPED: + if (offset >= i_size_read(inode)) + set_buffer_new(bh); + bh->b_blocknr = (iomap->blkno >> (inode->i_blkbits - 9)) + + ((offset - iomap->offset) >> inode->i_blkbits); + set_buffer_mapped(bh); + break; + } +} + +int __block_write_begin_int(struct page *page, loff_t pos, unsigned len, + get_block_t *get_block, struct iomap *iomap) { unsigned from = pos & (PAGE_SIZE - 1); unsigned to = from + len; @@ -1928,9 +1983,14 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len, clear_buffer_new(bh); if (!buffer_mapped(bh)) { WARN_ON(bh->b_size != blocksize); - err = get_block(inode, block, bh, 1); - if (err) - break; + if (get_block) { + err = get_block(inode, block, bh, 1); + if (err) + break; + } else { + iomap_to_bh(inode, block, bh, iomap); + } + if (buffer_new(bh)) { unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); @@ -1971,6 +2031,12 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len, page_zero_new_buffers(page, from, to); return err; } + +int __block_write_begin(struct page *page, loff_t pos, unsigned len, + get_block_t *get_block) +{ + return __block_write_begin_int(page, pos, len, get_block, NULL); +} EXPORT_SYMBOL(__block_write_begin); static int __block_commit_write(struct inode *inode, struct page *page, diff --git a/fs/internal.h b/fs/internal.h index b71deeecea17..c0c6f493ab8a 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -11,6 +11,7 @@ struct super_block; struct file_system_type; +struct iomap; struct linux_binprm; struct path; struct mount; @@ -39,6 +40,8 @@ static inline int __sync_blockdev(struct block_device *bdev, int wait) * buffer.c */ extern void guard_bio_eod(int rw, struct bio *bio); +extern int __block_write_begin_int(struct page *page, loff_t pos, unsigned len, + get_block_t *get_block, struct iomap *iomap); /* * char_dev.c diff --git a/fs/iomap.c b/fs/iomap.c new file mode 100644 index 000000000000..8e2fc17c266f --- /dev/null +++ b/fs/iomap.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * Copyright (c) 2016 Christoph Hellwig. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +typedef loff_t (*iomap_actor_t)(struct inode *inode, loff_t pos, loff_t len, + void *data, struct iomap *iomap); + +/* + * Execute a iomap write on a segment of the mapping that spans a + * contiguous range of pages that have identical block mapping state. + * + * This avoids the need to map pages individually, do individual allocations + * for each page and most importantly avoid the need for filesystem specific + * locking per page. Instead, all the operations are amortised over the entire + * range of pages. It is assumed that the filesystems will lock whatever + * resources they require in the iomap_begin call, and release them in the + * iomap_end call. + */ +static loff_t +iomap_apply(struct inode *inode, loff_t pos, loff_t length, unsigned flags, + struct iomap_ops *ops, void *data, iomap_actor_t actor) +{ + struct iomap iomap = { 0 }; + loff_t written = 0, ret; + + /* + * Need to map a range from start position for length bytes. This can + * span multiple pages - it is only guaranteed to return a range of a + * single type of pages (e.g. all into a hole, all mapped or all + * unwritten). Failure at this point has nothing to undo. + * + * If allocation is required for this range, reserve the space now so + * that the allocation is guaranteed to succeed later on. Once we copy + * the data into the page cache pages, then we cannot fail otherwise we + * expose transient stale data. If the reserve fails, we can safely + * back out at this point as there is nothing to undo. + */ + ret = ops->iomap_begin(inode, pos, length, flags, &iomap); + if (ret) + return ret; + if (WARN_ON(iomap.offset > pos)) + return -EIO; + + /* + * Cut down the length to the one actually provided by the filesystem, + * as it might not be able to give us the whole size that we requested. + */ + if (iomap.offset + iomap.length < pos + length) + length = iomap.offset + iomap.length - pos; + + /* + * Now that we have guaranteed that the space allocation will succeed. + * we can do the copy-in page by page without having to worry about + * failures exposing transient data. + */ + written = actor(inode, pos, length, data, &iomap); + + /* + * Now the data has been copied, commit the range we've copied. This + * should not fail unless the filesystem has had a fatal error. + */ + ret = ops->iomap_end(inode, pos, length, written > 0 ? written : 0, + flags, &iomap); + + return written ? written : ret; +} + +static void +iomap_write_failed(struct inode *inode, loff_t pos, unsigned len) +{ + loff_t i_size = i_size_read(inode); + + /* + * Only truncate newly allocated pages beyoned EOF, even if the + * write started inside the existing inode size. + */ + if (pos + len > i_size) + truncate_pagecache_range(inode, max(pos, i_size), pos + len); +} + +static int +iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags, + struct page **pagep, struct iomap *iomap) +{ + pgoff_t index = pos >> PAGE_SHIFT; + struct page *page; + int status = 0; + + BUG_ON(pos + len > iomap->offset + iomap->length); + + page = grab_cache_page_write_begin(inode->i_mapping, index, flags); + if (!page) + return -ENOMEM; + + status = __block_write_begin_int(page, pos, len, NULL, iomap); + if (unlikely(status)) { + unlock_page(page); + put_page(page); + page = NULL; + + iomap_write_failed(inode, pos, len); + } + + *pagep = page; + return status; +} + +static int +iomap_write_end(struct inode *inode, loff_t pos, unsigned len, + unsigned copied, struct page *page) +{ + int ret; + + ret = generic_write_end(NULL, inode->i_mapping, pos, len, + copied, page, NULL); + if (ret < len) + iomap_write_failed(inode, pos, len); + return ret; +} + +static loff_t +iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data, + struct iomap *iomap) +{ + struct iov_iter *i = data; + long status = 0; + ssize_t written = 0; + unsigned int flags = AOP_FLAG_NOFS; + + /* + * Copies from kernel address space cannot fail (NFSD is a big user). + */ + if (!iter_is_iovec(i)) + flags |= AOP_FLAG_UNINTERRUPTIBLE; + + do { + struct page *page; + unsigned long offset; /* Offset into pagecache page */ + unsigned long bytes; /* Bytes to write to page */ + size_t copied; /* Bytes copied from user */ + + offset = (pos & (PAGE_SIZE - 1)); + bytes = min_t(unsigned long, PAGE_SIZE - offset, + iov_iter_count(i)); +again: + if (bytes > length) + bytes = length; + + /* + * Bring in the user page that we will copy from _first_. + * Otherwise there's a nasty deadlock on copying from the + * same page as we're writing to, without it being marked + * up-to-date. + * + * Not only is this an optimisation, but it is also required + * to check that the address is actually valid, when atomic + * usercopies are used, below. + */ + if (unlikely(iov_iter_fault_in_readable(i, bytes))) { + status = -EFAULT; + break; + } + + status = iomap_write_begin(inode, pos, bytes, flags, &page, + iomap); + if (unlikely(status)) + break; + + if (mapping_writably_mapped(inode->i_mapping)) + flush_dcache_page(page); + + pagefault_disable(); + copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes); + pagefault_enable(); + + flush_dcache_page(page); + mark_page_accessed(page); + + status = iomap_write_end(inode, pos, bytes, copied, page); + if (unlikely(status < 0)) + break; + copied = status; + + cond_resched(); + + iov_iter_advance(i, copied); + if (unlikely(copied == 0)) { + /* + * If we were unable to copy any data at all, we must + * fall back to a single segment length write. + * + * If we didn't fallback here, we could livelock + * because not all segments in the iov can be copied at + * once without a pagefault. + */ + bytes = min_t(unsigned long, PAGE_SIZE - offset, + iov_iter_single_seg_count(i)); + goto again; + } + pos += copied; + written += copied; + length -= copied; + + balance_dirty_pages_ratelimited(inode->i_mapping); + } while (iov_iter_count(i) && length); + + return written ? written : status; +} + +ssize_t +iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter, + struct iomap_ops *ops) +{ + struct inode *inode = iocb->ki_filp->f_mapping->host; + loff_t pos = iocb->ki_pos, ret = 0, written = 0; + + while (iov_iter_count(iter)) { + ret = iomap_apply(inode, pos, iov_iter_count(iter), + IOMAP_WRITE, ops, iter, iomap_write_actor); + if (ret <= 0) + break; + pos += ret; + written += ret; + } + + return written ? written : ret; +} +EXPORT_SYMBOL_GPL(iomap_file_buffered_write); + +static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset, + unsigned bytes, struct iomap *iomap) +{ + struct page *page; + int status; + + status = iomap_write_begin(inode, pos, bytes, + AOP_FLAG_UNINTERRUPTIBLE | AOP_FLAG_NOFS, &page, iomap); + if (status) + return status; + + zero_user(page, offset, bytes); + mark_page_accessed(page); + + return iomap_write_end(inode, pos, bytes, bytes, page); +} + +static loff_t +iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count, + void *data, struct iomap *iomap) +{ + bool *did_zero = data; + loff_t written = 0; + int status; + + /* already zeroed? we're done. */ + if (iomap->type == IOMAP_HOLE || iomap->type == IOMAP_UNWRITTEN) + return count; + + do { + unsigned offset, bytes; + + offset = pos & (PAGE_SIZE - 1); /* Within page */ + bytes = min_t(unsigned, PAGE_SIZE - offset, count); + + status = iomap_zero(inode, pos, offset, bytes, iomap); + if (status < 0) + return status; + + pos += bytes; + count -= bytes; + written += bytes; + if (did_zero) + *did_zero = true; + } while (count > 0); + + return written; +} + +int +iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero, + struct iomap_ops *ops) +{ + loff_t ret; + + while (len > 0) { + ret = iomap_apply(inode, pos, len, IOMAP_ZERO, + ops, did_zero, iomap_zero_range_actor); + if (ret <= 0) + return ret; + + pos += ret; + len -= ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(iomap_zero_range); + +int +iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, + struct iomap_ops *ops) +{ + unsigned blocksize = (1 << inode->i_blkbits); + unsigned off = pos & (blocksize - 1); + + /* Block boundary? Nothing to do */ + if (!off) + return 0; + return iomap_zero_range(inode, pos, blocksize - off, did_zero, ops); +} +EXPORT_SYMBOL_GPL(iomap_truncate_page); + +static loff_t +iomap_page_mkwrite_actor(struct inode *inode, loff_t pos, loff_t length, + void *data, struct iomap *iomap) +{ + struct page *page = data; + int ret; + + ret = __block_write_begin_int(page, pos & ~PAGE_MASK, length, + NULL, iomap); + if (ret) + return ret; + + block_commit_write(page, 0, length); + return length; +} + +int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, + struct iomap_ops *ops) +{ + struct page *page = vmf->page; + struct inode *inode = file_inode(vma->vm_file); + unsigned long length; + loff_t offset, size; + ssize_t ret; + + lock_page(page); + size = i_size_read(inode); + if ((page->mapping != inode->i_mapping) || + (page_offset(page) > size)) { + /* We overload EFAULT to mean page got truncated */ + ret = -EFAULT; + goto out_unlock; + } + + /* page is wholly or partially inside EOF */ + if (((page->index + 1) << PAGE_SHIFT) > size) + length = size & ~PAGE_MASK; + else + length = PAGE_SIZE; + + offset = page_offset(page); + while (length > 0) { + ret = iomap_apply(inode, offset, length, IOMAP_WRITE, + ops, page, iomap_page_mkwrite_actor); + if (unlikely(ret <= 0)) + goto out_unlock; + offset += ret; + length -= ret; + } + + set_page_dirty(page); + wait_for_stable_page(page); + return 0; +out_unlock: + unlock_page(page); + return ret; +} +EXPORT_SYMBOL_GPL(iomap_page_mkwrite); diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 1b22197bcf01..d2f469ae899a 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -3,19 +3,65 @@ #include -/* types of block ranges for multipage write mappings. */ +struct inode; +struct iov_iter; +struct kiocb; +struct vm_area_struct; +struct vm_fault; + +/* + * Types of block ranges for iomap mappings: + */ #define IOMAP_HOLE 0x01 /* no blocks allocated, need allocation */ #define IOMAP_DELALLOC 0x02 /* delayed allocation blocks */ #define IOMAP_MAPPED 0x03 /* blocks allocated @blkno */ #define IOMAP_UNWRITTEN 0x04 /* blocks allocated @blkno in unwritten state */ +/* + * Magic value for blkno: + */ #define IOMAP_NULL_BLOCK -1LL /* blkno is not valid */ struct iomap { - sector_t blkno; /* first sector of mapping */ - loff_t offset; /* file offset of mapping, bytes */ - u64 length; /* length of mapping, bytes */ - int type; /* type of mapping */ + sector_t blkno; /* 1st sector of mapping, 512b units */ + loff_t offset; /* file offset of mapping, bytes */ + u64 length; /* length of mapping, bytes */ + int type; /* type of mapping */ + struct block_device *bdev; /* block device for I/O */ +}; + +/* + * Flags for iomap_begin / iomap_end. No flag implies a read. + */ +#define IOMAP_WRITE (1 << 0) +#define IOMAP_ZERO (1 << 1) + +struct iomap_ops { + /* + * Return the existing mapping at pos, or reserve space starting at + * pos for up to length, as long as we can do it as a single mapping. + * The actual length is returned in iomap->length. + */ + int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length, + unsigned flags, struct iomap *iomap); + + /* + * Commit and/or unreserve space previous allocated using iomap_begin. + * Written indicates the length of the successful write operation which + * needs to be commited, while the rest needs to be unreserved. + * Written might be zero if no data was written. + */ + int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length, + ssize_t written, unsigned flags, struct iomap *iomap); }; +ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from, + struct iomap_ops *ops); +int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, + bool *did_zero, struct iomap_ops *ops); +int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, + struct iomap_ops *ops); +int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, + struct iomap_ops *ops); + #endif /* LINUX_IOMAP_H */ -- cgit v1.2.3 From 8be9f564d25e7adc582f9f3689040ce5aa6f1f5b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Jun 2016 09:38:45 +1000 Subject: fs: iomap based fiemap implementation Add a simple fiemap implementation based on iomap_ops, partially based on a previous implementation from Bob Peterson . Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/iomap.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/iomap.h | 3 ++ 2 files changed, 93 insertions(+) (limited to 'include/linux') diff --git a/fs/iomap.c b/fs/iomap.c index 477817c00bac..48141b8eff5f 100644 --- a/fs/iomap.c +++ b/fs/iomap.c @@ -405,3 +405,93 @@ out_unlock: return ret; } EXPORT_SYMBOL_GPL(iomap_page_mkwrite); + +struct fiemap_ctx { + struct fiemap_extent_info *fi; + struct iomap prev; +}; + +static int iomap_to_fiemap(struct fiemap_extent_info *fi, + struct iomap *iomap, u32 flags) +{ + switch (iomap->type) { + case IOMAP_HOLE: + /* skip holes */ + return 0; + case IOMAP_DELALLOC: + flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; + break; + case IOMAP_UNWRITTEN: + flags |= FIEMAP_EXTENT_UNWRITTEN; + break; + case IOMAP_MAPPED: + break; + } + + return fiemap_fill_next_extent(fi, iomap->offset, + iomap->blkno != IOMAP_NULL_BLOCK ? iomap->blkno << 9: 0, + iomap->length, flags | FIEMAP_EXTENT_MERGED); + +} + +static loff_t +iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, + struct iomap *iomap) +{ + struct fiemap_ctx *ctx = data; + loff_t ret = length; + + if (iomap->type == IOMAP_HOLE) + return length; + + ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0); + ctx->prev = *iomap; + switch (ret) { + case 0: /* success */ + return length; + case 1: /* extent array full */ + return 0; + default: + return ret; + } +} + +int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, + loff_t start, loff_t len, struct iomap_ops *ops) +{ + struct fiemap_ctx ctx; + loff_t ret; + + memset(&ctx, 0, sizeof(ctx)); + ctx.fi = fi; + ctx.prev.type = IOMAP_HOLE; + + ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC); + if (ret) + return ret; + + ret = filemap_write_and_wait(inode->i_mapping); + if (ret) + return ret; + + while (len > 0) { + ret = iomap_apply(inode, start, len, 0, ops, &ctx, + iomap_fiemap_actor); + if (ret < 0) + return ret; + if (ret == 0) + break; + + start += ret; + len -= ret; + } + + if (ctx.prev.type != IOMAP_HOLE) { + ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST); + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(iomap_fiemap); diff --git a/include/linux/iomap.h b/include/linux/iomap.h index d2f469ae899a..3267df461012 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -3,6 +3,7 @@ #include +struct fiemap_extent_info; struct inode; struct iov_iter; struct kiocb; @@ -63,5 +64,7 @@ int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, struct iomap_ops *ops); int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, struct iomap_ops *ops); +int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + loff_t start, loff_t len, struct iomap_ops *ops); #endif /* LINUX_IOMAP_H */ -- cgit v1.2.3 From d366d28cd1325f11d582ec6d4a14b8329d3e1a20 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Fri, 20 May 2016 16:41:25 +1000 Subject: PCI: Add pcibios_setup_bridge() Currently, PowerPC PowerNV platform utilizes ppc_md.pcibios_fixup(), which is called for once after PCI probing and resource assignment are completed, to allocate platform required resources for PCI devices: PE#, IO and MMIO mapping, DMA address translation (TCE) table etc. Obviously, it's not hotplug friendly. This adds weak function pcibios_setup_bridge(), which is called by pci_setup_bridge(). PowerPC PowerNV platform will reuse the function to assign above platform required resources to newly plugged PCI devices during PCI hotplug in subsequent patches. Signed-off-by: Gavin Shan Acked-by: Bjorn Helgaas Signed-off-by: Michael Ellerman --- drivers/pci/setup-bus.c | 5 +++++ include/linux/pci.h | 1 + 2 files changed, 6 insertions(+) (limited to 'include/linux') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 55641a39a3e9..d678c46e5f03 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -695,11 +695,16 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } +void __weak pcibios_setup_bridge(struct pci_bus *bus, unsigned long type) +{ +} + void pci_setup_bridge(struct pci_bus *bus) { unsigned long type = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; + pcibios_setup_bridge(bus, type); __pci_setup_bridge(bus, type); } diff --git a/include/linux/pci.h b/include/linux/pci.h index b67e4df20801..c40ac910cce4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -854,6 +854,7 @@ void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev); void pci_stop_root_bus(struct pci_bus *bus); void pci_remove_root_bus(struct pci_bus *bus); void pci_setup_cardbus(struct pci_bus *bus); +void pcibios_setup_bridge(struct pci_bus *bus, unsigned long type); void pci_sort_breadthfirst(void); #define dev_is_pci(d) ((d)->bus == &pci_bus_type) #define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false)) -- cgit v1.2.3 From 5a8d651a2bde01e00caf78496390d6ae46df80af Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 31 May 2016 13:07:47 +0300 Subject: usb: gadget: move gadget API functions to udc-core instead of defining all functions as static inlines, let's move them to udc-core and export them with EXPORT_SYMBOL_GPL, that way we can make sure that only GPL drivers will use them. As a side effect, it'll be nicer to add tracepoints to the gadget API. While at that, also fix Kconfig dependencies to avoid randconfig build failures. Acked-By: Sebastian Reichel Acked-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/phy/Kconfig | 1 + drivers/power/Kconfig | 1 + drivers/usb/gadget/udc/udc-core.c | 573 +++++++++++++++++++++++++++++++++++++ drivers/usb/host/Kconfig | 2 +- drivers/usb/phy/Kconfig | 11 +- include/linux/usb/gadget.h | 585 ++++---------------------------------- 6 files changed, 645 insertions(+), 528 deletions(-) (limited to 'include/linux') diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index b869b98835f4..8d1cfb7f3ea2 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -176,6 +176,7 @@ config TWL4030_USB tristate "TWL4030 USB Transceiver Driver" depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS depends on USB_SUPPORT + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't 'y' select GENERIC_PHY select USB_PHY help diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 421770ddafa3..0f11a0f4c369 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -309,6 +309,7 @@ config BATTERY_RX51 config CHARGER_ISP1704 tristate "ISP1704 USB Charger Detection" depends on USB_PHY + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' help Say Y to enable support for USB Charger Detection with ISP1707/ISP1704 USB transceivers. diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index e1b2dcebdc2e..abf013865e51 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -59,6 +59,579 @@ static int udc_bind_to_driver(struct usb_udc *udc, /* ------------------------------------------------------------------------- */ +/** + * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint + * @ep:the endpoint being configured + * @maxpacket_limit:value of maximum packet size limit + * + * This function should be used only in UDC drivers to initialize endpoint + * (usually in probe function). + */ +void usb_ep_set_maxpacket_limit(struct usb_ep *ep, + unsigned maxpacket_limit) +{ + ep->maxpacket_limit = maxpacket_limit; + ep->maxpacket = maxpacket_limit; +} +EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * + * When configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB master".) + * + * returns zero, or a negative error code. + */ +int usb_ep_enable(struct usb_ep *ep) +{ + int ret; + + if (ep->enabled) + return 0; + + ret = ep->ops->enable(ep, ep->desc); + if (ret) + return ret; + + ep->enabled = true; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_ep_enable); + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * returns zero, or a negative error code. + */ +int usb_ep_disable(struct usb_ep *ep) +{ + int ret; + + if (!ep->enabled) + return 0; + + ret = ep->ops->disable(ep); + if (ret) + return ret; + + ep->enabled = false; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_ep_disable); + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) +{ + return ep->ops->alloc_request(ep, gfp_flags); +} +EXPORT_SYMBOL_GPL(usb_ep_alloc_request); + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +void usb_ep_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + ep->ops->free_request(ep, req); +} +EXPORT_SYMBOL_GPL(usb_ep_free_request); + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (even if it would be zero length). That enables the + * status ack, after transferring data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger protocol stalls. Depending on the controller, + * it may not be possible to trigger a status-stage protocol stall when the + * data stage is over, that is, from within the response's completion + * routine. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be + * reported when the usb peripheral is disconnected. + */ +int usb_ep_queue(struct usb_ep *ep, + struct usb_request *req, gfp_t gfp_flags) +{ + if (WARN_ON_ONCE(!ep->enabled && ep->address)) + return -ESHUTDOWN; + + return ep->ops->queue(ep, req, gfp_flags); +} +EXPORT_SYMBOL_GPL(usb_ep_queue); + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * If the request is still active on the endpoint, it is dequeued and its + * completion routine is called (with status -ECONNRESET); else a negative + * error code is returned. This is guaranteed to happen before the call to + * usb_ep_dequeue() returns. + * + * Note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. Such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + */ +int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + return ep->ops->dequeue(ep, req); +} +EXPORT_SYMBOL_GPL(usb_ep_dequeue); + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +int usb_ep_set_halt(struct usb_ep *ep) +{ + return ep->ops->set_halt(ep, 1); +} +EXPORT_SYMBOL_GPL(usb_ep_set_halt); + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * Use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * Returns zero, or a negative error code. On success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +int usb_ep_clear_halt(struct usb_ep *ep) +{ + return ep->ops->set_halt(ep, 0); +} +EXPORT_SYMBOL_GPL(usb_ep_clear_halt); + +/** + * usb_ep_set_wedge - sets the halt feature and ignores clear requests + * @ep: the endpoint being wedged + * + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) + * requests. If the gadget driver clears the halt status, it will + * automatically unwedge the endpoint. + * + * Returns zero on success, else negative errno. + */ +int usb_ep_set_wedge(struct usb_ep *ep) +{ + if (ep->ops->set_wedge) + return ep->ops->set_wedge(ep); + else + return ep->ops->set_halt(ep, 1); +} +EXPORT_SYMBOL_GPL(usb_ep_set_wedge); + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver (and reported by a request + * completion). The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +int usb_ep_fifo_status(struct usb_ep *ep) +{ + if (ep->ops->fifo_status) + return ep->ops->fifo_status(ep); + else + return -EOPNOTSUPP; +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_status); + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + */ +void usb_ep_fifo_flush(struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush(ep); +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_flush); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +int usb_gadget_frame_number(struct usb_gadget *gadget) +{ + return gadget->ops->get_frame(gadget); +} +EXPORT_SYMBOL_GPL(usb_gadget_frame_number); + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. + */ +int usb_gadget_wakeup(struct usb_gadget *gadget) +{ + if (!gadget->ops->wakeup) + return -EOPNOTSUPP; + return gadget->ops->wakeup(gadget); +} +EXPORT_SYMBOL_GPL(usb_gadget_wakeup); + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_set_selfpowered(struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered(gadget, 1); +} +EXPORT_SYMBOL_GPL(usb_gadget_set_selfpowered); + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered(gadget, 0); +} +EXPORT_SYMBOL_GPL(usb_gadget_clear_selfpowered); + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session(gadget, 1); +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_connect); + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + if (!gadget->ops->vbus_draw) + return -EOPNOTSUPP; + return gadget->ops->vbus_draw(gadget, mA); +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_draw); + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session(gadget, 0); +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_connect(struct usb_gadget *gadget) +{ + int ret; + + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will be connected automatically after activation. + */ + gadget->connected = true; + return 0; + } + + ret = gadget->ops->pullup(gadget, 1); + if (!ret) + gadget->connected = 1; + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_connect); + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_disconnect(struct usb_gadget *gadget) +{ + int ret; + + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will stay disconnected after activation. + */ + gadget->connected = false; + return 0; + } + + ret = gadget->ops->pullup(gadget, 0); + if (!ret) + gadget->connected = 0; + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_disconnect); + +/** + * usb_gadget_deactivate - deactivate function which is not ready to work + * @gadget: the peripheral being deactivated + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_activate() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_deactivate(struct usb_gadget *gadget) +{ + int ret; + + if (gadget->deactivated) + return 0; + + if (gadget->connected) { + ret = usb_gadget_disconnect(gadget); + if (ret) + return ret; + /* + * If gadget was being connected before deactivation, we want + * to reconnect it in usb_gadget_activate(). + */ + gadget->connected = true; + } + gadget->deactivated = true; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_deactivate); + +/** + * usb_gadget_activate - activate function which is not ready to work + * @gadget: the peripheral being activated + * + * This routine activates gadget which was previously deactivated with + * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_activate(struct usb_gadget *gadget) +{ + if (!gadget->deactivated) + return 0; + + gadget->deactivated = false; + + /* + * If gadget has been connected before deactivation, or became connected + * while it was being deactivated, we call usb_gadget_connect(). + */ + if (gadget->connected) + return usb_gadget_connect(gadget); + + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_activate); + +/* ------------------------------------------------------------------------- */ + #ifdef CONFIG_HAS_DMA int usb_gadget_map_request_by_dev(struct device *dev, diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index d8f5674809e8..2e710a4cca52 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -180,7 +180,7 @@ config USB_EHCI_MXC config USB_EHCI_HCD_OMAP tristate "EHCI support for OMAP3 and later chips" depends on ARCH_OMAP - select NOP_USB_XCEIV + depends on NOP_USB_XCEIV default y ---help--- Enables support for the on-chip EHCI controller on diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index c6904742e2aa..b9c409a18faa 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -21,6 +21,7 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help Enable this to support Freescale USB OTG transceiver. @@ -29,6 +30,7 @@ config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" depends on I2C && ARCH_OMAP_OTG depends on USB + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help If you say yes here you get support for the Philips ISP1301 @@ -43,7 +45,7 @@ config ISP1301_OMAP config KEYSTONE_USB_PHY tristate "Keystone USB PHY Driver" depends on ARCH_KEYSTONE || COMPILE_TEST - select NOP_USB_XCEIV + depends on NOP_USB_XCEIV help Enable this to support Keystone USB phy. This driver provides interface to interact with USB 2.0 and USB 3.0 PHY that is part @@ -51,6 +53,7 @@ config KEYSTONE_USB_PHY config NOP_USB_XCEIV tristate "NOP USB Transceiver Driver" + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, NOP can't be built-in select USB_PHY help This driver is to be used by all the usb transceiver which are either @@ -63,9 +66,9 @@ config AM335X_CONTROL_USB config AM335X_PHY_USB tristate "AM335x USB PHY Driver" depends on ARM || COMPILE_TEST + depends on NOP_USB_XCEIV select USB_PHY select AM335X_CONTROL_USB - select NOP_USB_XCEIV select USB_COMMON help This driver provides PHY support for that phy which part for the @@ -92,6 +95,7 @@ config TWL6030_USB config USB_GPIO_VBUS tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" depends on GPIOLIB || COMPILE_TEST + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help Provides simple GPIO VBUS sensing for controllers with an @@ -112,6 +116,7 @@ config OMAP_OTG config TAHVO_USB tristate "Tahvo USB transceiver driver" depends on MFD_RETU && EXTCON + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help Enable this to support USB transceiver on Tahvo. This is used @@ -140,6 +145,7 @@ config USB_ISP1301 config USB_MSM_OTG tristate "Qualcomm on-chip USB OTG controller support" depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST) + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' depends on RESET_CONTROLLER depends on EXTCON select USB_PHY @@ -169,6 +175,7 @@ config USB_QCOM_8X16_PHY config USB_MV_OTG tristate "Marvell USB OTG support" depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY help Say Y here if you want to build Marvell USB OTG transciever diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index fefe8b06a63d..c6e1149ddb0d 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -228,307 +228,49 @@ struct usb_ep { /*-------------------------------------------------------------------------*/ -/** - * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint - * @ep:the endpoint being configured - * @maxpacket_limit:value of maximum packet size limit - * - * This function should be used only in UDC drivers to initialize endpoint - * (usually in probe function). - */ +#if IS_ENABLED(CONFIG_USB_GADGET) +void usb_ep_set_maxpacket_limit(struct usb_ep *ep, unsigned maxpacket_limit); +int usb_ep_enable(struct usb_ep *ep); +int usb_ep_disable(struct usb_ep *ep); +struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags); +void usb_ep_free_request(struct usb_ep *ep, struct usb_request *req); +int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags); +int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req); +int usb_ep_set_halt(struct usb_ep *ep); +int usb_ep_clear_halt(struct usb_ep *ep); +int usb_ep_set_wedge(struct usb_ep *ep); +int usb_ep_fifo_status(struct usb_ep *ep); +void usb_ep_fifo_flush(struct usb_ep *ep); +#else static inline void usb_ep_set_maxpacket_limit(struct usb_ep *ep, - unsigned maxpacket_limit) -{ - ep->maxpacket_limit = maxpacket_limit; - ep->maxpacket = maxpacket_limit; -} - -/** - * usb_ep_enable - configure endpoint, making it usable - * @ep:the endpoint being configured. may not be the endpoint named "ep0". - * drivers discover endpoints through the ep_list of a usb_gadget. - * - * When configurations are set, or when interface settings change, the driver - * will enable or disable the relevant endpoints. while it is enabled, an - * endpoint may be used for i/o until the driver receives a disconnect() from - * the host or until the endpoint is disabled. - * - * the ep0 implementation (which calls this routine) must ensure that the - * hardware capabilities of each endpoint match the descriptor provided - * for it. for example, an endpoint named "ep2in-bulk" would be usable - * for interrupt transfers as well as bulk, but it likely couldn't be used - * for iso transfers or for endpoint 14. some endpoints are fully - * configurable, with more generic names like "ep-a". (remember that for - * USB, "in" means "towards the USB master".) - * - * returns zero, or a negative error code. - */ + unsigned maxpacket_limit) +{ } static inline int usb_ep_enable(struct usb_ep *ep) -{ - int ret; - - if (ep->enabled) - return 0; - - ret = ep->ops->enable(ep, ep->desc); - if (ret) - return ret; - - ep->enabled = true; - - return 0; -} - -/** - * usb_ep_disable - endpoint is no longer usable - * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". - * - * no other task may be using this endpoint when this is called. - * any pending and uncompleted requests will complete with status - * indicating disconnect (-ESHUTDOWN) before this call returns. - * gadget drivers must call usb_ep_enable() again before queueing - * requests to the endpoint. - * - * returns zero, or a negative error code. - */ +{ return 0; } static inline int usb_ep_disable(struct usb_ep *ep) -{ - int ret; - - if (!ep->enabled) - return 0; - - ret = ep->ops->disable(ep); - if (ret) - return ret; - - ep->enabled = false; - - return 0; -} - -/** - * usb_ep_alloc_request - allocate a request object to use with this endpoint - * @ep:the endpoint to be used with with the request - * @gfp_flags:GFP_* flags to use - * - * Request objects must be allocated with this call, since they normally - * need controller-specific setup and may even need endpoint-specific - * resources such as allocation of DMA descriptors. - * Requests may be submitted with usb_ep_queue(), and receive a single - * completion callback. Free requests with usb_ep_free_request(), when - * they are no longer needed. - * - * Returns the request, or null if one could not be allocated. - */ +{ return 0; } static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags) -{ - return ep->ops->alloc_request(ep, gfp_flags); -} - -/** - * usb_ep_free_request - frees a request object - * @ep:the endpoint associated with the request - * @req:the request being freed - * - * Reverses the effect of usb_ep_alloc_request(). - * Caller guarantees the request is not queued, and that it will - * no longer be requeued (or otherwise used). - */ + gfp_t gfp_flags) +{ return NULL; } static inline void usb_ep_free_request(struct usb_ep *ep, - struct usb_request *req) -{ - ep->ops->free_request(ep, req); -} - -/** - * usb_ep_queue - queues (submits) an I/O request to an endpoint. - * @ep:the endpoint associated with the request - * @req:the request being submitted - * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't - * pre-allocate all necessary memory with the request. - * - * This tells the device controller to perform the specified request through - * that endpoint (reading or writing a buffer). When the request completes, - * including being canceled by usb_ep_dequeue(), the request's completion - * routine is called to return the request to the driver. Any endpoint - * (except control endpoints like ep0) may have more than one transfer - * request queued; they complete in FIFO order. Once a gadget driver - * submits a request, that request may not be examined or modified until it - * is given back to that driver through the completion callback. - * - * Each request is turned into one or more packets. The controller driver - * never merges adjacent requests into the same packet. OUT transfers - * will sometimes use data that's already buffered in the hardware. - * Drivers can rely on the fact that the first byte of the request's buffer - * always corresponds to the first byte of some USB packet, for both - * IN and OUT transfers. - * - * Bulk endpoints can queue any amount of data; the transfer is packetized - * automatically. The last packet will be short if the request doesn't fill it - * out completely. Zero length packets (ZLPs) should be avoided in portable - * protocols since not all usb hardware can successfully handle zero length - * packets. (ZLPs may be explicitly written, and may be implicitly written if - * the request 'zero' flag is set.) Bulk endpoints may also be used - * for interrupt transfers; but the reverse is not true, and some endpoints - * won't support every interrupt transfer. (Such as 768 byte packets.) - * - * Interrupt-only endpoints are less functional than bulk endpoints, for - * example by not supporting queueing or not handling buffers that are - * larger than the endpoint's maxpacket size. They may also treat data - * toggle differently. - * - * Control endpoints ... after getting a setup() callback, the driver queues - * one response (even if it would be zero length). That enables the - * status ack, after transferring data as specified in the response. Setup - * functions may return negative error codes to generate protocol stalls. - * (Note that some USB device controllers disallow protocol stall responses - * in some cases.) When control responses are deferred (the response is - * written after the setup callback returns), then usb_ep_set_halt() may be - * used on ep0 to trigger protocol stalls. Depending on the controller, - * it may not be possible to trigger a status-stage protocol stall when the - * data stage is over, that is, from within the response's completion - * routine. - * - * For periodic endpoints, like interrupt or isochronous ones, the usb host - * arranges to poll once per interval, and the gadget driver usually will - * have queued some data to transfer at that time. - * - * Returns zero, or a negative error code. Endpoints that are not enabled - * report errors; errors will also be - * reported when the usb peripheral is disconnected. - */ -static inline int usb_ep_queue(struct usb_ep *ep, - struct usb_request *req, gfp_t gfp_flags) -{ - if (WARN_ON_ONCE(!ep->enabled && ep->address)) - return -ESHUTDOWN; - - return ep->ops->queue(ep, req, gfp_flags); -} - -/** - * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint - * @ep:the endpoint associated with the request - * @req:the request being canceled - * - * If the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. This is guaranteed to happen before the call to - * usb_ep_dequeue() returns. - * - * Note that some hardware can't clear out write fifos (to unlink the request - * at the head of the queue) except as part of disconnecting from usb. Such - * restrictions prevent drivers from supporting configuration changes, - * even to configuration zero (a "chapter 9" requirement). - */ + struct usb_request *req) +{ } +static inline int usb_ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags) +{ return 0; } static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - return ep->ops->dequeue(ep, req); -} - -/** - * usb_ep_set_halt - sets the endpoint halt feature. - * @ep: the non-isochronous endpoint being stalled - * - * Use this to stall an endpoint, perhaps as an error report. - * Except for control endpoints, - * the endpoint stays halted (will not stream any data) until the host - * clears this feature; drivers may need to empty the endpoint's request - * queue first, to make sure no inappropriate transfers happen. - * - * Note that while an endpoint CLEAR_FEATURE will be invisible to the - * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the - * current altsetting, see usb_ep_clear_halt(). When switching altsettings, - * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. - * - * Returns zero, or a negative error code. On success, this call sets - * underlying hardware state that blocks data transfers. - * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any - * transfer requests are still queued, or if the controller hardware - * (usually a FIFO) still holds bytes that the host hasn't collected. - */ +{ return 0; } static inline int usb_ep_set_halt(struct usb_ep *ep) -{ - return ep->ops->set_halt(ep, 1); -} - -/** - * usb_ep_clear_halt - clears endpoint halt, and resets toggle - * @ep:the bulk or interrupt endpoint being reset - * - * Use this when responding to the standard usb "set interface" request, - * for endpoints that aren't reconfigured, after clearing any other state - * in the endpoint's i/o queue. - * - * Returns zero, or a negative error code. On success, this call clears - * the underlying hardware state reflecting endpoint halt and data toggle. - * Note that some hardware can't support this request (like pxa2xx_udc), - * and accordingly can't correctly implement interface altsettings. - */ +{ return 0; } static inline int usb_ep_clear_halt(struct usb_ep *ep) -{ - return ep->ops->set_halt(ep, 0); -} - -/** - * usb_ep_set_wedge - sets the halt feature and ignores clear requests - * @ep: the endpoint being wedged - * - * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) - * requests. If the gadget driver clears the halt status, it will - * automatically unwedge the endpoint. - * - * Returns zero on success, else negative errno. - */ -static inline int -usb_ep_set_wedge(struct usb_ep *ep) -{ - if (ep->ops->set_wedge) - return ep->ops->set_wedge(ep); - else - return ep->ops->set_halt(ep, 1); -} - -/** - * usb_ep_fifo_status - returns number of bytes in fifo, or error - * @ep: the endpoint whose fifo status is being checked. - * - * FIFO endpoints may have "unclaimed data" in them in certain cases, - * such as after aborted transfers. Hosts may not have collected all - * the IN data written by the gadget driver (and reported by a request - * completion). The gadget driver may not have collected all the data - * written OUT to it by the host. Drivers that need precise handling for - * fault reporting or recovery may need to use this call. - * - * This returns the number of such bytes in the fifo, or a negative - * errno if the endpoint doesn't use a FIFO or doesn't support such - * precise handling. - */ +{ return 0; } +static inline int usb_ep_set_wedge(struct usb_ep *ep) +{ return 0; } static inline int usb_ep_fifo_status(struct usb_ep *ep) -{ - if (ep->ops->fifo_status) - return ep->ops->fifo_status(ep); - else - return -EOPNOTSUPP; -} - -/** - * usb_ep_fifo_flush - flushes contents of a fifo - * @ep: the endpoint whose fifo is being flushed. - * - * This call may be used to flush the "unclaimed data" that may exist in - * an endpoint fifo after abnormal transaction terminations. The call - * must never be used except when endpoint is not being used for any - * protocol translation. - */ +{ return 0; } static inline void usb_ep_fifo_flush(struct usb_ep *ep) -{ - if (ep->ops->fifo_flush) - ep->ops->fifo_flush(ep); -} - +{ } +#endif /* USB_GADGET */ /*-------------------------------------------------------------------------*/ @@ -760,251 +502,44 @@ static inline int gadget_is_otg(struct usb_gadget *g) #endif } -/** - * usb_gadget_frame_number - returns the current frame number - * @gadget: controller that reports the frame number - * - * Returns the usb frame number, normally eleven bits from a SOF packet, - * or negative errno if this device doesn't support this capability. - */ -static inline int usb_gadget_frame_number(struct usb_gadget *gadget) -{ - return gadget->ops->get_frame(gadget); -} +/*-------------------------------------------------------------------------*/ -/** - * usb_gadget_wakeup - tries to wake up the host connected to this gadget - * @gadget: controller used to wake up the host - * - * Returns zero on success, else negative error code if the hardware - * doesn't support such attempts, or its support has not been enabled - * by the usb host. Drivers must return device descriptors that report - * their ability to support this, or hosts won't enable it. - * - * This may also try to use SRP to wake the host and start enumeration, - * even if OTG isn't otherwise in use. OTG devices may also start - * remote wakeup even when hosts don't explicitly enable it. - */ +#if IS_ENABLED(CONFIG_USB_GADGET) +int usb_gadget_frame_number(struct usb_gadget *gadget); +int usb_gadget_wakeup(struct usb_gadget *gadget); +int usb_gadget_set_selfpowered(struct usb_gadget *gadget); +int usb_gadget_clear_selfpowered(struct usb_gadget *gadget); +int usb_gadget_vbus_connect(struct usb_gadget *gadget); +int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA); +int usb_gadget_vbus_disconnect(struct usb_gadget *gadget); +int usb_gadget_connect(struct usb_gadget *gadget); +int usb_gadget_disconnect(struct usb_gadget *gadget); +int usb_gadget_deactivate(struct usb_gadget *gadget); +int usb_gadget_activate(struct usb_gadget *gadget); +#else +static inline int usb_gadget_frame_number(struct usb_gadget *gadget) +{ return 0; } static inline int usb_gadget_wakeup(struct usb_gadget *gadget) -{ - if (!gadget->ops->wakeup) - return -EOPNOTSUPP; - return gadget->ops->wakeup(gadget); -} - -/** - * usb_gadget_set_selfpowered - sets the device selfpowered feature. - * @gadget:the device being declared as self-powered - * - * this affects the device status reported by the hardware driver - * to reflect that it now has a local power supply. - * - * returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered(gadget, 1); -} - -/** - * usb_gadget_clear_selfpowered - clear the device selfpowered feature. - * @gadget:the device being declared as bus-powered - * - * this affects the device status reported by the hardware driver. - * some hardware may not support bus-powered operation, in which - * case this feature's value can never change. - * - * returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered(gadget, 0); -} - -/** - * usb_gadget_vbus_connect - Notify controller that VBUS is powered - * @gadget:The device which now has VBUS power. - * Context: can sleep - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session starting. Common responses include - * resuming the controller, activating the D+ (or D-) pullup to let the - * host detect that a USB device is attached, and starting to draw power - * (8mA or possibly more, especially after SET_CONFIGURATION). - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session(gadget, 1); -} - -/** - * usb_gadget_vbus_draw - constrain controller's VBUS power usage - * @gadget:The device whose VBUS usage is being described - * @mA:How much current to draw, in milliAmperes. This should be twice - * the value listed in the configuration descriptor bMaxPower field. - * - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - if (!gadget->ops->vbus_draw) - return -EOPNOTSUPP; - return gadget->ops->vbus_draw(gadget, mA); -} - -/** - * usb_gadget_vbus_disconnect - notify controller about VBUS session end - * @gadget:the device whose VBUS supply is being described - * Context: can sleep - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session ending. Common responses include - * reversing everything done in usb_gadget_vbus_connect(). - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session(gadget, 0); -} - -/** - * usb_gadget_connect - software-controlled connect to USB host - * @gadget:the peripheral being connected - * - * Enables the D+ (or potentially D-) pullup. The host will start - * enumerating this gadget when the pullup is active and a VBUS session - * is active (the link is powered). This pullup is always enabled unless - * usb_gadget_disconnect() has been used to disable it. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_connect(struct usb_gadget *gadget) -{ - int ret; - - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - - if (gadget->deactivated) { - /* - * If gadget is deactivated we only save new state. - * Gadget will be connected automatically after activation. - */ - gadget->connected = true; - return 0; - } - - ret = gadget->ops->pullup(gadget, 1); - if (!ret) - gadget->connected = 1; - return ret; -} - -/** - * usb_gadget_disconnect - software-controlled disconnect from USB host - * @gadget:the peripheral being disconnected - * - * Disables the D+ (or potentially D-) pullup, which the host may see - * as a disconnect (when a VBUS session is active). Not all systems - * support software pullup controls. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_disconnect(struct usb_gadget *gadget) -{ - int ret; - - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - - if (gadget->deactivated) { - /* - * If gadget is deactivated we only save new state. - * Gadget will stay disconnected after activation. - */ - gadget->connected = false; - return 0; - } - - ret = gadget->ops->pullup(gadget, 0); - if (!ret) - gadget->connected = 0; - return ret; -} - -/** - * usb_gadget_deactivate - deactivate function which is not ready to work - * @gadget: the peripheral being deactivated - * - * This routine may be used during the gadget driver bind() call to prevent - * the peripheral from ever being visible to the USB host, unless later - * usb_gadget_activate() is called. For example, user mode components may - * need to be activated before the system can talk to hosts. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_deactivate(struct usb_gadget *gadget) -{ - int ret; - - if (gadget->deactivated) - return 0; - - if (gadget->connected) { - ret = usb_gadget_disconnect(gadget); - if (ret) - return ret; - /* - * If gadget was being connected before deactivation, we want - * to reconnect it in usb_gadget_activate(). - */ - gadget->connected = true; - } - gadget->deactivated = true; - - return 0; -} - -/** - * usb_gadget_activate - activate function which is not ready to work - * @gadget: the peripheral being activated - * - * This routine activates gadget which was previously deactivated with - * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. - * - * Returns zero on success, else negative errno. - */ +{ return 0; } static inline int usb_gadget_activate(struct usb_gadget *gadget) -{ - if (!gadget->deactivated) - return 0; - - gadget->deactivated = false; - - /* - * If gadget has been connected before deactivation, or became connected - * while it was being deactivated, we call usb_gadget_connect(). - */ - if (gadget->connected) - return usb_gadget_connect(gadget); - - return 0; -} +{ return 0; } +#endif /* CONFIG_USB_GADGET */ /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 5e42d710a108c23c104e083900d4ba9398e418b0 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 31 May 2016 13:39:21 +0300 Subject: usb: gadget: add tracepoints to the gadget API This new set of tracepoints will help all gadget drivers and UDC drivers when problem appears. Note that, in order to be able to add tracepoints to udc-core.c we had to rename that to core.c and statically link it with trace.c to form udc-core.o. This is to make sure that module name stays the same. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/Makefile | 5 + drivers/usb/gadget/udc/core.c | 1523 +++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/udc/trace.c | 18 + drivers/usb/gadget/udc/trace.h | 298 ++++++++ drivers/usb/gadget/udc/udc-core.c | 1373 --------------------------------- include/linux/usb/gadget.h | 4 + 6 files changed, 1848 insertions(+), 1373 deletions(-) create mode 100644 drivers/usb/gadget/udc/core.c create mode 100644 drivers/usb/gadget/udc/trace.c create mode 100644 drivers/usb/gadget/udc/trace.h delete mode 100644 drivers/usb/gadget/udc/udc-core.c (limited to 'include/linux') diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index dfee53446319..98e74ed9f555 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -1,3 +1,8 @@ +# define_trace.h needs to know how to find our header +CFLAGS_trace.o := -I$(src) + +udc-core-y := core.o trace.o + # # USB peripheral controller drivers # diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c new file mode 100644 index 000000000000..ff8685ea7219 --- /dev/null +++ b/drivers/usb/gadget/udc/core.c @@ -0,0 +1,1523 @@ +/** + * udc.c - Core UDC Framework + * + * Copyright (C) 2010 Texas Instruments + * Author: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "trace.h" + +/** + * struct usb_udc - describes one usb device controller + * @driver - the gadget driver pointer. For use by the class code + * @dev - the child device to the actual controller + * @gadget - the gadget. For use by the class code + * @list - for use by the udc class driver + * @vbus - for udcs who care about vbus status, this value is real vbus status; + * for udcs who do not care about vbus status, this value is always true + * + * This represents the internal data structure which is used by the UDC-class + * to hold information about udc driver and gadget together. + */ +struct usb_udc { + struct usb_gadget_driver *driver; + struct usb_gadget *gadget; + struct device dev; + struct list_head list; + bool vbus; +}; + +static struct class *udc_class; +static LIST_HEAD(udc_list); +static LIST_HEAD(gadget_driver_pending_list); +static DEFINE_MUTEX(udc_lock); + +static int udc_bind_to_driver(struct usb_udc *udc, + struct usb_gadget_driver *driver); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint + * @ep:the endpoint being configured + * @maxpacket_limit:value of maximum packet size limit + * + * This function should be used only in UDC drivers to initialize endpoint + * (usually in probe function). + */ +void usb_ep_set_maxpacket_limit(struct usb_ep *ep, + unsigned maxpacket_limit) +{ + ep->maxpacket_limit = maxpacket_limit; + ep->maxpacket = maxpacket_limit; + + trace_usb_ep_set_maxpacket_limit(ep, 0); +} +EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * + * When configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB master".) + * + * returns zero, or a negative error code. + */ +int usb_ep_enable(struct usb_ep *ep) +{ + int ret = 0; + + if (ep->enabled) + goto out; + + ret = ep->ops->enable(ep, ep->desc); + if (ret) { + ret = ret; + goto out; + } + + ep->enabled = true; + +out: + trace_usb_ep_enable(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_enable); + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * returns zero, or a negative error code. + */ +int usb_ep_disable(struct usb_ep *ep) +{ + int ret = 0; + + if (!ep->enabled) + goto out; + + ret = ep->ops->disable(ep); + if (ret) { + ret = ret; + goto out; + } + + ep->enabled = false; + +out: + trace_usb_ep_disable(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_disable); + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) +{ + struct usb_request *req = NULL; + + req = ep->ops->alloc_request(ep, gfp_flags); + + trace_usb_ep_alloc_request(ep, req, req ? 0 : -ENOMEM); + + return req; +} +EXPORT_SYMBOL_GPL(usb_ep_alloc_request); + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +void usb_ep_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + ep->ops->free_request(ep, req); + trace_usb_ep_free_request(ep, req, 0); +} +EXPORT_SYMBOL_GPL(usb_ep_free_request); + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (even if it would be zero length). That enables the + * status ack, after transferring data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger protocol stalls. Depending on the controller, + * it may not be possible to trigger a status-stage protocol stall when the + * data stage is over, that is, from within the response's completion + * routine. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Returns zero, or a negative error code. Endpoints that are not enabled + * report errors; errors will also be + * reported when the usb peripheral is disconnected. + */ +int usb_ep_queue(struct usb_ep *ep, + struct usb_request *req, gfp_t gfp_flags) +{ + int ret = 0; + + if (WARN_ON_ONCE(!ep->enabled && ep->address)) { + ret = -ESHUTDOWN; + goto out; + } + + ret = ep->ops->queue(ep, req, gfp_flags); + +out: + trace_usb_ep_queue(ep, req, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_queue); + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * If the request is still active on the endpoint, it is dequeued and its + * completion routine is called (with status -ECONNRESET); else a negative + * error code is returned. This is guaranteed to happen before the call to + * usb_ep_dequeue() returns. + * + * Note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. Such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + */ +int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + int ret; + + ret = ep->ops->dequeue(ep, req); + trace_usb_ep_dequeue(ep, req, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_dequeue); + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +int usb_ep_set_halt(struct usb_ep *ep) +{ + int ret; + + ret = ep->ops->set_halt(ep, 1); + trace_usb_ep_set_halt(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_set_halt); + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * Use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * Returns zero, or a negative error code. On success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +int usb_ep_clear_halt(struct usb_ep *ep) +{ + int ret; + + ret = ep->ops->set_halt(ep, 0); + trace_usb_ep_clear_halt(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_clear_halt); + +/** + * usb_ep_set_wedge - sets the halt feature and ignores clear requests + * @ep: the endpoint being wedged + * + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) + * requests. If the gadget driver clears the halt status, it will + * automatically unwedge the endpoint. + * + * Returns zero on success, else negative errno. + */ +int usb_ep_set_wedge(struct usb_ep *ep) +{ + int ret; + + if (ep->ops->set_wedge) + ret = ep->ops->set_wedge(ep); + else + ret = ep->ops->set_halt(ep, 1); + + trace_usb_ep_set_wedge(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_set_wedge); + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver (and reported by a request + * completion). The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +int usb_ep_fifo_status(struct usb_ep *ep) +{ + int ret; + + if (ep->ops->fifo_status) + ret = ep->ops->fifo_status(ep); + else + ret = -EOPNOTSUPP; + + trace_usb_ep_fifo_status(ep, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_status); + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + */ +void usb_ep_fifo_flush(struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush(ep); + + trace_usb_ep_fifo_flush(ep, 0); +} +EXPORT_SYMBOL_GPL(usb_ep_fifo_flush); + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +int usb_gadget_frame_number(struct usb_gadget *gadget) +{ + int ret; + + ret = gadget->ops->get_frame(gadget); + + trace_usb_gadget_frame_number(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_frame_number); + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly enable it. + */ +int usb_gadget_wakeup(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->wakeup) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->wakeup(gadget); + +out: + trace_usb_gadget_wakeup(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_wakeup); + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_set_selfpowered(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->set_selfpowered) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_selfpowered(gadget, 1); + +out: + trace_usb_gadget_set_selfpowered(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_set_selfpowered); + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->set_selfpowered) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_selfpowered(gadget, 0); + +out: + trace_usb_gadget_clear_selfpowered(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_clear_selfpowered); + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->vbus_session) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_session(gadget, 1); + +out: + trace_usb_gadget_vbus_connect(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_connect); + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + int ret = 0; + + if (!gadget->ops->vbus_draw) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_draw(gadget, mA); + if (!ret) + gadget->mA = mA; + +out: + trace_usb_gadget_vbus_draw(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_draw); + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * Context: can sleep + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->vbus_session) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->vbus_session(gadget, 0); + +out: + trace_usb_gadget_vbus_disconnect(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_connect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->pullup) { + ret = -EOPNOTSUPP; + goto out; + } + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will be connected automatically after activation. + */ + gadget->connected = true; + goto out; + } + + ret = gadget->ops->pullup(gadget, 1); + if (!ret) + gadget->connected = 1; + +out: + trace_usb_gadget_connect(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_connect); + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_disconnect(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->ops->pullup) { + ret = -EOPNOTSUPP; + goto out; + } + + if (gadget->deactivated) { + /* + * If gadget is deactivated we only save new state. + * Gadget will stay disconnected after activation. + */ + gadget->connected = false; + goto out; + } + + ret = gadget->ops->pullup(gadget, 0); + if (!ret) + gadget->connected = 0; + +out: + trace_usb_gadget_disconnect(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_disconnect); + +/** + * usb_gadget_deactivate - deactivate function which is not ready to work + * @gadget: the peripheral being deactivated + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_activate() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_deactivate(struct usb_gadget *gadget) +{ + int ret = 0; + + if (gadget->deactivated) + goto out; + + if (gadget->connected) { + ret = usb_gadget_disconnect(gadget); + if (ret) + goto out; + + /* + * If gadget was being connected before deactivation, we want + * to reconnect it in usb_gadget_activate(). + */ + gadget->connected = true; + } + gadget->deactivated = true; + +out: + trace_usb_gadget_deactivate(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_deactivate); + +/** + * usb_gadget_activate - activate function which is not ready to work + * @gadget: the peripheral being activated + * + * This routine activates gadget which was previously deactivated with + * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. + * + * Returns zero on success, else negative errno. + */ +int usb_gadget_activate(struct usb_gadget *gadget) +{ + int ret = 0; + + if (!gadget->deactivated) + goto out; + + gadget->deactivated = false; + + /* + * If gadget has been connected before deactivation, or became connected + * while it was being deactivated, we call usb_gadget_connect(). + */ + if (gadget->connected) + ret = usb_gadget_connect(gadget); + +out: + trace_usb_gadget_activate(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_activate); + +/* ------------------------------------------------------------------------- */ + +#ifdef CONFIG_HAS_DMA + +int usb_gadget_map_request_by_dev(struct device *dev, + struct usb_request *req, int is_in) +{ + if (req->length == 0) + return 0; + + if (req->num_sgs) { + int mapped; + + mapped = dma_map_sg(dev, req->sg, req->num_sgs, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (mapped == 0) { + dev_err(dev, "failed to map SGs\n"); + return -EFAULT; + } + + req->num_mapped_sgs = mapped; + } else { + req->dma = dma_map_single(dev, req->buf, req->length, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + if (dma_mapping_error(dev, req->dma)) { + dev_err(dev, "failed to map buffer\n"); + return -EFAULT; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev); + +int usb_gadget_map_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in); +} +EXPORT_SYMBOL_GPL(usb_gadget_map_request); + +void usb_gadget_unmap_request_by_dev(struct device *dev, + struct usb_request *req, int is_in) +{ + if (req->length == 0) + return; + + if (req->num_mapped_sgs) { + dma_unmap_sg(dev, req->sg, req->num_mapped_sgs, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + req->num_mapped_sgs = 0; + } else { + dma_unmap_single(dev, req->dma, req->length, + is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + } +} +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); + +void usb_gadget_unmap_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in); +} +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); + +#endif /* CONFIG_HAS_DMA */ + +/* ------------------------------------------------------------------------- */ + +/** + * usb_gadget_giveback_request - give the request back to the gadget layer + * Context: in_interrupt() + * + * This is called by device controller drivers in order to return the + * completed request back to the gadget layer. + */ +void usb_gadget_giveback_request(struct usb_ep *ep, + struct usb_request *req) +{ + if (likely(req->status == 0)) + usb_led_activity(USB_LED_EVENT_GADGET); + + trace_usb_gadget_giveback_request(ep, req, 0); + + req->complete(ep, req); +} +EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); + +/* ------------------------------------------------------------------------- */ + +/** + * gadget_find_ep_by_name - returns ep whose name is the same as sting passed + * in second parameter or NULL if searched endpoint not found + * @g: controller to check for quirk + * @name: name of searched endpoint + */ +struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name) +{ + struct usb_ep *ep; + + gadget_for_each_ep(ep, g) { + if (!strcmp(ep->name, name)) + return ep; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(gadget_find_ep_by_name); + +/* ------------------------------------------------------------------------- */ + +int usb_gadget_ep_match_desc(struct usb_gadget *gadget, + struct usb_ep *ep, struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + u8 type; + u16 max; + int num_req_streams = 0; + + /* endpoint already claimed? */ + if (ep->claimed) + return 0; + + type = usb_endpoint_type(desc); + max = 0x7ff & usb_endpoint_maxp(desc); + + if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) + return 0; + if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) + return 0; + + if (max > ep->maxpacket_limit) + return 0; + + /* "high bandwidth" works only at high speed */ + if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) + return 0; + + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + /* only support ep0 for portable CONTROL traffic */ + return 0; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->caps.type_iso) + return 0; + /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 1023) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if (!ep->caps.type_bulk) + return 0; + if (ep_comp && gadget_is_superspeed(gadget)) { + /* Get the number of required streams from the + * EP companion descriptor and see if the EP + * matches it + */ + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + } + break; + case USB_ENDPOINT_XFER_INT: + /* Bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if (!ep->caps.type_int && !ep->caps.type_bulk) + return 0; + /* INT: limit 64 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 64) + return 0; + break; + } + + return 1; +} +EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc); + +/* ------------------------------------------------------------------------- */ + +static void usb_gadget_state_work(struct work_struct *work) +{ + struct usb_gadget *gadget = work_to_gadget(work); + struct usb_udc *udc = gadget->udc; + + if (udc) + sysfs_notify(&udc->dev.kobj, NULL, "state"); +} + +void usb_gadget_set_state(struct usb_gadget *gadget, + enum usb_device_state state) +{ + gadget->state = state; + schedule_work(&gadget->work); +} +EXPORT_SYMBOL_GPL(usb_gadget_set_state); + +/* ------------------------------------------------------------------------- */ + +static void usb_udc_connect_control(struct usb_udc *udc) +{ + if (udc->vbus) + usb_gadget_connect(udc->gadget); + else + usb_gadget_disconnect(udc->gadget); +} + +/** + * usb_udc_vbus_handler - updates the udc core vbus status, and try to + * connect or disconnect gadget + * @gadget: The gadget which vbus change occurs + * @status: The vbus status + * + * The udc driver calls it when it wants to connect or disconnect gadget + * according to vbus status. + */ +void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status) +{ + struct usb_udc *udc = gadget->udc; + + if (udc) { + udc->vbus = status; + usb_udc_connect_control(udc); + } +} +EXPORT_SYMBOL_GPL(usb_udc_vbus_handler); + +/** + * usb_gadget_udc_reset - notifies the udc core that bus reset occurs + * @gadget: The gadget which bus reset occurs + * @driver: The gadget driver we want to notify + * + * If the udc driver has bus reset handler, it needs to call this when the bus + * reset occurs, it notifies the gadget driver that the bus reset occurs as + * well as updates gadget state. + */ +void usb_gadget_udc_reset(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + driver->reset(gadget); + usb_gadget_set_state(gadget, USB_STATE_DEFAULT); +} +EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); + +/** + * usb_gadget_udc_start - tells usb device controller to start up + * @udc: The UDC to be started + * + * This call is issued by the UDC Class driver when it's about + * to register a gadget driver to the device controller, before + * calling gadget driver's bind() method. + * + * It allows the controller to be powered off until strictly + * necessary to have it powered on. + * + * Returns zero on success, else negative errno. + */ +static inline int usb_gadget_udc_start(struct usb_udc *udc) +{ + return udc->gadget->ops->udc_start(udc->gadget, udc->driver); +} + +/** + * usb_gadget_udc_stop - tells usb device controller we don't need it anymore + * @gadget: The device we want to stop activity + * @driver: The driver to unbind from @gadget + * + * This call is issued by the UDC Class driver after calling + * gadget driver's unbind() method. + * + * The details are implementation specific, but it can go as + * far as powering off UDC completely and disable its data + * line pullups. + */ +static inline void usb_gadget_udc_stop(struct usb_udc *udc) +{ + udc->gadget->ops->udc_stop(udc->gadget); +} + +/** + * usb_udc_release - release the usb_udc struct + * @dev: the dev member within usb_udc + * + * This is called by driver's core in order to free memory once the last + * reference is released. + */ +static void usb_udc_release(struct device *dev) +{ + struct usb_udc *udc; + + udc = container_of(dev, struct usb_udc, dev); + dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); + kfree(udc); +} + +static const struct attribute_group *usb_udc_attr_groups[]; + +static void usb_udc_nop_release(struct device *dev) +{ + dev_vdbg(dev, "%s\n", __func__); +} + +/** + * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller driver's + * device. + * @gadget: the gadget to be added to the list. + * @release: a gadget release function. + * + * Returns zero on success, negative errno otherwise. + */ +int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, + void (*release)(struct device *dev)) +{ + struct usb_udc *udc; + struct usb_gadget_driver *driver; + int ret = -ENOMEM; + + udc = kzalloc(sizeof(*udc), GFP_KERNEL); + if (!udc) + goto err1; + + dev_set_name(&gadget->dev, "gadget"); + INIT_WORK(&gadget->work, usb_gadget_state_work); + gadget->dev.parent = parent; + + if (release) + gadget->dev.release = release; + else + gadget->dev.release = usb_udc_nop_release; + + ret = device_register(&gadget->dev); + if (ret) + goto err2; + + device_initialize(&udc->dev); + udc->dev.release = usb_udc_release; + udc->dev.class = udc_class; + udc->dev.groups = usb_udc_attr_groups; + udc->dev.parent = parent; + ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); + if (ret) + goto err3; + + udc->gadget = gadget; + gadget->udc = udc; + + mutex_lock(&udc_lock); + list_add_tail(&udc->list, &udc_list); + + ret = device_add(&udc->dev); + if (ret) + goto err4; + + usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + udc->vbus = true; + + /* pick up one of pending gadget drivers */ + list_for_each_entry(driver, &gadget_driver_pending_list, pending) { + if (!driver->udc_name || strcmp(driver->udc_name, + dev_name(&udc->dev)) == 0) { + ret = udc_bind_to_driver(udc, driver); + if (ret != -EPROBE_DEFER) + list_del(&driver->pending); + if (ret) + goto err4; + break; + } + } + + mutex_unlock(&udc_lock); + + return 0; + +err4: + list_del(&udc->list); + mutex_unlock(&udc_lock); + +err3: + put_device(&udc->dev); + device_del(&gadget->dev); + +err2: + put_device(&gadget->dev); + kfree(udc); + +err1: + return ret; +} +EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); + +/** + * usb_get_gadget_udc_name - get the name of the first UDC controller + * This functions returns the name of the first UDC controller in the system. + * Please note that this interface is usefull only for legacy drivers which + * assume that there is only one UDC controller in the system and they need to + * get its name before initialization. There is no guarantee that the UDC + * of the returned name will be still available, when gadget driver registers + * itself. + * + * Returns pointer to string with UDC controller name on success, NULL + * otherwise. Caller should kfree() returned string. + */ +char *usb_get_gadget_udc_name(void) +{ + struct usb_udc *udc; + char *name = NULL; + + /* For now we take the first available UDC */ + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) { + if (!udc->driver) { + name = kstrdup(udc->gadget->name, GFP_KERNEL); + break; + } + } + mutex_unlock(&udc_lock); + return name; +} +EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name); + +/** + * usb_add_gadget_udc - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller + * driver's device. + * @gadget: the gadget to be added to the list + * + * Returns zero on success, negative errno otherwise. + */ +int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) +{ + return usb_add_gadget_udc_release(parent, gadget, NULL); +} +EXPORT_SYMBOL_GPL(usb_add_gadget_udc); + +static void usb_gadget_remove_driver(struct usb_udc *udc) +{ + dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", + udc->driver->function); + + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + + usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); + udc->driver->unbind(udc->gadget); + usb_gadget_udc_stop(udc); + + udc->driver = NULL; + udc->dev.driver = NULL; + udc->gadget->dev.driver = NULL; +} + +/** + * usb_del_gadget_udc - deletes @udc from udc_list + * @gadget: the gadget to be removed. + * + * This, will call usb_gadget_unregister_driver() if + * the @udc is still busy. + */ +void usb_del_gadget_udc(struct usb_gadget *gadget) +{ + struct usb_udc *udc = gadget->udc; + + if (!udc) + return; + + dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); + + mutex_lock(&udc_lock); + list_del(&udc->list); + + if (udc->driver) { + struct usb_gadget_driver *driver = udc->driver; + + usb_gadget_remove_driver(udc); + list_add(&driver->pending, &gadget_driver_pending_list); + } + mutex_unlock(&udc_lock); + + kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); + flush_work(&gadget->work); + device_unregister(&udc->dev); + device_unregister(&gadget->dev); +} +EXPORT_SYMBOL_GPL(usb_del_gadget_udc); + +/* ------------------------------------------------------------------------- */ + +static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver) +{ + int ret; + + dev_dbg(&udc->dev, "registering UDC driver [%s]\n", + driver->function); + + udc->driver = driver; + udc->dev.driver = &driver->driver; + udc->gadget->dev.driver = &driver->driver; + + ret = driver->bind(udc->gadget, driver); + if (ret) + goto err1; + ret = usb_gadget_udc_start(udc); + if (ret) { + driver->unbind(udc->gadget); + goto err1; + } + usb_udc_connect_control(udc); + + kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); + return 0; +err1: + if (ret != -EISNAM) + dev_err(&udc->dev, "failed to start %s: %d\n", + udc->driver->function, ret); + udc->driver = NULL; + udc->dev.driver = NULL; + udc->gadget->dev.driver = NULL; + return ret; +} + +int usb_gadget_probe_driver(struct usb_gadget_driver *driver) +{ + struct usb_udc *udc = NULL; + int ret = -ENODEV; + + if (!driver || !driver->bind || !driver->setup) + return -EINVAL; + + mutex_lock(&udc_lock); + if (driver->udc_name) { + list_for_each_entry(udc, &udc_list, list) { + ret = strcmp(driver->udc_name, dev_name(&udc->dev)); + if (!ret) + break; + } + if (!ret && !udc->driver) + goto found; + } else { + list_for_each_entry(udc, &udc_list, list) { + /* For now we take the first one */ + if (!udc->driver) + goto found; + } + } + + if (!driver->match_existing_only) { + list_add_tail(&driver->pending, &gadget_driver_pending_list); + pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", + driver->function); + ret = 0; + } + + mutex_unlock(&udc_lock); + return ret; +found: + ret = udc_bind_to_driver(udc, driver); + mutex_unlock(&udc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct usb_udc *udc = NULL; + int ret = -ENODEV; + + if (!driver || !driver->unbind) + return -EINVAL; + + mutex_lock(&udc_lock); + list_for_each_entry(udc, &udc_list, list) + if (udc->driver == driver) { + usb_gadget_remove_driver(udc); + usb_gadget_set_state(udc->gadget, + USB_STATE_NOTATTACHED); + ret = 0; + break; + } + + if (ret) { + list_del(&driver->pending); + ret = 0; + } + mutex_unlock(&udc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); + +/* ------------------------------------------------------------------------- */ + +static ssize_t usb_udc_srp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + + if (sysfs_streq(buf, "1")) + usb_gadget_wakeup(udc->gadget); + + return n; +} +static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store); + +static ssize_t usb_udc_softconn_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + + if (!udc->driver) { + dev_err(dev, "soft-connect without a gadget driver\n"); + return -EOPNOTSUPP; + } + + if (sysfs_streq(buf, "connect")) { + usb_gadget_udc_start(udc); + usb_gadget_connect(udc->gadget); + } else if (sysfs_streq(buf, "disconnect")) { + usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); + usb_gadget_udc_stop(udc); + } else { + dev_err(dev, "unsupported command '%s'\n", buf); + return -EINVAL; + } + + return n; +} +static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); + +static ssize_t state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + struct usb_gadget *gadget = udc->gadget; + + return sprintf(buf, "%s\n", usb_state_string(gadget->state)); +} +static DEVICE_ATTR_RO(state); + +#define USB_UDC_SPEED_ATTR(name, param) \ +ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ + return snprintf(buf, PAGE_SIZE, "%s\n", \ + usb_speed_string(udc->gadget->param)); \ +} \ +static DEVICE_ATTR_RO(name) + +static USB_UDC_SPEED_ATTR(current_speed, speed); +static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); + +#define USB_UDC_ATTR(name) \ +ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ + struct usb_gadget *gadget = udc->gadget; \ + \ + return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \ +} \ +static DEVICE_ATTR_RO(name) + +static USB_UDC_ATTR(is_otg); +static USB_UDC_ATTR(is_a_peripheral); +static USB_UDC_ATTR(b_hnp_enable); +static USB_UDC_ATTR(a_hnp_support); +static USB_UDC_ATTR(a_alt_hnp_support); +static USB_UDC_ATTR(is_selfpowered); + +static struct attribute *usb_udc_attrs[] = { + &dev_attr_srp.attr, + &dev_attr_soft_connect.attr, + &dev_attr_state.attr, + &dev_attr_current_speed.attr, + &dev_attr_maximum_speed.attr, + + &dev_attr_is_otg.attr, + &dev_attr_is_a_peripheral.attr, + &dev_attr_b_hnp_enable.attr, + &dev_attr_a_hnp_support.attr, + &dev_attr_a_alt_hnp_support.attr, + &dev_attr_is_selfpowered.attr, + NULL, +}; + +static const struct attribute_group usb_udc_attr_group = { + .attrs = usb_udc_attrs, +}; + +static const struct attribute_group *usb_udc_attr_groups[] = { + &usb_udc_attr_group, + NULL, +}; + +static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + int ret; + + ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name); + if (ret) { + dev_err(dev, "failed to add uevent USB_UDC_NAME\n"); + return ret; + } + + if (udc->driver) { + ret = add_uevent_var(env, "USB_UDC_DRIVER=%s", + udc->driver->function); + if (ret) { + dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); + return ret; + } + } + + return 0; +} + +static int __init usb_udc_init(void) +{ + udc_class = class_create(THIS_MODULE, "udc"); + if (IS_ERR(udc_class)) { + pr_err("failed to create udc class --> %ld\n", + PTR_ERR(udc_class)); + return PTR_ERR(udc_class); + } + + udc_class->dev_uevent = usb_udc_uevent; + return 0; +} +subsys_initcall(usb_udc_init); + +static void __exit usb_udc_exit(void) +{ + class_destroy(udc_class); +} +module_exit(usb_udc_exit); + +MODULE_DESCRIPTION("UDC Framework"); +MODULE_AUTHOR("Felipe Balbi "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/gadget/udc/trace.c b/drivers/usb/gadget/udc/trace.c new file mode 100644 index 000000000000..8c551ab91ad8 --- /dev/null +++ b/drivers/usb/gadget/udc/trace.c @@ -0,0 +1,18 @@ +/** + * trace.c - USB Gadget Framework Trace Support + * + * Copyright (C) 2016 Intel Corporation + * Author: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h new file mode 100644 index 000000000000..da29874b5366 --- /dev/null +++ b/drivers/usb/gadget/udc/trace.h @@ -0,0 +1,298 @@ +/** + * udc.c - Core UDC Framework + * + * Copyright (C) 2016 Intel Corporation + * Author: Felipe Balbi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM gadget + +#if !defined(__UDC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __UDC_TRACE_H + +#include +#include +#include +#include + +DECLARE_EVENT_CLASS(udc_log_gadget, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret), + TP_STRUCT__entry( + __field(enum usb_device_speed, speed) + __field(enum usb_device_speed, max_speed) + __field(enum usb_device_state, state) + __field(unsigned, mA) + __field(unsigned, sg_supported) + __field(unsigned, is_otg) + __field(unsigned, is_a_peripheral) + __field(unsigned, b_hnp_enable) + __field(unsigned, a_hnp_support) + __field(unsigned, hnp_polling_support) + __field(unsigned, host_request_flag) + __field(unsigned, quirk_ep_out_aligned_size) + __field(unsigned, quirk_altset_not_supp) + __field(unsigned, quirk_stall_not_supp) + __field(unsigned, quirk_zlp_not_supp) + __field(unsigned, is_selfpowered) + __field(unsigned, deactivated) + __field(unsigned, connected) + __field(int, ret) + ), + TP_fast_assign( + __entry->speed = g->speed; + __entry->max_speed = g->max_speed; + __entry->state = g->state; + __entry->mA = g->mA; + __entry->sg_supported = g->sg_supported; + __entry->is_otg = g->is_otg; + __entry->is_a_peripheral = g->is_a_peripheral; + __entry->b_hnp_enable = g->b_hnp_enable; + __entry->a_hnp_support = g->a_hnp_support; + __entry->hnp_polling_support = g->hnp_polling_support; + __entry->host_request_flag = g->host_request_flag; + __entry->quirk_ep_out_aligned_size = g->quirk_ep_out_aligned_size; + __entry->quirk_altset_not_supp = g->quirk_altset_not_supp; + __entry->quirk_stall_not_supp = g->quirk_stall_not_supp; + __entry->quirk_zlp_not_supp = g->quirk_zlp_not_supp; + __entry->is_selfpowered = g->is_selfpowered; + __entry->deactivated = g->deactivated; + __entry->connected = g->connected; + __entry->ret = ret; + ), + TP_printk("speed %d/%d state %d %dmA [%s%s%s%s%s%s%s%s%s%s%s%s%s%s] --> %d", + __entry->speed, __entry->max_speed, __entry->state, __entry->mA, + __entry->sg_supported ? "sg:" : "", + __entry->is_otg ? "OTG:" : "", + __entry->is_a_peripheral ? "a_peripheral:" : "", + __entry->b_hnp_enable ? "b_hnp:" : "", + __entry->a_hnp_support ? "a_hnp:" : "", + __entry->hnp_polling_support ? "hnp_poll:" : "", + __entry->host_request_flag ? "hostreq:" : "", + __entry->quirk_ep_out_aligned_size ? "out_aligned:" : "", + __entry->quirk_altset_not_supp ? "no_altset:" : "", + __entry->quirk_stall_not_supp ? "no_stall:" : "", + __entry->quirk_zlp_not_supp ? "no_zlp" : "", + __entry->is_selfpowered ? "self-powered:" : "bus-powered:", + __entry->deactivated ? "deactivated:" : "activated:", + __entry->connected ? "connected" : "disconnected", + __entry->ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_frame_number, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_wakeup, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_set_selfpowered, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_clear_selfpowered, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_connect, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_draw, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_disconnect, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_connect, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_disconnect, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_deactivate, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DEFINE_EVENT(udc_log_gadget, usb_gadget_activate, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + +DECLARE_EVENT_CLASS(udc_log_ep, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret), + TP_STRUCT__entry( + __dynamic_array(char, name, UDC_TRACE_STR_MAX) + __field(unsigned, maxpacket) + __field(unsigned, maxpacket_limit) + __field(unsigned, max_streams) + __field(unsigned, mult) + __field(unsigned, maxburst) + __field(u8, address) + __field(bool, claimed) + __field(bool, enabled) + __field(int, ret) + ), + TP_fast_assign( + snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name); + __entry->maxpacket = ep->maxpacket; + __entry->maxpacket_limit = ep->maxpacket_limit; + __entry->max_streams = ep->max_streams; + __entry->mult = ep->mult; + __entry->maxburst = ep->maxburst; + __entry->address = ep->address, + __entry->claimed = ep->claimed; + __entry->enabled = ep->enabled; + __entry->ret = ret; + ), + TP_printk("%s: mps %d/%d streams %d mult %d burst %d addr %02x %s%s --> %d", + __get_str(name), __entry->maxpacket, __entry->maxpacket_limit, + __entry->max_streams, __entry->mult, __entry->maxburst, + __entry->address, __entry->claimed ? "claimed:" : "released:", + __entry->enabled ? "enabled" : "disabled", ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_set_maxpacket_limit, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_enable, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_disable, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_set_halt, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_clear_halt, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_set_wedge, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_fifo_status, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DEFINE_EVENT(udc_log_ep, usb_ep_fifo_flush, + TP_PROTO(struct usb_ep *ep, int ret), + TP_ARGS(ep, ret) +); + +DECLARE_EVENT_CLASS(udc_log_req, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret), + TP_STRUCT__entry( + __dynamic_array(char, name, UDC_TRACE_STR_MAX) + __field(unsigned, length) + __field(unsigned, actual) + __field(unsigned, num_sgs) + __field(unsigned, num_mapped_sgs) + __field(unsigned, stream_id) + __field(unsigned, no_interrupt) + __field(unsigned, zero) + __field(unsigned, short_not_ok) + __field(int, status) + __field(int, ret) + ), + TP_fast_assign( + snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name); + __entry->length = req->length; + __entry->actual = req->actual; + __entry->num_sgs = req->num_sgs; + __entry->num_mapped_sgs = req->num_mapped_sgs; + __entry->stream_id = req->stream_id; + __entry->no_interrupt = req->no_interrupt; + __entry->zero = req->zero; + __entry->short_not_ok = req->short_not_ok; + __entry->status = req->status; + __entry->ret = ret; + ), + TP_printk("%s: length %d/%d sgs %d/%d stream %d %s%s%s status %d --> %d", + __get_str(name), __entry->actual, __entry->length, + __entry->num_mapped_sgs, __entry->num_sgs, __entry->stream_id, + __entry->zero ? "Z" : "z", + __entry->short_not_ok ? "S" : "s", + __entry->no_interrupt ? "i" : "I", + __entry->status, __entry->ret + ) +); + +DEFINE_EVENT(udc_log_req, usb_ep_alloc_request, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +DEFINE_EVENT(udc_log_req, usb_ep_free_request, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +DEFINE_EVENT(udc_log_req, usb_ep_queue, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +DEFINE_EVENT(udc_log_req, usb_ep_dequeue, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +DEFINE_EVENT(udc_log_req, usb_gadget_giveback_request, + TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), + TP_ARGS(ep, req, ret) +); + +#endif /* __UDC_TRACE_H */ + +/* this part has to be here */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c deleted file mode 100644 index abf013865e51..000000000000 --- a/drivers/usb/gadget/udc/udc-core.c +++ /dev/null @@ -1,1373 +0,0 @@ -/** - * udc.c - Core UDC Framework - * - * Copyright (C) 2010 Texas Instruments - * Author: Felipe Balbi - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 of - * the License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/** - * struct usb_udc - describes one usb device controller - * @driver - the gadget driver pointer. For use by the class code - * @dev - the child device to the actual controller - * @gadget - the gadget. For use by the class code - * @list - for use by the udc class driver - * @vbus - for udcs who care about vbus status, this value is real vbus status; - * for udcs who do not care about vbus status, this value is always true - * - * This represents the internal data structure which is used by the UDC-class - * to hold information about udc driver and gadget together. - */ -struct usb_udc { - struct usb_gadget_driver *driver; - struct usb_gadget *gadget; - struct device dev; - struct list_head list; - bool vbus; -}; - -static struct class *udc_class; -static LIST_HEAD(udc_list); -static LIST_HEAD(gadget_driver_pending_list); -static DEFINE_MUTEX(udc_lock); - -static int udc_bind_to_driver(struct usb_udc *udc, - struct usb_gadget_driver *driver); - -/* ------------------------------------------------------------------------- */ - -/** - * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint - * @ep:the endpoint being configured - * @maxpacket_limit:value of maximum packet size limit - * - * This function should be used only in UDC drivers to initialize endpoint - * (usually in probe function). - */ -void usb_ep_set_maxpacket_limit(struct usb_ep *ep, - unsigned maxpacket_limit) -{ - ep->maxpacket_limit = maxpacket_limit; - ep->maxpacket = maxpacket_limit; -} -EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); - -/** - * usb_ep_enable - configure endpoint, making it usable - * @ep:the endpoint being configured. may not be the endpoint named "ep0". - * drivers discover endpoints through the ep_list of a usb_gadget. - * - * When configurations are set, or when interface settings change, the driver - * will enable or disable the relevant endpoints. while it is enabled, an - * endpoint may be used for i/o until the driver receives a disconnect() from - * the host or until the endpoint is disabled. - * - * the ep0 implementation (which calls this routine) must ensure that the - * hardware capabilities of each endpoint match the descriptor provided - * for it. for example, an endpoint named "ep2in-bulk" would be usable - * for interrupt transfers as well as bulk, but it likely couldn't be used - * for iso transfers or for endpoint 14. some endpoints are fully - * configurable, with more generic names like "ep-a". (remember that for - * USB, "in" means "towards the USB master".) - * - * returns zero, or a negative error code. - */ -int usb_ep_enable(struct usb_ep *ep) -{ - int ret; - - if (ep->enabled) - return 0; - - ret = ep->ops->enable(ep, ep->desc); - if (ret) - return ret; - - ep->enabled = true; - - return 0; -} -EXPORT_SYMBOL_GPL(usb_ep_enable); - -/** - * usb_ep_disable - endpoint is no longer usable - * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". - * - * no other task may be using this endpoint when this is called. - * any pending and uncompleted requests will complete with status - * indicating disconnect (-ESHUTDOWN) before this call returns. - * gadget drivers must call usb_ep_enable() again before queueing - * requests to the endpoint. - * - * returns zero, or a negative error code. - */ -int usb_ep_disable(struct usb_ep *ep) -{ - int ret; - - if (!ep->enabled) - return 0; - - ret = ep->ops->disable(ep); - if (ret) - return ret; - - ep->enabled = false; - - return 0; -} -EXPORT_SYMBOL_GPL(usb_ep_disable); - -/** - * usb_ep_alloc_request - allocate a request object to use with this endpoint - * @ep:the endpoint to be used with with the request - * @gfp_flags:GFP_* flags to use - * - * Request objects must be allocated with this call, since they normally - * need controller-specific setup and may even need endpoint-specific - * resources such as allocation of DMA descriptors. - * Requests may be submitted with usb_ep_queue(), and receive a single - * completion callback. Free requests with usb_ep_free_request(), when - * they are no longer needed. - * - * Returns the request, or null if one could not be allocated. - */ -struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags) -{ - return ep->ops->alloc_request(ep, gfp_flags); -} -EXPORT_SYMBOL_GPL(usb_ep_alloc_request); - -/** - * usb_ep_free_request - frees a request object - * @ep:the endpoint associated with the request - * @req:the request being freed - * - * Reverses the effect of usb_ep_alloc_request(). - * Caller guarantees the request is not queued, and that it will - * no longer be requeued (or otherwise used). - */ -void usb_ep_free_request(struct usb_ep *ep, - struct usb_request *req) -{ - ep->ops->free_request(ep, req); -} -EXPORT_SYMBOL_GPL(usb_ep_free_request); - -/** - * usb_ep_queue - queues (submits) an I/O request to an endpoint. - * @ep:the endpoint associated with the request - * @req:the request being submitted - * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't - * pre-allocate all necessary memory with the request. - * - * This tells the device controller to perform the specified request through - * that endpoint (reading or writing a buffer). When the request completes, - * including being canceled by usb_ep_dequeue(), the request's completion - * routine is called to return the request to the driver. Any endpoint - * (except control endpoints like ep0) may have more than one transfer - * request queued; they complete in FIFO order. Once a gadget driver - * submits a request, that request may not be examined or modified until it - * is given back to that driver through the completion callback. - * - * Each request is turned into one or more packets. The controller driver - * never merges adjacent requests into the same packet. OUT transfers - * will sometimes use data that's already buffered in the hardware. - * Drivers can rely on the fact that the first byte of the request's buffer - * always corresponds to the first byte of some USB packet, for both - * IN and OUT transfers. - * - * Bulk endpoints can queue any amount of data; the transfer is packetized - * automatically. The last packet will be short if the request doesn't fill it - * out completely. Zero length packets (ZLPs) should be avoided in portable - * protocols since not all usb hardware can successfully handle zero length - * packets. (ZLPs may be explicitly written, and may be implicitly written if - * the request 'zero' flag is set.) Bulk endpoints may also be used - * for interrupt transfers; but the reverse is not true, and some endpoints - * won't support every interrupt transfer. (Such as 768 byte packets.) - * - * Interrupt-only endpoints are less functional than bulk endpoints, for - * example by not supporting queueing or not handling buffers that are - * larger than the endpoint's maxpacket size. They may also treat data - * toggle differently. - * - * Control endpoints ... after getting a setup() callback, the driver queues - * one response (even if it would be zero length). That enables the - * status ack, after transferring data as specified in the response. Setup - * functions may return negative error codes to generate protocol stalls. - * (Note that some USB device controllers disallow protocol stall responses - * in some cases.) When control responses are deferred (the response is - * written after the setup callback returns), then usb_ep_set_halt() may be - * used on ep0 to trigger protocol stalls. Depending on the controller, - * it may not be possible to trigger a status-stage protocol stall when the - * data stage is over, that is, from within the response's completion - * routine. - * - * For periodic endpoints, like interrupt or isochronous ones, the usb host - * arranges to poll once per interval, and the gadget driver usually will - * have queued some data to transfer at that time. - * - * Returns zero, or a negative error code. Endpoints that are not enabled - * report errors; errors will also be - * reported when the usb peripheral is disconnected. - */ -int usb_ep_queue(struct usb_ep *ep, - struct usb_request *req, gfp_t gfp_flags) -{ - if (WARN_ON_ONCE(!ep->enabled && ep->address)) - return -ESHUTDOWN; - - return ep->ops->queue(ep, req, gfp_flags); -} -EXPORT_SYMBOL_GPL(usb_ep_queue); - -/** - * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint - * @ep:the endpoint associated with the request - * @req:the request being canceled - * - * If the request is still active on the endpoint, it is dequeued and its - * completion routine is called (with status -ECONNRESET); else a negative - * error code is returned. This is guaranteed to happen before the call to - * usb_ep_dequeue() returns. - * - * Note that some hardware can't clear out write fifos (to unlink the request - * at the head of the queue) except as part of disconnecting from usb. Such - * restrictions prevent drivers from supporting configuration changes, - * even to configuration zero (a "chapter 9" requirement). - */ -int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - return ep->ops->dequeue(ep, req); -} -EXPORT_SYMBOL_GPL(usb_ep_dequeue); - -/** - * usb_ep_set_halt - sets the endpoint halt feature. - * @ep: the non-isochronous endpoint being stalled - * - * Use this to stall an endpoint, perhaps as an error report. - * Except for control endpoints, - * the endpoint stays halted (will not stream any data) until the host - * clears this feature; drivers may need to empty the endpoint's request - * queue first, to make sure no inappropriate transfers happen. - * - * Note that while an endpoint CLEAR_FEATURE will be invisible to the - * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the - * current altsetting, see usb_ep_clear_halt(). When switching altsettings, - * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. - * - * Returns zero, or a negative error code. On success, this call sets - * underlying hardware state that blocks data transfers. - * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any - * transfer requests are still queued, or if the controller hardware - * (usually a FIFO) still holds bytes that the host hasn't collected. - */ -int usb_ep_set_halt(struct usb_ep *ep) -{ - return ep->ops->set_halt(ep, 1); -} -EXPORT_SYMBOL_GPL(usb_ep_set_halt); - -/** - * usb_ep_clear_halt - clears endpoint halt, and resets toggle - * @ep:the bulk or interrupt endpoint being reset - * - * Use this when responding to the standard usb "set interface" request, - * for endpoints that aren't reconfigured, after clearing any other state - * in the endpoint's i/o queue. - * - * Returns zero, or a negative error code. On success, this call clears - * the underlying hardware state reflecting endpoint halt and data toggle. - * Note that some hardware can't support this request (like pxa2xx_udc), - * and accordingly can't correctly implement interface altsettings. - */ -int usb_ep_clear_halt(struct usb_ep *ep) -{ - return ep->ops->set_halt(ep, 0); -} -EXPORT_SYMBOL_GPL(usb_ep_clear_halt); - -/** - * usb_ep_set_wedge - sets the halt feature and ignores clear requests - * @ep: the endpoint being wedged - * - * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) - * requests. If the gadget driver clears the halt status, it will - * automatically unwedge the endpoint. - * - * Returns zero on success, else negative errno. - */ -int usb_ep_set_wedge(struct usb_ep *ep) -{ - if (ep->ops->set_wedge) - return ep->ops->set_wedge(ep); - else - return ep->ops->set_halt(ep, 1); -} -EXPORT_SYMBOL_GPL(usb_ep_set_wedge); - -/** - * usb_ep_fifo_status - returns number of bytes in fifo, or error - * @ep: the endpoint whose fifo status is being checked. - * - * FIFO endpoints may have "unclaimed data" in them in certain cases, - * such as after aborted transfers. Hosts may not have collected all - * the IN data written by the gadget driver (and reported by a request - * completion). The gadget driver may not have collected all the data - * written OUT to it by the host. Drivers that need precise handling for - * fault reporting or recovery may need to use this call. - * - * This returns the number of such bytes in the fifo, or a negative - * errno if the endpoint doesn't use a FIFO or doesn't support such - * precise handling. - */ -int usb_ep_fifo_status(struct usb_ep *ep) -{ - if (ep->ops->fifo_status) - return ep->ops->fifo_status(ep); - else - return -EOPNOTSUPP; -} -EXPORT_SYMBOL_GPL(usb_ep_fifo_status); - -/** - * usb_ep_fifo_flush - flushes contents of a fifo - * @ep: the endpoint whose fifo is being flushed. - * - * This call may be used to flush the "unclaimed data" that may exist in - * an endpoint fifo after abnormal transaction terminations. The call - * must never be used except when endpoint is not being used for any - * protocol translation. - */ -void usb_ep_fifo_flush(struct usb_ep *ep) -{ - if (ep->ops->fifo_flush) - ep->ops->fifo_flush(ep); -} -EXPORT_SYMBOL_GPL(usb_ep_fifo_flush); - -/* ------------------------------------------------------------------------- */ - -/** - * usb_gadget_frame_number - returns the current frame number - * @gadget: controller that reports the frame number - * - * Returns the usb frame number, normally eleven bits from a SOF packet, - * or negative errno if this device doesn't support this capability. - */ -int usb_gadget_frame_number(struct usb_gadget *gadget) -{ - return gadget->ops->get_frame(gadget); -} -EXPORT_SYMBOL_GPL(usb_gadget_frame_number); - -/** - * usb_gadget_wakeup - tries to wake up the host connected to this gadget - * @gadget: controller used to wake up the host - * - * Returns zero on success, else negative error code if the hardware - * doesn't support such attempts, or its support has not been enabled - * by the usb host. Drivers must return device descriptors that report - * their ability to support this, or hosts won't enable it. - * - * This may also try to use SRP to wake the host and start enumeration, - * even if OTG isn't otherwise in use. OTG devices may also start - * remote wakeup even when hosts don't explicitly enable it. - */ -int usb_gadget_wakeup(struct usb_gadget *gadget) -{ - if (!gadget->ops->wakeup) - return -EOPNOTSUPP; - return gadget->ops->wakeup(gadget); -} -EXPORT_SYMBOL_GPL(usb_gadget_wakeup); - -/** - * usb_gadget_set_selfpowered - sets the device selfpowered feature. - * @gadget:the device being declared as self-powered - * - * this affects the device status reported by the hardware driver - * to reflect that it now has a local power supply. - * - * returns zero on success, else negative errno. - */ -int usb_gadget_set_selfpowered(struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered(gadget, 1); -} -EXPORT_SYMBOL_GPL(usb_gadget_set_selfpowered); - -/** - * usb_gadget_clear_selfpowered - clear the device selfpowered feature. - * @gadget:the device being declared as bus-powered - * - * this affects the device status reported by the hardware driver. - * some hardware may not support bus-powered operation, in which - * case this feature's value can never change. - * - * returns zero on success, else negative errno. - */ -int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) -{ - if (!gadget->ops->set_selfpowered) - return -EOPNOTSUPP; - return gadget->ops->set_selfpowered(gadget, 0); -} -EXPORT_SYMBOL_GPL(usb_gadget_clear_selfpowered); - -/** - * usb_gadget_vbus_connect - Notify controller that VBUS is powered - * @gadget:The device which now has VBUS power. - * Context: can sleep - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session starting. Common responses include - * resuming the controller, activating the D+ (or D-) pullup to let the - * host detect that a USB device is attached, and starting to draw power - * (8mA or possibly more, especially after SET_CONFIGURATION). - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_vbus_connect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session(gadget, 1); -} -EXPORT_SYMBOL_GPL(usb_gadget_vbus_connect); - -/** - * usb_gadget_vbus_draw - constrain controller's VBUS power usage - * @gadget:The device whose VBUS usage is being described - * @mA:How much current to draw, in milliAmperes. This should be twice - * the value listed in the configuration descriptor bMaxPower field. - * - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - if (!gadget->ops->vbus_draw) - return -EOPNOTSUPP; - return gadget->ops->vbus_draw(gadget, mA); -} -EXPORT_SYMBOL_GPL(usb_gadget_vbus_draw); - -/** - * usb_gadget_vbus_disconnect - notify controller about VBUS session end - * @gadget:the device whose VBUS supply is being described - * Context: can sleep - * - * This call is used by a driver for an external transceiver (or GPIO) - * that detects a VBUS power session ending. Common responses include - * reversing everything done in usb_gadget_vbus_connect(). - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_vbus_disconnect(struct usb_gadget *gadget) -{ - if (!gadget->ops->vbus_session) - return -EOPNOTSUPP; - return gadget->ops->vbus_session(gadget, 0); -} -EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect); - -/** - * usb_gadget_connect - software-controlled connect to USB host - * @gadget:the peripheral being connected - * - * Enables the D+ (or potentially D-) pullup. The host will start - * enumerating this gadget when the pullup is active and a VBUS session - * is active (the link is powered). This pullup is always enabled unless - * usb_gadget_disconnect() has been used to disable it. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_connect(struct usb_gadget *gadget) -{ - int ret; - - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - - if (gadget->deactivated) { - /* - * If gadget is deactivated we only save new state. - * Gadget will be connected automatically after activation. - */ - gadget->connected = true; - return 0; - } - - ret = gadget->ops->pullup(gadget, 1); - if (!ret) - gadget->connected = 1; - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_connect); - -/** - * usb_gadget_disconnect - software-controlled disconnect from USB host - * @gadget:the peripheral being disconnected - * - * Disables the D+ (or potentially D-) pullup, which the host may see - * as a disconnect (when a VBUS session is active). Not all systems - * support software pullup controls. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_disconnect(struct usb_gadget *gadget) -{ - int ret; - - if (!gadget->ops->pullup) - return -EOPNOTSUPP; - - if (gadget->deactivated) { - /* - * If gadget is deactivated we only save new state. - * Gadget will stay disconnected after activation. - */ - gadget->connected = false; - return 0; - } - - ret = gadget->ops->pullup(gadget, 0); - if (!ret) - gadget->connected = 0; - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_disconnect); - -/** - * usb_gadget_deactivate - deactivate function which is not ready to work - * @gadget: the peripheral being deactivated - * - * This routine may be used during the gadget driver bind() call to prevent - * the peripheral from ever being visible to the USB host, unless later - * usb_gadget_activate() is called. For example, user mode components may - * need to be activated before the system can talk to hosts. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_deactivate(struct usb_gadget *gadget) -{ - int ret; - - if (gadget->deactivated) - return 0; - - if (gadget->connected) { - ret = usb_gadget_disconnect(gadget); - if (ret) - return ret; - /* - * If gadget was being connected before deactivation, we want - * to reconnect it in usb_gadget_activate(). - */ - gadget->connected = true; - } - gadget->deactivated = true; - - return 0; -} -EXPORT_SYMBOL_GPL(usb_gadget_deactivate); - -/** - * usb_gadget_activate - activate function which is not ready to work - * @gadget: the peripheral being activated - * - * This routine activates gadget which was previously deactivated with - * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. - * - * Returns zero on success, else negative errno. - */ -int usb_gadget_activate(struct usb_gadget *gadget) -{ - if (!gadget->deactivated) - return 0; - - gadget->deactivated = false; - - /* - * If gadget has been connected before deactivation, or became connected - * while it was being deactivated, we call usb_gadget_connect(). - */ - if (gadget->connected) - return usb_gadget_connect(gadget); - - return 0; -} -EXPORT_SYMBOL_GPL(usb_gadget_activate); - -/* ------------------------------------------------------------------------- */ - -#ifdef CONFIG_HAS_DMA - -int usb_gadget_map_request_by_dev(struct device *dev, - struct usb_request *req, int is_in) -{ - if (req->length == 0) - return 0; - - if (req->num_sgs) { - int mapped; - - mapped = dma_map_sg(dev, req->sg, req->num_sgs, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (mapped == 0) { - dev_err(dev, "failed to map SGs\n"); - return -EFAULT; - } - - req->num_mapped_sgs = mapped; - } else { - req->dma = dma_map_single(dev, req->buf, req->length, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - if (dma_mapping_error(dev, req->dma)) { - dev_err(dev, "failed to map buffer\n"); - return -EFAULT; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev); - -int usb_gadget_map_request(struct usb_gadget *gadget, - struct usb_request *req, int is_in) -{ - return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in); -} -EXPORT_SYMBOL_GPL(usb_gadget_map_request); - -void usb_gadget_unmap_request_by_dev(struct device *dev, - struct usb_request *req, int is_in) -{ - if (req->length == 0) - return; - - if (req->num_mapped_sgs) { - dma_unmap_sg(dev, req->sg, req->num_mapped_sgs, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - req->num_mapped_sgs = 0; - } else { - dma_unmap_single(dev, req->dma, req->length, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - } -} -EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); - -void usb_gadget_unmap_request(struct usb_gadget *gadget, - struct usb_request *req, int is_in) -{ - usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in); -} -EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); - -#endif /* CONFIG_HAS_DMA */ - -/* ------------------------------------------------------------------------- */ - -/** - * usb_gadget_giveback_request - give the request back to the gadget layer - * Context: in_interrupt() - * - * This is called by device controller drivers in order to return the - * completed request back to the gadget layer. - */ -void usb_gadget_giveback_request(struct usb_ep *ep, - struct usb_request *req) -{ - if (likely(req->status == 0)) - usb_led_activity(USB_LED_EVENT_GADGET); - - req->complete(ep, req); -} -EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); - -/* ------------------------------------------------------------------------- */ - -/** - * gadget_find_ep_by_name - returns ep whose name is the same as sting passed - * in second parameter or NULL if searched endpoint not found - * @g: controller to check for quirk - * @name: name of searched endpoint - */ -struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name) -{ - struct usb_ep *ep; - - gadget_for_each_ep(ep, g) { - if (!strcmp(ep->name, name)) - return ep; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(gadget_find_ep_by_name); - -/* ------------------------------------------------------------------------- */ - -int usb_gadget_ep_match_desc(struct usb_gadget *gadget, - struct usb_ep *ep, struct usb_endpoint_descriptor *desc, - struct usb_ss_ep_comp_descriptor *ep_comp) -{ - u8 type; - u16 max; - int num_req_streams = 0; - - /* endpoint already claimed? */ - if (ep->claimed) - return 0; - - type = usb_endpoint_type(desc); - max = 0x7ff & usb_endpoint_maxp(desc); - - if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) - return 0; - if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) - return 0; - - if (max > ep->maxpacket_limit) - return 0; - - /* "high bandwidth" works only at high speed */ - if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) - return 0; - - switch (type) { - case USB_ENDPOINT_XFER_CONTROL: - /* only support ep0 for portable CONTROL traffic */ - return 0; - case USB_ENDPOINT_XFER_ISOC: - if (!ep->caps.type_iso) - return 0; - /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ - if (!gadget_is_dualspeed(gadget) && max > 1023) - return 0; - break; - case USB_ENDPOINT_XFER_BULK: - if (!ep->caps.type_bulk) - return 0; - if (ep_comp && gadget_is_superspeed(gadget)) { - /* Get the number of required streams from the - * EP companion descriptor and see if the EP - * matches it - */ - num_req_streams = ep_comp->bmAttributes & 0x1f; - if (num_req_streams > ep->max_streams) - return 0; - } - break; - case USB_ENDPOINT_XFER_INT: - /* Bulk endpoints handle interrupt transfers, - * except the toggle-quirky iso-synch kind - */ - if (!ep->caps.type_int && !ep->caps.type_bulk) - return 0; - /* INT: limit 64 bytes full speed, 1024 high/super speed */ - if (!gadget_is_dualspeed(gadget) && max > 64) - return 0; - break; - } - - return 1; -} -EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc); - -/* ------------------------------------------------------------------------- */ - -static void usb_gadget_state_work(struct work_struct *work) -{ - struct usb_gadget *gadget = work_to_gadget(work); - struct usb_udc *udc = gadget->udc; - - if (udc) - sysfs_notify(&udc->dev.kobj, NULL, "state"); -} - -void usb_gadget_set_state(struct usb_gadget *gadget, - enum usb_device_state state) -{ - gadget->state = state; - schedule_work(&gadget->work); -} -EXPORT_SYMBOL_GPL(usb_gadget_set_state); - -/* ------------------------------------------------------------------------- */ - -static void usb_udc_connect_control(struct usb_udc *udc) -{ - if (udc->vbus) - usb_gadget_connect(udc->gadget); - else - usb_gadget_disconnect(udc->gadget); -} - -/** - * usb_udc_vbus_handler - updates the udc core vbus status, and try to - * connect or disconnect gadget - * @gadget: The gadget which vbus change occurs - * @status: The vbus status - * - * The udc driver calls it when it wants to connect or disconnect gadget - * according to vbus status. - */ -void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status) -{ - struct usb_udc *udc = gadget->udc; - - if (udc) { - udc->vbus = status; - usb_udc_connect_control(udc); - } -} -EXPORT_SYMBOL_GPL(usb_udc_vbus_handler); - -/** - * usb_gadget_udc_reset - notifies the udc core that bus reset occurs - * @gadget: The gadget which bus reset occurs - * @driver: The gadget driver we want to notify - * - * If the udc driver has bus reset handler, it needs to call this when the bus - * reset occurs, it notifies the gadget driver that the bus reset occurs as - * well as updates gadget state. - */ -void usb_gadget_udc_reset(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - driver->reset(gadget); - usb_gadget_set_state(gadget, USB_STATE_DEFAULT); -} -EXPORT_SYMBOL_GPL(usb_gadget_udc_reset); - -/** - * usb_gadget_udc_start - tells usb device controller to start up - * @udc: The UDC to be started - * - * This call is issued by the UDC Class driver when it's about - * to register a gadget driver to the device controller, before - * calling gadget driver's bind() method. - * - * It allows the controller to be powered off until strictly - * necessary to have it powered on. - * - * Returns zero on success, else negative errno. - */ -static inline int usb_gadget_udc_start(struct usb_udc *udc) -{ - return udc->gadget->ops->udc_start(udc->gadget, udc->driver); -} - -/** - * usb_gadget_udc_stop - tells usb device controller we don't need it anymore - * @gadget: The device we want to stop activity - * @driver: The driver to unbind from @gadget - * - * This call is issued by the UDC Class driver after calling - * gadget driver's unbind() method. - * - * The details are implementation specific, but it can go as - * far as powering off UDC completely and disable its data - * line pullups. - */ -static inline void usb_gadget_udc_stop(struct usb_udc *udc) -{ - udc->gadget->ops->udc_stop(udc->gadget); -} - -/** - * usb_udc_release - release the usb_udc struct - * @dev: the dev member within usb_udc - * - * This is called by driver's core in order to free memory once the last - * reference is released. - */ -static void usb_udc_release(struct device *dev) -{ - struct usb_udc *udc; - - udc = container_of(dev, struct usb_udc, dev); - dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); - kfree(udc); -} - -static const struct attribute_group *usb_udc_attr_groups[]; - -static void usb_udc_nop_release(struct device *dev) -{ - dev_vdbg(dev, "%s\n", __func__); -} - -/** - * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list - * @parent: the parent device to this udc. Usually the controller driver's - * device. - * @gadget: the gadget to be added to the list. - * @release: a gadget release function. - * - * Returns zero on success, negative errno otherwise. - */ -int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, - void (*release)(struct device *dev)) -{ - struct usb_udc *udc; - struct usb_gadget_driver *driver; - int ret = -ENOMEM; - - udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (!udc) - goto err1; - - dev_set_name(&gadget->dev, "gadget"); - INIT_WORK(&gadget->work, usb_gadget_state_work); - gadget->dev.parent = parent; - - if (release) - gadget->dev.release = release; - else - gadget->dev.release = usb_udc_nop_release; - - ret = device_register(&gadget->dev); - if (ret) - goto err2; - - device_initialize(&udc->dev); - udc->dev.release = usb_udc_release; - udc->dev.class = udc_class; - udc->dev.groups = usb_udc_attr_groups; - udc->dev.parent = parent; - ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); - if (ret) - goto err3; - - udc->gadget = gadget; - gadget->udc = udc; - - mutex_lock(&udc_lock); - list_add_tail(&udc->list, &udc_list); - - ret = device_add(&udc->dev); - if (ret) - goto err4; - - usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); - udc->vbus = true; - - /* pick up one of pending gadget drivers */ - list_for_each_entry(driver, &gadget_driver_pending_list, pending) { - if (!driver->udc_name || strcmp(driver->udc_name, - dev_name(&udc->dev)) == 0) { - ret = udc_bind_to_driver(udc, driver); - if (ret != -EPROBE_DEFER) - list_del(&driver->pending); - if (ret) - goto err4; - break; - } - } - - mutex_unlock(&udc_lock); - - return 0; - -err4: - list_del(&udc->list); - mutex_unlock(&udc_lock); - -err3: - put_device(&udc->dev); - device_del(&gadget->dev); - -err2: - put_device(&gadget->dev); - kfree(udc); - -err1: - return ret; -} -EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); - -/** - * usb_get_gadget_udc_name - get the name of the first UDC controller - * This functions returns the name of the first UDC controller in the system. - * Please note that this interface is usefull only for legacy drivers which - * assume that there is only one UDC controller in the system and they need to - * get its name before initialization. There is no guarantee that the UDC - * of the returned name will be still available, when gadget driver registers - * itself. - * - * Returns pointer to string with UDC controller name on success, NULL - * otherwise. Caller should kfree() returned string. - */ -char *usb_get_gadget_udc_name(void) -{ - struct usb_udc *udc; - char *name = NULL; - - /* For now we take the first available UDC */ - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) { - if (!udc->driver) { - name = kstrdup(udc->gadget->name, GFP_KERNEL); - break; - } - } - mutex_unlock(&udc_lock); - return name; -} -EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name); - -/** - * usb_add_gadget_udc - adds a new gadget to the udc class driver list - * @parent: the parent device to this udc. Usually the controller - * driver's device. - * @gadget: the gadget to be added to the list - * - * Returns zero on success, negative errno otherwise. - */ -int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) -{ - return usb_add_gadget_udc_release(parent, gadget, NULL); -} -EXPORT_SYMBOL_GPL(usb_add_gadget_udc); - -static void usb_gadget_remove_driver(struct usb_udc *udc) -{ - dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", - udc->driver->function); - - kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - - usb_gadget_disconnect(udc->gadget); - udc->driver->disconnect(udc->gadget); - udc->driver->unbind(udc->gadget); - usb_gadget_udc_stop(udc); - - udc->driver = NULL; - udc->dev.driver = NULL; - udc->gadget->dev.driver = NULL; -} - -/** - * usb_del_gadget_udc - deletes @udc from udc_list - * @gadget: the gadget to be removed. - * - * This, will call usb_gadget_unregister_driver() if - * the @udc is still busy. - */ -void usb_del_gadget_udc(struct usb_gadget *gadget) -{ - struct usb_udc *udc = gadget->udc; - - if (!udc) - return; - - dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); - - mutex_lock(&udc_lock); - list_del(&udc->list); - - if (udc->driver) { - struct usb_gadget_driver *driver = udc->driver; - - usb_gadget_remove_driver(udc); - list_add(&driver->pending, &gadget_driver_pending_list); - } - mutex_unlock(&udc_lock); - - kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); - flush_work(&gadget->work); - device_unregister(&udc->dev); - device_unregister(&gadget->dev); -} -EXPORT_SYMBOL_GPL(usb_del_gadget_udc); - -/* ------------------------------------------------------------------------- */ - -static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver) -{ - int ret; - - dev_dbg(&udc->dev, "registering UDC driver [%s]\n", - driver->function); - - udc->driver = driver; - udc->dev.driver = &driver->driver; - udc->gadget->dev.driver = &driver->driver; - - ret = driver->bind(udc->gadget, driver); - if (ret) - goto err1; - ret = usb_gadget_udc_start(udc); - if (ret) { - driver->unbind(udc->gadget); - goto err1; - } - usb_udc_connect_control(udc); - - kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - return 0; -err1: - if (ret != -EISNAM) - dev_err(&udc->dev, "failed to start %s: %d\n", - udc->driver->function, ret); - udc->driver = NULL; - udc->dev.driver = NULL; - udc->gadget->dev.driver = NULL; - return ret; -} - -int usb_gadget_probe_driver(struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - if (!driver || !driver->bind || !driver->setup) - return -EINVAL; - - mutex_lock(&udc_lock); - if (driver->udc_name) { - list_for_each_entry(udc, &udc_list, list) { - ret = strcmp(driver->udc_name, dev_name(&udc->dev)); - if (!ret) - break; - } - if (!ret && !udc->driver) - goto found; - } else { - list_for_each_entry(udc, &udc_list, list) { - /* For now we take the first one */ - if (!udc->driver) - goto found; - } - } - - if (!driver->match_existing_only) { - list_add_tail(&driver->pending, &gadget_driver_pending_list); - pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n", - driver->function); - ret = 0; - } - - mutex_unlock(&udc_lock); - return ret; -found: - ret = udc_bind_to_driver(udc, driver); - mutex_unlock(&udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - if (!driver || !driver->unbind) - return -EINVAL; - - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) - if (udc->driver == driver) { - usb_gadget_remove_driver(udc); - usb_gadget_set_state(udc->gadget, - USB_STATE_NOTATTACHED); - ret = 0; - break; - } - - if (ret) { - list_del(&driver->pending); - ret = 0; - } - mutex_unlock(&udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); - -/* ------------------------------------------------------------------------- */ - -static ssize_t usb_udc_srp_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t n) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - - if (sysfs_streq(buf, "1")) - usb_gadget_wakeup(udc->gadget); - - return n; -} -static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store); - -static ssize_t usb_udc_softconn_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t n) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - - if (!udc->driver) { - dev_err(dev, "soft-connect without a gadget driver\n"); - return -EOPNOTSUPP; - } - - if (sysfs_streq(buf, "connect")) { - usb_gadget_udc_start(udc); - usb_gadget_connect(udc->gadget); - } else if (sysfs_streq(buf, "disconnect")) { - usb_gadget_disconnect(udc->gadget); - udc->driver->disconnect(udc->gadget); - usb_gadget_udc_stop(udc); - } else { - dev_err(dev, "unsupported command '%s'\n", buf); - return -EINVAL; - } - - return n; -} -static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); - -static ssize_t state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - struct usb_gadget *gadget = udc->gadget; - - return sprintf(buf, "%s\n", usb_state_string(gadget->state)); -} -static DEVICE_ATTR_RO(state); - -#define USB_UDC_SPEED_ATTR(name, param) \ -ssize_t name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ - return snprintf(buf, PAGE_SIZE, "%s\n", \ - usb_speed_string(udc->gadget->param)); \ -} \ -static DEVICE_ATTR_RO(name) - -static USB_UDC_SPEED_ATTR(current_speed, speed); -static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); - -#define USB_UDC_ATTR(name) \ -ssize_t name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ - struct usb_gadget *gadget = udc->gadget; \ - \ - return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \ -} \ -static DEVICE_ATTR_RO(name) - -static USB_UDC_ATTR(is_otg); -static USB_UDC_ATTR(is_a_peripheral); -static USB_UDC_ATTR(b_hnp_enable); -static USB_UDC_ATTR(a_hnp_support); -static USB_UDC_ATTR(a_alt_hnp_support); -static USB_UDC_ATTR(is_selfpowered); - -static struct attribute *usb_udc_attrs[] = { - &dev_attr_srp.attr, - &dev_attr_soft_connect.attr, - &dev_attr_state.attr, - &dev_attr_current_speed.attr, - &dev_attr_maximum_speed.attr, - - &dev_attr_is_otg.attr, - &dev_attr_is_a_peripheral.attr, - &dev_attr_b_hnp_enable.attr, - &dev_attr_a_hnp_support.attr, - &dev_attr_a_alt_hnp_support.attr, - &dev_attr_is_selfpowered.attr, - NULL, -}; - -static const struct attribute_group usb_udc_attr_group = { - .attrs = usb_udc_attrs, -}; - -static const struct attribute_group *usb_udc_attr_groups[] = { - &usb_udc_attr_group, - NULL, -}; - -static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - int ret; - - ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name); - if (ret) { - dev_err(dev, "failed to add uevent USB_UDC_NAME\n"); - return ret; - } - - if (udc->driver) { - ret = add_uevent_var(env, "USB_UDC_DRIVER=%s", - udc->driver->function); - if (ret) { - dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); - return ret; - } - } - - return 0; -} - -static int __init usb_udc_init(void) -{ - udc_class = class_create(THIS_MODULE, "udc"); - if (IS_ERR(udc_class)) { - pr_err("failed to create udc class --> %ld\n", - PTR_ERR(udc_class)); - return PTR_ERR(udc_class); - } - - udc_class->dev_uevent = usb_udc_uevent; - return 0; -} -subsys_initcall(usb_udc_init); - -static void __exit usb_udc_exit(void) -{ - class_destroy(udc_class); -} -module_exit(usb_udc_exit); - -MODULE_DESCRIPTION("UDC Framework"); -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index c6e1149ddb0d..612dbdfa388e 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -25,6 +25,8 @@ #include #include +#define UDC_TRACE_STR_MAX 512 + struct usb_ep; /** @@ -324,6 +326,7 @@ struct usb_gadget_ops { * @dev: Driver model state for this abstract device. * @out_epnum: last used out ep number * @in_epnum: last used in ep number + * @mA: last set mA value * @otg_caps: OTG capabilities of this gadget. * @sg_supported: true if we can handle scatter-gather * @is_otg: True if the USB device port uses a Mini-AB jack, so that the @@ -380,6 +383,7 @@ struct usb_gadget { struct device dev; unsigned out_epnum; unsigned in_epnum; + unsigned mA; struct usb_otg_caps *otg_caps; unsigned sg_supported:1; -- cgit v1.2.3 From df9b2b4a4aa49f874f8507680a533369e4b9c378 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 20 Jun 2016 12:09:41 +0200 Subject: mm/page_ref: introduce page_ref_inc_return Let's introduce that helper. Signed-off-by: David Hildenbrand Acked-by: Andrew Morton Signed-off-by: Christian Borntraeger --- include/linux/page_ref.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include/linux') diff --git a/include/linux/page_ref.h b/include/linux/page_ref.h index 8b5e0a9f2431..610e13271918 100644 --- a/include/linux/page_ref.h +++ b/include/linux/page_ref.h @@ -124,6 +124,15 @@ static inline int page_ref_sub_and_test(struct page *page, int nr) return ret; } +static inline int page_ref_inc_return(struct page *page) +{ + int ret = atomic_inc_return(&page->_refcount); + + if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_return)) + __page_ref_mod_and_return(page, 1, ret); + return ret; +} + static inline int page_ref_dec_and_test(struct page *page) { int ret = atomic_dec_and_test(&page->_refcount); -- cgit v1.2.3 From ce15ed4c5dfb3f7757e6611902aed5db253af977 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 10 Jun 2016 11:46:25 +0200 Subject: USB: Fix of_usb_get_dr_mode_by_phy with a shared phy block Some SoCs have a single phy-hw-block with multiple phys, this is modelled by a single phy dts node, so we end up with multiple controller nodes with a phys property pointing to the phy-node of the otg-phy. Only one of these controllers typically is an otg controller, yet we were checking the first controller who uses a phy from the block and then end up looking for a dr_mode property in e.g. the ehci controller. This commit fixes this by adding an arg0 parameter to of_usb_get_dr_mode_by_phy and make of_usb_get_dr_mode_by_phy check that this matches the phandle args[0] value when looking for the otg controller. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi --- drivers/usb/common/common.c | 26 ++++++++++++++++++++------ drivers/usb/phy/phy-am335x.c | 2 +- include/linux/usb/of.h | 4 ++-- 3 files changed, 23 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index e3d01619d6b3..5ef8da6e67c3 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -131,15 +131,17 @@ EXPORT_SYMBOL_GPL(usb_get_dr_mode); * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device * which is associated with the given phy device_node * @np: Pointer to the given phy device_node + * @arg0: phandle args[0] for phy's with #phy-cells >= 1, or -1 for + * phys which do not have phy-cells * * In dts a usb controller associates with phy devices. The function gets * the string from property 'dr_mode' of the controller associated with the * given phy device node, and returns the correspondig enum usb_dr_mode. */ -enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) { struct device_node *controller = NULL; - struct device_node *phy; + struct of_phandle_args args; const char *dr_mode; int index; int err; @@ -148,12 +150,24 @@ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np) controller = of_find_node_with_property(controller, "phys"); index = 0; do { - phy = of_parse_phandle(controller, "phys", index); - of_node_put(phy); - if (phy == phy_np) + if (arg0 == -1) { + args.np = of_parse_phandle(controller, "phys", + index); + args.args_count = 0; + } else { + err = of_parse_phandle_with_args(controller, + "phys", "#phy-cells", + index, &args); + if (err) + break; + } + + of_node_put(args.np); + if (args.np == np && (args.args_count == 0 || + args.args[0] == arg0)) goto finish; index++; - } while (phy); + } while (args.np); } while (controller); finish: diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index a262a4343f29..7e5aece769da 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -54,7 +54,7 @@ static int am335x_phy_probe(struct platform_device *pdev) return am_phy->id; } - am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node); + am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1); ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL); if (ret) diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index de3237fce6b2..5ff9032ee1b4 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -12,7 +12,7 @@ #include #if IS_ENABLED(CONFIG_OF) -enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np); +enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0); bool of_usb_host_tpl_support(struct device_node *np); int of_usb_update_otg_caps(struct device_node *np, struct usb_otg_caps *otg_caps); @@ -20,7 +20,7 @@ struct device_node *usb_of_get_child_node(struct device_node *parent, int portnum); #else static inline enum usb_dr_mode -of_usb_get_dr_mode_by_phy(struct device_node *phy_np) +of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) { return USB_DR_MODE_UNKNOWN; } -- cgit v1.2.3 From b9b092319be29bf665f1b004679de722b81c9123 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 May 2016 23:24:06 +0200 Subject: usb: phy: move msm_hsusb.h into driver As a preparation for another cleanup, this moves the header file for the phy-msm-usb driver into the driver itself. No other file includes it any more, and we don't really want it in the global namespace anyway. Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-msm-usb.c | 178 ++++++++++++++++++++++++++++++++++++- include/linux/usb/msm_hsusb.h | 200 ------------------------------------------ 2 files changed, 177 insertions(+), 201 deletions(-) delete mode 100644 include/linux/usb/msm_hsusb.h (limited to 'include/linux') diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 72b387d592c2..8a34759727bb 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -42,10 +45,183 @@ #include #include #include -#include #include #include +/** + * OTG control + * + * OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host + * only configuration. + * OTG_PHY_CONTROL Id/VBUS notifications comes form USB PHY. + * OTG_PMIC_CONTROL Id/VBUS notifications comes from PMIC hardware. + * OTG_USER_CONTROL Id/VBUS notifcations comes from User via sysfs. + * + */ +enum otg_control_type { + OTG_NO_CONTROL = 0, + OTG_PHY_CONTROL, + OTG_PMIC_CONTROL, + OTG_USER_CONTROL, +}; + +/** + * PHY used in + * + * INVALID_PHY Unsupported PHY + * CI_45NM_INTEGRATED_PHY Chipidea 45nm integrated PHY + * SNPS_28NM_INTEGRATED_PHY Synopsis 28nm integrated PHY + * + */ +enum msm_usb_phy_type { + INVALID_PHY = 0, + CI_45NM_INTEGRATED_PHY, + SNPS_28NM_INTEGRATED_PHY, +}; + +#define IDEV_CHG_MAX 1500 +#define IUNIT 100 + +/** + * Different states involved in USB charger detection. + * + * USB_CHG_STATE_UNDEFINED USB charger is not connected or detection + * process is not yet started. + * USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact. + * USB_CHG_STATE_DCD_DONE Data pin contact is detected. + * USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects + * between SDP and DCP/CDP). + * USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects + * between DCP and CDP). + * USB_CHG_STATE_DETECTED USB charger type is determined. + * + */ +enum usb_chg_state { + USB_CHG_STATE_UNDEFINED = 0, + USB_CHG_STATE_WAIT_FOR_DCD, + USB_CHG_STATE_DCD_DONE, + USB_CHG_STATE_PRIMARY_DONE, + USB_CHG_STATE_SECONDARY_DONE, + USB_CHG_STATE_DETECTED, +}; + +/** + * USB charger types + * + * USB_INVALID_CHARGER Invalid USB charger. + * USB_SDP_CHARGER Standard downstream port. Refers to a downstream port + * on USB2.0 compliant host/hub. + * USB_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger). + * USB_CDP_CHARGER Charging downstream port. Enumeration can happen and + * IDEV_CHG_MAX can be drawn irrespective of USB state. + * + */ +enum usb_chg_type { + USB_INVALID_CHARGER = 0, + USB_SDP_CHARGER, + USB_DCP_CHARGER, + USB_CDP_CHARGER, +}; + +/** + * struct msm_otg_platform_data - platform device data + * for msm_otg driver. + * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as + * "do not overwrite default vaule at this address". + * @phy_init_sz: PHY configuration sequence size. + * @vbus_power: VBUS power on/off routine. + * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). + * @mode: Supported mode (OTG/peripheral/host). + * @otg_control: OTG switch controlled by user/Id pin + */ +struct msm_otg_platform_data { + int *phy_init_seq; + int phy_init_sz; + void (*vbus_power)(bool on); + unsigned power_budget; + enum usb_dr_mode mode; + enum otg_control_type otg_control; + enum msm_usb_phy_type phy_type; + void (*setup_gpio)(enum usb_otg_state state); +}; + +/** + * struct msm_usb_cable - structure for exteternal connector cable + * state tracking + * @nb: hold event notification callback + * @conn: used for notification registration + */ +struct msm_usb_cable { + struct notifier_block nb; + struct extcon_dev *extcon; +}; + +/** + * struct msm_otg: OTG driver data. Shared by HCD and DCD. + * @otg: USB OTG Transceiver structure. + * @pdata: otg device platform data. + * @irq: IRQ number assigned for HSUSB controller. + * @clk: clock struct of usb_hs_clk. + * @pclk: clock struct of usb_hs_pclk. + * @core_clk: clock struct of usb_hs_core_clk. + * @regs: ioremapped register base address. + * @inputs: OTG state machine inputs(Id, SessValid etc). + * @sm_work: OTG state machine work. + * @in_lpm: indicates low power mode (LPM) state. + * @async_int: Async interrupt arrived. + * @cur_power: The amount of mA available from downstream port. + * @chg_work: Charger detection work. + * @chg_state: The state of charger detection process. + * @chg_type: The type of charger attached. + * @dcd_retires: The retry count used to track Data contact + * detection process. + * @manual_pullup: true if VBUS is not routed to USB controller/phy + * and controller driver therefore enables pull-up explicitly before + * starting controller using usbcmd run/stop bit. + * @vbus: VBUS signal state trakining, using extcon framework + * @id: ID signal state trakining, using extcon framework + * @switch_gpio: Descriptor for GPIO used to control external Dual + * SPDT USB Switch. + * @reboot: Used to inform the driver to route USB D+/D- line to Device + * connector + */ +struct msm_otg { + struct usb_phy phy; + struct msm_otg_platform_data *pdata; + int irq; + struct clk *clk; + struct clk *pclk; + struct clk *core_clk; + void __iomem *regs; +#define ID 0 +#define B_SESS_VLD 1 + unsigned long inputs; + struct work_struct sm_work; + atomic_t in_lpm; + int async_int; + unsigned cur_power; + int phy_number; + struct delayed_work chg_work; + enum usb_chg_state chg_state; + enum usb_chg_type chg_type; + u8 dcd_retries; + struct regulator *v3p3; + struct regulator *v1p8; + struct regulator *vddcx; + + struct reset_control *phy_rst; + struct reset_control *link_rst; + int vdd_levels[3]; + + bool manual_pullup; + + struct msm_usb_cable vbus; + struct msm_usb_cable id; + + struct gpio_desc *switch_gpio; + struct notifier_block reboot; +}; + #define MSM_USB_BASE (motg->regs) #define DRIVER_NAME "msm_otg" diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h deleted file mode 100644 index 8c8f6854c993..000000000000 --- a/include/linux/usb/msm_hsusb.h +++ /dev/null @@ -1,200 +0,0 @@ -/* linux/include/asm-arm/arch-msm/hsusb.h - * - * Copyright (C) 2008 Google, Inc. - * Author: Brian Swetland - * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __ASM_ARCH_MSM_HSUSB_H -#define __ASM_ARCH_MSM_HSUSB_H - -#include -#include -#include -#include - -/** - * OTG control - * - * OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host - * only configuration. - * OTG_PHY_CONTROL Id/VBUS notifications comes form USB PHY. - * OTG_PMIC_CONTROL Id/VBUS notifications comes from PMIC hardware. - * OTG_USER_CONTROL Id/VBUS notifcations comes from User via sysfs. - * - */ -enum otg_control_type { - OTG_NO_CONTROL = 0, - OTG_PHY_CONTROL, - OTG_PMIC_CONTROL, - OTG_USER_CONTROL, -}; - -/** - * PHY used in - * - * INVALID_PHY Unsupported PHY - * CI_45NM_INTEGRATED_PHY Chipidea 45nm integrated PHY - * SNPS_28NM_INTEGRATED_PHY Synopsis 28nm integrated PHY - * - */ -enum msm_usb_phy_type { - INVALID_PHY = 0, - CI_45NM_INTEGRATED_PHY, - SNPS_28NM_INTEGRATED_PHY, -}; - -#define IDEV_CHG_MAX 1500 -#define IUNIT 100 - -/** - * Different states involved in USB charger detection. - * - * USB_CHG_STATE_UNDEFINED USB charger is not connected or detection - * process is not yet started. - * USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact. - * USB_CHG_STATE_DCD_DONE Data pin contact is detected. - * USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects - * between SDP and DCP/CDP). - * USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects - * between DCP and CDP). - * USB_CHG_STATE_DETECTED USB charger type is determined. - * - */ -enum usb_chg_state { - USB_CHG_STATE_UNDEFINED = 0, - USB_CHG_STATE_WAIT_FOR_DCD, - USB_CHG_STATE_DCD_DONE, - USB_CHG_STATE_PRIMARY_DONE, - USB_CHG_STATE_SECONDARY_DONE, - USB_CHG_STATE_DETECTED, -}; - -/** - * USB charger types - * - * USB_INVALID_CHARGER Invalid USB charger. - * USB_SDP_CHARGER Standard downstream port. Refers to a downstream port - * on USB2.0 compliant host/hub. - * USB_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger). - * USB_CDP_CHARGER Charging downstream port. Enumeration can happen and - * IDEV_CHG_MAX can be drawn irrespective of USB state. - * - */ -enum usb_chg_type { - USB_INVALID_CHARGER = 0, - USB_SDP_CHARGER, - USB_DCP_CHARGER, - USB_CDP_CHARGER, -}; - -/** - * struct msm_otg_platform_data - platform device data - * for msm_otg driver. - * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as - * "do not overwrite default vaule at this address". - * @phy_init_sz: PHY configuration sequence size. - * @vbus_power: VBUS power on/off routine. - * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). - * @mode: Supported mode (OTG/peripheral/host). - * @otg_control: OTG switch controlled by user/Id pin - */ -struct msm_otg_platform_data { - int *phy_init_seq; - int phy_init_sz; - void (*vbus_power)(bool on); - unsigned power_budget; - enum usb_dr_mode mode; - enum otg_control_type otg_control; - enum msm_usb_phy_type phy_type; - void (*setup_gpio)(enum usb_otg_state state); -}; - -/** - * struct msm_usb_cable - structure for exteternal connector cable - * state tracking - * @nb: hold event notification callback - * @conn: used for notification registration - */ -struct msm_usb_cable { - struct notifier_block nb; - struct extcon_dev *extcon; -}; - -/** - * struct msm_otg: OTG driver data. Shared by HCD and DCD. - * @otg: USB OTG Transceiver structure. - * @pdata: otg device platform data. - * @irq: IRQ number assigned for HSUSB controller. - * @clk: clock struct of usb_hs_clk. - * @pclk: clock struct of usb_hs_pclk. - * @core_clk: clock struct of usb_hs_core_clk. - * @regs: ioremapped register base address. - * @inputs: OTG state machine inputs(Id, SessValid etc). - * @sm_work: OTG state machine work. - * @in_lpm: indicates low power mode (LPM) state. - * @async_int: Async interrupt arrived. - * @cur_power: The amount of mA available from downstream port. - * @chg_work: Charger detection work. - * @chg_state: The state of charger detection process. - * @chg_type: The type of charger attached. - * @dcd_retires: The retry count used to track Data contact - * detection process. - * @manual_pullup: true if VBUS is not routed to USB controller/phy - * and controller driver therefore enables pull-up explicitly before - * starting controller using usbcmd run/stop bit. - * @vbus: VBUS signal state trakining, using extcon framework - * @id: ID signal state trakining, using extcon framework - * @switch_gpio: Descriptor for GPIO used to control external Dual - * SPDT USB Switch. - * @reboot: Used to inform the driver to route USB D+/D- line to Device - * connector - */ -struct msm_otg { - struct usb_phy phy; - struct msm_otg_platform_data *pdata; - int irq; - struct clk *clk; - struct clk *pclk; - struct clk *core_clk; - void __iomem *regs; -#define ID 0 -#define B_SESS_VLD 1 - unsigned long inputs; - struct work_struct sm_work; - atomic_t in_lpm; - int async_int; - unsigned cur_power; - int phy_number; - struct delayed_work chg_work; - enum usb_chg_state chg_state; - enum usb_chg_type chg_type; - u8 dcd_retries; - struct regulator *v3p3; - struct regulator *v1p8; - struct regulator *vddcx; - - struct reset_control *phy_rst; - struct reset_control *link_rst; - int vdd_levels[3]; - - bool manual_pullup; - - struct msm_usb_cable vbus; - struct msm_usb_cable id; - - struct gpio_desc *switch_gpio; - struct notifier_block reboot; -}; - -#endif -- cgit v1.2.3 From 37a441dcd5f4db7f769fee50ba7a2c602903a052 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 20 Apr 2016 14:05:14 +0100 Subject: firmware: arm_scpi: add support for device power state management SCPI protocol supports device power state management. This deals with power states of various peripheral devices in the system other than the core compute subsystem. This patch adds support for the power state management of those peripheral devices. Tested-by: Mathieu Poirier Tested-by: Jon Medhurst Reviewed-by: Jon Medhurst Reviewed-by: Kevin Hilman Reviewed-by: Ulf Hansson Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scpi.c | 30 ++++++++++++++++++++++++++++++ include/linux/scpi_protocol.h | 2 ++ 2 files changed, 32 insertions(+) (limited to 'include/linux') diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 51c6db0774cc..438893762076 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -231,6 +231,11 @@ struct sensor_value { __le32 hi_val; } __packed; +struct dev_pstate_set { + u16 dev_id; + u8 pstate; +} __packed; + static struct scpi_drvinfo *scpi_info; static int scpi_linux_errmap[SCPI_ERR_MAX] = { @@ -537,6 +542,29 @@ static int scpi_sensor_get_value(u16 sensor, u64 *val) return ret; } +static int scpi_device_get_power_state(u16 dev_id) +{ + int ret; + u8 pstate; + __le16 id = cpu_to_le16(dev_id); + + ret = scpi_send_message(SCPI_CMD_GET_DEVICE_PWR_STATE, &id, + sizeof(id), &pstate, sizeof(pstate)); + return ret ? ret : pstate; +} + +static int scpi_device_set_power_state(u16 dev_id, u8 pstate) +{ + int stat; + struct dev_pstate_set dev_set = { + .dev_id = cpu_to_le16(dev_id), + .pstate = pstate, + }; + + return scpi_send_message(SCPI_CMD_SET_DEVICE_PWR_STATE, &dev_set, + sizeof(dev_set), &stat, sizeof(stat)); +} + static struct scpi_ops scpi_ops = { .get_version = scpi_get_version, .clk_get_range = scpi_clk_get_range, @@ -548,6 +576,8 @@ static struct scpi_ops scpi_ops = { .sensor_get_capability = scpi_sensor_get_capability, .sensor_get_info = scpi_sensor_get_info, .sensor_get_value = scpi_sensor_get_value, + .device_get_power_state = scpi_device_get_power_state, + .device_set_power_state = scpi_device_set_power_state, }; struct scpi_ops *get_scpi_ops(void) diff --git a/include/linux/scpi_protocol.h b/include/linux/scpi_protocol.h index 35de50a65665..dc5f989be226 100644 --- a/include/linux/scpi_protocol.h +++ b/include/linux/scpi_protocol.h @@ -70,6 +70,8 @@ struct scpi_ops { int (*sensor_get_capability)(u16 *sensors); int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *); int (*sensor_get_value)(u16, u64 *); + int (*device_get_power_state)(u16); + int (*device_set_power_state)(u16, u8); }; #if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL) -- cgit v1.2.3 From be9d2e8927cef02076bb7b5b2637cd9f4be2e8df Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Tue, 7 Jun 2016 09:44:01 +0200 Subject: PCI: Add helpers to request/release memory and I/O regions Add helpers to request and release a device's memory or I/O regions. With these helpers in place, one does not need to select a device's memory or I/O regions with pci_select_bars() prior to requesting or releasing them. Suggested-by: Christoph Hellwig Signed-off-by: Johannes Thumshirn Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig --- include/linux/pci.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 9c201d4dbd51..6af3b93f0710 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1402,6 +1402,34 @@ typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode, unsigned int command_bits, u32 flags); void pci_register_set_vga_state(arch_set_vga_state_t func); +static inline int +pci_request_io_regions(struct pci_dev *pdev, const char *name) +{ + return pci_request_selected_regions(pdev, + pci_select_bars(pdev, IORESOURCE_IO), name); +} + +static inline void +pci_release_io_regions(struct pci_dev *pdev) +{ + return pci_release_selected_regions(pdev, + pci_select_bars(pdev, IORESOURCE_IO)); +} + +static inline int +pci_request_mem_regions(struct pci_dev *pdev, const char *name) +{ + return pci_request_selected_regions(pdev, + pci_select_bars(pdev, IORESOURCE_MEM), name); +} + +static inline void +pci_release_mem_regions(struct pci_dev *pdev) +{ + return pci_release_selected_regions(pdev, + pci_select_bars(pdev, IORESOURCE_MEM)); +} + #else /* CONFIG_PCI is not enabled */ static inline void pci_set_flags(int flags) { } -- cgit v1.2.3 From da3d3f98d28bc071a2d566aefc8c461bd564be35 Mon Sep 17 00:00:00 2001 From: Aleksey Makarov Date: Mon, 20 Jun 2016 13:56:10 +0300 Subject: ACPI / tables: table upgrade: refactor function definitions Refer initrd_start, initrd_end directly from drivers/acpi/tables.c. This allows to use the table upgrade feature in architectures other than x86. Also this simplifies header files. The patch renames acpi_table_initrd_init() to acpi_table_upgrade() (what reflects the purpose of the function) and removes the unneeded wraps early_acpi_table_init() and early_initrd_acpi_init(). Signed-off-by: Aleksey Makarov Acked-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/setup.c | 9 +-------- drivers/acpi/tables.c | 14 ++++---------- include/linux/acpi.h | 8 ++++++-- 3 files changed, 11 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index c4e7b3991b60..aac91beabf05 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -399,10 +399,6 @@ static void __init reserve_initrd(void) memblock_free(ramdisk_image, ramdisk_end - ramdisk_image); } -static void __init early_initrd_acpi_init(void) -{ - early_acpi_table_init((void *)initrd_start, initrd_end - initrd_start); -} #else static void __init early_reserve_initrd(void) { @@ -410,9 +406,6 @@ static void __init early_reserve_initrd(void) static void __init reserve_initrd(void) { } -static void __init early_initrd_acpi_init(void) -{ -} #endif /* CONFIG_BLK_DEV_INITRD */ static void __init parse_setup_data(void) @@ -1146,7 +1139,7 @@ void __init setup_arch(char **cmdline_p) reserve_initrd(); - early_initrd_acpi_init(); + acpi_table_upgrade(); vsmp_init(); diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index f829e6a2e663..b05df13bd79f 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "internal.h" #ifdef CONFIG_ACPI_CUSTOM_DSDT @@ -481,8 +482,10 @@ static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES); #define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) -static void __init acpi_table_initrd_init(void *data, size_t size) +void __init acpi_table_upgrade(void) { + void *data = (void *)initrd_start; + size_t size = initrd_end - initrd_start; int sig, no, table_nr = 0, total_offset = 0; long offset = 0; struct acpi_table_header *table; @@ -696,10 +699,6 @@ next_table: } } #else -static void __init acpi_table_initrd_init(void *data, size_t size) -{ -} - static acpi_status acpi_table_initrd_override(struct acpi_table_header *existing_table, acpi_physical_address *address, @@ -742,11 +741,6 @@ acpi_os_table_override(struct acpi_table_header *existing_table, return AE_OK; } -void __init early_acpi_table_init(void *data, size_t size) -{ - acpi_table_initrd_init(data, size); -} - /* * acpi_table_init() * diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 288fac5294f5..ef2ad26abede 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -208,7 +208,6 @@ void acpi_boot_table_init (void); int acpi_mps_check (void); int acpi_numa_init (void); -void early_acpi_table_init(void *data, size_t size); int acpi_table_init (void); int acpi_table_parse(char *id, acpi_tbl_table_handler handler); int __init acpi_parse_entries(char *id, unsigned long table_size, @@ -588,7 +587,6 @@ static inline const char *acpi_dev_name(struct acpi_device *adev) return NULL; } -static inline void early_acpi_table_init(void *data, size_t size) { } static inline void acpi_early_init(void) { } static inline void acpi_subsystem_init(void) { } @@ -997,4 +995,10 @@ static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev, #define acpi_probe_device_table(t) ({ int __r = 0; __r;}) #endif +#ifdef CONFIG_ACPI_TABLE_UPGRADE +void acpi_table_upgrade(void); +#else +static inline void acpi_table_upgrade(void) { } +#endif + #endif /*_LINUX_ACPI_H*/ -- cgit v1.2.3 From 4bac6fa73db77d4ff49a965a7c6dc69d9e235e5f Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Fri, 17 Jun 2016 11:53:02 +0800 Subject: ACPI / NUMA: Enable ACPI based NUMA on ARM64 Add function needed for cpu to node mapping, and enable ACPI based NUMA for ARM64 in Kconfig Signed-off-by: Hanjun Guo Signed-off-by: Robert Richter [david.daney@cavium.com added ACPI_NUMA default to y for ARM64] Signed-off-by: David Daney Acked-by: Catalin Marinas Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 4 ++-- drivers/acpi/numa.c | 37 ++++++++++++++++++++++++++++++++++++- include/linux/acpi.h | 17 ++++++++++++++++- 3 files changed, 54 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index b7e2e776397d..dd76b36c431f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -291,8 +291,8 @@ config ACPI_THERMAL config ACPI_NUMA bool "NUMA support" depends on NUMA - depends on (X86 || IA64) - default y if IA64_GENERIC || IA64_SGI_SN2 + depends on (X86 || IA64 || ARM64) + default y if IA64_GENERIC || IA64_SGI_SN2 || ARM64 config ACPI_CUSTOM_DSDT_FILE string "Custom DSDT Table file to include" diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index fad6d288117f..ce3a7a16f03f 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -170,6 +170,18 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header) } break; + case ACPI_SRAT_TYPE_GICC_AFFINITY: + { + struct acpi_srat_gicc_affinity *p = + (struct acpi_srat_gicc_affinity *)header; + pr_debug("SRAT Processor (acpi id[0x%04x]) in proximity domain %d %s\n", + p->acpi_processor_uid, + p->proximity_domain, + (p->flags & ACPI_SRAT_GICC_ENABLED) ? + "enabled" : "disabled"); + } + break; + default: pr_warn("Found unsupported SRAT entry (type = 0x%x)\n", header->type); @@ -360,6 +372,24 @@ acpi_parse_processor_affinity(struct acpi_subtable_header *header, return 0; } +static int __init +acpi_parse_gicc_affinity(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_srat_gicc_affinity *processor_affinity; + + processor_affinity = (struct acpi_srat_gicc_affinity *)header; + if (!processor_affinity) + return -EINVAL; + + acpi_table_print_srat_entry(header); + + /* let architecture-dependent part to do it */ + acpi_numa_gicc_affinity_init(processor_affinity); + + return 0; +} + static int __initdata parsed_numa_memblks; static int __init @@ -404,6 +434,9 @@ int __init acpi_numa_init(void) { int cnt = 0; + if (acpi_disabled) + return -EINVAL; + /* * Should not limit number with cpu num that is from NR_CPUS or nr_cpus= * SRAT cpu entries could have different order with that in MADT. @@ -412,13 +445,15 @@ int __init acpi_numa_init(void) /* SRAT: Static Resource Affinity Table */ if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { - struct acpi_subtable_proc srat_proc[2]; + struct acpi_subtable_proc srat_proc[3]; memset(srat_proc, 0, sizeof(srat_proc)); srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY; srat_proc[0].handler = acpi_parse_processor_affinity; srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY; srat_proc[1].handler = acpi_parse_x2apic_affinity; + srat_proc[2].id = ACPI_SRAT_TYPE_GICC_AFFINITY; + srat_proc[2].handler = acpi_parse_gicc_affinity; acpi_table_parse_entries_array(ACPI_SIG_SRAT, sizeof(struct acpi_table_srat), diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 8010b266e856..9515db6f03f0 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -232,10 +232,25 @@ int acpi_table_parse_madt(enum acpi_madt_type id, int acpi_parse_mcfg (struct acpi_table_header *header); void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); -/* the following four functions are architecture-dependent */ +/* the following numa functions are architecture-dependent */ void acpi_numa_slit_init (struct acpi_table_slit *slit); + +#if defined(CONFIG_X86) || defined(CONFIG_IA64) void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); +#else +static inline void +acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) { } +#endif + void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa); + +#ifdef CONFIG_ARM64 +void acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa); +#else +static inline void +acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa) { } +#endif + int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); #ifndef PHYS_CPUID_INVALID -- cgit v1.2.3 From cc8feb8edd92d854be552fe4f5e0eeabca40b9ee Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 4 Apr 2016 14:00:37 +0100 Subject: rxrpc: Fix exclusive connection handling "Exclusive connections" are meant to be used for a single client call and then scrapped. The idea is to limit the use of the negotiated security context. The current code, however, isn't doing this: it is instead restricting the socket to a single virtual connection and doing all the calls over that. This is changed such that the socket no longer maintains a special virtual connection over which it will do all the calls, but rather gets a new one each time a new exclusive call is made. Further, using a socket option for this is a poor choice. It should be done on sendmsg with a control message marker instead so that calls can be marked exclusive individually. To that end, add RXRPC_EXCLUSIVE_CALL which, if passed to sendmsg() as a control message element, will cause the call to be done on an single-use connection. The socket option (RXRPC_EXCLUSIVE_CONNECTION) still exists and, if set, will override any lack of RXRPC_EXCLUSIVE_CALL being specified so that programs using the setsockopt() will appear to work the same. Signed-off-by: David Howells --- include/linux/rxrpc.h | 3 +- net/rxrpc/af_rxrpc.c | 7 +--- net/rxrpc/ar-internal.h | 7 ++-- net/rxrpc/conn_object.c | 97 ++++++++++++++++++++----------------------------- net/rxrpc/output.c | 19 +++++++--- 5 files changed, 60 insertions(+), 73 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rxrpc.h b/include/linux/rxrpc.h index 1e8f216e2cf1..c68307bc306f 100644 --- a/include/linux/rxrpc.h +++ b/include/linux/rxrpc.h @@ -35,7 +35,7 @@ struct sockaddr_rxrpc { */ #define RXRPC_SECURITY_KEY 1 /* [clnt] set client security key */ #define RXRPC_SECURITY_KEYRING 2 /* [srvr] set ring of server security keys */ -#define RXRPC_EXCLUSIVE_CONNECTION 3 /* [clnt] use exclusive RxRPC connection */ +#define RXRPC_EXCLUSIVE_CONNECTION 3 /* Deprecated; use RXRPC_EXCLUSIVE_CALL instead */ #define RXRPC_MIN_SECURITY_LEVEL 4 /* minimum security level */ /* @@ -52,6 +52,7 @@ struct sockaddr_rxrpc { #define RXRPC_LOCAL_ERROR 7 /* -r: local error generated [terminal] */ #define RXRPC_NEW_CALL 8 /* -r: [Service] new incoming call notification */ #define RXRPC_ACCEPT 9 /* s-: [Service] accept request */ +#define RXRPC_EXCLUSIVE_CALL 10 /* s-: Call should be on exclusive connection */ /* * RxRPC security levels diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 48b45a0280c0..73f5c553eef4 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -494,7 +494,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname, ret = -EISCONN; if (rx->sk.sk_state != RXRPC_UNBOUND) goto error; - set_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags); + rx->exclusive = true; goto success; case RXRPC_SECURITY_KEY: @@ -669,11 +669,6 @@ static int rxrpc_release_sock(struct sock *sk) flush_workqueue(rxrpc_workqueue); rxrpc_purge_queue(&sk->sk_receive_queue); - if (rx->conn) { - rxrpc_put_connection(rx->conn); - rx->conn = NULL; - } - if (rx->local) { rxrpc_put_local(rx->local); rx->local = NULL; diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index efe6673deb28..4ca99445e0b7 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -37,6 +37,8 @@ struct rxrpc_crypt { #define rxrpc_queue_call(CALL) rxrpc_queue_work(&(CALL)->processor) #define rxrpc_queue_conn(CONN) rxrpc_queue_work(&(CONN)->processor) +struct rxrpc_connection; + /* * sk_state for RxRPC sockets */ @@ -57,7 +59,6 @@ struct rxrpc_sock { struct sock sk; rxrpc_interceptor_t interceptor; /* kernel service Rx interceptor function */ struct rxrpc_local *local; /* local endpoint */ - struct rxrpc_connection *conn; /* exclusive virtual connection */ struct list_head listen_link; /* link in the local endpoint's listen list */ struct list_head secureq; /* calls awaiting connection security clearance */ struct list_head acceptq; /* calls awaiting acceptance */ @@ -66,13 +67,13 @@ struct rxrpc_sock { struct rb_root calls; /* outstanding calls on this socket */ unsigned long flags; #define RXRPC_SOCK_CONNECTED 0 /* connect_srx is set */ -#define RXRPC_SOCK_EXCLUSIVE_CONN 1 /* exclusive connection for a client socket */ rwlock_t call_lock; /* lock for calls */ u32 min_sec_level; /* minimum security level */ #define RXRPC_SECURITY_MAX RXRPC_SECURITY_ENCRYPT + bool exclusive; /* Exclusive connection for a client socket */ + sa_family_t family; /* Protocol family created with */ struct sockaddr_rxrpc srx; /* local address */ struct sockaddr_rxrpc connect_srx; /* Default client address from connect() */ - sa_family_t family; /* protocol family created with */ }; #define rxrpc_sk(__sk) container_of((__sk), struct rxrpc_sock, sk) diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index c6787b6f459f..6164373d6ce3 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -328,71 +328,57 @@ static int rxrpc_connect_exclusive(struct rxrpc_sock *rx, _enter(""); - conn = rx->conn; + conn = rxrpc_alloc_connection(gfp); if (!conn) { - /* not yet present - create a candidate for a new connection - * and then redo the check */ - conn = rxrpc_alloc_connection(gfp); - if (!conn) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } + _leave(" = -ENOMEM"); + return -ENOMEM; + } - conn->trans = trans; - conn->bundle = NULL; - conn->params = *cp; - conn->proto.local = cp->local; - conn->proto.epoch = rxrpc_epoch; - conn->proto.cid = 0; - conn->proto.in_clientflag = 0; - conn->proto.family = cp->peer->srx.transport.family; - conn->out_clientflag = RXRPC_CLIENT_INITIATED; - conn->state = RXRPC_CONN_CLIENT; - conn->avail_calls = RXRPC_MAXCALLS - 1; - - key_get(conn->params.key); - - ret = rxrpc_init_client_conn_security(conn); - if (ret < 0) { - key_put(conn->params.key); - kfree(conn); - _leave(" = %d [key]", ret); - return ret; - } + conn->trans = trans; + conn->bundle = NULL; + conn->params = *cp; + conn->proto.local = cp->local; + conn->proto.epoch = rxrpc_epoch; + conn->proto.cid = 0; + conn->proto.in_clientflag = 0; + conn->proto.family = cp->peer->srx.transport.family; + conn->out_clientflag = RXRPC_CLIENT_INITIATED; + conn->state = RXRPC_CONN_CLIENT; + conn->avail_calls = RXRPC_MAXCALLS - 1; + + key_get(conn->params.key); + + ret = rxrpc_init_client_conn_security(conn); + if (ret < 0) { + key_put(conn->params.key); + kfree(conn); + _leave(" = %d [key]", ret); + return ret; + } - write_lock_bh(&rxrpc_connection_lock); - list_add_tail(&conn->link, &rxrpc_connections); - write_unlock_bh(&rxrpc_connection_lock); + write_lock_bh(&rxrpc_connection_lock); + list_add_tail(&conn->link, &rxrpc_connections); + write_unlock_bh(&rxrpc_connection_lock); - spin_lock(&trans->client_lock); - atomic_inc(&trans->usage); + spin_lock(&trans->client_lock); + atomic_inc(&trans->usage); - _net("CONNECT EXCL new %d on TRANS %d", - conn->debug_id, conn->trans->debug_id); + _net("CONNECT EXCL new %d on TRANS %d", + conn->debug_id, conn->trans->debug_id); - rxrpc_assign_connection_id(conn); - rx->conn = conn; - } else { - spin_lock(&trans->client_lock); - } + rxrpc_assign_connection_id(conn); - /* we've got a connection with a free channel and we can now attach the - * call to it - * - we're holding the transport's client lock - * - we're holding a reference on the connection + /* Since no one else can use the connection, we just use the first + * channel. */ - for (chan = 0; chan < RXRPC_MAXCALLS; chan++) - if (!conn->channels[chan]) - goto found_channel; - goto no_free_channels; - -found_channel: + chan = 0; atomic_inc(&conn->usage); conn->channels[chan] = call; + conn->call_counter = 1; call->conn = conn; call->channel = chan; call->cid = conn->proto.cid | chan; - call->call_id = ++conn->call_counter; + call->call_id = 1; _net("CONNECT client on conn %d chan %d as call %x", conn->debug_id, chan, call->call_id); @@ -402,11 +388,6 @@ found_channel: rxrpc_add_call_ID_to_conn(conn, call); _leave(" = 0"); return 0; - -no_free_channels: - spin_unlock(&trans->client_lock); - _leave(" = -ENOSR"); - return -ENOSR; } /* @@ -427,7 +408,7 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, _enter("%p,%lx,", rx, call->user_call_ID); - if (test_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags)) + if (cp->exclusive) return rxrpc_connect_exclusive(rx, cp, trans, call, gfp); spin_lock(&trans->client_lock); diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index becbaa7c0a7c..6f8ab0ef839f 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -35,7 +35,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, static int rxrpc_sendmsg_cmsg(struct msghdr *msg, unsigned long *user_call_ID, enum rxrpc_command *command, - u32 *abort_code) + u32 *abort_code, + bool *_exclusive) { struct cmsghdr *cmsg; bool got_user_ID = false; @@ -93,6 +94,11 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg, return -EINVAL; break; + case RXRPC_EXCLUSIVE_CALL: + *_exclusive = true; + if (len != 0) + return -EINVAL; + break; default: return -EINVAL; } @@ -131,7 +137,7 @@ static void rxrpc_send_abort(struct rxrpc_call *call, u32 abort_code) */ static struct rxrpc_call * rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, - unsigned long user_call_ID) + unsigned long user_call_ID, bool exclusive) { struct rxrpc_conn_parameters cp; struct rxrpc_conn_bundle *bundle; @@ -155,7 +161,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, cp.local = rx->local; cp.key = rx->key; cp.security_level = rx->min_sec_level; - cp.exclusive = test_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags); + cp.exclusive = rx->exclusive | exclusive; cp.service_id = srx->srx_service; trans = rxrpc_name_to_transport(&cp, msg->msg_name, msg->msg_namelen, GFP_KERNEL); @@ -201,12 +207,14 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) enum rxrpc_command cmd; struct rxrpc_call *call; unsigned long user_call_ID = 0; + bool exclusive = false; u32 abort_code = 0; int ret; _enter(""); - ret = rxrpc_sendmsg_cmsg(msg, &user_call_ID, &cmd, &abort_code); + ret = rxrpc_sendmsg_cmsg(msg, &user_call_ID, &cmd, &abort_code, + &exclusive); if (ret < 0) return ret; @@ -224,7 +232,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) if (!call) { if (cmd != RXRPC_CMD_SEND_DATA) return -EBADSLT; - call = rxrpc_new_client_call_for_sendmsg(rx, msg, user_call_ID); + call = rxrpc_new_client_call_for_sendmsg(rx, msg, user_call_ID, + exclusive); if (IS_ERR(call)) return PTR_ERR(call); } -- cgit v1.2.3 From 6b56a89833fa7903595c8d138bb4927187315cba Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 1 Jun 2016 18:23:01 -0400 Subject: NFS: Kill NFS_INO_NFS_INO_FLUSHING: it is a performance killer filemap_datawrite() and friends already deal just fine with livelock. Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 8 -------- fs/nfs/nfstrace.h | 1 - fs/nfs/write.c | 11 ----------- include/linux/nfs_fs.h | 1 - 4 files changed, 21 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 2d39d9f9da7d..29d7477a62e8 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -359,14 +359,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping, file, mapping->host->i_ino, len, (long long) pos); start: - /* - * Prevent starvation issues if someone is doing a consistency - * sync-to-disk - */ - ret = wait_on_bit_action(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING, - nfs_wait_bit_killable, TASK_KILLABLE); - if (ret) - return ret; /* * Wait for O_DIRECT to complete */ diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h index 0b9e5cc9a747..fe80a1c26340 100644 --- a/fs/nfs/nfstrace.h +++ b/fs/nfs/nfstrace.h @@ -37,7 +37,6 @@ { 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \ { 1 << NFS_INO_STALE, "STALE" }, \ { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \ - { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \ { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \ { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \ { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" }) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e1c74d3db64d..980d44f3a84c 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -657,16 +657,9 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control * int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) { struct inode *inode = mapping->host; - unsigned long *bitlock = &NFS_I(inode)->flags; struct nfs_pageio_descriptor pgio; int err; - /* Stop dirtying of new pages while we sync */ - err = wait_on_bit_lock_action(bitlock, NFS_INO_FLUSHING, - nfs_wait_bit_killable, TASK_KILLABLE); - if (err) - goto out_err; - nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), false, @@ -674,10 +667,6 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); nfs_pageio_complete(&pgio); - clear_bit_unlock(NFS_INO_FLUSHING, bitlock); - smp_mb__after_atomic(); - wake_up_bit(bitlock, NFS_INO_FLUSHING); - if (err < 0) goto out_err; err = pgio.pg_error; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index d71278c3c5bd..120dd04b553c 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -205,7 +205,6 @@ struct nfs_inode { #define NFS_INO_STALE (1) /* possible stale inode */ #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ #define NFS_INO_INVALIDATING (3) /* inode is being invalidated */ -#define NFS_INO_FLUSHING (4) /* inode is flushing out data */ #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ -- cgit v1.2.3 From 4e5f2c400765e3a3ce512dc1ae890bac53401798 Mon Sep 17 00:00:00 2001 From: Salvatore Benedetto Date: Wed, 22 Jun 2016 17:49:13 +0100 Subject: crypto: kpp - Key-agreement Protocol Primitives API (KPP) Add key-agreement protocol primitives (kpp) API which allows to implement primitives required by protocols such as DH and ECDH. The API is composed mainly by the following functions * set_secret() - It allows the user to set his secret, also referred to as his private key, along with the parameters known to both parties involved in the key-agreement session. * generate_public_key() - It generates the public key to be sent to the other counterpart involved in the key-agreement session. The function has to be called after set_params() and set_secret() * generate_secret() - It generates the shared secret for the session Other functions such as init() and exit() are provided for allowing cryptographic hardware to be inizialized properly before use Signed-off-by: Salvatore Benedetto Signed-off-by: Herbert Xu --- crypto/Kconfig | 10 ++ crypto/Makefile | 1 + crypto/crypto_user.c | 20 +++ crypto/kpp.c | 123 +++++++++++++++ include/crypto/internal/kpp.h | 64 ++++++++ include/crypto/kpp.h | 328 ++++++++++++++++++++++++++++++++++++++++ include/linux/crypto.h | 1 + include/uapi/linux/cryptouser.h | 5 + 8 files changed, 552 insertions(+) create mode 100644 crypto/kpp.c create mode 100644 include/crypto/internal/kpp.h create mode 100644 include/crypto/kpp.h (limited to 'include/linux') diff --git a/crypto/Kconfig b/crypto/Kconfig index 6881d1a5f859..e72c4270173d 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -93,6 +93,15 @@ config CRYPTO_AKCIPHER select CRYPTO_AKCIPHER2 select CRYPTO_ALGAPI +config CRYPTO_KPP2 + tristate + select CRYPTO_ALGAPI2 + +config CRYPTO_KPP + tristate + select CRYPTO_ALGAPI + select CRYPTO_KPP2 + config CRYPTO_RSA tristate "RSA algorithm" select CRYPTO_AKCIPHER @@ -115,6 +124,7 @@ config CRYPTO_MANAGER2 select CRYPTO_HASH2 select CRYPTO_BLKCIPHER2 select CRYPTO_AKCIPHER2 + select CRYPTO_KPP2 config CRYPTO_USER tristate "Userspace cryptographic algorithm configuration" diff --git a/crypto/Makefile b/crypto/Makefile index 0b82c4753743..07b0f51bd645 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -30,6 +30,7 @@ crypto_hash-y += shash.o obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o +obj-$(CONFIG_CRYPTO_KPP2) += kpp.o $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 43fe85f20d57..d28513fb5a90 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "internal.h" @@ -126,6 +127,21 @@ nla_put_failure: return -EMSGSIZE; } +static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_report_kpp rkpp; + + strncpy(rkpp.type, "kpp", sizeof(rkpp.type)); + + if (nla_put(skb, CRYPTOCFGA_REPORT_KPP, + sizeof(struct crypto_report_kpp), &rkpp)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + static int crypto_report_one(struct crypto_alg *alg, struct crypto_user_alg *ualg, struct sk_buff *skb) { @@ -176,6 +192,10 @@ static int crypto_report_one(struct crypto_alg *alg, goto nla_put_failure; break; + case CRYPTO_ALG_TYPE_KPP: + if (crypto_report_kpp(skb, alg)) + goto nla_put_failure; + break; } out: diff --git a/crypto/kpp.c b/crypto/kpp.c new file mode 100644 index 000000000000..d36ce05eee43 --- /dev/null +++ b/crypto/kpp.c @@ -0,0 +1,123 @@ +/* + * Key-agreement Protocol Primitives (KPP) + * + * Copyright (c) 2016, Intel Corporation + * Authors: Salvatore Benedetto + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +#ifdef CONFIG_NET +static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_report_kpp rkpp; + + strncpy(rkpp.type, "kpp", sizeof(rkpp.type)); + + if (nla_put(skb, CRYPTOCFGA_REPORT_KPP, + sizeof(struct crypto_report_kpp), &rkpp)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} +#else +static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg) +{ + return -ENOSYS; +} +#endif + +static void crypto_kpp_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); + +static void crypto_kpp_show(struct seq_file *m, struct crypto_alg *alg) +{ + seq_puts(m, "type : kpp\n"); +} + +static void crypto_kpp_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_kpp *kpp = __crypto_kpp_tfm(tfm); + struct kpp_alg *alg = crypto_kpp_alg(kpp); + + alg->exit(kpp); +} + +static int crypto_kpp_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_kpp *kpp = __crypto_kpp_tfm(tfm); + struct kpp_alg *alg = crypto_kpp_alg(kpp); + + if (alg->exit) + kpp->base.exit = crypto_kpp_exit_tfm; + + if (alg->init) + return alg->init(kpp); + + return 0; +} + +static const struct crypto_type crypto_kpp_type = { + .extsize = crypto_alg_extsize, + .init_tfm = crypto_kpp_init_tfm, +#ifdef CONFIG_PROC_FS + .show = crypto_kpp_show, +#endif + .report = crypto_kpp_report, + .maskclear = ~CRYPTO_ALG_TYPE_MASK, + .maskset = CRYPTO_ALG_TYPE_MASK, + .type = CRYPTO_ALG_TYPE_KPP, + .tfmsize = offsetof(struct crypto_kpp, base), +}; + +struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask) +{ + return crypto_alloc_tfm(alg_name, &crypto_kpp_type, type, mask); +} +EXPORT_SYMBOL_GPL(crypto_alloc_kpp); + +static void kpp_prepare_alg(struct kpp_alg *alg) +{ + struct crypto_alg *base = &alg->base; + + base->cra_type = &crypto_kpp_type; + base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + base->cra_flags |= CRYPTO_ALG_TYPE_KPP; +} + +int crypto_register_kpp(struct kpp_alg *alg) +{ + struct crypto_alg *base = &alg->base; + + kpp_prepare_alg(alg); + return crypto_register_alg(base); +} +EXPORT_SYMBOL_GPL(crypto_register_kpp); + +void crypto_unregister_kpp(struct kpp_alg *alg) +{ + crypto_unregister_alg(&alg->base); +} +EXPORT_SYMBOL_GPL(crypto_unregister_kpp); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Key-agreement Protocol Primitives"); diff --git a/include/crypto/internal/kpp.h b/include/crypto/internal/kpp.h new file mode 100644 index 000000000000..ad3acf3649be --- /dev/null +++ b/include/crypto/internal/kpp.h @@ -0,0 +1,64 @@ +/* + * Key-agreement Protocol Primitives (KPP) + * + * Copyright (c) 2016, Intel Corporation + * Authors: Salvatore Benedetto + * + * 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 _CRYPTO_KPP_INT_H +#define _CRYPTO_KPP_INT_H +#include +#include + +/* + * Transform internal helpers. + */ +static inline void *kpp_request_ctx(struct kpp_request *req) +{ + return req->__ctx; +} + +static inline void *kpp_tfm_ctx(struct crypto_kpp *tfm) +{ + return tfm->base.__crt_ctx; +} + +static inline void kpp_request_complete(struct kpp_request *req, int err) +{ + req->base.complete(&req->base, err); +} + +static inline const char *kpp_alg_name(struct crypto_kpp *tfm) +{ + return crypto_kpp_tfm(tfm)->__crt_alg->cra_name; +} + +/** + * crypto_register_kpp() -- Register key-agreement protocol primitives algorithm + * + * Function registers an implementation of a key-agreement protocol primitive + * algorithm + * + * @alg: algorithm definition + * + * Return: zero on success; error code in case of error + */ +int crypto_register_kpp(struct kpp_alg *alg); + +/** + * crypto_unregister_kpp() -- Unregister key-agreement protocol primitive + * algorithm + * + * Function unregisters an implementation of a key-agreement protocol primitive + * algorithm + * + * @alg: algorithm definition + */ +void crypto_unregister_kpp(struct kpp_alg *alg); + +#endif diff --git a/include/crypto/kpp.h b/include/crypto/kpp.h new file mode 100644 index 000000000000..4fa897f3366b --- /dev/null +++ b/include/crypto/kpp.h @@ -0,0 +1,328 @@ +/* + * Key-agreement Protocol Primitives (KPP) + * + * Copyright (c) 2016, Intel Corporation + * Authors: Salvatore Benedetto + * + * 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 _CRYPTO_KPP_ +#define _CRYPTO_KPP_ +#include + +/** + * struct kpp_request + * + * @base: Common attributes for async crypto requests + * @src: Source data + * @dst: Destination data + * @src_len: Size of the input buffer + * @dst_len: Size of the output buffer. It needs to be at least + * as big as the expected result depending on the operation + * After operation it will be updated with the actual size of the + * result. In case of error where the dst sgl size was insufficient, + * it will be updated to the size required for the operation. + * @__ctx: Start of private context data + */ +struct kpp_request { + struct crypto_async_request base; + struct scatterlist *src; + struct scatterlist *dst; + unsigned int src_len; + unsigned int dst_len; + void *__ctx[] CRYPTO_MINALIGN_ATTR; +}; + +/** + * struct crypto_kpp - user-instantiated object which encapsulate + * algorithms and core processing logic + * + * @base: Common crypto API algorithm data structure + */ +struct crypto_kpp { + struct crypto_tfm base; +}; + +/** + * struct kpp_alg - generic key-agreement protocol primitives + * + * @set_secret: Function invokes the protocol specific function to + * store the secret private key along with parameters. + * The implementation knows how to decode thie buffer + * @generate_public_key: Function generate the public key to be sent to the + * counterpart. In case of error, where output is not big + * enough req->dst_len will be updated to the size + * required + * @compute_shared_secret: Function compute the shared secret as defined by + * the algorithm. The result is given back to the user. + * In case of error, where output is not big enough, + * req->dst_len will be updated to the size required + * @max_size: Function returns the size of the output buffer + * @init: Initialize the object. This is called only once at + * instantiation time. In case the cryptographic hardware + * needs to be initialized. Software fallback should be + * put in place here. + * @exit: Undo everything @init did. + * + * @reqsize: Request context size required by algorithm + * implementation + * @base Common crypto API algorithm data structure + */ +struct kpp_alg { + int (*set_secret)(struct crypto_kpp *tfm, void *buffer, + unsigned int len); + int (*generate_public_key)(struct kpp_request *req); + int (*compute_shared_secret)(struct kpp_request *req); + + int (*max_size)(struct crypto_kpp *tfm); + + int (*init)(struct crypto_kpp *tfm); + void (*exit)(struct crypto_kpp *tfm); + + unsigned int reqsize; + struct crypto_alg base; +}; + +/** + * DOC: Generic Key-agreement Protocol Primitevs API + * + * The KPP API is used with the algorithm type + * CRYPTO_ALG_TYPE_KPP (listed as type "kpp" in /proc/crypto) + */ + +/** + * crypto_alloc_kpp() - allocate KPP tfm handle + * @alg_name: is the name of the kpp algorithm (e.g. "dh", "ecdh") + * @type: specifies the type of the algorithm + * @mask: specifies the mask for the algorithm + * + * Allocate a handle for kpp algorithm. The returned struct crypto_kpp + * is requeried for any following API invocation + * + * Return: allocated handle in case of success; IS_ERR() is true in case of + * an error, PTR_ERR() returns the error code. + */ +struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask); + +static inline struct crypto_tfm *crypto_kpp_tfm(struct crypto_kpp *tfm) +{ + return &tfm->base; +} + +static inline struct kpp_alg *__crypto_kpp_alg(struct crypto_alg *alg) +{ + return container_of(alg, struct kpp_alg, base); +} + +static inline struct crypto_kpp *__crypto_kpp_tfm(struct crypto_tfm *tfm) +{ + return container_of(tfm, struct crypto_kpp, base); +} + +static inline struct kpp_alg *crypto_kpp_alg(struct crypto_kpp *tfm) +{ + return __crypto_kpp_alg(crypto_kpp_tfm(tfm)->__crt_alg); +} + +static inline unsigned int crypto_kpp_reqsize(struct crypto_kpp *tfm) +{ + return crypto_kpp_alg(tfm)->reqsize; +} + +static inline void kpp_request_set_tfm(struct kpp_request *req, + struct crypto_kpp *tfm) +{ + req->base.tfm = crypto_kpp_tfm(tfm); +} + +static inline struct crypto_kpp *crypto_kpp_reqtfm(struct kpp_request *req) +{ + return __crypto_kpp_tfm(req->base.tfm); +} + +/** + * crypto_free_kpp() - free KPP tfm handle + * + * @tfm: KPP tfm handle allocated with crypto_alloc_kpp() + */ +static inline void crypto_free_kpp(struct crypto_kpp *tfm) +{ + crypto_destroy_tfm(tfm, crypto_kpp_tfm(tfm)); +} + +/** + * kpp_request_alloc() - allocates kpp request + * + * @tfm: KPP tfm handle allocated with crypto_alloc_kpp() + * @gfp: allocation flags + * + * Return: allocated handle in case of success or NULL in case of an error. + */ +static inline struct kpp_request *kpp_request_alloc(struct crypto_kpp *tfm, + gfp_t gfp) +{ + struct kpp_request *req; + + req = kmalloc(sizeof(*req) + crypto_kpp_reqsize(tfm), gfp); + if (likely(req)) + kpp_request_set_tfm(req, tfm); + + return req; +} + +/** + * kpp_request_free() - zeroize and free kpp request + * + * @req: request to free + */ +static inline void kpp_request_free(struct kpp_request *req) +{ + kzfree(req); +} + +/** + * kpp_request_set_callback() - Sets an asynchronous callback. + * + * Callback will be called when an asynchronous operation on a given + * request is finished. + * + * @req: request that the callback will be set for + * @flgs: specify for instance if the operation may backlog + * @cmpl: callback which will be called + * @data: private data used by the caller + */ +static inline void kpp_request_set_callback(struct kpp_request *req, + u32 flgs, + crypto_completion_t cmpl, + void *data) +{ + req->base.complete = cmpl; + req->base.data = data; + req->base.flags = flgs; +} + +/** + * kpp_request_set_input() - Sets input buffer + * + * Sets parameters required by generate_public_key + * + * @req: kpp request + * @input: ptr to input scatter list + * @input_len: size of the input scatter list + */ +static inline void kpp_request_set_input(struct kpp_request *req, + struct scatterlist *input, + unsigned int input_len) +{ + req->src = input; + req->src_len = input_len; +} + +/** + * kpp_request_set_output() - Sets output buffer + * + * Sets parameters required by kpp operation + * + * @req: kpp request + * @output: ptr to output scatter list + * @output_len: size of the output scatter list + */ +static inline void kpp_request_set_output(struct kpp_request *req, + struct scatterlist *output, + unsigned int output_len) +{ + req->dst = output; + req->dst_len = output_len; +} + +enum { + CRYPTO_KPP_SECRET_TYPE_UNKNOWN, +}; + +/** + * struct kpp_secret - small header for packing secret buffer + * + * @type: define type of secret. Each kpp type will define its own + * @len: specify the len of the secret, include the header, that + * follows the struct + */ +struct kpp_secret { + unsigned short type; + unsigned short len; +}; + +/** + * crypto_kpp_set_secret() - Invoke kpp operation + * + * Function invokes the specific kpp operation for a given alg. + * + * @tfm: tfm handle + * + * Return: zero on success; error code in case of error + */ +static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, void *buffer, + unsigned int len) +{ + struct kpp_alg *alg = crypto_kpp_alg(tfm); + + return alg->set_secret(tfm, buffer, len); +} + +/** + * crypto_kpp_generate_public_key() - Invoke kpp operation + * + * Function invokes the specific kpp operation for generating the public part + * for a given kpp algorithm + * + * @req: kpp key request + * + * Return: zero on success; error code in case of error + */ +static inline int crypto_kpp_generate_public_key(struct kpp_request *req) +{ + struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + struct kpp_alg *alg = crypto_kpp_alg(tfm); + + return alg->generate_public_key(req); +} + +/** + * crypto_kpp_compute_shared_secret() - Invoke kpp operation + * + * Function invokes the specific kpp operation for computing the shared secret + * for a given kpp algorithm. + * + * @req: kpp key request + * + * Return: zero on success; error code in case of error + */ +static inline int crypto_kpp_compute_shared_secret(struct kpp_request *req) +{ + struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); + struct kpp_alg *alg = crypto_kpp_alg(tfm); + + return alg->compute_shared_secret(req); +} + +/** + * crypto_kpp_maxsize() - Get len for output buffer + * + * Function returns the output buffer size required + * + * @tfm: KPP tfm handle allocated with crypto_alloc_kpp() + * + * Return: minimum len for output buffer or error code if key hasn't been set + */ +static inline int crypto_kpp_maxsize(struct crypto_kpp *tfm) +{ + struct kpp_alg *alg = crypto_kpp_alg(tfm); + + return alg->max_size(tfm); +} + +#endif diff --git a/include/linux/crypto.h b/include/linux/crypto.h index d844cbc365f7..992cfc2e5df1 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -48,6 +48,7 @@ #define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 #define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005 #define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006 +#define CRYPTO_ALG_TYPE_KPP 0x00000008 #define CRYPTO_ALG_TYPE_RNG 0x0000000c #define CRYPTO_ALG_TYPE_AKCIPHER 0x0000000d #define CRYPTO_ALG_TYPE_DIGEST 0x0000000e diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h index 2e67bb64c1da..79b5ded2001a 100644 --- a/include/uapi/linux/cryptouser.h +++ b/include/uapi/linux/cryptouser.h @@ -45,6 +45,7 @@ enum crypto_attr_type_t { CRYPTOCFGA_REPORT_RNG, /* struct crypto_report_rng */ CRYPTOCFGA_REPORT_CIPHER, /* struct crypto_report_cipher */ CRYPTOCFGA_REPORT_AKCIPHER, /* struct crypto_report_akcipher */ + CRYPTOCFGA_REPORT_KPP, /* struct crypto_report_kpp */ __CRYPTOCFGA_MAX #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1) @@ -107,5 +108,9 @@ struct crypto_report_akcipher { char type[CRYPTO_MAX_NAME]; }; +struct crypto_report_kpp { + char type[CRYPTO_MAX_NAME]; +}; + #define CRYPTO_REPORT_MAXSIZE (sizeof(struct crypto_user_alg) + \ sizeof(struct crypto_report_blkcipher)) -- cgit v1.2.3 From 89ea94a7b6c40eb423c144aef1caceebaff79c8d Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Fri, 17 Jun 2016 15:01:38 +0300 Subject: IB/mlx5: Reset flow support for IB kernel ULPs The driver exposes interfaces that directly relate to HW state. Upon fatal error, consumers of these interfaces (ULPs) that rely on completion of all their posted work-request could hang, thereby introducing dependencies in shutdown order. To prevent this from happening, we manage the relevant resources (CQs, QPs) that are used by the device. Upon a fatal error, we now generate simulated completions for outstanding WQEs that were not completed at the time the HW was reset. It includes invoking the completion event handler for all involved CQs so that the ULPs will poll those CQs. When polled we return simulated CQEs with IB_WC_WR_FLUSH_ERR return code enabling ULPs to clean up their resources and not wait forever for completions upon receiving remove_one. The above change requires an extra check in the data path to make sure that when device is in error state, the simulated CQEs will be returned and no further WQEs will be posted. Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/cq.c | 87 +++++++++++++++++++++++++++++++- drivers/infiniband/hw/mlx5/main.c | 62 +++++++++++++++++++++++ drivers/infiniband/hw/mlx5/mlx5_ib.h | 8 +++ drivers/infiniband/hw/mlx5/mr.c | 4 ++ drivers/infiniband/hw/mlx5/qp.c | 98 +++++++++++++++++++++++++++++------- drivers/infiniband/hw/mlx5/srq.c | 10 +++- include/linux/mlx5/cq.h | 2 + 7 files changed, 250 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 9c0e67bd2ba7..308a358e5b46 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -424,6 +424,83 @@ static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe, item->key = be32_to_cpu(cqe->mkey); } +static void sw_send_comp(struct mlx5_ib_qp *qp, int num_entries, + struct ib_wc *wc, int *npolled) +{ + struct mlx5_ib_wq *wq; + unsigned int cur; + unsigned int idx; + int np; + int i; + + wq = &qp->sq; + cur = wq->head - wq->tail; + np = *npolled; + + if (cur == 0) + return; + + for (i = 0; i < cur && np < num_entries; i++) { + idx = wq->last_poll & (wq->wqe_cnt - 1); + wc->wr_id = wq->wrid[idx]; + wc->status = IB_WC_WR_FLUSH_ERR; + wc->vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR; + wq->tail++; + np++; + wc->qp = &qp->ibqp; + wc++; + wq->last_poll = wq->w_list[idx].next; + } + *npolled = np; +} + +static void sw_recv_comp(struct mlx5_ib_qp *qp, int num_entries, + struct ib_wc *wc, int *npolled) +{ + struct mlx5_ib_wq *wq; + unsigned int cur; + int np; + int i; + + wq = &qp->rq; + cur = wq->head - wq->tail; + np = *npolled; + + if (cur == 0) + return; + + for (i = 0; i < cur && np < num_entries; i++) { + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + wc->status = IB_WC_WR_FLUSH_ERR; + wc->vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR; + wq->tail++; + np++; + wc->qp = &qp->ibqp; + wc++; + } + *npolled = np; +} + +static void mlx5_ib_poll_sw_comp(struct mlx5_ib_cq *cq, int num_entries, + struct ib_wc *wc, int *npolled) +{ + struct mlx5_ib_qp *qp; + + *npolled = 0; + /* Find uncompleted WQEs belonging to that cq and retrun mmics ones */ + list_for_each_entry(qp, &cq->list_send_qp, cq_send_list) { + sw_send_comp(qp, num_entries, wc + *npolled, npolled); + if (*npolled >= num_entries) + return; + } + + list_for_each_entry(qp, &cq->list_recv_qp, cq_recv_list) { + sw_recv_comp(qp, num_entries, wc + *npolled, npolled); + if (*npolled >= num_entries) + return; + } +} + static int mlx5_poll_one(struct mlx5_ib_cq *cq, struct mlx5_ib_qp **cur_qp, struct ib_wc *wc) @@ -594,12 +671,18 @@ int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) { struct mlx5_ib_cq *cq = to_mcq(ibcq); struct mlx5_ib_qp *cur_qp = NULL; + struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); + struct mlx5_core_dev *mdev = dev->mdev; unsigned long flags; int soft_polled = 0; int npolled; int err = 0; spin_lock_irqsave(&cq->lock, flags); + if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { + mlx5_ib_poll_sw_comp(cq, num_entries, wc, &npolled); + goto out; + } if (unlikely(!list_empty(&cq->wc_list))) soft_polled = poll_soft_wc(cq, num_entries, wc); @@ -612,7 +695,7 @@ int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) if (npolled) mlx5_cq_set_ci(&cq->mcq); - +out: spin_unlock_irqrestore(&cq->lock, flags); if (err == 0 || err == -EAGAIN) @@ -843,6 +926,8 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, cq->resize_buf = NULL; cq->resize_umem = NULL; cq->create_flags = attr->flags; + INIT_LIST_HEAD(&cq->list_send_qp); + INIT_LIST_HEAD(&cq->list_recv_qp); if (context) { err = create_cq_user(dev, udata, context, cq, entries, diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 21acee41f0ec..9b6d2838072d 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1980,6 +1980,65 @@ static void pkey_change_handler(struct work_struct *work) mutex_unlock(&ports->devr->mutex); } +static void mlx5_ib_handle_internal_error(struct mlx5_ib_dev *ibdev) +{ + struct mlx5_ib_qp *mqp; + struct mlx5_ib_cq *send_mcq, *recv_mcq; + struct mlx5_core_cq *mcq; + struct list_head cq_armed_list; + unsigned long flags_qp; + unsigned long flags_cq; + unsigned long flags; + + INIT_LIST_HEAD(&cq_armed_list); + + /* Go over qp list reside on that ibdev, sync with create/destroy qp.*/ + spin_lock_irqsave(&ibdev->reset_flow_resource_lock, flags); + list_for_each_entry(mqp, &ibdev->qp_list, qps_list) { + spin_lock_irqsave(&mqp->sq.lock, flags_qp); + if (mqp->sq.tail != mqp->sq.head) { + send_mcq = to_mcq(mqp->ibqp.send_cq); + spin_lock_irqsave(&send_mcq->lock, flags_cq); + if (send_mcq->mcq.comp && + mqp->ibqp.send_cq->comp_handler) { + if (!send_mcq->mcq.reset_notify_added) { + send_mcq->mcq.reset_notify_added = 1; + list_add_tail(&send_mcq->mcq.reset_notify, + &cq_armed_list); + } + } + spin_unlock_irqrestore(&send_mcq->lock, flags_cq); + } + spin_unlock_irqrestore(&mqp->sq.lock, flags_qp); + spin_lock_irqsave(&mqp->rq.lock, flags_qp); + /* no handling is needed for SRQ */ + if (!mqp->ibqp.srq) { + if (mqp->rq.tail != mqp->rq.head) { + recv_mcq = to_mcq(mqp->ibqp.recv_cq); + spin_lock_irqsave(&recv_mcq->lock, flags_cq); + if (recv_mcq->mcq.comp && + mqp->ibqp.recv_cq->comp_handler) { + if (!recv_mcq->mcq.reset_notify_added) { + recv_mcq->mcq.reset_notify_added = 1; + list_add_tail(&recv_mcq->mcq.reset_notify, + &cq_armed_list); + } + } + spin_unlock_irqrestore(&recv_mcq->lock, + flags_cq); + } + } + spin_unlock_irqrestore(&mqp->rq.lock, flags_qp); + } + /*At that point all inflight post send were put to be executed as of we + * lock/unlock above locks Now need to arm all involved CQs. + */ + list_for_each_entry(mcq, &cq_armed_list, reset_notify) { + mcq->comp(mcq); + } + spin_unlock_irqrestore(&ibdev->reset_flow_resource_lock, flags); +} + static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context, enum mlx5_dev_event event, unsigned long param) { @@ -1992,6 +2051,7 @@ static void mlx5_ib_event(struct mlx5_core_dev *dev, void *context, case MLX5_DEV_EVENT_SYS_ERROR: ibdev->ib_active = false; ibev.event = IB_EVENT_DEVICE_FATAL; + mlx5_ib_handle_internal_error(ibdev); break; case MLX5_DEV_EVENT_PORT_UP: @@ -2595,6 +2655,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) mutex_init(&dev->flow_db.lock); mutex_init(&dev->cap_mask_mutex); + INIT_LIST_HEAD(&dev->qp_list); + spin_lock_init(&dev->reset_flow_resource_lock); if (ll == IB_LINK_LAYER_ETHERNET) { err = mlx5_enable_roce(dev); diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 391588e01317..0001ed51e1bd 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -380,6 +380,9 @@ struct mlx5_ib_qp { spinlock_t disable_page_faults_lock; struct mlx5_ib_pfault pagefaults[MLX5_IB_PAGEFAULT_CONTEXTS]; #endif + struct list_head qps_list; + struct list_head cq_recv_list; + struct list_head cq_send_list; }; struct mlx5_ib_cq_buf { @@ -441,6 +444,8 @@ struct mlx5_ib_cq { struct mlx5_ib_cq_buf *resize_buf; struct ib_umem *resize_umem; int cqe_size; + struct list_head list_send_qp; + struct list_head list_recv_qp; u32 create_flags; struct list_head wc_list; enum ib_cq_notify_flags notify_flags; @@ -621,6 +626,9 @@ struct mlx5_ib_dev { struct srcu_struct mr_srcu; #endif struct mlx5_ib_flow_db flow_db; + /* protect resources needed as part of reset flow */ + spinlock_t reset_flow_resource_lock; + struct list_head qp_list; }; static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 8cf2ce50511f..4b021305c321 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1193,12 +1193,16 @@ error: static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr) { + struct mlx5_core_dev *mdev = dev->mdev; struct umr_common *umrc = &dev->umrc; struct mlx5_ib_umr_context umr_context; struct mlx5_umr_wr umrwr = {}; struct ib_send_wr *bad; int err; + if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) + return 0; + mlx5_ib_init_umr_context(&umr_context); umrwr.wr.wr_cqe = &umr_context.cqe; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index f9df4b527a11..9004905d3d93 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -77,6 +77,10 @@ struct mlx5_wqe_eth_pad { u8 rsvd0[16]; }; +static void get_cqs(enum ib_qp_type qp_type, + struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq, + struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq); + static int is_qp0(enum ib_qp_type qp_type) { return qp_type == IB_QPT_SMI; @@ -609,6 +613,11 @@ static int to_mlx5_st(enum ib_qp_type type) } } +static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, + struct mlx5_ib_cq *recv_cq); +static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, + struct mlx5_ib_cq *recv_cq); + static int uuarn_to_uar_index(struct mlx5_uuar_info *uuari, int uuarn) { return uuari->uars[uuarn / MLX5_BF_REGS_PER_PAGE].index; @@ -1457,6 +1466,9 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, struct mlx5_ib_create_qp_resp resp; struct mlx5_create_qp_mbox_in *in; struct mlx5_ib_create_qp ucmd; + struct mlx5_ib_cq *send_cq; + struct mlx5_ib_cq *recv_cq; + unsigned long flags; int inlen = sizeof(*in); int err; u32 uidx = MLX5_IB_DEFAULT_UIDX; @@ -1714,6 +1726,23 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, base->container_mibqp = qp; base->mqp.event = mlx5_ib_qp_event; + get_cqs(init_attr->qp_type, init_attr->send_cq, init_attr->recv_cq, + &send_cq, &recv_cq); + spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); + mlx5_ib_lock_cqs(send_cq, recv_cq); + /* Maintain device to QPs access, needed for further handling via reset + * flow + */ + list_add_tail(&qp->qps_list, &dev->qp_list); + /* Maintain CQ to QPs access, needed for further handling via reset flow + */ + if (send_cq) + list_add_tail(&qp->cq_send_list, &send_cq->list_send_qp); + if (recv_cq) + list_add_tail(&qp->cq_recv_list, &recv_cq->list_recv_qp); + mlx5_ib_unlock_cqs(send_cq, recv_cq); + spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); + return 0; err_create: @@ -1732,23 +1761,23 @@ static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv if (send_cq) { if (recv_cq) { if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { - spin_lock_irq(&send_cq->lock); + spin_lock(&send_cq->lock); spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) { - spin_lock_irq(&send_cq->lock); + spin_lock(&send_cq->lock); __acquire(&recv_cq->lock); } else { - spin_lock_irq(&recv_cq->lock); + spin_lock(&recv_cq->lock); spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); } } else { - spin_lock_irq(&send_cq->lock); + spin_lock(&send_cq->lock); __acquire(&recv_cq->lock); } } else if (recv_cq) { - spin_lock_irq(&recv_cq->lock); + spin_lock(&recv_cq->lock); __acquire(&send_cq->lock); } else { __acquire(&send_cq->lock); @@ -1763,21 +1792,21 @@ static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *re if (recv_cq) { if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { spin_unlock(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); + spin_unlock(&send_cq->lock); } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) { __release(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); + spin_unlock(&send_cq->lock); } else { spin_unlock(&send_cq->lock); - spin_unlock_irq(&recv_cq->lock); + spin_unlock(&recv_cq->lock); } } else { __release(&recv_cq->lock); - spin_unlock_irq(&send_cq->lock); + spin_unlock(&send_cq->lock); } } else if (recv_cq) { __release(&send_cq->lock); - spin_unlock_irq(&recv_cq->lock); + spin_unlock(&recv_cq->lock); } else { __release(&recv_cq->lock); __release(&send_cq->lock); @@ -1789,17 +1818,18 @@ static struct mlx5_ib_pd *get_pd(struct mlx5_ib_qp *qp) return to_mpd(qp->ibqp.pd); } -static void get_cqs(struct mlx5_ib_qp *qp, +static void get_cqs(enum ib_qp_type qp_type, + struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq, struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq) { - switch (qp->ibqp.qp_type) { + switch (qp_type) { case IB_QPT_XRC_TGT: *send_cq = NULL; *recv_cq = NULL; break; case MLX5_IB_QPT_REG_UMR: case IB_QPT_XRC_INI: - *send_cq = to_mcq(qp->ibqp.send_cq); + *send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL; *recv_cq = NULL; break; @@ -1811,8 +1841,8 @@ static void get_cqs(struct mlx5_ib_qp *qp, case IB_QPT_RAW_IPV6: case IB_QPT_RAW_ETHERTYPE: case IB_QPT_RAW_PACKET: - *send_cq = to_mcq(qp->ibqp.send_cq); - *recv_cq = to_mcq(qp->ibqp.recv_cq); + *send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL; + *recv_cq = ib_recv_cq ? to_mcq(ib_recv_cq) : NULL; break; case IB_QPT_MAX: @@ -1831,6 +1861,7 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) struct mlx5_ib_cq *send_cq, *recv_cq; struct mlx5_ib_qp_base *base = &qp->trans_qp.base; struct mlx5_modify_qp_mbox_in *in; + unsigned long flags; int err; if (qp->ibqp.rwq_ind_tbl) { @@ -1861,17 +1892,28 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) base->mqp.qpn); } - get_cqs(qp, &send_cq, &recv_cq); + get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq, + &send_cq, &recv_cq); + + spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); + mlx5_ib_lock_cqs(send_cq, recv_cq); + /* del from lists under both locks above to protect reset flow paths */ + list_del(&qp->qps_list); + if (send_cq) + list_del(&qp->cq_send_list); + + if (recv_cq) + list_del(&qp->cq_recv_list); if (qp->create_type == MLX5_QP_KERNEL) { - mlx5_ib_lock_cqs(send_cq, recv_cq); __mlx5_ib_cq_clean(recv_cq, base->mqp.qpn, qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); if (send_cq != recv_cq) __mlx5_ib_cq_clean(send_cq, base->mqp.qpn, NULL); - mlx5_ib_unlock_cqs(send_cq, recv_cq); } + mlx5_ib_unlock_cqs(send_cq, recv_cq); + spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) { destroy_raw_packet_qp(dev, qp); @@ -2559,7 +2601,8 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, } pd = get_pd(qp); - get_cqs(qp, &send_cq, &recv_cq); + get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq, + &send_cq, &recv_cq); context->flags_pd = cpu_to_be32(pd ? pd->pdn : to_mpd(dev->devr.p0)->pdn); context->cqn_send = send_cq ? cpu_to_be32(send_cq->mcq.cqn) : 0; @@ -3658,6 +3701,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, { struct mlx5_wqe_ctrl_seg *ctrl = NULL; /* compiler warning */ struct mlx5_ib_dev *dev = to_mdev(ibqp->device); + struct mlx5_core_dev *mdev = dev->mdev; struct mlx5_ib_qp *qp; struct mlx5_ib_mr *mr; struct mlx5_wqe_data_seg *dpseg; @@ -3685,6 +3729,13 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, spin_lock_irqsave(&qp->sq.lock, flags); + if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { + err = -EIO; + *bad_wr = wr; + nreq = 0; + goto out; + } + for (nreq = 0; wr; nreq++, wr = wr->next) { if (unlikely(wr->opcode >= ARRAY_SIZE(mlx5_ib_opcode))) { mlx5_ib_warn(dev, "\n"); @@ -3986,6 +4037,8 @@ int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, struct mlx5_ib_qp *qp = to_mqp(ibqp); struct mlx5_wqe_data_seg *scat; struct mlx5_rwqe_sig *sig; + struct mlx5_ib_dev *dev = to_mdev(ibqp->device); + struct mlx5_core_dev *mdev = dev->mdev; unsigned long flags; int err = 0; int nreq; @@ -3997,6 +4050,13 @@ int mlx5_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, spin_lock_irqsave(&qp->rq.lock, flags); + if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { + err = -EIO; + *bad_wr = wr; + nreq = 0; + goto out; + } + ind = qp->rq.head & (qp->rq.wqe_cnt - 1); for (nreq = 0; wr; nreq++, wr = wr->next) { diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 3b2ddd64a371..55efb343137b 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -458,6 +458,8 @@ int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, struct mlx5_ib_srq *srq = to_msrq(ibsrq); struct mlx5_wqe_srq_next_seg *next; struct mlx5_wqe_data_seg *scat; + struct mlx5_ib_dev *dev = to_mdev(ibsrq->device); + struct mlx5_core_dev *mdev = dev->mdev; unsigned long flags; int err = 0; int nreq; @@ -465,6 +467,12 @@ int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, spin_lock_irqsave(&srq->lock, flags); + if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { + err = -EIO; + *bad_wr = wr; + goto out; + } + for (nreq = 0; wr; nreq++, wr = wr->next) { if (unlikely(wr->num_sge > srq->msrq.max_gs)) { err = -EINVAL; @@ -507,7 +515,7 @@ int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, *srq->db.db = cpu_to_be32(srq->wqe_ctr); } - +out: spin_unlock_irqrestore(&srq->lock, flags); return err; diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h index 2be976dd4966..2566f6d6444f 100644 --- a/include/linux/mlx5/cq.h +++ b/include/linux/mlx5/cq.h @@ -58,6 +58,8 @@ struct mlx5_core_cq { void (*comp)(struct mlx5_core_cq *); void *priv; } tasklet_ctx; + int reset_notify_added; + struct list_head reset_notify; }; -- cgit v1.2.3 From e3353c268b06236d6c40fa1714c114f21f44451c Mon Sep 17 00:00:00 2001 From: Artemy Kovalyov Date: Fri, 17 Jun 2016 15:33:31 +0300 Subject: IB/mlx5: Fix MODIFY_QP command input structure Make MODIFY_QP command input structure compliant to specification Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters') Signed-off-by: Artemy Kovalyov Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- include/linux/mlx5/qp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index 266320feb160..acb28c989dee 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -555,9 +555,9 @@ struct mlx5_destroy_qp_mbox_out { struct mlx5_modify_qp_mbox_in { struct mlx5_inbox_hdr hdr; __be32 qpn; - u8 rsvd1[4]; - __be32 optparam; u8 rsvd0[4]; + __be32 optparam; + u8 rsvd1[4]; struct mlx5_qp_context ctx; u8 rsvd2[16]; }; -- cgit v1.2.3 From af1ba291c5e498973cc325c501dd8da80b234571 Mon Sep 17 00:00:00 2001 From: Artemy Kovalyov Date: Fri, 17 Jun 2016 15:33:32 +0300 Subject: {net, IB}/mlx5: Refactor internal SRQ API Currently, the SRQ API uses the obsolete mlx5_*_srq_mbox_{in,out} structs which limit the ability to pass the SRQ attributes between net and IB parts of the driver. This patch changes the SRQ API so as to use auto-generated structs and provides a better way to pass attributes which will be in use by coming features. Signed-off-by: Artemy Kovalyov Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/srq.c | 102 ++++------ drivers/net/ethernet/mellanox/mlx5/core/srq.c | 265 ++++++++++++++------------ include/linux/mlx5/driver.h | 6 +- include/linux/mlx5/srq.h | 25 +++ 4 files changed, 215 insertions(+), 183 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 55efb343137b..ed6ac52355f1 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -74,14 +74,12 @@ static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type) } static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, - struct mlx5_create_srq_mbox_in **in, - struct ib_udata *udata, int buf_size, int *inlen, - int is_xrc) + struct mlx5_srq_attr *in, + struct ib_udata *udata, int buf_size) { struct mlx5_ib_dev *dev = to_mdev(pd->device); struct mlx5_ib_create_srq ucmd = {}; size_t ucmdlen; - void *xsrqc; int err; int npages; int page_shift; @@ -104,7 +102,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, udata->inlen - sizeof(ucmd))) return -EINVAL; - if (is_xrc) { + if (in->type == IB_SRQT_XRC) { err = get_srq_user_index(to_mucontext(pd->uobject->context), &ucmd, udata->inlen, &uidx); if (err) @@ -130,14 +128,13 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, goto err_umem; } - *inlen = sizeof(**in) + sizeof(*(*in)->pas) * ncont; - *in = mlx5_vzalloc(*inlen); - if (!(*in)) { + in->pas = mlx5_vzalloc(sizeof(*in->pas) * ncont); + if (!in->pas) { err = -ENOMEM; goto err_umem; } - mlx5_ib_populate_pas(dev, srq->umem, page_shift, (*in)->pas, 0); + mlx5_ib_populate_pas(dev, srq->umem, page_shift, in->pas, 0); err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context), ucmd.db_addr, &srq->db); @@ -146,20 +143,16 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, goto err_in; } - (*in)->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT; - (*in)->ctx.pgoff_cqn = cpu_to_be32(offset << 26); - - if ((MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) && - is_xrc){ - xsrqc = MLX5_ADDR_OF(create_xrc_srq_in, *in, - xrc_srq_context_entry); - MLX5_SET(xrc_srqc, xsrqc, user_index, uidx); - } + in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT; + in->page_offset = offset; + if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 && + in->type == IB_SRQT_XRC) + in->user_index = uidx; return 0; err_in: - kvfree(*in); + kvfree(in->pas); err_umem: ib_umem_release(srq->umem); @@ -168,15 +161,13 @@ err_umem: } static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, - struct mlx5_create_srq_mbox_in **in, int buf_size, - int *inlen, int is_xrc) + struct mlx5_srq_attr *in, int buf_size) { int err; int i; struct mlx5_wqe_srq_next_seg *next; int page_shift; int npages; - void *xsrqc; err = mlx5_db_alloc(dev->mdev, &srq->db); if (err) { @@ -204,13 +195,12 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, npages = DIV_ROUND_UP(srq->buf.npages, 1 << (page_shift - PAGE_SHIFT)); mlx5_ib_dbg(dev, "buf_size %d, page_shift %d, npages %d, calc npages %d\n", buf_size, page_shift, srq->buf.npages, npages); - *inlen = sizeof(**in) + sizeof(*(*in)->pas) * npages; - *in = mlx5_vzalloc(*inlen); - if (!*in) { + in->pas = mlx5_vzalloc(sizeof(*in->pas) * npages); + if (!in->pas) { err = -ENOMEM; goto err_buf; } - mlx5_fill_page_array(&srq->buf, (*in)->pas); + mlx5_fill_page_array(&srq->buf, in->pas); srq->wrid = kmalloc(srq->msrq.max * sizeof(u64), GFP_KERNEL); if (!srq->wrid) { @@ -221,20 +211,15 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, } srq->wq_sig = !!srq_signature; - (*in)->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT; - - if ((MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) && - is_xrc){ - xsrqc = MLX5_ADDR_OF(create_xrc_srq_in, *in, - xrc_srq_context_entry); - /* 0xffffff means we ask to work with cqe version 0 */ - MLX5_SET(xrc_srqc, xsrqc, user_index, MLX5_IB_DEFAULT_UIDX); - } + in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT; + if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 && + in->type == IB_SRQT_XRC) + in->user_index = MLX5_IB_DEFAULT_UIDX; return 0; err_in: - kvfree(*in); + kvfree(in->pas); err_buf: mlx5_buf_free(dev->mdev, &srq->buf); @@ -267,10 +252,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, int desc_size; int buf_size; int err; - struct mlx5_create_srq_mbox_in *uninitialized_var(in); - int uninitialized_var(inlen); - int is_xrc; - u32 flgs, xrcdn; + struct mlx5_srq_attr in = {0}; __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz); /* Sanity check SRQ size before proceeding */ @@ -302,14 +284,10 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs, srq->msrq.max_avail_gather); - is_xrc = (init_attr->srq_type == IB_SRQT_XRC); - if (pd->uobject) - err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen, - is_xrc); + err = create_srq_user(pd, srq, &in, udata, buf_size); else - err = create_srq_kernel(dev, srq, &in, buf_size, &inlen, - is_xrc); + err = create_srq_kernel(dev, srq, &in, buf_size); if (err) { mlx5_ib_warn(dev, "create srq %s failed, err %d\n", @@ -317,23 +295,23 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, goto err_srq; } - in->ctx.state_log_sz = ilog2(srq->msrq.max); - flgs = ((srq->msrq.wqe_shift - 4) | (is_xrc << 5) | (srq->wq_sig << 7)) << 24; - xrcdn = 0; - if (is_xrc) { - xrcdn = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn; - in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(init_attr->ext.xrc.cq)->mcq.cqn); + in.type = init_attr->srq_type; + in.log_size = ilog2(srq->msrq.max); + in.wqe_shift = srq->msrq.wqe_shift - 4; + if (srq->wq_sig) + in.flags |= MLX5_SRQ_FLAG_WQ_SIG; + if (init_attr->srq_type == IB_SRQT_XRC) { + in.xrcd = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn; + in.cqn = to_mcq(init_attr->ext.xrc.cq)->mcq.cqn; } else if (init_attr->srq_type == IB_SRQT_BASIC) { - xrcdn = to_mxrcd(dev->devr.x0)->xrcdn; - in->ctx.pgoff_cqn |= cpu_to_be32(to_mcq(dev->devr.c0)->mcq.cqn); + in.xrcd = to_mxrcd(dev->devr.x0)->xrcdn; + in.cqn = to_mcq(dev->devr.c0)->mcq.cqn; } - in->ctx.flags_xrcd = cpu_to_be32((flgs & 0xFF000000) | (xrcdn & 0xFFFFFF)); - - in->ctx.pd = cpu_to_be32(to_mpd(pd)->pdn); - in->ctx.db_record = cpu_to_be64(srq->db.dma); - err = mlx5_core_create_srq(dev->mdev, &srq->msrq, in, inlen, is_xrc); - kvfree(in); + in.pd = to_mpd(pd)->pdn; + in.db_record = srq->db.dma; + err = mlx5_core_create_srq(dev->mdev, &srq->msrq, &in); + kvfree(in.pas); if (err) { mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err); goto err_usr_kern_srq; @@ -401,7 +379,7 @@ int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) struct mlx5_ib_dev *dev = to_mdev(ibsrq->device); struct mlx5_ib_srq *srq = to_msrq(ibsrq); int ret; - struct mlx5_query_srq_mbox_out *out; + struct mlx5_srq_attr *out; out = kzalloc(sizeof(*out), GFP_KERNEL); if (!out) @@ -411,7 +389,7 @@ int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) if (ret) goto out_box; - srq_attr->srq_limit = be16_to_cpu(out->ctx.lwm); + srq_attr->srq_limit = out->lwm; srq_attr->max_wr = srq->msrq.max - 1; srq_attr->max_sge = srq->msrq.max_gs; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c index 04bc522605a0..c07f4d01b70e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c @@ -63,12 +63,12 @@ void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type) complete(&srq->free); } -static int get_pas_size(void *srqc) +static int get_pas_size(struct mlx5_srq_attr *in) { - u32 log_page_size = MLX5_GET(srqc, srqc, log_page_size) + 12; - u32 log_srq_size = MLX5_GET(srqc, srqc, log_srq_size); - u32 log_rq_stride = MLX5_GET(srqc, srqc, log_rq_stride); - u32 page_offset = MLX5_GET(srqc, srqc, page_offset); + u32 log_page_size = in->log_page_size + 12; + u32 log_srq_size = in->log_size; + u32 log_rq_stride = in->wqe_shift; + u32 page_offset = in->page_offset; u32 po_quanta = 1 << (log_page_size - 6); u32 rq_sz = 1 << (log_srq_size + 4 + log_rq_stride); u32 page_size = 1 << log_page_size; @@ -78,57 +78,58 @@ static int get_pas_size(void *srqc) return rq_num_pas * sizeof(u64); } -static void rmpc_srqc_reformat(void *srqc, void *rmpc, bool srqc_to_rmpc) +static void set_wq(void *wq, struct mlx5_srq_attr *in) { - void *wq = MLX5_ADDR_OF(rmpc, rmpc, wq); - - if (srqc_to_rmpc) { - switch (MLX5_GET(srqc, srqc, state)) { - case MLX5_SRQC_STATE_GOOD: - MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY); - break; - case MLX5_SRQC_STATE_ERROR: - MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_ERR); - break; - default: - pr_warn("%s: %d: Unknown srq state = 0x%x\n", __func__, - __LINE__, MLX5_GET(srqc, srqc, state)); - MLX5_SET(rmpc, rmpc, state, MLX5_GET(srqc, srqc, state)); - } - - MLX5_SET(wq, wq, wq_signature, MLX5_GET(srqc, srqc, wq_signature)); - MLX5_SET(wq, wq, log_wq_pg_sz, MLX5_GET(srqc, srqc, log_page_size)); - MLX5_SET(wq, wq, log_wq_stride, MLX5_GET(srqc, srqc, log_rq_stride) + 4); - MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(srqc, srqc, log_srq_size)); - MLX5_SET(wq, wq, page_offset, MLX5_GET(srqc, srqc, page_offset)); - MLX5_SET(wq, wq, lwm, MLX5_GET(srqc, srqc, lwm)); - MLX5_SET(wq, wq, pd, MLX5_GET(srqc, srqc, pd)); - MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(srqc, srqc, dbr_addr)); - } else { - switch (MLX5_GET(rmpc, rmpc, state)) { - case MLX5_RMPC_STATE_RDY: - MLX5_SET(srqc, srqc, state, MLX5_SRQC_STATE_GOOD); - break; - case MLX5_RMPC_STATE_ERR: - MLX5_SET(srqc, srqc, state, MLX5_SRQC_STATE_ERROR); - break; - default: - pr_warn("%s: %d: Unknown rmp state = 0x%x\n", - __func__, __LINE__, - MLX5_GET(rmpc, rmpc, state)); - MLX5_SET(srqc, srqc, state, - MLX5_GET(rmpc, rmpc, state)); - } - - MLX5_SET(srqc, srqc, wq_signature, MLX5_GET(wq, wq, wq_signature)); - MLX5_SET(srqc, srqc, log_page_size, MLX5_GET(wq, wq, log_wq_pg_sz)); - MLX5_SET(srqc, srqc, log_rq_stride, MLX5_GET(wq, wq, log_wq_stride) - 4); - MLX5_SET(srqc, srqc, log_srq_size, MLX5_GET(wq, wq, log_wq_sz)); - MLX5_SET(srqc, srqc, page_offset, MLX5_GET(wq, wq, page_offset)); - MLX5_SET(srqc, srqc, lwm, MLX5_GET(wq, wq, lwm)); - MLX5_SET(srqc, srqc, pd, MLX5_GET(wq, wq, pd)); - MLX5_SET64(srqc, srqc, dbr_addr, MLX5_GET64(wq, wq, dbr_addr)); - } + MLX5_SET(wq, wq, wq_signature, !!(in->flags + & MLX5_SRQ_FLAG_WQ_SIG)); + MLX5_SET(wq, wq, log_wq_pg_sz, in->log_page_size); + MLX5_SET(wq, wq, log_wq_stride, in->wqe_shift + 4); + MLX5_SET(wq, wq, log_wq_sz, in->log_size); + MLX5_SET(wq, wq, page_offset, in->page_offset); + MLX5_SET(wq, wq, lwm, in->lwm); + MLX5_SET(wq, wq, pd, in->pd); + MLX5_SET64(wq, wq, dbr_addr, in->db_record); +} + +static void set_srqc(void *srqc, struct mlx5_srq_attr *in) +{ + MLX5_SET(srqc, srqc, wq_signature, !!(in->flags + & MLX5_SRQ_FLAG_WQ_SIG)); + MLX5_SET(srqc, srqc, log_page_size, in->log_page_size); + MLX5_SET(srqc, srqc, log_rq_stride, in->wqe_shift); + MLX5_SET(srqc, srqc, log_srq_size, in->log_size); + MLX5_SET(srqc, srqc, page_offset, in->page_offset); + MLX5_SET(srqc, srqc, lwm, in->lwm); + MLX5_SET(srqc, srqc, pd, in->pd); + MLX5_SET64(srqc, srqc, dbr_addr, in->db_record); + MLX5_SET(srqc, srqc, xrcd, in->xrcd); + MLX5_SET(srqc, srqc, cqn, in->cqn); +} + +static void get_wq(void *wq, struct mlx5_srq_attr *in) +{ + if (MLX5_GET(wq, wq, wq_signature)) + in->flags &= MLX5_SRQ_FLAG_WQ_SIG; + in->log_page_size = MLX5_GET(wq, wq, log_wq_pg_sz); + in->wqe_shift = MLX5_GET(wq, wq, log_wq_stride) - 4; + in->log_size = MLX5_GET(wq, wq, log_wq_sz); + in->page_offset = MLX5_GET(wq, wq, page_offset); + in->lwm = MLX5_GET(wq, wq, lwm); + in->pd = MLX5_GET(wq, wq, pd); + in->db_record = MLX5_GET64(wq, wq, dbr_addr); +} + +static void get_srqc(void *srqc, struct mlx5_srq_attr *in) +{ + if (MLX5_GET(srqc, srqc, wq_signature)) + in->flags &= MLX5_SRQ_FLAG_WQ_SIG; + in->log_page_size = MLX5_GET(srqc, srqc, log_page_size); + in->wqe_shift = MLX5_GET(srqc, srqc, log_rq_stride); + in->log_size = MLX5_GET(srqc, srqc, log_srq_size); + in->page_offset = MLX5_GET(srqc, srqc, page_offset); + in->lwm = MLX5_GET(srqc, srqc, lwm); + in->pd = MLX5_GET(srqc, srqc, pd); + in->db_record = MLX5_GET64(srqc, srqc, dbr_addr); } struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn) @@ -149,19 +150,36 @@ struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn) EXPORT_SYMBOL(mlx5_core_get_srq); static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_create_srq_mbox_in *in, int inlen) + struct mlx5_srq_attr *in) { - struct mlx5_create_srq_mbox_out out; + u32 create_out[MLX5_ST_SZ_DW(create_srq_out)] = {0}; + void *create_in; + void *srqc; + void *pas; + int pas_size; + int inlen; int err; - memset(&out, 0, sizeof(out)); + pas_size = get_pas_size(in); + inlen = MLX5_ST_SZ_BYTES(create_srq_in) + pas_size; + create_in = mlx5_vzalloc(inlen); + if (!create_in) + return -ENOMEM; + + srqc = MLX5_ADDR_OF(create_srq_in, create_in, srq_context_entry); + pas = MLX5_ADDR_OF(create_srq_in, create_in, pas); - in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_SRQ); + set_srqc(srqc, in); + memcpy(pas, in->pas, pas_size); - err = mlx5_cmd_exec_check_status(dev, (u32 *)in, inlen, (u32 *)(&out), - sizeof(out)); + MLX5_SET(create_srq_in, create_in, opcode, + MLX5_CMD_OP_CREATE_SRQ); - srq->srqn = be32_to_cpu(out.srqn) & 0xffffff; + err = mlx5_cmd_exec_check_status(dev, create_in, inlen, create_out, + sizeof(create_out)); + kvfree(create_in); + if (!err) + srq->srqn = MLX5_GET(create_srq_out, create_out, srqn); return err; } @@ -169,67 +187,75 @@ static int create_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, static int destroy_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq) { - struct mlx5_destroy_srq_mbox_in in; - struct mlx5_destroy_srq_mbox_out out; + u32 srq_in[MLX5_ST_SZ_DW(destroy_srq_in)] = {0}; + u32 srq_out[MLX5_ST_SZ_DW(destroy_srq_out)] = {0}; - memset(&in, 0, sizeof(in)); - memset(&out, 0, sizeof(out)); - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ); - in.srqn = cpu_to_be32(srq->srqn); + MLX5_SET(destroy_srq_in, srq_in, opcode, + MLX5_CMD_OP_DESTROY_SRQ); + MLX5_SET(destroy_srq_in, srq_in, srqn, srq->srqn); - return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), sizeof(in), - (u32 *)(&out), sizeof(out)); + return mlx5_cmd_exec_check_status(dev, srq_in, sizeof(srq_in), + srq_out, sizeof(srq_out)); } static int arm_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, u16 lwm, int is_srq) { - struct mlx5_arm_srq_mbox_in in; - struct mlx5_arm_srq_mbox_out out; - - memset(&in, 0, sizeof(in)); - memset(&out, 0, sizeof(out)); + /* arm_srq structs missing using identical xrc ones */ + u32 srq_in[MLX5_ST_SZ_DW(arm_xrc_srq_in)] = {0}; + u32 srq_out[MLX5_ST_SZ_DW(arm_xrc_srq_out)] = {0}; - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ); - in.hdr.opmod = cpu_to_be16(!!is_srq); - in.srqn = cpu_to_be32(srq->srqn); - in.lwm = cpu_to_be16(lwm); + MLX5_SET(arm_xrc_srq_in, srq_in, opcode, MLX5_CMD_OP_ARM_XRC_SRQ); + MLX5_SET(arm_xrc_srq_in, srq_in, xrc_srqn, srq->srqn); + MLX5_SET(arm_xrc_srq_in, srq_in, lwm, lwm); - return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), - sizeof(in), (u32 *)(&out), - sizeof(out)); + return mlx5_cmd_exec_check_status(dev, srq_in, sizeof(srq_in), + srq_out, sizeof(srq_out)); } static int query_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_query_srq_mbox_out *out) + struct mlx5_srq_attr *out) { - struct mlx5_query_srq_mbox_in in; + u32 srq_in[MLX5_ST_SZ_DW(query_srq_in)] = {0}; + u32 *srq_out; + void *srqc; + int err; - memset(&in, 0, sizeof(in)); + srq_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_srq_out)); + if (!srq_out) + return -ENOMEM; - in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ); - in.srqn = cpu_to_be32(srq->srqn); + MLX5_SET(query_srq_in, srq_in, opcode, + MLX5_CMD_OP_QUERY_SRQ); + MLX5_SET(query_srq_in, srq_in, srqn, srq->srqn); + err = mlx5_cmd_exec_check_status(dev, srq_in, sizeof(srq_in), + srq_out, + MLX5_ST_SZ_BYTES(query_srq_out)); + if (err) + goto out; - return mlx5_cmd_exec_check_status(dev, (u32 *)(&in), sizeof(in), - (u32 *)out, sizeof(*out)); + srqc = MLX5_ADDR_OF(query_srq_out, srq_out, srq_context_entry); + get_srqc(srqc, out); + if (MLX5_GET(srqc, srqc, state) != MLX5_SRQC_STATE_GOOD) + out->flags |= MLX5_SRQ_FLAG_ERR; +out: + kvfree(srq_out); + return err; } static int create_xrc_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_create_srq_mbox_in *in, - int srq_inlen) + struct mlx5_srq_attr *in) { u32 create_out[MLX5_ST_SZ_DW(create_xrc_srq_out)]; void *create_in; - void *srqc; void *xrc_srqc; void *pas; int pas_size; int inlen; int err; - srqc = MLX5_ADDR_OF(create_srq_in, in, srq_context_entry); - pas_size = get_pas_size(srqc); + pas_size = get_pas_size(in); inlen = MLX5_ST_SZ_BYTES(create_xrc_srq_in) + pas_size; create_in = mlx5_vzalloc(inlen); if (!create_in) @@ -239,7 +265,8 @@ static int create_xrc_srq_cmd(struct mlx5_core_dev *dev, xrc_srq_context_entry); pas = MLX5_ADDR_OF(create_xrc_srq_in, create_in, pas); - memcpy(xrc_srqc, srqc, MLX5_ST_SZ_BYTES(srqc)); + set_srqc(xrc_srqc, in); + MLX5_SET(xrc_srqc, xrc_srqc, user_index, in->user_index); memcpy(pas, in->pas, pas_size); MLX5_SET(create_xrc_srq_in, create_in, opcode, MLX5_CMD_OP_CREATE_XRC_SRQ); @@ -293,11 +320,10 @@ static int arm_xrc_srq_cmd(struct mlx5_core_dev *dev, static int query_xrc_srq_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_query_srq_mbox_out *out) + struct mlx5_srq_attr *out) { u32 xrcsrq_in[MLX5_ST_SZ_DW(query_xrc_srq_in)]; u32 *xrcsrq_out; - void *srqc; void *xrc_srqc; int err; @@ -317,8 +343,9 @@ static int query_xrc_srq_cmd(struct mlx5_core_dev *dev, xrc_srqc = MLX5_ADDR_OF(query_xrc_srq_out, xrcsrq_out, xrc_srq_context_entry); - srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry); - memcpy(srqc, xrc_srqc, MLX5_ST_SZ_BYTES(srqc)); + get_srqc(xrc_srqc, out); + if (MLX5_GET(xrc_srqc, xrc_srqc, state) != MLX5_XRC_SRQC_STATE_GOOD) + out->flags |= MLX5_SRQ_FLAG_ERR; out: kvfree(xrcsrq_out); @@ -326,26 +353,27 @@ out: } static int create_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_create_srq_mbox_in *in, int srq_inlen) + struct mlx5_srq_attr *in) { void *create_in; void *rmpc; - void *srqc; + void *wq; int pas_size; int inlen; int err; - srqc = MLX5_ADDR_OF(create_srq_in, in, srq_context_entry); - pas_size = get_pas_size(srqc); + pas_size = get_pas_size(in); inlen = MLX5_ST_SZ_BYTES(create_rmp_in) + pas_size; create_in = mlx5_vzalloc(inlen); if (!create_in) return -ENOMEM; rmpc = MLX5_ADDR_OF(create_rmp_in, create_in, ctx); + wq = MLX5_ADDR_OF(rmpc, rmpc, wq); + MLX5_SET(rmpc, rmpc, state, MLX5_RMPC_STATE_RDY); + set_wq(wq, in); memcpy(MLX5_ADDR_OF(rmpc, rmpc, wq.pas), in->pas, pas_size); - rmpc_srqc_reformat(srqc, rmpc, true); err = mlx5_core_create_rmp(dev, create_in, inlen, &srq->srqn); @@ -390,11 +418,10 @@ static int arm_rmp_cmd(struct mlx5_core_dev *dev, } static int query_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_query_srq_mbox_out *out) + struct mlx5_srq_attr *out) { u32 *rmp_out; void *rmpc; - void *srqc; int err; rmp_out = mlx5_vzalloc(MLX5_ST_SZ_BYTES(query_rmp_out)); @@ -405,9 +432,10 @@ static int query_rmp_cmd(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, if (err) goto out; - srqc = MLX5_ADDR_OF(query_srq_out, out, srq_context_entry); rmpc = MLX5_ADDR_OF(query_rmp_out, rmp_out, rmp_context); - rmpc_srqc_reformat(srqc, rmpc, false); + get_wq(MLX5_ADDR_OF(rmpc, rmpc, wq), out); + if (MLX5_GET(rmpc, rmpc, state) != MLX5_RMPC_STATE_RDY) + out->flags |= MLX5_SRQ_FLAG_ERR; out: kvfree(rmp_out); @@ -416,15 +444,14 @@ out: static int create_srq_split(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_create_srq_mbox_in *in, - int inlen, int is_xrc) + struct mlx5_srq_attr *in) { if (!dev->issi) - return create_srq_cmd(dev, srq, in, inlen); + return create_srq_cmd(dev, srq, in); else if (srq->common.res == MLX5_RES_XSRQ) - return create_xrc_srq_cmd(dev, srq, in, inlen); + return create_xrc_srq_cmd(dev, srq, in); else - return create_rmp_cmd(dev, srq, in, inlen); + return create_rmp_cmd(dev, srq, in); } static int destroy_srq_split(struct mlx5_core_dev *dev, @@ -439,15 +466,17 @@ static int destroy_srq_split(struct mlx5_core_dev *dev, } int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_create_srq_mbox_in *in, int inlen, - int is_xrc) + struct mlx5_srq_attr *in) { int err; struct mlx5_srq_table *table = &dev->priv.srq_table; - srq->common.res = is_xrc ? MLX5_RES_XSRQ : MLX5_RES_SRQ; + if (in->type == IB_SRQT_XRC) + srq->common.res = MLX5_RES_XSRQ; + else + srq->common.res = MLX5_RES_SRQ; - err = create_srq_split(dev, srq, in, inlen, is_xrc); + err = create_srq_split(dev, srq, in); if (err) return err; @@ -502,7 +531,7 @@ int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq) EXPORT_SYMBOL(mlx5_core_destroy_srq); int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_query_srq_mbox_out *out) + struct mlx5_srq_attr *out) { if (!dev->issi) return query_srq_cmd(dev, srq, out); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 80776d0c52dc..ba933335772c 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -46,6 +46,7 @@ #include #include +#include enum { MLX5_RQ_BITMASK_VSD = 1 << 1, @@ -772,11 +773,10 @@ struct mlx5_cmd_mailbox *mlx5_alloc_cmd_mailbox_chain(struct mlx5_core_dev *dev, void mlx5_free_cmd_mailbox_chain(struct mlx5_core_dev *dev, struct mlx5_cmd_mailbox *head); int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_create_srq_mbox_in *in, int inlen, - int is_xrc); + struct mlx5_srq_attr *in); int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq); int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, - struct mlx5_query_srq_mbox_out *out); + struct mlx5_srq_attr *out); int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, u16 lwm, int is_srq); void mlx5_init_mkey_table(struct mlx5_core_dev *dev); diff --git a/include/linux/mlx5/srq.h b/include/linux/mlx5/srq.h index f43ed054a3e0..33c97dc900f8 100644 --- a/include/linux/mlx5/srq.h +++ b/include/linux/mlx5/srq.h @@ -35,6 +35,31 @@ #include +enum { + MLX5_SRQ_FLAG_ERR = (1 << 0), + MLX5_SRQ_FLAG_WQ_SIG = (1 << 1), +}; + +struct mlx5_srq_attr { + u32 type; + u32 flags; + u32 log_size; + u32 wqe_shift; + u32 log_page_size; + u32 wqe_cnt; + u32 srqn; + u32 xrcd; + u32 page_offset; + u32 cqn; + u32 pd; + u32 lwm; + u32 user_index; + u64 db_record; + u64 *pas; +}; + +struct mlx5_core_dev; + void mlx5_init_srq_table(struct mlx5_core_dev *dev); void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev); -- cgit v1.2.3 From 765bf9b739731b925ca26a8f05765b87f2bd9724 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 8 Jun 2016 12:04:47 +0100 Subject: PCI: Add generic pci_bus_claim_resources() All PCI resources (bridge windows and BARs) should be inserted in the iomem_resource and ioport_resource trees so we know what space is occupied and what is available for other devices. There's nothing arch-specific about this, but it is currently done by arch-specific code. Add a generic pci_bus_claim_resources() interface so we can migrate away from the arch-specific code. [bhelgaas: changelog] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas CC: Arnd Bergmann CC: Yinghai Lu --- drivers/pci/setup-bus.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 2 files changed, 69 insertions(+) (limited to 'include/linux') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 55641a39a3e9..1d1a2c952c35 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1423,6 +1423,74 @@ void pci_bus_assign_resources(const struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_assign_resources); +static void pci_claim_device_resources(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { + struct resource *r = &dev->resource[i]; + + if (!r->flags || r->parent) + continue; + + pci_claim_resource(dev, i); + } +} + +static void pci_claim_bridge_resources(struct pci_dev *dev) +{ + int i; + + for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { + struct resource *r = &dev->resource[i]; + + if (!r->flags || r->parent) + continue; + + pci_claim_bridge_resource(dev, i); + } +} + +static void pci_bus_allocate_dev_resources(struct pci_bus *b) +{ + struct pci_dev *dev; + struct pci_bus *child; + + list_for_each_entry(dev, &b->devices, bus_list) { + pci_claim_device_resources(dev); + + child = dev->subordinate; + if (child) + pci_bus_allocate_dev_resources(child); + } +} + +static void pci_bus_allocate_resources(struct pci_bus *b) +{ + struct pci_bus *child; + + /* + * Carry out a depth-first search on the PCI bus + * tree to allocate bridge apertures. Read the + * programmed bridge bases and recursively claim + * the respective bridge resources. + */ + if (b->self) { + pci_read_bridge_bases(b); + pci_claim_bridge_resources(b->self); + } + + list_for_each_entry(child, &b->children, node) + pci_bus_allocate_resources(child); +} + +void pci_bus_claim_resources(struct pci_bus *b) +{ + pci_bus_allocate_resources(b); + pci_bus_allocate_dev_resources(b); +} +EXPORT_SYMBOL(pci_bus_claim_resources); + static void __pci_bridge_assign_resources(const struct pci_dev *bridge, struct list_head *add_head, struct list_head *fail_head) diff --git a/include/linux/pci.h b/include/linux/pci.h index 6af3b93f0710..d6cfecfee864 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1114,6 +1114,7 @@ int pci_set_vpd_size(struct pci_dev *dev, size_t len); /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx); void pci_bus_assign_resources(const struct pci_bus *bus); +void pci_bus_claim_resources(struct pci_bus *bus); void pci_bus_size_bridges(struct pci_bus *bus); int pci_claim_resource(struct pci_dev *, int); int pci_claim_bridge_resource(struct pci_dev *bridge, int i); -- cgit v1.2.3 From d1bd330a229fc8a69f0e7532138dfd42b4542fd4 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 21 Jun 2016 01:17:17 +0100 Subject: of_mdio: Enable fixed PHY support if driver is a module The fixed_phy driver doesn't have to be built-in, and it's important that of_mdio supports it even if it's a module. Signed-off-by: Ben Hutchings Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/of/of_mdio.c | 2 +- include/linux/of_mdio.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index e051e1b57609..de68707a99c7 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -361,7 +361,7 @@ struct phy_device *of_phy_attach(struct net_device *dev, } EXPORT_SYMBOL(of_phy_attach); -#if defined(CONFIG_FIXED_PHY) +#if IS_ENABLED(CONFIG_FIXED_PHY) /* * of_phy_is_fixed_link() and of_phy_register_fixed_link() must * support two DT bindings: diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h index 8f2237eb3485..6c8cb9aa4c00 100644 --- a/include/linux/of_mdio.h +++ b/include/linux/of_mdio.h @@ -69,7 +69,7 @@ static inline int of_mdio_parse_addr(struct device *dev, } #endif /* CONFIG_OF */ -#if defined(CONFIG_OF) && defined(CONFIG_FIXED_PHY) +#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_FIXED_PHY) extern int of_phy_register_fixed_link(struct device_node *np); extern bool of_phy_is_fixed_link(struct device_node *np); #else -- cgit v1.2.3 From af7d5185263133f859dd4f35d45594deef9db854 Mon Sep 17 00:00:00 2001 From: Rana Shahout Date: Tue, 21 Jun 2016 12:43:59 +0300 Subject: net/mlx4_en: Add DCB PFC support through CEE netlink commands This patch adds support for reading and updating priority flow control (PFC) attributes in the driver via netlink. Signed-off-by: Rana Shahout Signed-off-by: Eran Ben Elisha Signed-off-by: Eugenia Emantayev Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 277 +++++++++++++++++++++++-- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 25 +++ drivers/net/ethernet/mellanox/mlx4/fw.c | 1 + drivers/net/ethernet/mellanox/mlx4/fw.h | 1 + drivers/net/ethernet/mellanox/mlx4/main.c | 1 + drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 26 +++ drivers/net/ethernet/mellanox/mlx4/port.c | 12 ++ include/linux/mlx4/device.h | 2 + 8 files changed, 331 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index f01918c63f28..99c6bbdff501 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -37,6 +37,11 @@ #include "mlx4_en.h" #include "fw_qos.h" +enum { + MLX4_CEE_STATE_DOWN = 0, + MLX4_CEE_STATE_UP = 1, +}; + /* Definitions for QCN */ @@ -80,13 +85,202 @@ struct mlx4_congestion_control_mb_prio_802_1_qau_statistics { __be32 reserved3[4]; }; +static u8 mlx4_en_dcbnl_getcap(struct net_device *dev, int capid, u8 *cap) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + switch (capid) { + case DCB_CAP_ATTR_PFC: + *cap = true; + break; + case DCB_CAP_ATTR_DCBX: + *cap = priv->cee_params.dcbx_cap; + break; + case DCB_CAP_ATTR_PFC_TCS: + *cap = 1 << mlx4_max_tc(priv->mdev->dev); + break; + default: + *cap = false; + break; + } + + return 0; +} + +static u8 mlx4_en_dcbnl_getpfcstate(struct net_device *netdev) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + + return priv->cee_params.dcb_cfg.pfc_state; +} + +static void mlx4_en_dcbnl_setpfcstate(struct net_device *netdev, u8 state) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + + priv->cee_params.dcb_cfg.pfc_state = state; +} + +static void mlx4_en_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, + u8 *setting) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + + *setting = priv->cee_params.dcb_cfg.tc_config[priority].dcb_pfc; +} + +static void mlx4_en_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority, + u8 setting) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + + priv->cee_params.dcb_cfg.tc_config[priority].dcb_pfc = setting; + priv->cee_params.dcb_cfg.pfc_state = true; +} + +static int mlx4_en_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + + if (!(priv->flags & MLX4_EN_FLAG_DCB_ENABLED)) + return -EINVAL; + + if (tcid == DCB_NUMTCS_ATTR_PFC) + *num = mlx4_max_tc(priv->mdev->dev); + else + *num = 0; + + return 0; +} + +static u8 mlx4_en_dcbnl_set_all(struct net_device *netdev) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_cee_config *dcb_cfg = &priv->cee_params.dcb_cfg; + int err = 0; + + if (!(priv->cee_params.dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return -EINVAL; + + if (dcb_cfg->pfc_state) { + int tc; + + priv->prof->rx_pause = 0; + priv->prof->tx_pause = 0; + for (tc = 0; tc < CEE_DCBX_MAX_PRIO; tc++) { + u8 tc_mask = 1 << tc; + + switch (dcb_cfg->tc_config[tc].dcb_pfc) { + case pfc_disabled: + priv->prof->tx_ppp &= ~tc_mask; + priv->prof->rx_ppp &= ~tc_mask; + break; + case pfc_enabled_full: + priv->prof->tx_ppp |= tc_mask; + priv->prof->rx_ppp |= tc_mask; + break; + case pfc_enabled_tx: + priv->prof->tx_ppp |= tc_mask; + priv->prof->rx_ppp &= ~tc_mask; + break; + case pfc_enabled_rx: + priv->prof->tx_ppp &= ~tc_mask; + priv->prof->rx_ppp |= tc_mask; + break; + default: + break; + } + } + en_dbg(DRV, priv, "Set pfc on\n"); + } else { + priv->prof->rx_pause = 1; + priv->prof->tx_pause = 1; + en_dbg(DRV, priv, "Set pfc off\n"); + } + + err = mlx4_SET_PORT_general(mdev->dev, priv->port, + priv->rx_skb_size + ETH_FCS_LEN, + priv->prof->tx_pause, + priv->prof->tx_ppp, + priv->prof->rx_pause, + priv->prof->rx_ppp); + if (err) + en_err(priv, "Failed setting pause params\n"); + return err; +} + +static u8 mlx4_en_dcbnl_get_state(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + if (priv->flags & MLX4_EN_FLAG_DCB_ENABLED) + return MLX4_CEE_STATE_UP; + + return MLX4_CEE_STATE_DOWN; +} + +static u8 mlx4_en_dcbnl_set_state(struct net_device *dev, u8 state) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int num_tcs = 0; + + if (!(priv->cee_params.dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return 1; + + if (!!(state) == !!(priv->flags & MLX4_EN_FLAG_DCB_ENABLED)) + return 0; + + if (state) { + priv->flags |= MLX4_EN_FLAG_DCB_ENABLED; + num_tcs = IEEE_8021QAZ_MAX_TCS; + } else { + priv->flags &= ~MLX4_EN_FLAG_DCB_ENABLED; + } + + return mlx4_en_setup_tc(dev, num_tcs); +} + +/* On success returns a non-zero 802.1p user priority bitmap + * otherwise returns 0 as the invalid user priority bitmap to + * indicate an error. + */ +static int mlx4_en_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + struct dcb_app app = { + .selector = idtype, + .protocol = id, + }; + if (!(priv->cee_params.dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return 0; + + return dcb_getapp(netdev, &app); +} + +static int mlx4_en_dcbnl_setapp(struct net_device *netdev, u8 idtype, + u16 id, u8 up) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + struct dcb_app app; + + if (!(priv->cee_params.dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return -EINVAL; + + memset(&app, 0, sizeof(struct dcb_app)); + app.selector = idtype; + app.protocol = id; + app.priority = up; + + return dcb_setapp(netdev, &app); +} + static int mlx4_en_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) { struct mlx4_en_priv *priv = netdev_priv(dev); struct ieee_ets *my_ets = &priv->ets; - /* No IEEE PFC settings available */ if (!my_ets) return -EINVAL; @@ -237,18 +431,51 @@ static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev, static u8 mlx4_en_dcbnl_getdcbx(struct net_device *dev) { - return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; + struct mlx4_en_priv *priv = netdev_priv(dev); + + return priv->cee_params.dcbx_cap; } static u8 mlx4_en_dcbnl_setdcbx(struct net_device *dev, u8 mode) { + struct mlx4_en_priv *priv = netdev_priv(dev); + struct ieee_ets ets = {0}; + struct ieee_pfc pfc = {0}; + + if (mode == priv->cee_params.dcbx_cap) + return 0; + if ((mode & DCB_CAP_DCBX_LLD_MANAGED) || - (mode & DCB_CAP_DCBX_VER_CEE) || - !(mode & DCB_CAP_DCBX_VER_IEEE) || + ((mode & DCB_CAP_DCBX_VER_IEEE) && + (mode & DCB_CAP_DCBX_VER_CEE)) || !(mode & DCB_CAP_DCBX_HOST)) - return 1; + goto err; + + priv->cee_params.dcbx_cap = mode; + + ets.ets_cap = IEEE_8021QAZ_MAX_TCS; + pfc.pfc_cap = IEEE_8021QAZ_MAX_TCS; + + if (mode & DCB_CAP_DCBX_VER_IEEE) { + if (mlx4_en_dcbnl_ieee_setets(dev, &ets)) + goto err; + if (mlx4_en_dcbnl_ieee_setpfc(dev, &pfc)) + goto err; + } else if (mode & DCB_CAP_DCBX_VER_CEE) { + if (mlx4_en_dcbnl_set_all(dev)) + goto err; + } else { + if (mlx4_en_dcbnl_ieee_setets(dev, &ets)) + goto err; + if (mlx4_en_dcbnl_ieee_setpfc(dev, &pfc)) + goto err; + if (mlx4_en_setup_tc(dev, 0)) + goto err; + } return 0; +err: + return 1; } #define MLX4_RATELIMIT_UNITS_IN_KB 100000 /* rate-limit HW unit in Kbps */ @@ -463,24 +690,46 @@ static int mlx4_en_dcbnl_ieee_getqcnstats(struct net_device *dev, } const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops = { - .ieee_getets = mlx4_en_dcbnl_ieee_getets, - .ieee_setets = mlx4_en_dcbnl_ieee_setets, - .ieee_getmaxrate = mlx4_en_dcbnl_ieee_getmaxrate, - .ieee_setmaxrate = mlx4_en_dcbnl_ieee_setmaxrate, - .ieee_getpfc = mlx4_en_dcbnl_ieee_getpfc, - .ieee_setpfc = mlx4_en_dcbnl_ieee_setpfc, + .ieee_getets = mlx4_en_dcbnl_ieee_getets, + .ieee_setets = mlx4_en_dcbnl_ieee_setets, + .ieee_getmaxrate = mlx4_en_dcbnl_ieee_getmaxrate, + .ieee_setmaxrate = mlx4_en_dcbnl_ieee_setmaxrate, + .ieee_getqcn = mlx4_en_dcbnl_ieee_getqcn, + .ieee_setqcn = mlx4_en_dcbnl_ieee_setqcn, + .ieee_getqcnstats = mlx4_en_dcbnl_ieee_getqcnstats, + .ieee_getpfc = mlx4_en_dcbnl_ieee_getpfc, + .ieee_setpfc = mlx4_en_dcbnl_ieee_setpfc, + + .getstate = mlx4_en_dcbnl_get_state, + .setstate = mlx4_en_dcbnl_set_state, + .getpfccfg = mlx4_en_dcbnl_get_pfc_cfg, + .setpfccfg = mlx4_en_dcbnl_set_pfc_cfg, + .setall = mlx4_en_dcbnl_set_all, + .getcap = mlx4_en_dcbnl_getcap, + .getnumtcs = mlx4_en_dcbnl_getnumtcs, + .getpfcstate = mlx4_en_dcbnl_getpfcstate, + .setpfcstate = mlx4_en_dcbnl_setpfcstate, + .getapp = mlx4_en_dcbnl_getapp, + .setapp = mlx4_en_dcbnl_setapp, .getdcbx = mlx4_en_dcbnl_getdcbx, .setdcbx = mlx4_en_dcbnl_setdcbx, - .ieee_getqcn = mlx4_en_dcbnl_ieee_getqcn, - .ieee_setqcn = mlx4_en_dcbnl_ieee_setqcn, - .ieee_getqcnstats = mlx4_en_dcbnl_ieee_getqcnstats, }; const struct dcbnl_rtnl_ops mlx4_en_dcbnl_pfc_ops = { .ieee_getpfc = mlx4_en_dcbnl_ieee_getpfc, .ieee_setpfc = mlx4_en_dcbnl_ieee_setpfc, + .setstate = mlx4_en_dcbnl_set_state, + .getpfccfg = mlx4_en_dcbnl_get_pfc_cfg, + .setpfccfg = mlx4_en_dcbnl_set_pfc_cfg, + .setall = mlx4_en_dcbnl_set_all, + .getnumtcs = mlx4_en_dcbnl_getnumtcs, + .getpfcstate = mlx4_en_dcbnl_getpfcstate, + .setpfcstate = mlx4_en_dcbnl_setpfcstate, + .getapp = mlx4_en_dcbnl_getapp, + .setapp = mlx4_en_dcbnl_setapp, + .getdcbx = mlx4_en_dcbnl_getdcbx, .setdcbx = mlx4_en_dcbnl_setdcbx, }; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 8e318d21321f..d42083a8a104 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -67,6 +67,17 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up) offset += priv->num_tx_rings_p_up; } +#ifdef CONFIG_MLX4_EN_DCB + if (!mlx4_is_slave(priv->mdev->dev)) { + if (up) { + priv->flags |= MLX4_EN_FLAG_DCB_ENABLED; + } else { + priv->flags &= ~MLX4_EN_FLAG_DCB_ENABLED; + priv->cee_params.dcb_cfg.pfc_state = false; + } + } +#endif /* CONFIG_MLX4_EN_DCB */ + return 0; } @@ -2815,6 +2826,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, struct mlx4_en_priv *priv; int i; int err; +#ifdef CONFIG_MLX4_EN_DCB + struct tc_configuration *tc; +#endif dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv), MAX_TX_RINGS, MAX_RX_RINGS); @@ -2881,6 +2895,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->msg_enable = MLX4_EN_MSG_LEVEL; #ifdef CONFIG_MLX4_EN_DCB if (!mlx4_is_slave(priv->mdev->dev)) { + priv->cee_params.dcbx_cap = DCB_CAP_DCBX_VER_CEE | + DCB_CAP_DCBX_HOST | + DCB_CAP_DCBX_VER_IEEE; + priv->flags |= MLX4_EN_DCB_ENABLED; + priv->cee_params.dcb_cfg.pfc_state = false; + + for (i = 0; i < MLX4_EN_NUM_UP; i++) { + tc = &priv->cee_params.dcb_cfg.tc_config[i]; + tc->dcb_pfc = pfc_disabled; + } + if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { dev->dcbnl_ops = &mlx4_en_dcbnl_ops; } else { diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index e97094598b2d..f4497cf4d06d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -1128,6 +1128,7 @@ int mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_c port_cap->max_pkeys = 1 << (field & 0xf); MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET); port_cap->max_vl = field & 0xf; + port_cap->max_tc_eth = field >> 4; MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET); port_cap->log_max_macs = field & 0xf; port_cap->log_max_vlans = field >> 4; diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index 7ea258af636a..cdbd76f10ced 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -53,6 +53,7 @@ struct mlx4_port_cap { int ib_mtu; int max_port_width; int max_vl; + int max_tc_eth; int max_gids; int max_pkeys; u64 def_mac; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 12c77a70abdb..3564aad778a3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -292,6 +292,7 @@ static int _mlx4_dev_port(struct mlx4_dev *dev, int port, dev->caps.pkey_table_len[port] = port_cap->max_pkeys; dev->caps.port_width_cap[port] = port_cap->max_port_width; dev->caps.eth_mtu_cap[port] = port_cap->eth_mtu; + dev->caps.max_tc_eth = port_cap->max_tc_eth; dev->caps.def_mac[port] = port_cap->def_mac; dev->caps.supported_type[port] = port_cap->supported_port_types; dev->caps.suggested_type[port] = port_cap->suggested_type; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 6b3b0fefabad..d39bf594abe4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -448,6 +448,27 @@ struct mlx4_en_frag_info { #define MLX4_EN_TC_ETS 7 +enum dcb_pfc_type { + pfc_disabled = 0, + pfc_enabled_full, + pfc_enabled_tx, + pfc_enabled_rx +}; + +struct tc_configuration { + enum dcb_pfc_type dcb_pfc; +}; + +struct mlx4_en_cee_config { + bool pfc_state; + struct tc_configuration tc_config[MLX4_EN_NUM_UP]; +}; + +struct mlx4_en_cee_params { + u8 dcbx_cap; + struct mlx4_en_cee_config dcb_cfg; +}; + #endif struct ethtool_flow_id { @@ -467,6 +488,9 @@ enum { MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3), MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4), MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP = (1 << 5), +#ifdef CONFIG_MLX4_EN_DCB + MLX4_EN_FLAG_DCB_ENABLED = (1 << 6), +#endif }; #define PORT_BEACON_MAX_LIMIT (65535) @@ -568,9 +592,11 @@ struct mlx4_en_priv { u32 counter_index; #ifdef CONFIG_MLX4_EN_DCB +#define MLX4_EN_DCB_ENABLED 0x3 struct ieee_ets ets; u16 maxrate[IEEE_8021QAZ_MAX_TCS]; enum dcbnl_cndd_states cndd_state[IEEE_8021QAZ_MAX_TCS]; + struct mlx4_en_cee_params cee_params; #endif #ifdef CONFIG_RFS_ACCEL spinlock_t filters_lock; diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 087b23b320cb..3d2095e5c61c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -52,6 +52,7 @@ #define MLX4_FLAG_V_IGNORE_FCS_MASK 0x2 #define MLX4_IGNORE_FCS_MASK 0x1 +#define MLNX4_TX_MAX_NUMBER 8 void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) { @@ -2015,3 +2016,14 @@ out: return ret; } EXPORT_SYMBOL(mlx4_get_module_info); + +int mlx4_max_tc(struct mlx4_dev *dev) +{ + u8 num_tc = dev->caps.max_tc_eth; + + if (!num_tc) + num_tc = MLNX4_TX_MAX_NUMBER; + + return num_tc; +} +EXPORT_SYMBOL(mlx4_max_tc); diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 80dec87a94f8..4dbc1450bbe0 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -535,6 +535,7 @@ struct mlx4_caps { int max_rq_desc_sz; int max_qp_init_rdma; int max_qp_dest_rdma; + int max_tc_eth; u32 *qp0_qkey; u32 *qp0_proxy; u32 *qp1_proxy; @@ -1494,6 +1495,7 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr, int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, u16 offset, u16 size, u8 *data); +int mlx4_max_tc(struct mlx4_dev *dev); /* Returns true if running in low memory profile (kdump kernel) */ static inline bool mlx4_low_memory_profile(void) -- cgit v1.2.3 From 722003ac40c2c397bd5bc2b714125bc82ab27043 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Tue, 21 Jun 2016 09:36:21 -0400 Subject: qed: Add support for coalescing config read/update. This patch adds support for configuring the device tx/rx coalescing timeout values in the order of micro seconds. It also adds APIs for upper layer drivers for reading/updating the coalescing values. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 104 +++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 47 +++++++++++ drivers/net/ethernet/qlogic/qed/qed_hw.c | 23 ++++++ drivers/net/ethernet/qlogic/qed/qed_int.c | 75 ++++++++++++++++-- drivers/net/ethernet/qlogic/qed/qed_int.h | 3 + drivers/net/ethernet/qlogic/qed/qed_main.c | 34 ++++++++ drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 2 + include/linux/qed/qed_if.h | 24 ++++++ 8 files changed, 307 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index e45cff4df280..b26fe267a150 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -2222,6 +2222,110 @@ int qed_fw_rss_eng(struct qed_hwfn *p_hwfn, return 0; } +static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + u32 hw_addr, void *p_eth_qzone, + size_t eth_qzone_size, u8 timeset) +{ + struct coalescing_timeset *p_coal_timeset; + + if (p_hwfn->cdev->int_coalescing_mode != QED_COAL_MODE_ENABLE) { + DP_NOTICE(p_hwfn, "Coalescing configuration not enabled\n"); + return -EINVAL; + } + + p_coal_timeset = p_eth_qzone; + memset(p_coal_timeset, 0, eth_qzone_size); + SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_TIMESET, timeset); + SET_FIELD(p_coal_timeset->value, COALESCING_TIMESET_VALID, 1); + qed_memcpy_to(p_hwfn, p_ptt, hw_addr, p_eth_qzone, eth_qzone_size); + + return 0; +} + +int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + u16 coalesce, u8 qid, u16 sb_id) +{ + struct ustorm_eth_queue_zone eth_qzone; + u8 timeset, timer_res; + u16 fw_qid = 0; + u32 address; + int rc; + + /* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */ + if (coalesce <= 0x7F) { + timer_res = 0; + } else if (coalesce <= 0xFF) { + timer_res = 1; + } else if (coalesce <= 0x1FF) { + timer_res = 2; + } else { + DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce); + return -EINVAL; + } + timeset = (u8)(coalesce >> timer_res); + + rc = qed_fw_l2_queue(p_hwfn, (u16)qid, &fw_qid); + if (rc) + return rc; + + rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res, sb_id, false); + if (rc) + goto out; + + address = BAR0_MAP_REG_USDM_RAM + USTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid); + + rc = qed_set_coalesce(p_hwfn, p_ptt, address, ð_qzone, + sizeof(struct ustorm_eth_queue_zone), timeset); + if (rc) + goto out; + + p_hwfn->cdev->rx_coalesce_usecs = coalesce; +out: + return rc; +} + +int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + u16 coalesce, u8 qid, u16 sb_id) +{ + struct xstorm_eth_queue_zone eth_qzone; + u8 timeset, timer_res; + u16 fw_qid = 0; + u32 address; + int rc; + + /* Coalesce = (timeset << timer-resolution), timeset is 7bit wide */ + if (coalesce <= 0x7F) { + timer_res = 0; + } else if (coalesce <= 0xFF) { + timer_res = 1; + } else if (coalesce <= 0x1FF) { + timer_res = 2; + } else { + DP_ERR(p_hwfn, "Invalid coalesce value - %d\n", coalesce); + return -EINVAL; + } + timeset = (u8)(coalesce >> timer_res); + + rc = qed_fw_l2_queue(p_hwfn, (u16)qid, &fw_qid); + if (rc) + return rc; + + rc = qed_int_set_timer_res(p_hwfn, p_ptt, timer_res, sb_id, true); + if (rc) + goto out; + + address = BAR0_MAP_REG_XSDM_RAM + XSTORM_ETH_QUEUE_ZONE_OFFSET(fw_qid); + + rc = qed_set_coalesce(p_hwfn, p_ptt, address, ð_qzone, + sizeof(struct xstorm_eth_queue_zone), timeset); + if (rc) + goto out; + + p_hwfn->cdev->tx_coalesce_usecs = coalesce; +out: + return rc; +} + /* Calculate final WFQ values for all vports and configure them. * After this configuration each vport will have * approx min rate = min_pf_rate * (vport_wfq / QED_WFQ_UNIT) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h index f810ce45d463..343bb0344f62 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h @@ -212,6 +212,20 @@ qed_dmae_host2grc(struct qed_hwfn *p_hwfn, u32 size_in_dwords, u32 flags); + /** + * @brief qed_dmae_grc2host - Read data from dmae data offset + * to source address using the given ptt + * + * @param p_ptt + * @param grc_addr (dmae_data_offset) + * @param dest_addr + * @param size_in_dwords + * @param flags - one of the flags defined above + */ +int qed_dmae_grc2host(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + u32 grc_addr, dma_addr_t dest_addr, u32 size_in_dwords, + u32 flags); + /** * @brief qed_dmae_host2host - copy data from to source address * to a destination adress (for SRIOV) using the given ptt @@ -308,4 +322,37 @@ int qed_fw_rss_eng(struct qed_hwfn *p_hwfn, int qed_final_cleanup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u16 id, bool is_vf); +/** + * @brief qed_set_rxq_coalesce - Configure coalesce parameters for an Rx queue + * The fact that we can configure coalescing to up to 511, but on varying + * accuracy [the bigger the value the less accurate] up to a mistake of 3usec + * for the highest values. + * + * @param p_hwfn + * @param p_ptt + * @param coalesce - Coalesce value in micro seconds. + * @param qid - Queue index. + * @param qid - SB Id + * + * @return int + */ +int qed_set_rxq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + u16 coalesce, u8 qid, u16 sb_id); + +/** + * @brief qed_set_txq_coalesce - Configure coalesce parameters for a Tx queue + * While the API allows setting coalescing per-qid, all tx queues sharing a + * SB should be in same range [i.e., either 0-0x7f, 0x80-0xff or 0x100-0x1ff] + * otherwise configuration would break. + * + * @param p_hwfn + * @param p_ptt + * @param coalesce - Coalesce value in micro seconds. + * @param qid - Queue index. + * @param qid - SB Id + * + * @return int + */ +int qed_set_txq_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + u16 coalesce, u8 qid, u16 sb_id); #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c index 2693c30981eb..e17885321faf 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hw.c +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c @@ -768,6 +768,29 @@ int qed_dmae_host2grc(struct qed_hwfn *p_hwfn, return rc; } +int +qed_dmae_grc2host(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u32 grc_addr, + dma_addr_t dest_addr, u32 size_in_dwords, u32 flags) +{ + u32 grc_addr_in_dw = grc_addr / sizeof(u32); + struct qed_dmae_params params; + int rc; + + memset(¶ms, 0, sizeof(struct qed_dmae_params)); + params.flags = flags; + + mutex_lock(&p_hwfn->dmae_info.mutex); + + rc = qed_dmae_execute_command(p_hwfn, p_ptt, grc_addr_in_dw, + dest_addr, QED_DMAE_ADDRESS_GRC, + QED_DMAE_ADDRESS_HOST_VIRT, + size_in_dwords, ¶ms); + + mutex_unlock(&p_hwfn->dmae_info.mutex); + + return rc; +} + int qed_dmae_host2host(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 09a6ad3d22dd..8fa50fa23c8d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -2418,6 +2418,7 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn, { struct qed_dev *cdev = p_hwfn->cdev; u32 cau_state; + u8 timer_res; memset(p_sb_entry, 0, sizeof(*p_sb_entry)); @@ -2443,6 +2444,23 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn, cdev->tx_coalesce_usecs = QED_CAU_DEF_TX_USECS; } + /* Coalesce = (timeset << timer-res), timeset is 7bit wide */ + if (cdev->rx_coalesce_usecs <= 0x7F) + timer_res = 0; + else if (cdev->rx_coalesce_usecs <= 0xFF) + timer_res = 1; + else + timer_res = 2; + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_TIMER_RES0, timer_res); + + if (cdev->tx_coalesce_usecs <= 0x7F) + timer_res = 0; + else if (cdev->tx_coalesce_usecs <= 0xFF) + timer_res = 1; + else + timer_res = 2; + SET_FIELD(p_sb_entry->params, CAU_SB_ENTRY_TIMER_RES1, timer_res); + SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE0, cau_state); SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE1, cau_state); } @@ -2484,17 +2502,28 @@ void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn, /* Configure pi coalescing if set */ if (p_hwfn->cdev->int_coalescing_mode == QED_COAL_MODE_ENABLE) { - u8 timeset = p_hwfn->cdev->rx_coalesce_usecs >> - (QED_CAU_DEF_RX_TIMER_RES + 1); + u8 timeset, timer_res; u8 num_tc = 1, i; + /* timeset = (coalesce >> timer-res), timeset is 7bit wide */ + if (p_hwfn->cdev->rx_coalesce_usecs <= 0x7F) + timer_res = 0; + else if (p_hwfn->cdev->rx_coalesce_usecs <= 0xFF) + timer_res = 1; + else + timer_res = 2; + timeset = (u8)(p_hwfn->cdev->rx_coalesce_usecs >> timer_res); qed_int_cau_conf_pi(p_hwfn, p_ptt, igu_sb_id, RX_PI, QED_COAL_RX_STATE_MACHINE, timeset); - timeset = p_hwfn->cdev->tx_coalesce_usecs >> - (QED_CAU_DEF_TX_TIMER_RES + 1); - + if (p_hwfn->cdev->tx_coalesce_usecs <= 0x7F) + timer_res = 0; + else if (p_hwfn->cdev->tx_coalesce_usecs <= 0xFF) + timer_res = 1; + else + timer_res = 2; + timeset = (u8)(p_hwfn->cdev->tx_coalesce_usecs >> timer_res); for (i = 0; i < num_tc; i++) { qed_int_cau_conf_pi(p_hwfn, p_ptt, igu_sb_id, TX_PI(i), @@ -3199,3 +3228,39 @@ void qed_int_disable_post_isr_release(struct qed_dev *cdev) for_each_hwfn(cdev, i) cdev->hwfns[i].b_int_requested = false; } + +int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + u8 timer_res, u16 sb_id, bool tx) +{ + struct cau_sb_entry sb_entry; + int rc; + + if (!p_hwfn->hw_init_done) { + DP_ERR(p_hwfn, "hardware not initialized yet\n"); + return -EINVAL; + } + + rc = qed_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY + + sb_id * sizeof(u64), + (u64)(uintptr_t)&sb_entry, 2, 0); + if (rc) { + DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc); + return rc; + } + + if (tx) + SET_FIELD(sb_entry.params, CAU_SB_ENTRY_TIMER_RES1, timer_res); + else + SET_FIELD(sb_entry.params, CAU_SB_ENTRY_TIMER_RES0, timer_res); + + rc = qed_dmae_host2grc(p_hwfn, p_ptt, + (u64)(uintptr_t)&sb_entry, + CAU_REG_SB_VAR_MEMORY + + sb_id * sizeof(u64), 2, 0); + if (rc) { + DP_ERR(p_hwfn, "dmae_host2grc failed %d\n", rc); + return rc; + } + + return rc; +} diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 20b468637504..0948be64dc78 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -389,6 +389,9 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn, u16 vf_number, u8 vf_valid); +int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + u8 timer_res, u16 sb_id, bool tx); + #define QED_MAPPING_MEMORY_SIZE(dev) (NUM_OF_SBS(dev)) #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 6c4606b44b7e..e32ee57cdfee 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -1303,6 +1303,38 @@ static int qed_drain(struct qed_dev *cdev) return 0; } +static void qed_get_coalesce(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal) +{ + *rx_coal = cdev->rx_coalesce_usecs; + *tx_coal = cdev->tx_coalesce_usecs; +} + +static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, + u8 qid, u16 sb_id) +{ + struct qed_hwfn *hwfn; + struct qed_ptt *ptt; + int hwfn_index; + int status = 0; + + hwfn_index = qid % cdev->num_hwfns; + hwfn = &cdev->hwfns[hwfn_index]; + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return -EAGAIN; + + status = qed_set_rxq_coalesce(hwfn, ptt, rx_coal, + qid / cdev->num_hwfns, sb_id); + if (status) + goto out; + status = qed_set_txq_coalesce(hwfn, ptt, tx_coal, + qid / cdev->num_hwfns, sb_id); +out: + qed_ptt_release(hwfn, ptt); + + return status; +} + static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) { struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); @@ -1349,5 +1381,7 @@ const struct qed_common_ops qed_common_ops_pass = { .update_msglvl = &qed_init_dp, .chain_alloc = &qed_chain_alloc, .chain_free = &qed_chain_free, + .get_coalesce = &qed_get_coalesce, + .set_coalesce = &qed_set_coalesce, .set_led = &qed_set_led, }; diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index aa08ddbd95df..f6b86ca1ff79 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -80,6 +80,8 @@ 0x1f00000UL #define BAR0_MAP_REG_TSDM_RAM \ 0x1c80000UL +#define BAR0_MAP_REG_XSDM_RAM \ + 0x1e00000UL #define NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF \ 0x5011f4UL #define PRS_REG_SEARCH_TCP \ diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index e1d5122e8a96..b1e3c57c7117 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -488,6 +488,30 @@ struct qed_common_ops { void (*chain_free)(struct qed_dev *cdev, struct qed_chain *p_chain); +/** + * @brief get_coalesce - Get coalesce parameters in usec + * + * @param cdev + * @param rx_coal - Rx coalesce value in usec + * @param tx_coal - Tx coalesce value in usec + * + */ + void (*get_coalesce)(struct qed_dev *cdev, u16 *rx_coal, u16 *tx_coal); + +/** + * @brief set_coalesce - Configure Rx coalesce value in usec + * + * @param cdev + * @param rx_coal - Rx coalesce value in usec + * @param tx_coal - Tx coalesce value in usec + * @param qid - Queue index + * @param sb_id - Status Block Id + * + * @return 0 on success, error otherwise. + */ + int (*set_coalesce)(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, + u8 qid, u16 sb_id); + /** * @brief set_led - Configure LED mode * -- cgit v1.2.3 From bb8e15d60462a84a25a3bf33e8bc29b46c6d470a Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Wed, 1 Jun 2016 14:06:15 +0800 Subject: of: iommu: make of_iommu_init() postcore_initcall_sync The of_iommu_init() is called multiple times by arch code, make it postcore_initcall_sync, then we can drop relevant calls fully. Note, the IOMMUs should have a chance to perform some basic initialisation before we start adding masters to them. So postcore_initcall_sync is good choice, it ensures of_iommu_init() called before of_platform_populate. Acked-by: Rich Felker Tested-by: Marek Szyprowski Cc: Arnd Bergmann Cc: Catalin Marinas Cc: Marek Szyprowski Cc: Rich Felker Cc: Rob Herring Cc: Robin Murphy Cc: Will Deacon Signed-off-by: Kefeng Wang Acked-by: Joerg Roedel Signed-off-by: Rob Herring --- arch/arm/kernel/setup.c | 2 -- arch/arm64/kernel/setup.c | 2 -- arch/sh/boards/of-generic.c | 2 -- drivers/iommu/of_iommu.c | 5 ++++- include/linux/of_iommu.h | 2 -- 5 files changed, 4 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 7b5350060612..7e455339789b 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -903,7 +902,6 @@ static int __init customize_machine(void) * machine from the device tree, if no callback is provided, * otherwise we would always need an init_machine callback. */ - of_iommu_init(); if (machine_desc->init_machine) machine_desc->init_machine(); #ifdef CONFIG_OF diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 3279defabaa2..8412520ef62d 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -305,7 +304,6 @@ void __init setup_arch(char **cmdline_p) static int __init arm64_device_init(void) { if (of_have_populated_dt()) { - of_iommu_init(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } else if (acpi_disabled) { diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c index bf3a166a5407..b4d4313af6f1 100644 --- a/arch/sh/boards/of-generic.c +++ b/arch/sh/boards/of-generic.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -185,7 +184,6 @@ static int __init sh_of_device_init(void) { pr_info("SH generic board support: populating platform devices\n"); if (of_have_populated_dt()) { - of_iommu_init(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } else { diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index af499aea0a1a..57f23eaaa2f9 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -174,7 +174,7 @@ err_put_node: return NULL; } -void __init of_iommu_init(void) +static int __init of_iommu_init(void) { struct device_node *np; const struct of_device_id *match, *matches = &__iommu_of_table; @@ -186,4 +186,7 @@ void __init of_iommu_init(void) pr_err("Failed to initialise IOMMU %s\n", of_node_full_name(np)); } + + return 0; } +postcore_initcall_sync(of_iommu_init); diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h index bd02b44902d0..e80b9c762a03 100644 --- a/include/linux/of_iommu.h +++ b/include/linux/of_iommu.h @@ -11,7 +11,6 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix, int index, unsigned long *busno, dma_addr_t *addr, size_t *size); -extern void of_iommu_init(void); extern const struct iommu_ops *of_iommu_configure(struct device *dev, struct device_node *master_np); @@ -24,7 +23,6 @@ static inline int of_get_dma_window(struct device_node *dn, const char *prefix, return -EINVAL; } -static inline void of_iommu_init(void) { } static inline const struct iommu_ops *of_iommu_configure(struct device *dev, struct device_node *master_np) { -- cgit v1.2.3 From 8654df4e2ac9704905198d63845554c2ddf6a93f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 9 Jun 2016 16:06:06 -0500 Subject: mnt: Refactor fs_fully_visible into mount_too_revealing Replace the call of fs_fully_visible in do_new_mount from before the new superblock is allocated with a call of mount_too_revealing after the superblock is allocated. This winds up being a much better location for maintainability of the code. The first change this enables is the replacement of FS_USERNS_VISIBLE with SB_I_USERNS_VISIBLE. Moving the flag from struct filesystem_type to sb_iflags on the superblock. Unfortunately mount_too_revealing fundamentally needs to touch mnt_flags adding several MNT_LOCKED_XXX flags at the appropriate times. If the mnt_flags did not need to be touched the code could be easily moved into the filesystem specific mount code. Acked-by: Seth Forshee Signed-off-by: "Eric W. Biederman" --- fs/namespace.c | 38 +++++++++++++++++++++++++------------- fs/proc/inode.c | 1 + fs/proc/root.c | 2 +- fs/sysfs/mount.c | 4 ++-- include/linux/fs.h | 4 +++- 5 files changed, 32 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/fs/namespace.c b/fs/namespace.c index 783004af5707..1a69aa786975 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2375,7 +2375,7 @@ unlock: return err; } -static bool fs_fully_visible(struct file_system_type *fs_type, int *new_mnt_flags); +static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags); /* * create a new mount for userspace and request it to be added into the @@ -2408,12 +2408,6 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, flags |= MS_NODEV; mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; } - if (type->fs_flags & FS_USERNS_VISIBLE) { - if (!fs_fully_visible(type, &mnt_flags)) { - put_filesystem(type); - return -EPERM; - } - } } mnt = vfs_kern_mount(type, flags, name, data); @@ -2425,6 +2419,11 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, if (IS_ERR(mnt)) return PTR_ERR(mnt); + if (mount_too_revealing(mnt, &mnt_flags)) { + mntput(mnt); + return -EPERM; + } + err = do_add_mount(real_mount(mnt), path, mnt_flags); if (err) mntput(mnt); @@ -3216,22 +3215,19 @@ bool current_chrooted(void) return chrooted; } -static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) +static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new, + int *new_mnt_flags) { - struct mnt_namespace *ns = current->nsproxy->mnt_ns; int new_flags = *new_mnt_flags; struct mount *mnt; bool visible = false; - if (unlikely(!ns)) - return false; - down_read(&namespace_sem); list_for_each_entry(mnt, &ns->list, mnt_list) { struct mount *child; int mnt_flags; - if (mnt->mnt.mnt_sb->s_type != type) + if (mnt->mnt.mnt_sb->s_type != new->mnt_sb->s_type) continue; /* This mount is not fully visible if it's root directory @@ -3298,6 +3294,22 @@ found: return visible; } +static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags) +{ + struct mnt_namespace *ns = current->nsproxy->mnt_ns; + unsigned long s_iflags; + + if (ns->user_ns == &init_user_ns) + return false; + + /* Can this filesystem be too revealing? */ + s_iflags = mnt->mnt_sb->s_iflags; + if (!(s_iflags & SB_I_USERNS_VISIBLE)) + return false; + + return !mnt_already_visible(ns, mnt, new_mnt_flags); +} + static struct ns_common *mntns_get(struct task_struct *task) { struct ns_common *ns = NULL; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 42305ddcbaa0..78fa452d65ed 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -462,6 +462,7 @@ int proc_fill_super(struct super_block *s) struct inode *root_inode; int ret; + s->s_iflags |= SB_I_USERNS_VISIBLE; s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; s->s_blocksize = 1024; s->s_blocksize_bits = 10; diff --git a/fs/proc/root.c b/fs/proc/root.c index 55bc7d6c8aac..a1b2860fec62 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -158,7 +158,7 @@ static struct file_system_type proc_fs_type = { .name = "proc", .mount = proc_mount, .kill_sb = proc_kill_sb, - .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT, + .fs_flags = FS_USERNS_MOUNT, }; void __init proc_root_init(void) diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index f3db82071cfb..f31e36994dfb 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -42,7 +42,7 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); else if (new_sb) /* Userspace would break if executables appear on sysfs */ - root->d_sb->s_iflags |= SB_I_NOEXEC; + root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC; return root; } @@ -59,7 +59,7 @@ static struct file_system_type sysfs_fs_type = { .name = "sysfs", .mount = sysfs_mount, .kill_sb = sysfs_kill_sb, - .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT, + .fs_flags = FS_USERNS_MOUNT, }; int __init sysfs_init(void) diff --git a/include/linux/fs.h b/include/linux/fs.h index dd288148a6b1..71988dd3af95 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1328,6 +1328,9 @@ struct mm_struct; #define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ #define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ +/* sb->s_iflags to limit user namespace mounts */ +#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */ + /* Possible states of 'frozen' field */ enum { SB_UNFROZEN = 0, /* FS is unfrozen */ @@ -2011,7 +2014,6 @@ struct file_system_type { #define FS_HAS_SUBTYPE 4 #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ #define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */ -#define FS_USERNS_VISIBLE 32 /* FS must already be visible */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); -- cgit v1.2.3 From d91ee87d8d85a0808c01787e8b4a6b48f2ba487b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 23 May 2016 14:51:59 -0500 Subject: vfs: Pass data, ns, and ns->userns to mount_ns Today what is normally called data (the mount options) is not passed to fill_super through mount_ns. Pass the mount options and the namespace separately to mount_ns so that filesystems such as proc that have mount options, can use mount_ns. Pass the user namespace to mount_ns so that the standard permission check that verifies the mounter has permissions over the namespace can be performed in mount_ns instead of in each filesystems .mount method. Thus removing the duplication between mqueuefs and proc in terms of permission checks. The extra permission check does not currently affect the rpc_pipefs filesystem and the nfsd filesystem as those filesystems do not currently allow unprivileged mounts. Without unpvileged mounts it is guaranteed that the caller has already passed capable(CAP_SYS_ADMIN) which guarantees extra permission check will pass. Update rpc_pipefs and the nfsd filesystem to ensure that the network namespace reference is always taken in fill_super and always put in kill_sb so that the logic is simpler and so that errors originating inside of fill_super do not cause a network namespace leak. Acked-by: Seth Forshee Signed-off-by: "Eric W. Biederman" --- fs/nfsd/nfsctl.c | 13 ++++--------- fs/super.c | 13 ++++++++++--- include/linux/fs.h | 5 +++-- ipc/mqueue.c | 19 ++++++++----------- net/sunrpc/rpc_pipe.c | 8 ++++---- 5 files changed, 29 insertions(+), 29 deletions(-) (limited to 'include/linux') diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 9690cb4dd588..5a6ae2522266 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1154,20 +1154,15 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) #endif /* last one */ {""} }; - struct net *net = data; - int ret; - - ret = simple_fill_super(sb, 0x6e667364, nfsd_files); - if (ret) - return ret; - sb->s_fs_info = get_net(net); - return 0; + get_net(sb->s_fs_info); + return simple_fill_super(sb, 0x6e667364, nfsd_files); } static struct dentry *nfsd_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_ns(fs_type, flags, current->nsproxy->net_ns, nfsd_fill_super); + struct net *net = current->nsproxy->net_ns; + return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super); } static void nfsd_umount(struct super_block *sb) diff --git a/fs/super.c b/fs/super.c index d78b9847e6cb..fd65667832e5 100644 --- a/fs/super.c +++ b/fs/super.c @@ -918,12 +918,19 @@ static int ns_set_super(struct super_block *sb, void *data) return set_anon_super(sb, NULL); } -struct dentry *mount_ns(struct file_system_type *fs_type, int flags, - void *data, int (*fill_super)(struct super_block *, void *, int)) +struct dentry *mount_ns(struct file_system_type *fs_type, + int flags, void *data, void *ns, struct user_namespace *user_ns, + int (*fill_super)(struct super_block *, void *, int)) { struct super_block *sb; - sb = sget(fs_type, ns_test_super, ns_set_super, flags, data); + /* Don't allow mounting unless the caller has CAP_SYS_ADMIN + * over the namespace. + */ + if (!(flags & MS_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + + sb = sget(fs_type, ns_test_super, ns_set_super, flags, ns); if (IS_ERR(sb)) return ERR_CAST(sb); diff --git a/include/linux/fs.h b/include/linux/fs.h index 71988dd3af95..1ce006a24f49 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2034,8 +2034,9 @@ struct file_system_type { #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME) -extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags, - void *data, int (*fill_super)(struct super_block *, void *, int)); +extern struct dentry *mount_ns(struct file_system_type *fs_type, + int flags, void *data, void *ns, struct user_namespace *user_ns, + int (*fill_super)(struct super_block *, void *, int)); extern struct dentry *mount_bdev(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, int (*fill_super)(struct super_block *, void *, int)); diff --git a/ipc/mqueue.c b/ipc/mqueue.c index ade739f67f1d..60d97082f4dc 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -305,7 +305,7 @@ err: static int mqueue_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; - struct ipc_namespace *ns = data; + struct ipc_namespace *ns = sb->s_fs_info; sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; @@ -326,17 +326,14 @@ static struct dentry *mqueue_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - if (!(flags & MS_KERNMOUNT)) { - struct ipc_namespace *ns = current->nsproxy->ipc_ns; - /* Don't allow mounting unless the caller has CAP_SYS_ADMIN - * over the ipc namespace. - */ - if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - data = ns; + struct ipc_namespace *ns; + if (flags & MS_KERNMOUNT) { + ns = data; + data = NULL; + } else { + ns = current->nsproxy->ipc_ns; } - return mount_ns(fs_type, flags, data, mqueue_fill_super); + return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super); } static void init_once(void *foo) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index fc48eca21fd2..84f98cbe31c3 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1386,7 +1386,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; struct dentry *root, *gssd_dentry; - struct net *net = data; + struct net *net = get_net(sb->s_fs_info); struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); int err; @@ -1419,7 +1419,6 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) sb); if (err) goto err_depopulate; - sb->s_fs_info = get_net(net); mutex_unlock(&sn->pipefs_sb_lock); return 0; @@ -1448,7 +1447,8 @@ static struct dentry * rpc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_ns(fs_type, flags, current->nsproxy->net_ns, rpc_fill_super); + struct net *net = current->nsproxy->net_ns; + return mount_ns(fs_type, flags, data, net, net->user_ns, rpc_fill_super); } static void rpc_kill_sb(struct super_block *sb) @@ -1468,9 +1468,9 @@ static void rpc_kill_sb(struct super_block *sb) RPC_PIPEFS_UMOUNT, sb); mutex_unlock(&sn->pipefs_sb_lock); - put_net(net); out: kill_litter_super(sb); + put_net(net); } static struct file_system_type rpc_pipe_fs_type = { -- cgit v1.2.3 From 6e4eab577a0cae15b3da9b888cff16fe57981b3e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 24 May 2016 09:29:01 -0500 Subject: fs: Add user namespace member to struct super_block Start marking filesystems with a user namespace owner, s_user_ns. In this change this is only used for permission checks of who may mount a filesystem. Ultimately s_user_ns will be used for translating ids and checking capabilities for filesystems mounted from user namespaces. The default policy for setting s_user_ns is implemented in sget(), which arranges for s_user_ns to be set to current_user_ns() and to ensure that the mounter of the filesystem has CAP_SYS_ADMIN in that user_ns. The guts of sget are split out into another function sget_userns(). The function sget_userns calls alloc_super with the specified user namespace or it verifies the existing superblock that was found has the expected user namespace, and fails with EBUSY when it is not. This failing prevents users with the wrong privileges mounting a filesystem. The reason for the split of sget_userns from sget is that in some cases such as mount_ns and kernfs_mount_ns a different policy for permission checking of mounts and setting s_user_ns is necessary, and the existence of sget_userns() allows those policies to be implemented. The helper mount_ns is expected to be used for filesystems such as proc and mqueuefs which present per namespace information. The function mount_ns is modified to call sget_userns instead of sget to ensure the user namespace owner of the namespace whose information is presented by the filesystem is used on the superblock. For sysfs and cgroup the appropriate permission checks are already in place, and kernfs_mount_ns is modified to call sget_userns so that the init_user_ns is the only user namespace used. For the cgroup filesystem cgroup namespace mounts are bind mounts of a subset of the full cgroup filesystem and as such s_user_ns must be the same for all of them as there is only a single superblock. Mounts of sysfs that vary based on the network namespace could in principle change s_user_ns but it keeps the analysis and implementation of kernfs simpler if that is not supported, and at present there appear to be no benefits from supporting a different s_user_ns on any sysfs mount. Getting the details of setting s_user_ns correct has been a long process. Thanks to Pavel Tikhorirorv who spotted a leak in sget_userns. Thanks to Seth Forshee who has kept the work alive. Thanks-to: Seth Forshee Thanks-to: Pavel Tikhomirov Acked-by: Seth Forshee Signed-off-by: Eric W. Biederman --- fs/kernfs/mount.c | 3 ++- fs/super.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ include/linux/fs.h | 12 ++++++++++++ 3 files changed, 60 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 63534f5f9073..d90d574c15a2 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -241,7 +241,8 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, info->root = root; info->ns = ns; - sb = sget(fs_type, kernfs_test_super, kernfs_set_super, flags, info); + sb = sget_userns(fs_type, kernfs_test_super, kernfs_set_super, flags, + &init_user_ns, info); if (IS_ERR(sb) || sb->s_fs_info != info) kfree(info); if (IS_ERR(sb)) diff --git a/fs/super.c b/fs/super.c index fd65667832e5..874c7e3ebb8f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "internal.h" @@ -165,6 +166,7 @@ static void destroy_super(struct super_block *s) list_lru_destroy(&s->s_inode_lru); security_sb_free(s); WARN_ON(!list_empty(&s->s_mounts)); + put_user_ns(s->s_user_ns); kfree(s->s_subtype); kfree(s->s_options); call_rcu(&s->rcu, destroy_super_rcu); @@ -174,11 +176,13 @@ static void destroy_super(struct super_block *s) * alloc_super - create new superblock * @type: filesystem type superblock should belong to * @flags: the mount flags + * @user_ns: User namespace for the super_block * * Allocates and initializes a new &struct super_block. alloc_super() * returns a pointer new superblock or %NULL if allocation had failed. */ -static struct super_block *alloc_super(struct file_system_type *type, int flags) +static struct super_block *alloc_super(struct file_system_type *type, int flags, + struct user_namespace *user_ns) { struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER); static const struct super_operations default_op; @@ -188,6 +192,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags) return NULL; INIT_LIST_HEAD(&s->s_mounts); + s->s_user_ns = get_user_ns(user_ns); if (security_sb_alloc(s)) goto fail; @@ -443,17 +448,18 @@ void generic_shutdown_super(struct super_block *sb) EXPORT_SYMBOL(generic_shutdown_super); /** - * sget - find or create a superblock + * sget_userns - find or create a superblock * @type: filesystem type superblock should belong to * @test: comparison callback * @set: setup callback * @flags: mount flags + * @user_ns: User namespace for the super_block * @data: argument to each of them */ -struct super_block *sget(struct file_system_type *type, +struct super_block *sget_userns(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), - int flags, + int flags, struct user_namespace *user_ns, void *data) { struct super_block *s = NULL; @@ -466,6 +472,14 @@ retry: hlist_for_each_entry(old, &type->fs_supers, s_instances) { if (!test(old, data)) continue; + if (user_ns != old->s_user_ns) { + spin_unlock(&sb_lock); + if (s) { + up_write(&s->s_umount); + destroy_super(s); + } + return ERR_PTR(-EBUSY); + } if (!grab_super(old)) goto retry; if (s) { @@ -478,7 +492,7 @@ retry: } if (!s) { spin_unlock(&sb_lock); - s = alloc_super(type, flags); + s = alloc_super(type, flags, user_ns); if (!s) return ERR_PTR(-ENOMEM); goto retry; @@ -501,6 +515,31 @@ retry: return s; } +EXPORT_SYMBOL(sget_userns); + +/** + * sget - find or create a superblock + * @type: filesystem type superblock should belong to + * @test: comparison callback + * @set: setup callback + * @flags: mount flags + * @data: argument to each of them + */ +struct super_block *sget(struct file_system_type *type, + int (*test)(struct super_block *,void *), + int (*set)(struct super_block *,void *), + int flags, + void *data) +{ + struct user_namespace *user_ns = current_user_ns(); + + /* Ensure the requestor has permissions over the target filesystem */ + if (!(flags & MS_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + + return sget_userns(type, test, set, flags, user_ns, data); +} + EXPORT_SYMBOL(sget); void drop_super(struct super_block *sb) @@ -930,7 +969,8 @@ struct dentry *mount_ns(struct file_system_type *fs_type, if (!(flags & MS_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN)) return ERR_PTR(-EPERM); - sb = sget(fs_type, ns_test_super, ns_set_super, flags, ns); + sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags, + user_ns, ns); if (IS_ERR(sb)) return ERR_CAST(sb); diff --git a/include/linux/fs.h b/include/linux/fs.h index 1ce006a24f49..9eef64f23a75 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1432,6 +1432,13 @@ struct super_block { struct workqueue_struct *s_dio_done_wq; struct hlist_head s_pins; + /* + * Owning user namespace and default context in which to + * interpret filesystem uids, gids, quotas, device nodes, + * xattrs and security labels. + */ + struct user_namespace *s_user_ns; + /* * Keep the lru lists last in the structure so they always sit on their * own individual cachelines. @@ -2056,6 +2063,11 @@ void deactivate_locked_super(struct super_block *sb); int set_anon_super(struct super_block *s, void *data); int get_anon_bdev(dev_t *); void free_anon_bdev(dev_t); +struct super_block *sget_userns(struct file_system_type *type, + int (*test)(struct super_block *,void *), + int (*set)(struct super_block *,void *), + int flags, struct user_namespace *user_ns, + void *data); struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), -- cgit v1.2.3 From a2982cc922c3068783eb9a1f77a5626a1ec36a1f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 9 Jun 2016 15:34:02 -0500 Subject: vfs: Generalize filesystem nodev handling. Introduce a function may_open_dev that tests MNT_NODEV and a new superblock flab SB_I_NODEV. Use this new function in all of the places where MNT_NODEV was previously tested. Add the new SB_I_NODEV s_iflag to proc, sysfs, and mqueuefs as those filesystems should never support device nodes, and a simple superblock flags makes that very hard to get wrong. With SB_I_NODEV set if any device nodes somehow manage to show up on on a filesystem those device nodes will be unopenable. Acked-by: Seth Forshee Signed-off-by: "Eric W. Biederman" --- fs/block_dev.c | 2 +- fs/kernfs/mount.c | 4 ++-- fs/namei.c | 8 +++++++- fs/proc/inode.c | 4 ++-- include/linux/fs.h | 2 ++ ipc/mqueue.c | 2 +- 6 files changed, 15 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/fs/block_dev.c b/fs/block_dev.c index 71ccab1d22c6..30b8d568203a 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1857,7 +1857,7 @@ struct block_device *lookup_bdev(const char *pathname) if (!S_ISBLK(inode->i_mode)) goto fail; error = -EACCES; - if (path.mnt->mnt_flags & MNT_NODEV) + if (!may_open_dev(&path)) goto fail; error = -ENOMEM; bdev = bd_acquire(inode); diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 1443df670260..b3d73ad52b22 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -152,8 +152,8 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic) struct dentry *root; info->sb = sb; - /* Userspace would break if executables appear on sysfs */ - sb->s_iflags |= SB_I_NOEXEC; + /* Userspace would break if executables or devices appear on sysfs */ + sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; sb->s_magic = magic; diff --git a/fs/namei.c b/fs/namei.c index 6a82fb7e2127..757a32725d92 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2881,6 +2881,12 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, } EXPORT_SYMBOL(vfs_create); +bool may_open_dev(const struct path *path) +{ + return !(path->mnt->mnt_flags & MNT_NODEV) && + !(path->mnt->mnt_sb->s_iflags & SB_I_NODEV); +} + static int may_open(struct path *path, int acc_mode, int flag) { struct dentry *dentry = path->dentry; @@ -2899,7 +2905,7 @@ static int may_open(struct path *path, int acc_mode, int flag) break; case S_IFBLK: case S_IFCHR: - if (path->mnt->mnt_flags & MNT_NODEV) + if (!may_open_dev(path)) return -EACCES; /*FALLTHRU*/ case S_IFIFO: diff --git a/fs/proc/inode.c b/fs/proc/inode.c index f4817efb25a6..a5b2c33745b7 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -466,8 +466,8 @@ int proc_fill_super(struct super_block *s, void *data, int silent) if (!proc_parse_options(data, ns)) return -EINVAL; - /* User space would break if executables appear on proc */ - s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC; + /* User space would break if executables or devices appear on proc */ + s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV; s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; s->s_blocksize = 1024; s->s_blocksize_bits = 10; diff --git a/include/linux/fs.h b/include/linux/fs.h index 9eef64f23a75..e05983170d23 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1327,6 +1327,7 @@ struct mm_struct; /* sb->s_iflags */ #define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ #define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ +#define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */ /* sb->s_iflags to limit user namespace mounts */ #define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */ @@ -1602,6 +1603,7 @@ extern int vfs_whiteout(struct inode *, struct dentry *); */ extern void inode_init_owner(struct inode *inode, const struct inode *dir, umode_t mode); +extern bool may_open_dev(const struct path *path); /* * VFS FS_IOC_FIEMAP helper definitions. */ diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 5bdd50de7d05..0b13ace266f2 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -307,7 +307,7 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent) struct inode *inode; struct ipc_namespace *ns = sb->s_fs_info; - sb->s_iflags |= SB_I_NOEXEC; + sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; sb->s_magic = MQUEUE_MAGIC; -- cgit v1.2.3 From cc50a07a247e17db76b1f0b0ca06652556e04fa3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 9 Jun 2016 15:44:48 -0500 Subject: userns: Remove the now unnecessary FS_USERNS_DEV_MOUNT flag Now that SB_I_NODEV controls the nodev behavior devpts can just clear this flag during mount. Simplifying the code and making it easier to audit how the code works. While still preserving the invariant that s_iflags is only modified during mount. Acked-by: Seth Forshee Signed-off-by: "Eric W. Biederman" --- fs/devpts/inode.c | 3 ++- fs/super.c | 3 +-- include/linux/fs.h | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 37c134a132c7..d116453b0276 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -396,6 +396,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent) { struct inode *inode; + s->s_iflags &= ~SB_I_NODEV; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = DEVPTS_SUPER_MAGIC; @@ -480,7 +481,7 @@ static struct file_system_type devpts_fs_type = { .name = "devpts", .mount = devpts_mount, .kill_sb = devpts_kill_sb, - .fs_flags = FS_USERNS_MOUNT | FS_USERNS_DEV_MOUNT, + .fs_flags = FS_USERNS_MOUNT, }; /* diff --git a/fs/super.c b/fs/super.c index 25cdceed2ad3..37813bf479cf 100644 --- a/fs/super.c +++ b/fs/super.c @@ -206,8 +206,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, init_waitqueue_head(&s->s_writers.wait_unfrozen); s->s_bdi = &noop_backing_dev_info; s->s_flags = flags; - if ((s->s_user_ns != &init_user_ns) && - !(type->fs_flags & FS_USERNS_DEV_MOUNT)) + if (s->s_user_ns != &init_user_ns) s->s_iflags |= SB_I_NODEV; INIT_HLIST_NODE(&s->s_instances); INIT_HLIST_BL_HEAD(&s->s_anon); diff --git a/include/linux/fs.h b/include/linux/fs.h index e05983170d23..375e37f42cdf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2022,7 +2022,6 @@ struct file_system_type { #define FS_BINARY_MOUNTDATA 2 #define FS_HAS_SUBTYPE 4 #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ -#define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); -- cgit v1.2.3 From d07b846f6200454c50d791796edb82660192513d Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Wed, 23 Sep 2015 15:16:04 -0500 Subject: fs: Limit file caps to the user namespace of the super block Capability sets attached to files must be ignored except in the user namespaces where the mounter is privileged, i.e. s_user_ns and its descendants. Otherwise a vector exists for gaining privileges in namespaces where a user is not already privileged. Add a new helper function, current_in_user_ns(), to test whether a user namespace is the same as or a descendant of another namespace. Use this helper to determine whether a file's capability set should be applied to the caps constructed during exec. --EWB Replaced in_userns with the simpler current_in_userns. Acked-by: Serge Hallyn Signed-off-by: Seth Forshee Signed-off-by: Eric W. Biederman --- include/linux/user_namespace.h | 6 ++++++ kernel/user_namespace.c | 14 ++++++++++++++ security/commoncap.c | 2 ++ 3 files changed, 22 insertions(+) (limited to 'include/linux') diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 8297e5b341d8..9217169c64cb 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -72,6 +72,7 @@ extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t, extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *); extern int proc_setgroups_show(struct seq_file *m, void *v); extern bool userns_may_setgroups(const struct user_namespace *ns); +extern bool current_in_userns(const struct user_namespace *target_ns); #else static inline struct user_namespace *get_user_ns(struct user_namespace *ns) @@ -100,6 +101,11 @@ static inline bool userns_may_setgroups(const struct user_namespace *ns) { return true; } + +static inline bool current_in_userns(const struct user_namespace *target_ns) +{ + return true; +} #endif #endif /* _LINUX_USER_H */ diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 9bafc211930c..68f594212759 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -938,6 +938,20 @@ bool userns_may_setgroups(const struct user_namespace *ns) return allowed; } +/* + * Returns true if @ns is the same namespace as or a descendant of + * @target_ns. + */ +bool current_in_userns(const struct user_namespace *target_ns) +{ + struct user_namespace *ns; + for (ns = current_user_ns(); ns; ns = ns->parent) { + if (ns == target_ns) + return true; + } + return false; +} + static inline struct user_namespace *to_user_ns(struct ns_common *ns) { return container_of(ns, struct user_namespace, ns); diff --git a/security/commoncap.c b/security/commoncap.c index e7fadde737f4..e109e6dac858 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -455,6 +455,8 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) return 0; + if (!current_in_userns(bprm->file->f_path.mnt->mnt_sb->s_user_ns)) + return 0; rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); if (rc < 0) { -- cgit v1.2.3 From 380cf5ba6b0a0b307f4afb62b186ca801defb203 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 23 Jun 2016 16:41:05 -0500 Subject: fs: Treat foreign mounts as nosuid If a process gets access to a mount from a different user namespace, that process should not be able to take advantage of setuid files or selinux entrypoints from that filesystem. Prevent this by treating mounts from other mount namespaces and those not owned by current_user_ns() or an ancestor as nosuid. This will make it safer to allow more complex filesystems to be mounted in non-root user namespaces. This does not remove the need for MNT_LOCK_NOSUID. The setuid, setgid, and file capability bits can no longer be abused if code in a user namespace were to clear nosuid on an untrusted filesystem, but this patch, by itself, is insufficient to protect the system from abuse of files that, when execed, would increase MAC privilege. As a more concrete explanation, any task that can manipulate a vfsmount associated with a given user namespace already has capabilities in that namespace and all of its descendents. If they can cause a malicious setuid, setgid, or file-caps executable to appear in that mount, then that executable will only allow them to elevate privileges in exactly the set of namespaces in which they are already privileges. On the other hand, if they can cause a malicious executable to appear with a dangerous MAC label, running it could change the caller's security context in a way that should not have been possible, even inside the namespace in which the task is confined. As a hardening measure, this would have made CVE-2014-5207 much more difficult to exploit. Signed-off-by: Andy Lutomirski Signed-off-by: Seth Forshee Acked-by: James Morris Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- fs/exec.c | 2 +- fs/namespace.c | 13 +++++++++++++ include/linux/mount.h | 1 + security/commoncap.c | 8 +++++++- security/selinux/hooks.c | 2 +- 5 files changed, 23 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/fs/exec.c b/fs/exec.c index 887c1c955df8..ca239fc86d8d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1411,7 +1411,7 @@ static void bprm_fill_uid(struct linux_binprm *bprm) bprm->cred->euid = current_euid(); bprm->cred->egid = current_egid(); - if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) + if (!mnt_may_suid(bprm->file->f_path.mnt)) return; if (task_no_new_privs(current)) diff --git a/fs/namespace.c b/fs/namespace.c index 9786a38d1681..aabe8e397fc3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3280,6 +3280,19 @@ static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags) return !mnt_already_visible(ns, mnt, new_mnt_flags); } +bool mnt_may_suid(struct vfsmount *mnt) +{ + /* + * Foreign mounts (accessed via fchdir or through /proc + * symlinks) are always treated as if they are nosuid. This + * prevents namespaces from trusting potentially unsafe + * suid/sgid bits, file caps, or security labels that originate + * in other namespaces. + */ + return !(mnt->mnt_flags & MNT_NOSUID) && check_mnt(real_mount(mnt)) && + current_in_userns(mnt->mnt_sb->s_user_ns); +} + static struct ns_common *mntns_get(struct task_struct *task) { struct ns_common *ns = NULL; diff --git a/include/linux/mount.h b/include/linux/mount.h index f822c3c11377..54a594d49733 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -81,6 +81,7 @@ extern void mntput(struct vfsmount *mnt); extern struct vfsmount *mntget(struct vfsmount *mnt); extern struct vfsmount *mnt_clone_internal(struct path *path); extern int __mnt_is_readonly(struct vfsmount *mnt); +extern bool mnt_may_suid(struct vfsmount *mnt); struct path; extern struct vfsmount *clone_private_mount(struct path *path); diff --git a/security/commoncap.c b/security/commoncap.c index e109e6dac858..14540bd78561 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -453,8 +453,14 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c if (!file_caps_enabled) return 0; - if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) + if (!mnt_may_suid(bprm->file->f_path.mnt)) return 0; + + /* + * This check is redundant with mnt_may_suid() but is kept to make + * explicit that capability bits are limited to s_user_ns and its + * descendants. + */ if (!current_in_userns(bprm->file->f_path.mnt->mnt_sb->s_user_ns)) return 0; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a86d537eb79b..15541756eb07 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2259,7 +2259,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm, const struct task_security_struct *new_tsec) { int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS); - int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID); + int nosuid = !mnt_may_suid(bprm->file->f_path.mnt); int rc; if (!nnp && !nosuid) -- cgit v1.2.3 From 6be2b3d0848d1ed3e78e416cc4ae9007e85c7533 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 6 Jun 2016 16:58:20 -0700 Subject: soc: qcom: wcnss_ctrl: Make wcnss_ctrl parent the other components We need the signal from wcnss_ctrl indicating that the firmware is up and running before we can communicate with the other components of the chip. So make these other components children of the wcnss_ctrl device, so they can be probed in order. The process seems to take between 1/2-5 seconds, so this is done in a worker, instead of holding up the probe. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/wcnss_ctrl.c | 125 ++++++++++++++++++++++++++++++------ include/linux/soc/qcom/wcnss_ctrl.h | 8 +++ 2 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 include/linux/soc/qcom/wcnss_ctrl.h (limited to 'include/linux') diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index c544f3d2c6ee..520aedd29965 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2015, Sony Mobile Communications Inc. * * This program is free software; you can redistribute it and/or modify @@ -14,8 +15,16 @@ #include #include #include +#include +#include +#include +#include #define WCNSS_REQUEST_TIMEOUT (5 * HZ) +#define WCNSS_CBC_TIMEOUT (10 * HZ) + +#define WCNSS_ACK_DONE_BOOTING 1 +#define WCNSS_ACK_COLD_BOOTING 2 #define NV_FRAGMENT_SIZE 3072 #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" @@ -25,17 +34,19 @@ * @dev: device handle * @channel: SMD channel handle * @ack: completion for outstanding requests + * @cbc: completion for cbc complete indication * @ack_status: status of the outstanding request - * @download_nv_work: worker for uploading nv binary + * @probe_work: worker for uploading nv binary */ struct wcnss_ctrl { struct device *dev; struct qcom_smd_channel *channel; struct completion ack; + struct completion cbc; int ack_status; - struct work_struct download_nv_work; + struct work_struct probe_work; }; /* message types */ @@ -48,6 +59,11 @@ enum { WCNSS_UPLOAD_CAL_RESP, WCNSS_DOWNLOAD_CAL_REQ, WCNSS_DOWNLOAD_CAL_RESP, + WCNSS_VBAT_LEVEL_IND, + WCNSS_BUILD_VERSION_REQ, + WCNSS_BUILD_VERSION_RESP, + WCNSS_PM_CONFIG_REQ, + WCNSS_CBC_COMPLETE_IND, }; /** @@ -128,7 +144,7 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, version->major, version->minor, version->version, version->revision); - schedule_work(&wcnss->download_nv_work); + complete(&wcnss->ack); break; case WCNSS_DOWNLOAD_NV_RESP: if (count != sizeof(*nvresp)) { @@ -141,6 +157,10 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, wcnss->ack_status = nvresp->status; complete(&wcnss->ack); break; + case WCNSS_CBC_COMPLETE_IND: + dev_dbg(wcnss->dev, "cold boot complete\n"); + complete(&wcnss->cbc); + break; default: dev_info(wcnss->dev, "unknown message type %d\n", hdr->type); break; @@ -156,20 +176,32 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, static int wcnss_request_version(struct wcnss_ctrl *wcnss) { struct wcnss_msg_hdr msg; + int ret; msg.type = WCNSS_VERSION_REQ; msg.len = sizeof(msg); + ret = qcom_smd_send(wcnss->channel, &msg, sizeof(msg)); + if (ret < 0) + return ret; + + ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_CBC_TIMEOUT); + if (!ret) { + dev_err(wcnss->dev, "timeout waiting for version response\n"); + return -ETIMEDOUT; + } - return qcom_smd_send(wcnss->channel, &msg, sizeof(msg)); + return 0; } /** * wcnss_download_nv() - send nv binary to WCNSS - * @work: work struct to acquire wcnss context + * @wcnss: wcnss_ctrl state handle + * @expect_cbc: indicator to caller that an cbc event is expected + * + * Returns 0 on success. Negative errno on failure. */ -static void wcnss_download_nv(struct work_struct *work) +static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) { - struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work); struct wcnss_download_nv_req *req; const struct firmware *fw; const void *data; @@ -178,10 +210,10 @@ static void wcnss_download_nv(struct work_struct *work) req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); if (!req) - return; + return -ENOMEM; ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev); - if (ret) { + if (ret < 0) { dev_err(wcnss->dev, "Failed to load nv file %s: %d\n", NVBIN_FILE, ret); goto free_req; @@ -207,7 +239,7 @@ static void wcnss_download_nv(struct work_struct *work) memcpy(req->fragment, data, req->frag_size); ret = qcom_smd_send(wcnss->channel, req, req->hdr.len); - if (ret) { + if (ret < 0) { dev_err(wcnss->dev, "failed to send smd packet\n"); goto release_fw; } @@ -220,16 +252,58 @@ static void wcnss_download_nv(struct work_struct *work) } while (left > 0); ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT); - if (!ret) + if (!ret) { dev_err(wcnss->dev, "timeout waiting for nv upload ack\n"); - else if (wcnss->ack_status != 1) - dev_err(wcnss->dev, "nv upload response failed err: %d\n", - wcnss->ack_status); + ret = -ETIMEDOUT; + } else { + *expect_cbc = wcnss->ack_status == WCNSS_ACK_COLD_BOOTING; + ret = 0; + } release_fw: release_firmware(fw); free_req: kfree(req); + + return ret; +} + +/** + * qcom_wcnss_open_channel() - open additional SMD channel to WCNSS + * @wcnss: wcnss handle, retrieved from drvdata + * @name: SMD channel name + * @cb: callback to handle incoming data on the channel + */ +struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb) +{ + struct wcnss_ctrl *_wcnss = wcnss; + + return qcom_smd_open_channel(_wcnss->channel, name, cb); +} +EXPORT_SYMBOL(qcom_wcnss_open_channel); + +static void wcnss_async_probe(struct work_struct *work) +{ + struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, probe_work); + bool expect_cbc; + int ret; + + ret = wcnss_request_version(wcnss); + if (ret < 0) + return; + + ret = wcnss_download_nv(wcnss, &expect_cbc); + if (ret < 0) + return; + + /* Wait for pending cold boot completion if indicated by the nv downloader */ + if (expect_cbc) { + ret = wait_for_completion_timeout(&wcnss->cbc, WCNSS_REQUEST_TIMEOUT); + if (!ret) + dev_err(wcnss->dev, "expected cold boot completion\n"); + } + + of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev); } static int wcnss_ctrl_probe(struct qcom_smd_device *sdev) @@ -244,25 +318,38 @@ static int wcnss_ctrl_probe(struct qcom_smd_device *sdev) wcnss->channel = sdev->channel; init_completion(&wcnss->ack); - INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv); + init_completion(&wcnss->cbc); + INIT_WORK(&wcnss->probe_work, wcnss_async_probe); qcom_smd_set_drvdata(sdev->channel, wcnss); + dev_set_drvdata(&sdev->dev, wcnss); + + schedule_work(&wcnss->probe_work); + + return 0; +} + +static void wcnss_ctrl_remove(struct qcom_smd_device *sdev) +{ + struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(sdev->channel); - return wcnss_request_version(wcnss); + cancel_work_sync(&wcnss->probe_work); + of_platform_depopulate(&sdev->dev); } -static const struct qcom_smd_id wcnss_ctrl_smd_match[] = { - { .name = "WCNSS_CTRL" }, +static const struct of_device_id wcnss_ctrl_of_match[] = { + { .compatible = "qcom,wcnss", }, {} }; static struct qcom_smd_driver wcnss_ctrl_driver = { .probe = wcnss_ctrl_probe, + .remove = wcnss_ctrl_remove, .callback = wcnss_ctrl_smd_callback, - .smd_match_table = wcnss_ctrl_smd_match, .driver = { .name = "qcom_wcnss_ctrl", .owner = THIS_MODULE, + .of_match_table = wcnss_ctrl_of_match, }, }; diff --git a/include/linux/soc/qcom/wcnss_ctrl.h b/include/linux/soc/qcom/wcnss_ctrl.h new file mode 100644 index 000000000000..a37bc5538f19 --- /dev/null +++ b/include/linux/soc/qcom/wcnss_ctrl.h @@ -0,0 +1,8 @@ +#ifndef __WCNSS_CTRL_H__ +#define __WCNSS_CTRL_H__ + +#include + +struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb); + +#endif -- cgit v1.2.3 From f295e53b60eb93ee53ed5ac610374ed293caa57b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 17 Jun 2016 11:08:06 -0700 Subject: libnvdimm, pmem: allow nfit_test to override pmem_direct_access() Currently phys_to_pfn_t() is an exported symbol to allow nfit_test to override it and indicate that nfit_test-pmem is not device-mapped. Now, we want to enable nfit_test to operate without DMA_CMA and the pmem it provides will no longer be physically contiguous, i.e. won't be capable of supporting direct_access requests larger than a page. Make pmem_direct_access() a weak symbol so that it can be replaced by the tools/testing/nvdimm/ version, and move phys_to_pfn_t() to a static inline now that it no longer needs to be overridden. Acked-by: Johannes Thumshirn Signed-off-by: Dan Williams --- drivers/nvdimm/pmem.c | 18 +++------------ drivers/nvdimm/pmem.h | 24 ++++++++++++++++++++ include/linux/pfn_t.h | 5 ++++- kernel/memremap.c | 6 ----- tools/testing/nvdimm/Kbuild | 3 ++- tools/testing/nvdimm/pmem-dax.c | 42 +++++++++++++++++++++++++++++++++++ tools/testing/nvdimm/test/iomap.c | 3 ++- tools/testing/nvdimm/test/nfit_test.h | 2 ++ 8 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 drivers/nvdimm/pmem.h create mode 100644 tools/testing/nvdimm/pmem-dax.c (limited to 'include/linux') diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index ba253df6233f..b6fcb97a601c 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -29,23 +29,10 @@ #include #include #include +#include "pmem.h" #include "pfn.h" #include "nd.h" -struct pmem_device { - /* One contiguous memory region per device */ - phys_addr_t phys_addr; - /* when non-zero this device is hosting a 'pfn' instance */ - phys_addr_t data_offset; - u64 pfn_flags; - void __pmem *virt_addr; - /* immutable base size of the namespace */ - size_t size; - /* trim size when namespace capacity has been section aligned */ - u32 pfn_pad; - struct badblocks bb; -}; - static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, unsigned int len) { @@ -163,7 +150,8 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector, return rc; } -static long pmem_direct_access(struct block_device *bdev, sector_t sector, +/* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */ +__weak long pmem_direct_access(struct block_device *bdev, sector_t sector, void __pmem **kaddr, pfn_t *pfn, long size) { struct pmem_device *pmem = bdev->bd_queue->queuedata; diff --git a/drivers/nvdimm/pmem.h b/drivers/nvdimm/pmem.h new file mode 100644 index 000000000000..c48d4e3aa346 --- /dev/null +++ b/drivers/nvdimm/pmem.h @@ -0,0 +1,24 @@ +#ifndef __NVDIMM_PMEM_H__ +#define __NVDIMM_PMEM_H__ +#include +#include +#include +#include + +long pmem_direct_access(struct block_device *bdev, sector_t sector, + void __pmem **kaddr, pfn_t *pfn, long size); +/* this definition is in it's own header for tools/testing/nvdimm to consume */ +struct pmem_device { + /* One contiguous memory region per device */ + phys_addr_t phys_addr; + /* when non-zero this device is hosting a 'pfn' instance */ + phys_addr_t data_offset; + u64 pfn_flags; + void __pmem *virt_addr; + /* immutable base size of the namespace */ + size_t size; + /* trim size when namespace capacity has been section aligned */ + u32 pfn_pad; + struct badblocks bb; +}; +#endif /* __NVDIMM_PMEM_H__ */ diff --git a/include/linux/pfn_t.h b/include/linux/pfn_t.h index 94994810c7c0..a3d90b9da18d 100644 --- a/include/linux/pfn_t.h +++ b/include/linux/pfn_t.h @@ -28,7 +28,10 @@ static inline pfn_t pfn_to_pfn_t(unsigned long pfn) return __pfn_to_pfn_t(pfn, 0); } -extern pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags); +static inline pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags) +{ + return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags); +} static inline bool pfn_t_has_page(pfn_t pfn) { diff --git a/kernel/memremap.c b/kernel/memremap.c index 017532193fb1..852e5266124a 100644 --- a/kernel/memremap.c +++ b/kernel/memremap.c @@ -169,12 +169,6 @@ void devm_memunmap(struct device *dev, void *addr) } EXPORT_SYMBOL(devm_memunmap); -pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags) -{ - return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags); -} -EXPORT_SYMBOL(phys_to_pfn_t); - #ifdef CONFIG_ZONE_DEVICE static DEFINE_MUTEX(pgmap_lock); static RADIX_TREE(pgmap_radix, GFP_KERNEL); diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 785985677159..4adfa9cdf26f 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -11,12 +11,12 @@ ldflags-y += --wrap=__devm_release_region ldflags-y += --wrap=__request_region ldflags-y += --wrap=__release_region ldflags-y += --wrap=devm_memremap_pages -ldflags-y += --wrap=phys_to_pfn_t DRIVERS := ../../../drivers NVDIMM_SRC := $(DRIVERS)/nvdimm ACPI_SRC := $(DRIVERS)/acpi DAX_SRC := $(DRIVERS)/dax +ccflags-y := -I$(src)/$(NVDIMM_SRC)/ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o @@ -31,6 +31,7 @@ nfit-y := $(ACPI_SRC)/nfit.o nfit-y += config_check.o nd_pmem-y := $(NVDIMM_SRC)/pmem.o +nd_pmem-y += pmem-dax.o nd_pmem-y += config_check.o nd_btt-y := $(NVDIMM_SRC)/btt.o diff --git a/tools/testing/nvdimm/pmem-dax.c b/tools/testing/nvdimm/pmem-dax.c new file mode 100644 index 000000000000..fdba77f2bb06 --- /dev/null +++ b/tools/testing/nvdimm/pmem-dax.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014-2016, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#include "test/nfit_test.h" +#include +#include +#include + +long pmem_direct_access(struct block_device *bdev, sector_t sector, + void __pmem **kaddr, pfn_t *pfn, long size) +{ + struct pmem_device *pmem = bdev->bd_queue->queuedata; + resource_size_t offset = sector * 512 + pmem->data_offset; + + /* disable DAX for nfit_test pmem devices */ + if (get_nfit_res(pmem->phys_addr + offset)) { + dev_info_once(pmem->bb.dev, "dax is disabled for nfit_test\n"); + return -EIO; + } + + if (unlikely(is_bad_pmem(&pmem->bb, sector, size))) + return -EIO; + *kaddr = pmem->virt_addr + offset; + *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); + + /* + * If badblocks are present, limit known good range to the + * requested range. + */ + if (unlikely(pmem->bb.count)) + return size; + return pmem->size - pmem->pfn_pad - offset; +} diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index c842095f2801..9966f093b4ff 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c @@ -52,7 +52,7 @@ static struct nfit_test_resource *__get_nfit_res(resource_size_t resource) return NULL; } -static struct nfit_test_resource *get_nfit_res(resource_size_t resource) +struct nfit_test_resource *get_nfit_res(resource_size_t resource) { struct nfit_test_resource *res; @@ -62,6 +62,7 @@ static struct nfit_test_resource *get_nfit_res(resource_size_t resource) return res; } +EXPORT_SYMBOL(get_nfit_res); void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size, void __iomem *(*fallback_fn)(resource_size_t, unsigned long)) diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index 96c5e16d7db9..9f18e2a4a862 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h @@ -12,6 +12,7 @@ */ #ifndef __NFIT_TEST_H__ #define __NFIT_TEST_H__ +#include struct nfit_test_resource { struct list_head list; @@ -26,4 +27,5 @@ void __iomem *__wrap_ioremap_nocache(resource_size_t offset, void __wrap_iounmap(volatile void __iomem *addr); void nfit_test_setup(nfit_test_lookup_fn lookup); void nfit_test_teardown(void); +struct nfit_test_resource *get_nfit_res(resource_size_t resource); #endif -- cgit v1.2.3 From f01e90fe34f563a5e189d4070de4a23948105642 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 23 Sep 2015 12:56:12 -0700 Subject: firmware: qcom: scm: Peripheral Authentication Service This adds the Peripheral Authentication Service (PAS) interface to the Qualcomm SCM interface. The API is used to authenticate and boot a range of external processors in various Qualcomm platforms. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/firmware/qcom_scm-32.c | 89 +++++++++++++++++++++++++++ drivers/firmware/qcom_scm-64.c | 89 +++++++++++++++++++++++++++ drivers/firmware/qcom_scm.c | 134 +++++++++++++++++++++++++++++++++++++++++ drivers/firmware/qcom_scm.h | 14 +++++ include/linux/qcom_scm.h | 8 +++ 5 files changed, 334 insertions(+) (limited to 'include/linux') diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index bbf1780b8781..7cb6a5d648fa 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -458,3 +458,92 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req, void __qcom_scm_init(void) { } + +bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral) +{ + __le32 out; + __le32 in; + int ret; + + in = cpu_to_le32(peripheral); + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PAS_IS_SUPPORTED_CMD, + &in, sizeof(in), + &out, sizeof(out)); + + return ret ? false : !!out; +} + +int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, + dma_addr_t metadata_phys) +{ + __le32 scm_ret; + int ret; + struct { + __le32 proc; + __le32 image_addr; + } request; + + request.proc = cpu_to_le32(peripheral); + request.image_addr = cpu_to_le32(metadata_phys); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PAS_INIT_IMAGE_CMD, + &request, sizeof(request), + &scm_ret, sizeof(scm_ret)); + + return ret ? : le32_to_cpu(scm_ret); +} + +int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, + phys_addr_t addr, phys_addr_t size) +{ + __le32 scm_ret; + int ret; + struct { + __le32 proc; + __le32 addr; + __le32 len; + } request; + + request.proc = cpu_to_le32(peripheral); + request.addr = cpu_to_le32(addr); + request.len = cpu_to_le32(size); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PAS_MEM_SETUP_CMD, + &request, sizeof(request), + &scm_ret, sizeof(scm_ret)); + + return ret ? : le32_to_cpu(scm_ret); +} + +int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral) +{ + __le32 out; + __le32 in; + int ret; + + in = cpu_to_le32(peripheral); + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PAS_AUTH_AND_RESET_CMD, + &in, sizeof(in), + &out, sizeof(out)); + + return ret ? : le32_to_cpu(out); +} + +int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral) +{ + __le32 out; + __le32 in; + int ret; + + in = cpu_to_le32(peripheral); + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PAS_SHUTDOWN_CMD, + &in, sizeof(in), + &out, sizeof(out)); + + return ret ? : le32_to_cpu(out); +} diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c index 01949f1828f4..3ac249037dbf 100644 --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -27,6 +27,13 @@ #define MAX_QCOM_SCM_ARGS 10 #define MAX_QCOM_SCM_RETS 3 +enum qcom_scm_arg_types { + QCOM_SCM_VAL, + QCOM_SCM_RO, + QCOM_SCM_RW, + QCOM_SCM_BUFVAL, +}; + #define QCOM_SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\ (((a) & 0x3) << 4) | \ (((b) & 0x3) << 6) | \ @@ -253,3 +260,85 @@ void __qcom_scm_init(void) else qcom_smccc_convention = ARM_SMCCC_SMC_32; } + +bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral) +{ + int ret; + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + + desc.args[0] = peripheral; + desc.arginfo = QCOM_SCM_ARGS(1); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PAS_IS_SUPPORTED_CMD, + &desc, &res); + + return ret ? false : !!res.a1; +} + +int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, + dma_addr_t metadata_phys) +{ + int ret; + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + + desc.args[0] = peripheral; + desc.args[1] = metadata_phys; + desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD, + &desc, &res); + + return ret ? : res.a1; +} + +int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, + phys_addr_t addr, phys_addr_t size) +{ + int ret; + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + + desc.args[0] = peripheral; + desc.args[1] = addr; + desc.args[2] = size; + desc.arginfo = QCOM_SCM_ARGS(3); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MEM_SETUP_CMD, + &desc, &res); + + return ret ? : res.a1; +} + +int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral) +{ + int ret; + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + + desc.args[0] = peripheral; + desc.arginfo = QCOM_SCM_ARGS(1); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PAS_AUTH_AND_RESET_CMD, + &desc, &res); + + return ret ? : res.a1; +} + +int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral) +{ + int ret; + struct qcom_scm_desc desc = {0}; + struct arm_smccc_res res; + + desc.args[0] = peripheral; + desc.arginfo = QCOM_SCM_ARGS(1); + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_SHUTDOWN_CMD, + &desc, &res); + + return ret ? : res.a1; +} diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index fca0744c1b73..ec46c68e3e83 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -149,6 +150,139 @@ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) } EXPORT_SYMBOL(qcom_scm_hdcp_req); +/** + * qcom_scm_pas_supported() - Check if the peripheral authentication service is + * available for the given peripherial + * @peripheral: peripheral id + * + * Returns true if PAS is supported for this peripheral, otherwise false. + */ +bool qcom_scm_pas_supported(u32 peripheral) +{ + int ret; + + ret = __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PAS_IS_SUPPORTED_CMD); + if (ret <= 0) + return false; + + return __qcom_scm_pas_supported(__scm->dev, peripheral); +} +EXPORT_SYMBOL(qcom_scm_pas_supported); + +/** + * qcom_scm_pas_init_image() - Initialize peripheral authentication service + * state machine for a given peripheral, using the + * metadata + * @peripheral: peripheral id + * @metadata: pointer to memory containing ELF header, program header table + * and optional blob of data used for authenticating the metadata + * and the rest of the firmware + * @size: size of the metadata + * + * Returns 0 on success. + */ +int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size) +{ + dma_addr_t mdata_phys; + void *mdata_buf; + int ret; + + /* + * During the scm call memory protection will be enabled for the meta + * data blob, so make sure it's physically contiguous, 4K aligned and + * non-cachable to avoid XPU violations. + */ + mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys, + GFP_KERNEL); + if (!mdata_buf) { + dev_err(__scm->dev, "Allocation of metadata buffer failed.\n"); + return -ENOMEM; + } + memcpy(mdata_buf, metadata, size); + + ret = qcom_scm_clk_enable(); + if (ret) + goto free_metadata; + + ret = __qcom_scm_pas_init_image(__scm->dev, peripheral, mdata_phys); + + qcom_scm_clk_disable(); + +free_metadata: + dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_pas_init_image); + +/** + * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral + * for firmware loading + * @peripheral: peripheral id + * @addr: start address of memory area to prepare + * @size: size of the memory area to prepare + * + * Returns 0 on success. + */ +int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) +{ + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + + ret = __qcom_scm_pas_mem_setup(__scm->dev, peripheral, addr, size); + qcom_scm_clk_disable(); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_pas_mem_setup); + +/** + * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware + * and reset the remote processor + * @peripheral: peripheral id + * + * Return 0 on success. + */ +int qcom_scm_pas_auth_and_reset(u32 peripheral) +{ + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + + ret = __qcom_scm_pas_auth_and_reset(__scm->dev, peripheral); + qcom_scm_clk_disable(); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset); + +/** + * qcom_scm_pas_shutdown() - Shut down the remote processor + * @peripheral: peripheral id + * + * Returns 0 on success. + */ +int qcom_scm_pas_shutdown(u32 peripheral) +{ + int ret; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + + ret = __qcom_scm_pas_shutdown(__scm->dev, peripheral); + qcom_scm_clk_disable(); + + return ret; +} +EXPORT_SYMBOL(qcom_scm_pas_shutdown); + static int qcom_scm_probe(struct platform_device *pdev) { struct qcom_scm *scm; diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 0ea55d7fb076..1a16ff925d6d 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -40,6 +40,20 @@ extern int __qcom_scm_hdcp_req(struct device *dev, extern void __qcom_scm_init(void); +#define QCOM_SCM_SVC_PIL 0x2 +#define QCOM_SCM_PAS_INIT_IMAGE_CMD 0x1 +#define QCOM_SCM_PAS_MEM_SETUP_CMD 0x2 +#define QCOM_SCM_PAS_AUTH_AND_RESET_CMD 0x5 +#define QCOM_SCM_PAS_SHUTDOWN_CMD 0x6 +#define QCOM_SCM_PAS_IS_SUPPORTED_CMD 0x7 +extern bool __qcom_scm_pas_supported(struct device *dev, u32 peripheral); +extern int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, + dma_addr_t metadata_phys); +extern int __qcom_scm_pas_mem_setup(struct device *dev, u32 peripheral, + phys_addr_t addr, phys_addr_t size); +extern int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 peripheral); +extern int __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral); + /* common error codes */ #define QCOM_SCM_V2_EBUSY -12 #define QCOM_SCM_ENOMEM -5 diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 9e12000914b3..cc32ab852fbc 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -29,6 +29,14 @@ extern bool qcom_scm_hdcp_available(void); extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp); +extern bool qcom_scm_pas_supported(u32 peripheral); +extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, + size_t size); +extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, + phys_addr_t size); +extern int qcom_scm_pas_auth_and_reset(u32 peripheral); +extern int qcom_scm_pas_shutdown(u32 peripheral); + #define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0 #define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1 -- cgit v1.2.3 From 2c2b217a13ed11ff6d8f4583f9bee3a54e8f1034 Mon Sep 17 00:00:00 2001 From: Christophe RICARD Date: Sat, 13 Feb 2016 16:15:31 +0100 Subject: tpm/st33zp24: Extend Copyright headers Extend copyright header to 2016 Signed-off-by: Christophe Ricard Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/st33zp24/i2c.c | 2 +- drivers/char/tpm/st33zp24/spi.c | 2 +- drivers/char/tpm/st33zp24/st33zp24.c | 2 +- drivers/char/tpm/st33zp24/st33zp24.h | 2 +- include/linux/platform_data/st33zp24.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c index a05fbd8bddf0..a49b6f10836d 100644 --- a/drivers/char/tpm/st33zp24/i2c.c +++ b/drivers/char/tpm/st33zp24/i2c.c @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c index a2ef8ec4ba80..eb351ba48689 100644 --- a/drivers/char/tpm/st33zp24/spi.c +++ b/drivers/char/tpm/st33zp24/spi.c @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 8d626784cd8d..944d279f2402 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM Linux driver for TPM ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h index c207cebf67dd..bcbd5ffbdaa5 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.h +++ b/drivers/char/tpm/st33zp24/st33zp24.h @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM Linux driver for TPM ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/include/linux/platform_data/st33zp24.h b/include/linux/platform_data/st33zp24.h index 817dfdb37885..6f0fb6ebd7db 100644 --- a/include/linux/platform_data/st33zp24.h +++ b/include/linux/platform_data/st33zp24.h @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM Linux driver for TPM 1.2 ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * 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 -- cgit v1.2.3 From a6c50912508d80164a5e607993b617be85a46d73 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 2 Jun 2016 12:05:12 +0100 Subject: nvmem: Declare nvmem_cell_read() consistently nvmem_cell_read() is declared as void * if CONFIG_NVMEM is enabled, and as char * otherwise. This can result in a build warning if CONFIG_NVMEM is not enabled and a caller asigns the result to a type other than char * without using a typecast. Use a consistent declaration to avoid the problem. Fixes: e2a5402ec7c6 ("nvmem: Add nvmem_device based consumer apis.") Cc: Srinivas Kandagatla Signed-off-by: Guenter Roeck Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman --- include/linux/nvmem-consumer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 9bb77d3ed6e0..c2256d746543 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -74,7 +74,7 @@ static inline void nvmem_cell_put(struct nvmem_cell *cell) { } -static inline char *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) +static inline void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) { return ERR_PTR(-ENOSYS); } -- cgit v1.2.3 From 1b0ec88ac1cb0413a717bc3cefea72d6f2533672 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:23 +0200 Subject: vt: remove lines parameter from scrollback It is always called with 0, so remove the parameter and pass the default down to scrolldelta without checking. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 2 +- drivers/tty/vt/vt.c | 6 ++---- include/linux/vt_kern.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index f973bfce5d08..cd08c103eb47 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -579,7 +579,7 @@ static void fn_scroll_forw(struct vc_data *vc) static void fn_scroll_back(struct vc_data *vc) { - scrollback(vc, 0); + scrollback(vc); } static void fn_show_mem(struct vc_data *vc) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index dc125322f48f..abc79ae19079 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1102,11 +1102,9 @@ static void gotoxay(struct vc_data *vc, int new_x, int new_y) gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y); } -void scrollback(struct vc_data *vc, int lines) +void scrollback(struct vc_data *vc) { - if (!lines) - lines = vc->vc_rows / 2; - scrolldelta(-lines); + scrolldelta(-(vc->vc_rows / 2)); } void scrollfront(struct vc_data *vc, int lines) diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 8d7634247fb4..160f81fe3eb8 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -45,7 +45,7 @@ void poke_blanked_console(void); int con_font_op(struct vc_data *vc, struct console_font_op *op); int con_set_cmap(unsigned char __user *cmap); int con_get_cmap(unsigned char __user *cmap); -void scrollback(struct vc_data *vc, int lines); +void scrollback(struct vc_data *vc); void scrollfront(struct vc_data *vc, int lines); void clear_buffer_attributes(struct vc_data *vc); void update_region(struct vc_data *vc, unsigned long start, int count); -- cgit v1.2.3 From a4bedd019ec9690c1e5c7105509a2ef52c5ae3e0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:24 +0200 Subject: vt: document vc_data by example All those members of vc_data are each explained in short. But it needs an example for one to understand the whole picture. So add an ascii art depicting the most important vc_data members. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- include/linux/console_struct.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'include/linux') diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index e329ee2667e1..5fa605c93428 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -21,6 +21,38 @@ struct uni_pagedir; #define NPAR 16 +/* + * Example: vc_data of a console that was scrolled 3 lines down. + * + * Console buffer + * vc_screenbuf ---------> +----------------------+-. + * | initializing W | \ + * | initializing X | | + * | initializing Y | > scroll-back area + * | initializing Z | | + * | | / + * vc_visible_origin ---> ^+----------------------+-: + * (changes by scroll) || Welcome to linux | \ + * || | | + * vc_rows --->< | login: root | | visible on console + * || password: | > (vc_screenbuf_size is + * vc_origin -----------> || | | vc_size_row * vc_rows) + * (start when no scroll) || Last login: 12:28 | / + * v+----------------------+-: + * | Have a lot of fun... | \ + * vc_pos -----------------|--------v | > scroll-front area + * | ~ # cat_ | / + * vc_scr_end -----------> +----------------------+-: + * (vc_origin + | | \ EMPTY, to be filled by + * vc_screenbuf_size) | | / vc_video_erase_char + * +----------------------+-' + * <---- 2 * vc_cols -----> + * <---- vc_size_row -----> + * + * Note that every character in the console buffer is accompanied with an + * attribute in the buffer right after the character. This is not depicted + * in the figure. + */ struct vc_data { struct tty_port port; /* Upper level data */ -- cgit v1.2.3 From 97293de977365fe672daec2523e66ef457104921 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:26 +0200 Subject: tty: vt, consw->con_scrolldelta cleanup * allow NULL consw->con_scrolldelta (some consoles define an empty hook) * => remove empty hooks now * return value of consw->con_scrolldelta is never checked => make the function void * document consw->con_scrolldelta a bit Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/usb/misc/sisusbvga/sisusb_con.c | 11 +++-------- drivers/video/console/dummycon.c | 1 - drivers/video/console/fbcon.c | 16 +++++++--------- drivers/video/console/mdacon.c | 6 ------ drivers/video/console/newport_con.c | 7 ------- drivers/video/console/sticon.c | 6 ------ drivers/video/console/vgacon.c | 13 +++++-------- include/linux/console.h | 8 +++++++- 9 files changed, 23 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index abc79ae19079..365a91d01a0e 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2468,7 +2468,7 @@ static void console_callback(struct work_struct *ignored) if (scrollback_delta) { struct vc_data *vc = vc_cons[fg_console].d; clear_selection(); - if (vc->vc_mode == KD_TEXT) + if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta) vc->vc_sw->con_scrolldelta(vc, scrollback_delta); scrollback_delta = 0; } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 0ebbf49cd649..a8244ebeb7a7 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -717,24 +717,22 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) } /* interface routine */ -static int +static void sisusbcon_scrolldelta(struct vc_data *c, int lines) { struct sisusb_usb_data *sisusb; int margin = c->vc_size_row * 4; int ul, we, p, st; - /* The return value does not seem to be used */ - sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) - return 0; + return; /* sisusb->lock is down */ if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); - return 0; + return; } if (!lines) /* Turn scrollback off */ @@ -774,8 +772,6 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines) sisusbcon_set_start_address(sisusb, c); mutex_unlock(&sisusb->lock); - - return 1; } /* Interface routine */ @@ -1433,7 +1429,6 @@ static const struct consw sisusb_dummy_con = { .con_font_default = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY, .con_set_palette = SISUSBCONDUMMY, - .con_scrolldelta = SISUSBCONDUMMY, }; int diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0efc52f11ad0..9ce03b9aba88 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -72,6 +72,5 @@ const struct consw dummy_con = { .con_font_default = DUMMY, .con_font_copy = DUMMY, .con_set_palette = DUMMY, - .con_scrolldelta = DUMMY, }; EXPORT_SYMBOL_GPL(dummy_con); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index afd3301ac40c..eadc7bf62eb3 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -171,7 +171,6 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, static int fbcon_switch(struct vc_data *vc); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table); -static int fbcon_scrolldelta(struct vc_data *vc, int lines); /* * Internal routines @@ -2765,7 +2764,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) } } -static int fbcon_scrolldelta(struct vc_data *vc, int lines) +static void fbcon_scrolldelta(struct vc_data *vc, int lines) { struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fbcon_ops *ops = info->fbcon_par; @@ -2774,9 +2773,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) if (softback_top) { if (vc->vc_num != fg_console) - return 0; + return; if (vc->vc_mode != KD_TEXT || !lines) - return 0; + return; if (logo_shown >= 0) { struct vc_data *conp2 = vc_cons[logo_shown].d; @@ -2809,11 +2808,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); fbcon_redraw_softback(vc, disp, lines); fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); - return 0; + return; } if (!scrollback_phys_max) - return -ENOSYS; + return; scrollback_old = scrollback_current; scrollback_current -= lines; @@ -2822,10 +2821,10 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) else if (scrollback_current > scrollback_max) scrollback_current = scrollback_max; if (scrollback_current == scrollback_old) - return 0; + return; if (fbcon_is_inactive(vc, info)) - return 0; + return; fbcon_cursor(vc, CM_ERASE); @@ -2852,7 +2851,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) if (!scrollback_current) fbcon_cursor(vc, CM_DRAW); - return 0; } static int fbcon_set_origin(struct vc_data *vc) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 8edc062536a8..234af26b4829 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -505,11 +505,6 @@ static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) } } -static int mdacon_scrolldelta(struct vc_data *c, int lines) -{ - return 0; -} - static void mdacon_cursor(struct vc_data *c, int mode) { if (mode == CM_ERASE) { @@ -578,7 +573,6 @@ static const struct consw mda_con = { .con_switch = mdacon_switch, .con_blank = mdacon_blank, .con_set_palette = mdacon_set_palette, - .con_scrolldelta = mdacon_scrolldelta, .con_build_attr = mdacon_build_attr, .con_invert_region = mdacon_invert_region, }; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 0553dfe684ef..eb3d4ce12cd5 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -579,12 +579,6 @@ static int newport_set_palette(struct vc_data *vc, const unsigned char *table) return -EINVAL; } -static int newport_scrolldelta(struct vc_data *vc, int lines) -{ - /* there is (nearly) no off-screen memory, so we can't scroll back */ - return 0; -} - static int newport_scroll(struct vc_data *vc, int t, int b, int dir, int lines) { @@ -735,7 +729,6 @@ const struct consw newport_con = { .con_font_set = newport_font_set, .con_font_default = newport_font_default, .con_set_palette = newport_set_palette, - .con_scrolldelta = newport_scrolldelta, .con_set_origin = DUMMY, .con_save_screen = DUMMY }; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index e440c2d9fe7c..20f6a2f5d4a7 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -256,11 +256,6 @@ static int sticon_blank(struct vc_data *c, int blank, int mode_switch) return 1; } -static int sticon_scrolldelta(struct vc_data *conp, int lines) -{ - return 0; -} - static u16 *sticon_screen_pos(struct vc_data *conp, int offset) { int line; @@ -359,7 +354,6 @@ static const struct consw sti_con = { .con_switch = sticon_switch, .con_blank = sticon_blank, .con_set_palette = sticon_set_palette, - .con_scrolldelta = sticon_scrolldelta, .con_set_origin = sticon_set_origin, .con_save_screen = sticon_save_screen, .con_build_attr = sticon_build_attr, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 8bf911002cba..f447d6916991 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -80,7 +80,7 @@ static void vgacon_deinit(struct vc_data *c); static void vgacon_cursor(struct vc_data *c, int mode); static int vgacon_switch(struct vc_data *c); static int vgacon_blank(struct vc_data *c, int blank, int mode_switch); -static int vgacon_scrolldelta(struct vc_data *c, int lines); +static void vgacon_scrolldelta(struct vc_data *c, int lines); static int vgacon_set_origin(struct vc_data *c); static void vgacon_save_screen(struct vc_data *c); static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, @@ -248,18 +248,18 @@ static void vgacon_restore_screen(struct vc_data *c) } } -static int vgacon_scrolldelta(struct vc_data *c, int lines) +static void vgacon_scrolldelta(struct vc_data *c, int lines) { int start, end, count, soff; if (!lines) { c->vc_visible_origin = c->vc_origin; vga_set_mem_top(c); - return 1; + return; } if (!vgacon_scrollback) - return 1; + return; if (!vgacon_scrollback_save) { vgacon_cursor(c, CM_ERASE); @@ -320,8 +320,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) scr_memcpyw(d, s, diff * c->vc_size_row); } else vgacon_cursor(c, CM_MOVE); - - return 1; } #else #define vgacon_scrollback_startup(...) do { } while (0) @@ -334,7 +332,7 @@ static void vgacon_restore_screen(struct vc_data *c) vgacon_scrolldelta(c, 0); } -static int vgacon_scrolldelta(struct vc_data *c, int lines) +static void vgacon_scrolldelta(struct vc_data *c, int lines) { if (!lines) /* Turn scrollback off */ c->vc_visible_origin = c->vc_origin; @@ -362,7 +360,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) c->vc_visible_origin = vga_vram_base + (p + ul) % we; } vga_set_mem_top(c); - return 1; } #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ diff --git a/include/linux/console.h b/include/linux/console.h index 98c8615dc300..d175de8d7006 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -28,6 +28,12 @@ struct tty_struct; #define VT100ID "\033[?1;2c" #define VT102ID "\033[?6c" +/** + * struct consw - callbacks for consoles + * + * @con_scrolldelta: the contents of the console should be scrolled by @lines. + * Invoked by user. (optional) + */ struct consw { struct module *owner; const char *(*con_startup)(void); @@ -48,7 +54,7 @@ struct consw { int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); int (*con_set_palette)(struct vc_data *, const unsigned char *); - int (*con_scrolldelta)(struct vc_data *, int); + void (*con_scrolldelta)(struct vc_data *, int lines); int (*con_set_origin)(struct vc_data *); void (*con_save_screen)(struct vc_data *); u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8); -- cgit v1.2.3 From 709280da6238629c3b488b7be87c6d9185f4d03e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:27 +0200 Subject: tty: vt, consw->con_set_palette cleanup * allow NULL consw->con_set_palette (some consoles define an empty hook) * => remove empty hooks now * return value of consw->con_set_palette is never checked => make the function void * document consw->con_set_palette a bit Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- drivers/usb/misc/sisusbvga/sisusb_con.c | 11 ++++------- drivers/video/console/dummycon.c | 1 - drivers/video/console/fbcon.c | 10 +++++----- drivers/video/console/mdacon.c | 6 ------ drivers/video/console/newport_con.c | 6 ------ drivers/video/console/sticon.c | 6 ------ drivers/video/console/vgacon.c | 7 ++----- include/linux/console.h | 4 +++- 9 files changed, 15 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 365a91d01a0e..d5d906051613 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3978,7 +3978,7 @@ static void set_palette(struct vc_data *vc) { WARN_CONSOLE_UNLOCKED(); - if (vc->vc_mode != KD_GRAPHICS) + if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_set_palette) vc->vc_sw->con_set_palette(vc, color_table); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index a8244ebeb7a7..4112835f4aed 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -595,7 +595,7 @@ sisusbcon_save_screen(struct vc_data *c) } /* interface routine */ -static int +static void sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) { struct sisusb_usb_data *sisusb; @@ -604,17 +604,17 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) /* Return value not used by vt */ if (!CON_IS_VISIBLE(c)) - return -EINVAL; + return; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); if (!sisusb) - return -EINVAL; + return; /* sisusb->lock is down */ if (sisusb_is_inactive(c, sisusb)) { mutex_unlock(&sisusb->lock); - return -EINVAL; + return; } for (i = j = 0; i < 16; i++) { @@ -629,8 +629,6 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) } mutex_unlock(&sisusb->lock); - - return 0; } /* interface routine */ @@ -1428,7 +1426,6 @@ static const struct consw sisusb_dummy_con = { .con_font_get = SISUSBCONDUMMY, .con_font_default = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY, - .con_set_palette = SISUSBCONDUMMY, }; int diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 9ce03b9aba88..0ef544ef5634 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -71,6 +71,5 @@ const struct consw dummy_con = { .con_font_get = DUMMY, .con_font_default = DUMMY, .con_font_copy = DUMMY, - .con_set_palette = DUMMY, }; EXPORT_SYMBOL_GPL(dummy_con); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index eadc7bf62eb3..9359b06377cf 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -170,7 +170,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, int height, int width); static int fbcon_switch(struct vc_data *vc); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); -static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table); +static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table); /* * Internal routines @@ -2651,17 +2651,17 @@ static struct fb_cmap palette_cmap = { 0, 16, palette_red, palette_green, palette_blue, NULL }; -static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table) +static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; int i, j, k, depth; u8 val; if (fbcon_is_inactive(vc, info)) - return -EINVAL; + return; if (!CON_IS_VISIBLE(vc)) - return 0; + return; depth = fb_get_color_depth(&info->var, &info->fix); if (depth > 3) { @@ -2683,7 +2683,7 @@ static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table) } else fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); - return fb_set_cmap(&palette_cmap, info); + fb_set_cmap(&palette_cmap, info); } static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 234af26b4829..1fe5245eb6dd 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -481,11 +481,6 @@ static int mdacon_switch(struct vc_data *c) return 1; /* redrawing needed */ } -static int mdacon_set_palette(struct vc_data *c, const unsigned char *table) -{ - return -EINVAL; -} - static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) { if (mda_type == TYPE_MDA) { @@ -572,7 +567,6 @@ static const struct consw mda_con = { .con_bmove = mdacon_bmove, .con_switch = mdacon_switch, .con_blank = mdacon_blank, - .con_set_palette = mdacon_set_palette, .con_build_attr = mdacon_build_attr, .con_invert_region = mdacon_invert_region, }; diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index eb3d4ce12cd5..a436930f9e5d 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -574,11 +574,6 @@ static int newport_font_set(struct vc_data *vc, struct console_font *font, unsig return newport_set_font(vc->vc_num, font); } -static int newport_set_palette(struct vc_data *vc, const unsigned char *table) -{ - return -EINVAL; -} - static int newport_scroll(struct vc_data *vc, int t, int b, int dir, int lines) { @@ -728,7 +723,6 @@ const struct consw newport_con = { .con_blank = newport_blank, .con_font_set = newport_font_set, .con_font_default = newport_font_default, - .con_set_palette = newport_set_palette, .con_set_origin = DUMMY, .con_save_screen = DUMMY }; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 20f6a2f5d4a7..fe7c4dbb676e 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -79,11 +79,6 @@ static const char *sticon_startup(void) return "STI console"; } -static int sticon_set_palette(struct vc_data *c, const unsigned char *table) -{ - return -EINVAL; -} - static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) { int redraw_cursor = 0; @@ -353,7 +348,6 @@ static const struct consw sti_con = { .con_bmove = sticon_bmove, .con_switch = sticon_switch, .con_blank = sticon_blank, - .con_set_palette = sticon_set_palette, .con_set_origin = sticon_set_origin, .con_save_screen = sticon_save_screen, .con_build_attr = sticon_build_attr, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f447d6916991..aaae9bd23900 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -856,16 +856,13 @@ static void vga_set_palette(struct vc_data *vc, const unsigned char *table) } } -static int vgacon_set_palette(struct vc_data *vc, const unsigned char *table) +static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) { #ifdef CAN_LOAD_PALETTE if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked || !CON_IS_VISIBLE(vc)) - return -EINVAL; + return; vga_set_palette(vc, table); - return 0; -#else - return -EINVAL; #endif } diff --git a/include/linux/console.h b/include/linux/console.h index d175de8d7006..382a527104c4 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -31,6 +31,7 @@ struct tty_struct; /** * struct consw - callbacks for consoles * + * @con_set_palette: sets the palette of the console to @table (optional) * @con_scrolldelta: the contents of the console should be scrolled by @lines. * Invoked by user. (optional) */ @@ -53,7 +54,8 @@ struct consw { int (*con_font_copy)(struct vc_data *, int); int (*con_resize)(struct vc_data *, unsigned int, unsigned int, unsigned int); - int (*con_set_palette)(struct vc_data *, const unsigned char *); + void (*con_set_palette)(struct vc_data *, + const unsigned char *table); void (*con_scrolldelta)(struct vc_data *, int lines); int (*con_set_origin)(struct vc_data *); void (*con_save_screen)(struct vc_data *); -- cgit v1.2.3 From 52ad1f38b4f6e2f2133668247036ad64ef7ae18a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:28 +0200 Subject: tty: vt, remove consw->con_bmove It is never called since commit 81732c3b2fede (tty vt: Fix line garbage in virtual console on command line edition) in 3.7. So remove all the callbacks. Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: linux-usb@vger.kernel.org Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: "James E.J. Bottomley" Cc: Helge Deller Cc: linux-fbdev@vger.kernel.org Cc: linux-parisc@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb_con.c | 35 --------------------------------- drivers/video/console/dummycon.c | 1 - drivers/video/console/fbcon.c | 1 - drivers/video/console/mdacon.c | 33 ------------------------------- drivers/video/console/newport_con.c | 29 --------------------------- drivers/video/console/sticon.c | 17 ---------------- drivers/video/console/vgacon.c | 1 - include/linux/console.h | 1 - 8 files changed, 118 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 4112835f4aed..52a6da991165 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -477,39 +477,6 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) mutex_unlock(&sisusb->lock); } -/* Interface routine */ -static void -sisusbcon_bmove(struct vc_data *c, int sy, int sx, - int dy, int dx, int height, int width) -{ - struct sisusb_usb_data *sisusb; - int cols, length; - - if (width <= 0 || height <= 0) - return; - - sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); - if (!sisusb) - return; - - /* sisusb->lock is down */ - - cols = sisusb->sisusb_num_columns; - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - length = ((height * cols) - dx - (cols - width - dx)) * 2; - - - sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), - (long)SISUSB_HADDR(dx, dy), length); - - mutex_unlock(&sisusb->lock); -} - /* interface routine */ static int sisusbcon_switch(struct vc_data *c) @@ -1371,7 +1338,6 @@ static const struct consw sisusb_con = { .con_putcs = sisusbcon_putcs, .con_cursor = sisusbcon_cursor, .con_scroll = sisusbcon_scroll, - .con_bmove = sisusbcon_bmove, .con_switch = sisusbcon_switch, .con_blank = sisusbcon_blank, .con_font_set = sisusbcon_font_set, @@ -1419,7 +1385,6 @@ static const struct consw sisusb_dummy_con = { .con_putcs = SISUSBCONDUMMY, .con_cursor = SISUSBCONDUMMY, .con_scroll = SISUSBCONDUMMY, - .con_bmove = SISUSBCONDUMMY, .con_switch = SISUSBCONDUMMY, .con_blank = SISUSBCONDUMMY, .con_font_set = SISUSBCONDUMMY, diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0ef544ef5634..9269d5685239 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -64,7 +64,6 @@ const struct consw dummy_con = { .con_putcs = DUMMY, .con_cursor = DUMMY, .con_scroll = DUMMY, - .con_bmove = DUMMY, .con_switch = DUMMY, .con_blank = DUMMY, .con_font_set = DUMMY, diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 9359b06377cf..eef8a8b7274f 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -3334,7 +3334,6 @@ static const struct consw fb_con = { .con_putcs = fbcon_putcs, .con_cursor = fbcon_cursor, .con_scroll = fbcon_scroll, - .con_bmove = fbcon_bmove, .con_switch = fbcon_switch, .con_blank = fbcon_blank, .con_font_set = fbcon_set_font, diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 1fe5245eb6dd..bacbb044d77c 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -444,38 +444,6 @@ static void mdacon_clear(struct vc_data *c, int y, int x, } } -static void mdacon_bmove(struct vc_data *c, int sy, int sx, - int dy, int dx, int height, int width) -{ - u16 *src, *dest; - - if (width <= 0 || height <= 0) - return; - - if (sx==0 && dx==0 && width==mda_num_columns) { - scr_memmovew(MDA_ADDR(0,dy), MDA_ADDR(0,sy), height*width*2); - - } else if (dy < sy || (dy == sy && dx < sx)) { - src = MDA_ADDR(sx, sy); - dest = MDA_ADDR(dx, dy); - - for (; height > 0; height--) { - scr_memmovew(dest, src, width*2); - src += mda_num_columns; - dest += mda_num_columns; - } - } else { - src = MDA_ADDR(sx, sy+height-1); - dest = MDA_ADDR(dx, dy+height-1); - - for (; height > 0; height--) { - scr_memmovew(dest, src, width*2); - src -= mda_num_columns; - dest -= mda_num_columns; - } - } -} - static int mdacon_switch(struct vc_data *c) { return 1; /* redrawing needed */ @@ -564,7 +532,6 @@ static const struct consw mda_con = { .con_putcs = mdacon_putcs, .con_cursor = mdacon_cursor, .con_scroll = mdacon_scroll, - .con_bmove = mdacon_bmove, .con_switch = mdacon_switch, .con_blank = mdacon_blank, .con_build_attr = mdacon_build_attr, diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index a436930f9e5d..e3b9521e4ec3 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -673,34 +673,6 @@ static int newport_scroll(struct vc_data *vc, int t, int b, int dir, return 1; } -static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy, - int dx, int h, int w) -{ - short xs, ys, xe, ye, xoffs, yoffs; - - xs = sx << 3; - xe = ((sx + w) << 3) - 1; - /* - * as bmove is only used to move stuff around in the same line - * (h == 1), we don't care about wrap arounds caused by topscan != 0 - */ - ys = ((sy << 4) + topscan) & 0x3ff; - ye = (((sy + h) << 4) - 1 + topscan) & 0x3ff; - xoffs = (dx - sx) << 3; - yoffs = (dy - sy) << 4; - if (xoffs > 0) { - /* move to the right, exchange starting points */ - swap(xe, xs); - } - newport_wait(npregs); - npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK | - NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX - | NPORT_DMODE0_STOPY); - npregs->set.xystarti = (xs << 16) | ys; - npregs->set.xyendi = (xe << 16) | ye; - npregs->go.xymove = (xoffs << 16) | yoffs; -} - static int newport_dummy(struct vc_data *c) { return 0; @@ -718,7 +690,6 @@ const struct consw newport_con = { .con_putcs = newport_putcs, .con_cursor = newport_cursor, .con_scroll = newport_scroll, - .con_bmove = newport_bmove, .con_switch = newport_switch, .con_blank = newport_blank, .con_font_set = newport_font_set, diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index fe7c4dbb676e..3a10ac19598f 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -177,22 +177,6 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) return 0; } -static void sticon_bmove(struct vc_data *conp, int sy, int sx, - int dy, int dx, int height, int width) -{ - if (!width || !height) - return; -#if 0 - if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) && - (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || - ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && - (dx <= p->cursor_x) && (p->cursor_x < dx+width))) - sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/); -#endif - - sti_bmove(sticon_sti, sy, sx, dy, dx, height, width); -} - static void sticon_init(struct vc_data *c, int init) { struct sti_struct *sti = sticon_sti; @@ -345,7 +329,6 @@ static const struct consw sti_con = { .con_putcs = sticon_putcs, .con_cursor = sticon_cursor, .con_scroll = sticon_scroll, - .con_bmove = sticon_bmove, .con_switch = sticon_switch, .con_blank = sticon_blank, .con_set_origin = sticon_set_origin, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index aaae9bd23900..e280b3ceebd9 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1421,7 +1421,6 @@ const struct consw vga_con = { .con_putcs = DUMMY, .con_cursor = vgacon_cursor, .con_scroll = vgacon_scroll, - .con_bmove = DUMMY, .con_switch = vgacon_switch, .con_blank = vgacon_blank, .con_font_set = vgacon_font_set, diff --git a/include/linux/console.h b/include/linux/console.h index 382a527104c4..d530c4627e54 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -45,7 +45,6 @@ struct consw { void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int); void (*con_cursor)(struct vc_data *, int); int (*con_scroll)(struct vc_data *, int, int, int, int); - void (*con_bmove)(struct vc_data *, int, int, int, int, int, int); int (*con_switch)(struct vc_data *); int (*con_blank)(struct vc_data *, int, int); int (*con_font_set)(struct vc_data *, struct console_font *, unsigned); -- cgit v1.2.3 From 6ca8dfd78187d8238abc5b2996848a0c8f07948d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:35 +0200 Subject: tty: vt, convert more macros to functions Namely convert: * IS_FG -> con_is_fg * DO_UPDATE -> con_should_update * CON_IS_VISIBLE -> con_is_visible DO_UPDATE was a weird name for a yes/no answer, so the new name is con_should_update. Signed-off-by: Jiri Slaby Cc: Thomas Winischhofer Cc: Jean-Christophe Plagniol-Villard Cc: linux-usb@vger.kernel.org Cc: linux-fbdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 62 ++++++++++++++++++--------------- drivers/usb/misc/sisusbvga/sisusb_con.c | 4 +-- drivers/video/console/fbcon.c | 26 +++++++------- drivers/video/console/vgacon.c | 8 ++--- include/linux/console_struct.h | 5 ++- 5 files changed, 57 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 8ceabfd20561..26de5c0fc056 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -277,8 +277,15 @@ static void notify_update(struct vc_data *vc) * Low-Level Functions */ -#define IS_FG(vc) ((vc)->vc_num == fg_console) -#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked) +static inline bool con_is_fg(const struct vc_data *vc) +{ + return vc->vc_num == fg_console; +} + +static inline bool con_should_update(const struct vc_data *vc) +{ + return con_is_visible(vc) && !console_blanked; +} static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) { @@ -316,7 +323,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; - if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) + if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) return; d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); @@ -334,7 +341,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; - if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) + if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr)) return; s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); step = vc->vc_cols * nr; @@ -390,7 +397,7 @@ void update_region(struct vc_data *vc, unsigned long start, int count) { WARN_CONSOLE_UNLOCKED(); - if (DO_UPDATE(vc)) { + if (con_should_update(vc)) { hide_cursor(vc); do_update_region(vc, start, count); set_cursor(vc); @@ -490,7 +497,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) } } - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, count); notify_update(vc); } @@ -507,7 +514,7 @@ void complement_pos(struct vc_data *vc, int offset) if (old_offset != -1 && old_offset >= 0 && old_offset < vc->vc_screenbuf_size) { scr_writew(old, screenpos(vc, old_offset, 1)); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); notify_update(vc); } @@ -522,7 +529,7 @@ void complement_pos(struct vc_data *vc, int offset) old = scr_readw(p); new = old ^ vc->vc_complement_mask; scr_writew(new, p); - if (DO_UPDATE(vc)) { + if (con_should_update(vc)) { oldx = (offset >> 1) % vc->vc_cols; oldy = (offset >> 1) / vc->vc_cols; vc->vc_sw->con_putc(vc, new, oldy, oldx); @@ -538,7 +545,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr) scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2); scr_memsetw(p, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, vc->vc_cols - vc->vc_x); } @@ -551,7 +558,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr) scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) p, vc->vc_cols - vc->vc_x); } @@ -571,7 +578,7 @@ static void add_softcursor(struct vc_data *vc) if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; scr_writew(i, (u16 *) vc->vc_pos); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x); } @@ -579,7 +586,7 @@ static void hide_softcursor(struct vc_data *vc) { if (softcursor_original != -1) { scr_writew(softcursor_original, (u16 *)vc->vc_pos); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_putc(vc, softcursor_original, vc->vc_y, vc->vc_x); softcursor_original = -1; @@ -596,8 +603,7 @@ static void hide_cursor(struct vc_data *vc) static void set_cursor(struct vc_data *vc) { - if (!IS_FG(vc) || console_blanked || - vc->vc_mode == KD_GRAPHICS) + if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS) return; if (vc->vc_deccm) { if (vc == sel_cons) @@ -613,7 +619,7 @@ static void set_origin(struct vc_data *vc) { WARN_CONSOLE_UNLOCKED(); - if (!CON_IS_VISIBLE(vc) || + if (!con_is_visible(vc) || !vc->vc_sw->con_set_origin || !vc->vc_sw->con_set_origin(vc)) vc->vc_origin = (unsigned long)vc->vc_screenbuf; @@ -661,12 +667,12 @@ void redraw_screen(struct vc_data *vc, int is_switch) struct vc_data *old_vc = vc_cons[fg_console].d; if (old_vc == vc) return; - if (!CON_IS_VISIBLE(vc)) + if (!con_is_visible(vc)) redraw = 1; *vc->vc_display_fg = vc; fg_console = vc->vc_num; hide_cursor(old_vc); - if (!CON_IS_VISIBLE(old_vc)) { + if (!con_is_visible(old_vc)) { save_screen(old_vc); set_origin(old_vc); } @@ -941,7 +947,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, tty_do_resize(tty, &ws); } - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) update_screen(vc); vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); return err; @@ -1171,7 +1177,7 @@ static void csi_J(struct vc_data *vc, int vpar) scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, vc->vc_screenbuf_size >> 1); set_origin(vc); - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) update_screen(vc); /* fall through */ case 2: /* erase whole display */ @@ -1182,7 +1188,7 @@ static void csi_J(struct vc_data *vc, int vpar) return; } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) start, count); vc->vc_need_wrap = 0; } @@ -1210,7 +1216,7 @@ static void csi_K(struct vc_data *vc, int vpar) } scr_memsetw(start, vc->vc_video_erase_char, 2 * count); vc->vc_need_wrap = 0; - if (DO_UPDATE(vc)) + if (con_should_update(vc)) do_update_region(vc, (unsigned long) start, count); } @@ -1223,7 +1229,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar; scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); - if (DO_UPDATE(vc)) + if (con_should_update(vc)) vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count); vc->vc_need_wrap = 0; } @@ -2208,7 +2214,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co charmask = himask ? 0x1ff : 0xff; /* undraw cursor first */ - if (IS_FG(vc)) + if (con_is_fg(vc)) hide_cursor(vc); param.vc = vc; @@ -2380,7 +2386,7 @@ rescan_last_byte: ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : (vc_attr << 8) + tc, (u16 *) vc->vc_pos); - if (DO_UPDATE(vc) && draw_x < 0) { + if (con_should_update(vc) && draw_x < 0) { draw_x = vc->vc_x; draw_from = vc->vc_pos; } @@ -2564,7 +2570,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) goto quit; /* undraw cursor first */ - if (IS_FG(vc)) + if (con_is_fg(vc)) hide_cursor(vc); start = (ushort *)vc->vc_pos; @@ -2575,7 +2581,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) c = *b++; if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { if (cnt > 0) { - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_x += cnt; if (vc->vc_need_wrap) @@ -2607,7 +2613,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) myx++; } if (cnt > 0) { - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_x += cnt; if (vc->vc_x == vc->vc_cols) { @@ -3154,7 +3160,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last, j = i; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { k = i; save_screen(vc); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 52a6da991165..460cebf322e3 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -570,7 +570,7 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) /* Return value not used by vt */ - if (!CON_IS_VISIBLE(c)) + if (!con_is_visible(c)) return; sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); @@ -1226,7 +1226,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, struct vc_data *vc = vc_cons[i].d; if (vc && vc->vc_sw == &sisusb_con) { - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { vc->vc_sw->con_cursor(vc, CM_DRAW); } vc->vc_font.height = fh; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index eef8a8b7274f..b87f5cfdaea5 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -380,7 +380,7 @@ static void fb_flashcursor(struct work_struct *work) if (ops && ops->currcon != -1) vc = vc_cons[ops->currcon].d; - if (!vc || !CON_IS_VISIBLE(vc) || + if (!vc || !con_is_visible(vc) || registered_fb[con2fb_map[vc->vc_num]] != info || vc->vc_deccm != 1) { console_unlock(); @@ -618,7 +618,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, erase, vc->vc_size_row * logo_lines); - if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { + if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); update_screen(vc); } @@ -1112,7 +1112,7 @@ static void fbcon_init(struct vc_data *vc, int init) * * We need to do it in fbcon_init() to prevent screen corruption. */ - if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { + if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) { ret = info->fbops->fb_set_par(info); @@ -1192,7 +1192,7 @@ static void fbcon_deinit(struct vc_data *vc) if (!ops) goto finished; - if (CON_IS_VISIBLE(vc)) + if (con_is_visible(vc)) fbcon_del_cursor_timer(info); ops->flags &= ~FBCON_FLAGS_INIT; @@ -1397,7 +1397,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, rows /= vc->vc_font.height; vc_resize(vc, cols, rows); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { update_screen(vc); if (softback_buf) fbcon_update_softback(vc); @@ -2145,7 +2145,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, return -EINVAL; DPRINTK("resize now %ix%i\n", var.xres, var.yres); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; fb_set_var(info, &var); @@ -2448,7 +2448,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int cnt; char *old_data = NULL; - if (CON_IS_VISIBLE(vc) && softback_lines) + if (con_is_visible(vc) && softback_lines) fbcon_set_origin(vc); resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); @@ -2529,9 +2529,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, cols /= w; rows /= h; vc_resize(vc, cols, rows); - if (CON_IS_VISIBLE(vc) && softback_buf) + if (con_is_visible(vc) && softback_buf) fbcon_update_softback(vc); - } else if (CON_IS_VISIBLE(vc) + } else if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); update_screen(vc); @@ -2660,7 +2660,7 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table) if (fbcon_is_inactive(vc, info)) return; - if (!CON_IS_VISIBLE(vc)) + if (!con_is_visible(vc)) return; depth = fb_get_color_depth(&info->var, &info->fix); @@ -2902,7 +2902,7 @@ static void fbcon_modechanged(struct fb_info *info) p = &fb_display[vc->vc_num]; set_blitting_type(vc, info); - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { var_to_display(p, &info->var, info); cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); @@ -2941,7 +2941,7 @@ static void fbcon_set_all_vcs(struct fb_info *info) registered_fb[con2fb_map[i]] != info) continue; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { fg = i; continue; } @@ -3180,7 +3180,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank) registered_fb[con2fb_map[ops->currcon]] != info) return; - if (CON_IS_VISIBLE(vc)) { + if (con_is_visible(vc)) { if (blank) do_blank_screen(0); else diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index e280b3ceebd9..11576611a974 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -589,7 +589,7 @@ static void vgacon_init(struct vc_data *c, int init) static void vgacon_deinit(struct vc_data *c) { /* When closing the active console, reset video origin */ - if (CON_IS_VISIBLE(c)) { + if (con_is_visible(c)) { c->vc_visible_origin = vga_vram_base; vga_set_mem_top(c); } @@ -860,7 +860,7 @@ static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) { #ifdef CAN_LOAD_PALETTE if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked - || !CON_IS_VISIBLE(vc)) + || !con_is_visible(vc)) return; vga_set_palette(vc, table); #endif @@ -1248,7 +1248,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) struct vc_data *c = vc_cons[i].d; if (c && c->vc_sw == &vga_con) { - if (CON_IS_VISIBLE(c)) { + if (con_is_visible(c)) { /* void size to cause regs to be rewritten */ cursor_size_lastfrom = 0; cursor_size_lastto = 0; @@ -1312,7 +1312,7 @@ static int vgacon_resize(struct vc_data *c, unsigned int width, return success */ return (user) ? 0 : -EINVAL; - if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ + if (con_is_visible(c) && !vga_is_gfx) /* who knows */ vgacon_doresize(c, width, height); return 0; } diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 5fa605c93428..a12d3f2899a8 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -168,6 +168,9 @@ extern void vc_SAK(struct work_struct *work); #define CUR_DEFAULT CUR_UNDERLINE -#define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp) +static inline bool con_is_visible(const struct vc_data *vc) +{ + return *vc->vc_display_fg == vc; +} #endif /* _LINUX_CONSOLE_STRUCT_H */ -- cgit v1.2.3 From f8b0c2e688f086d22157afc734755ed370e288dc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:36 +0200 Subject: tty: vt, ignore PIO_UNIMAPCLR param We do not do hashtables for unicode fonts since 1995 (1.3.28). So it is time to remove the second parameter of con_clear_unimap and ignore the advice from userspace completely. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 13 ++++++------- drivers/tty/vt/vt_ioctl.c | 8 +------- include/linux/vt_kern.h | 5 ++--- 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index c8c91f0476a2..9d7ab7b66a8a 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -499,9 +499,8 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) return 0; } -/* ui is a leftover from using a hashtable, but might be used again - Caller must hold the lock */ -static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +/* Caller must hold the lock */ +static int con_do_clear_unimap(struct vc_data *vc) { struct uni_pagedir *p, *q; @@ -524,11 +523,11 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui) return 0; } -int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +int con_clear_unimap(struct vc_data *vc) { int ret; console_lock(); - ret = con_do_clear_unimap(vc, ui); + ret = con_do_clear_unimap(vc); console_unlock(); return ret; } @@ -556,7 +555,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) int j, k; u16 **p1, *p2, l; - err1 = con_do_clear_unimap(vc, NULL); + err1 = con_do_clear_unimap(vc); if (err1) { console_unlock(); return err1; @@ -677,7 +676,7 @@ int con_set_default_unimap(struct vc_data *vc) /* The default font is always 256 characters */ - err = con_do_clear_unimap(vc, NULL); + err = con_do_clear_unimap(vc); if (err) return err; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 97d5a74558a3..f62c598810ff 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -1006,16 +1006,10 @@ int vt_ioctl(struct tty_struct *tty, break; case PIO_UNIMAPCLR: - { struct unimapinit ui; if (!perm) return -EPERM; - ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); - if (ret) - ret = -EFAULT; - else - con_clear_unimap(vc, &ui); + con_clear_unimap(vc); break; - } case PIO_UNIMAP: case GIO_UNIMAP: diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 160f81fe3eb8..6abd24f258bc 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -59,14 +59,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg); #ifdef CONFIG_CONSOLE_TRANSLATIONS /* consolemap.c */ -struct unimapinit; struct unipair; int con_set_trans_old(unsigned char __user * table); int con_get_trans_old(unsigned char __user * table); int con_set_trans_new(unsigned short __user * table); int con_get_trans_new(unsigned short __user * table); -int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui); +int con_clear_unimap(struct vc_data *vc); int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list); int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list); int con_set_default_unimap(struct vc_data *vc); @@ -92,7 +91,7 @@ static inline int con_get_trans_new(unsigned short __user *table) { return -EINVAL; } -static inline int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) +static inline int con_clear_unimap(struct vc_data *vc) { return 0; } -- cgit v1.2.3 From abd530de2a55c1a74271e27d6e8c71c74c25e222 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 23 Jun 2016 13:34:37 +0200 Subject: tty: vt, remove unused vc_deccolm vc_deccolm is only set and never read, remove the member from vc_data. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 1 - include/linux/console_struct.h | 1 - 2 files changed, 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 26de5c0fc056..213ce24060b5 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1482,7 +1482,6 @@ static void set_mode(struct vc_data *vc, int on_off) clr_kbd(vc, decckm); break; case 3: /* 80/132 mode switch unimplemented */ - vc->vc_deccolm = on_off; #if 0 vc_resize(deccolm ? 132 : 80, vc->vc_rows); /* this alone does not suffice; some user mode diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index a12d3f2899a8..6fd3c908a340 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -106,7 +106,6 @@ struct vc_data { unsigned int vc_decawm : 1; /* Autowrap Mode */ unsigned int vc_deccm : 1; /* Cursor Visible */ unsigned int vc_decim : 1; /* Insert Mode */ - unsigned int vc_deccolm : 1; /* 80/132 Column Mode */ /* attribute flags */ unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ unsigned int vc_italic:1; -- cgit v1.2.3 From c6f82787a5a193a5c4c49ddaeb362d320efa5fba Mon Sep 17 00:00:00 2001 From: "Chuah, Kim Tatt" Date: Wed, 15 Jun 2016 13:44:11 +0800 Subject: dmaengine: hsu: Export hsu_dma_get_status() To allow other code to safely read DMA Channel Status Register (where the register attribute for Channel Error, Descriptor Time Out & Descriptor Done fields are read-clear), export hsu_dma_get_status(). hsu_dma_irq() is renamed to hsu_dma_do_irq() and requires Status Register value to be passed in. Signed-off-by: Chuah, Kim Tatt Acked-by: Andy Shevchenko Reviewed-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/dma/hsu/hsu.c | 90 +++++++++++++++++++++++++++++--------- drivers/dma/hsu/pci.c | 11 ++++- drivers/tty/serial/8250/8250_mid.c | 22 +++++++--- include/linux/dma/hsu.h | 14 ++++-- 4 files changed, 106 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index f8c5cd53307c..c5f21efd6090 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -126,28 +126,33 @@ static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc) hsu_dma_start_channel(hsuc); } -static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) -{ - unsigned long flags; - u32 sr; - - spin_lock_irqsave(&hsuc->vchan.lock, flags); - sr = hsu_chan_readl(hsuc, HSU_CH_SR); - spin_unlock_irqrestore(&hsuc->vchan.lock, flags); - - return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); -} - -irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) +/* + * hsu_dma_get_status() - get DMA channel status + * @chip: HSUART DMA chip + * @nr: DMA channel number + * @status: pointer for DMA Channel Status Register value + * + * Description: + * The function reads and clears the DMA Channel Status Register, checks + * if it was a timeout interrupt and returns a corresponding value. + * + * Caller should provide a valid pointer for the DMA Channel Status + * Register value that will be returned in @status. + * + * Return: + * 1 for DMA timeout status, 0 for other DMA status, or error code for + * invalid parameters or no interrupt pending. + */ +int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, + u32 *status) { struct hsu_dma_chan *hsuc; - struct hsu_dma_desc *desc; unsigned long flags; u32 sr; /* Sanity check */ if (nr >= chip->hsu->nr_channels) - return IRQ_NONE; + return -EINVAL; hsuc = &chip->hsu->chan[nr]; @@ -155,22 +160,65 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) * No matter what situation, need read clear the IRQ status * There is a bug, see Errata 5, HSD 2900918 */ - sr = hsu_dma_chan_get_sr(hsuc); + spin_lock_irqsave(&hsuc->vchan.lock, flags); + sr = hsu_chan_readl(hsuc, HSU_CH_SR); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); + + /* Check if any interrupt is pending */ + sr &= ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); if (!sr) - return IRQ_NONE; + return -EIO; /* Timeout IRQ, need wait some time, see Errata 2 */ if (sr & HSU_CH_SR_DESCTO_ANY) udelay(2); + /* + * At this point, at least one of Descriptor Time Out, Channel Error + * or Descriptor Done bits must be set. Clear the Descriptor Time Out + * bits and if sr is still non-zero, it must be channel error or + * descriptor done which are higher priority than timeout and handled + * in hsu_dma_do_irq(). Else, it must be a timeout. + */ sr &= ~HSU_CH_SR_DESCTO_ANY; - if (!sr) - return IRQ_HANDLED; + + *status = sr; + + return sr ? 0 : 1; +} +EXPORT_SYMBOL_GPL(hsu_dma_get_status); + +/* + * hsu_dma_do_irq() - DMA interrupt handler + * @chip: HSUART DMA chip + * @nr: DMA channel number + * @status: Channel Status Register value + * + * Description: + * This function handles Channel Error and Descriptor Done interrupts. + * This function should be called after determining that the DMA interrupt + * is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0. + * + * Return: + * IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise. + */ +irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, + u32 status) +{ + struct hsu_dma_chan *hsuc; + struct hsu_dma_desc *desc; + unsigned long flags; + + /* Sanity check */ + if (nr >= chip->hsu->nr_channels) + return IRQ_NONE; + + hsuc = &chip->hsu->chan[nr]; spin_lock_irqsave(&hsuc->vchan.lock, flags); desc = hsuc->desc; if (desc) { - if (sr & HSU_CH_SR_CHE) { + if (status & HSU_CH_SR_CHE) { desc->status = DMA_ERROR; } else if (desc->active < desc->nents) { hsu_dma_start_channel(hsuc); @@ -184,7 +232,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) return IRQ_HANDLED; } -EXPORT_SYMBOL_GPL(hsu_dma_irq); +EXPORT_SYMBOL_GPL(hsu_dma_do_irq); static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) { diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index e2db76bd56d8..9916058531d9 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c @@ -27,13 +27,20 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev) { struct hsu_dma_chip *chip = dev; u32 dmaisr; + u32 status; unsigned short i; irqreturn_t ret = IRQ_NONE; + int err; dmaisr = readl(chip->regs + HSU_PCI_DMAISR); for (i = 0; i < chip->hsu->nr_channels; i++) { - if (dmaisr & 0x1) - ret |= hsu_dma_irq(chip, i); + if (dmaisr & 0x1) { + err = hsu_dma_get_status(chip, i, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(chip, i, status); + } dmaisr >>= 1; } diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 86379a79a6a3..b218ff528df7 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -97,12 +97,24 @@ static int dnv_handle_irq(struct uart_port *p) { struct mid8250 *mid = p->private_data; unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); + u32 status; int ret = IRQ_NONE; - - if (fisr & BIT(2)) - ret |= hsu_dma_irq(&mid->dma_chip, 1); - if (fisr & BIT(1)) - ret |= hsu_dma_irq(&mid->dma_chip, 0); + int err; + + if (fisr & BIT(2)) { + err = hsu_dma_get_status(&mid->dma_chip, 1, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status); + } + if (fisr & BIT(1)) { + err = hsu_dma_get_status(&mid->dma_chip, 0, &status); + if (err > 0) + ret |= IRQ_HANDLED; + else if (err == 0) + ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status); + } if (fisr & BIT(0)) ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); return ret; diff --git a/include/linux/dma/hsu.h b/include/linux/dma/hsu.h index 79df69dc629c..aaff68efba5d 100644 --- a/include/linux/dma/hsu.h +++ b/include/linux/dma/hsu.h @@ -39,14 +39,22 @@ struct hsu_dma_chip { #if IS_ENABLED(CONFIG_HSU_DMA) /* Export to the internal users */ -irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr); +int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, + u32 *status); +irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, + u32 status); /* Export to the platform drivers */ int hsu_dma_probe(struct hsu_dma_chip *chip); int hsu_dma_remove(struct hsu_dma_chip *chip); #else -static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, - unsigned short nr) +static inline int hsu_dma_get_status(struct hsu_dma_chip *chip, + unsigned short nr, u32 *status) +{ + return 0; +} +static inline irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, + unsigned short nr, u32 status) { return IRQ_NONE; } -- cgit v1.2.3 From 4ef03d328769eddbfeca1f1c958fdb181a69c341 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Tue, 31 May 2016 10:59:18 +0200 Subject: tty/serial/8250: use mctrl_gpio helpers This patch permits the usage for GPIOs to control the CTS/RTS/DTR/DSR/DCD/RI signals. Signed-off-by: Yegor Yefremov Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/8250.txt | 19 ++++++++++++ drivers/tty/serial/8250/8250.h | 35 ++++++++++++++++++++++- drivers/tty/serial/8250/8250_core.c | 9 ++++++ drivers/tty/serial/8250/8250_omap.c | 31 +++++++++++--------- drivers/tty/serial/8250/8250_port.c | 7 ++++- drivers/tty/serial/8250/Kconfig | 1 + include/linux/serial_8250.h | 1 + 7 files changed, 88 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt index 936ab5b87324..f5561ac7e17e 100644 --- a/Documentation/devicetree/bindings/serial/8250.txt +++ b/Documentation/devicetree/bindings/serial/8250.txt @@ -42,6 +42,9 @@ Optional properties: - auto-flow-control: one way to enable automatic flow control support. The driver is allowed to detect support for the capability even without this property. +- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD + line respectively. It will use specified GPIO instead of the peripheral + function pin for the UART feature. If unsure, don't specify this property. Note: * fsl,ns16550: @@ -63,3 +66,19 @@ Example: interrupts = <10>; reg-shift = <2>; }; + +Example for OMAP UART using GPIO-based modem control signals: + + uart4: serial@49042000 { + compatible = "ti,omap3-uart"; + reg = <0x49042000 0x400>; + interrupts = <80>; + ti,hwmods = "uart4"; + clock-frequency = <48000000>; + cts-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>; + rts-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; + dtr-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; + dsr-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>; + dcd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; + rng-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + }; diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 1a16feac9a36..122e0e4029fe 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -15,6 +15,8 @@ #include #include +#include "../serial_mctrl_gpio.h" + struct uart_8250_dma { int (*tx_dma)(struct uart_8250_port *p); int (*rx_dma)(struct uart_8250_port *p); @@ -131,12 +133,43 @@ void serial8250_em485_destroy(struct uart_8250_port *p); static inline void serial8250_out_MCR(struct uart_8250_port *up, int value) { + int mctrl_gpio = 0; + serial_out(up, UART_MCR, value); + + if (value & UART_MCR_RTS) + mctrl_gpio |= TIOCM_RTS; + if (value & UART_MCR_DTR) + mctrl_gpio |= TIOCM_DTR; + + mctrl_gpio_set(up->gpios, mctrl_gpio); } static inline int serial8250_in_MCR(struct uart_8250_port *up) { - return serial_in(up, UART_MCR); + int mctrl, mctrl_gpio = 0; + + mctrl = serial_in(up, UART_MCR); + + /* save current MCR values */ + if (mctrl & UART_MCR_RTS) + mctrl_gpio |= TIOCM_RTS; + if (mctrl & UART_MCR_DTR) + mctrl_gpio |= TIOCM_DTR; + + mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, &mctrl_gpio); + + if (mctrl_gpio & TIOCM_RTS) + mctrl |= UART_MCR_RTS; + else + mctrl &= ~UART_MCR_RTS; + + if (mctrl_gpio & TIOCM_DTR) + mctrl |= UART_MCR_DTR; + else + mctrl &= ~UART_MCR_DTR; + + return mctrl; } #if defined(__alpha__) && !defined(CONFIG_PCI) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index dcf43f66404f..13ad5c3d2e68 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -974,6 +974,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart = serial8250_find_match_or_unused(&up->port); if (uart && uart->port.type != PORT_8250_CIR) { + struct mctrl_gpios *gpios; + if (uart->port.dev) uart_remove_one_port(&serial8250_reg, &uart->port); @@ -1011,6 +1013,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->port.flags & UPF_FIXED_TYPE) uart->port.type = up->port.type; + gpios = mctrl_gpio_init(&uart->port, 0); + if (IS_ERR(gpios)) { + if (PTR_ERR(gpios) != -ENOSYS) + return PTR_ERR(gpios); + } else + uart->gpios = gpios; + serial8250_set_defaults(uart); /* Possibly override default I/O functions. */ diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 61ad6c3b20a0..e14982f36a04 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -134,18 +134,21 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl) serial8250_do_set_mctrl(port, mctrl); - /* - * Turn off autoRTS if RTS is lowered and restore autoRTS setting - * if RTS is raised - */ - lcr = serial_in(up, UART_LCR); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) - priv->efr |= UART_EFR_RTS; - else - priv->efr &= ~UART_EFR_RTS; - serial_out(up, UART_EFR, priv->efr); - serial_out(up, UART_LCR, lcr); + if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios, + UART_GPIO_RTS))) { + /* + * Turn off autoRTS if RTS is lowered and restore autoRTS + * setting if RTS is raised + */ + lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) + priv->efr |= UART_EFR_RTS; + else + priv->efr &= ~UART_EFR_RTS; + serial_out(up, UART_EFR, priv->efr); + serial_out(up, UART_LCR, lcr); + } } /* @@ -446,7 +449,9 @@ static void omap_8250_set_termios(struct uart_port *port, priv->efr = 0; up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); - if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { + if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW + && IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios, + UART_GPIO_RTS))) { /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */ up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; priv->efr |= UART_EFR_CTS; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index bdfa659b9606..7481b95c6d84 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1618,6 +1618,8 @@ static void serial8250_disable_ms(struct uart_port *port) if (up->bugs & UART_BUG_NOMSR) return; + mctrl_gpio_disable_ms(up->gpios); + up->ier &= ~UART_IER_MSI; serial_port_out(port, UART_IER, up->ier); } @@ -1630,6 +1632,8 @@ static void serial8250_enable_ms(struct uart_port *port) if (up->bugs & UART_BUG_NOMSR) return; + mctrl_gpio_enable_ms(up->gpios); + up->ier |= UART_IER_MSI; serial8250_rpm_get(up); @@ -1913,7 +1917,8 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port) ret |= TIOCM_DSR; if (status & UART_MSR_CTS) ret |= TIOCM_CTS; - return ret; + + return mctrl_gpio_get(up->gpios, &ret); } EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index b5a0f2e76f08..b1c73dec7eda 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -6,6 +6,7 @@ config SERIAL_8250 tristate "8250/16550 and compatible serial support" select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB ---help--- This selects whether you want to include the driver for the standard serial ports. The standard answer is Y. People who might say N diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 48ec7651989b..923266cd294a 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -111,6 +111,7 @@ struct uart_8250_port { * if no_console_suspend */ unsigned char probe; + struct mctrl_gpios *gpios; #define UART_PROBE_RSA (1 << 0) /* -- cgit v1.2.3 From f8ba3647f30ab22daeb5110453e2dad8a2c1d841 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 6 Jun 2016 18:41:00 +0900 Subject: earlycon: mark earlycon code as __used iif the caller is built-in Keep earlycon related symbols only when CONFIG_SERIAL_EARLYCON is enabled and the driver is built-in. This will be helpful to clean up ifdefs surrounding earlycon code in serial drivers. Signed-off-by: Masahiro Yamada Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- include/linux/serial_core.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index a3d7c0d4a03e..2f44e2013654 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -352,9 +352,15 @@ struct earlycon_id { extern const struct earlycon_id __earlycon_table[]; extern const struct earlycon_id __earlycon_table_end[]; +#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) +#define EARLYCON_USED_OR_UNUSED __used +#else +#define EARLYCON_USED_OR_UNUSED __maybe_unused +#endif + #define OF_EARLYCON_DECLARE(_name, compat, fn) \ static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ - __used __section(__earlycon_table) \ + EARLYCON_USED_OR_UNUSED __section(__earlycon_table) \ = { .name = __stringify(_name), \ .compatible = compat, \ .setup = fn } -- cgit v1.2.3 From d6faca40f40b62aca8ea8c29289c7bf7456172bb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 1 Jun 2016 16:46:23 +0200 Subject: rtc: move mc146818 helper functions out-of-line The mc146818_get_time/mc146818_set_time functions are rather large inline functions in a global header file and are used in several drivers and in x86 specific code. Here we move them into a separate .c file that is compiled whenever any of the users require it. This also lets us remove the linux/acpi.h header inclusion from mc146818rtc.h, which in turn avoids some warnings about duplicate definition of the TRUE/FALSE macros. Signed-off-by: Arnd Bergmann Signed-off-by: Alexandre Belloni --- arch/x86/Kconfig | 1 + drivers/rtc/Kconfig | 6 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-mc146818-lib.c | 198 +++++++++++++++++++++++++++++++++++++++++ include/linux/mc146818rtc.h | 193 +-------------------------------------- 5 files changed, 208 insertions(+), 191 deletions(-) create mode 100644 drivers/rtc/rtc-mc146818-lib.c (limited to 'include/linux') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0a7b885964ba..54d46c5c04d0 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -151,6 +151,7 @@ config X86 select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION select PERF_EVENTS select RTC_LIB + select RTC_MC146818_LIB select SPARSE_IRQ select SRCU select SYSCTL_EXCEPTION_TRACE diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 13128a89657b..8526f1cded08 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -5,6 +5,10 @@ config RTC_LIB bool +config RTC_MC146818_LIB + bool + select RTC_LIB + menuconfig RTC_CLASS bool "Real Time Clock" default n @@ -809,6 +813,7 @@ config RTC_DRV_CMOS tristate "PC-style 'CMOS'" depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 || MN10300 default y if X86 + select RTC_MC146818_LIB help Say "yes" here to get direct support for the real time clock found in every PC or ACPI-based system, and some other boards. @@ -827,6 +832,7 @@ config RTC_DRV_CMOS config RTC_DRV_ALPHA bool "Alpha PC-style CMOS" depends on ALPHA + select RTC_MC146818_LIB default y help Direct support for the real-time clock found on every Alpha diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 024da2723d86..7cf7ad559c79 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_RTC_LIB) += rtc-lib.o obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o +obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o rtc-core-y := class.o interface.o ifdef CONFIG_RTC_DRV_EFI diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c new file mode 100644 index 000000000000..2f1772a358ca --- /dev/null +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include + +#ifdef CONFIG_ACPI +#include +#endif + +/* + * Returns true if a clock update is in progress + */ +static inline unsigned char mc146818_is_updating(void) +{ + unsigned char uip; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + spin_unlock_irqrestore(&rtc_lock, flags); + return uip; +} + +unsigned int mc146818_get_time(struct rtc_time *time) +{ + unsigned char ctrl; + unsigned long flags; + unsigned char century = 0; + +#ifdef CONFIG_MACH_DECSTATION + unsigned int real_year; +#endif + + /* + * read RTC once any update in progress is done. The update + * can take just over 2ms. We wait 20ms. There is no need to + * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. + * If you need to know *exactly* when a second has started, enable + * periodic update complete interrupts, (via ioctl) and then + * immediately read /dev/rtc which will block until you get the IRQ. + * Once the read clears, read the RTC time (again via ioctl). Easy. + */ + if (mc146818_is_updating()) + mdelay(20); + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + spin_lock_irqsave(&rtc_lock, flags); + time->tm_sec = CMOS_READ(RTC_SECONDS); + time->tm_min = CMOS_READ(RTC_MINUTES); + time->tm_hour = CMOS_READ(RTC_HOURS); + time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); + time->tm_mon = CMOS_READ(RTC_MONTH); + time->tm_year = CMOS_READ(RTC_YEAR); +#ifdef CONFIG_MACH_DECSTATION + real_year = CMOS_READ(RTC_DEC_YEAR); +#endif +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century = CMOS_READ(acpi_gbl_FADT.century); +#endif + ctrl = CMOS_READ(RTC_CONTROL); + spin_unlock_irqrestore(&rtc_lock, flags); + + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + time->tm_sec = bcd2bin(time->tm_sec); + time->tm_min = bcd2bin(time->tm_min); + time->tm_hour = bcd2bin(time->tm_hour); + time->tm_mday = bcd2bin(time->tm_mday); + time->tm_mon = bcd2bin(time->tm_mon); + time->tm_year = bcd2bin(time->tm_year); + century = bcd2bin(century); + } + +#ifdef CONFIG_MACH_DECSTATION + time->tm_year += real_year - 72; +#endif + + if (century) + time->tm_year += (century - 19) * 100; + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if (time->tm_year <= 69) + time->tm_year += 100; + + time->tm_mon--; + + return RTC_24H; +} +EXPORT_SYMBOL_GPL(mc146818_get_time); + +/* Set the current date and time in the real time clock. */ +int mc146818_set_time(struct rtc_time *time) +{ + unsigned long flags; + unsigned char mon, day, hrs, min, sec; + unsigned char save_control, save_freq_select; + unsigned int yrs; +#ifdef CONFIG_MACH_DECSTATION + unsigned int real_yrs, leap_yr; +#endif + unsigned char century = 0; + + yrs = time->tm_year; + mon = time->tm_mon + 1; /* tm_mon starts at zero */ + day = time->tm_mday; + hrs = time->tm_hour; + min = time->tm_min; + sec = time->tm_sec; + + if (yrs > 255) /* They are unsigned */ + return -EINVAL; + + spin_lock_irqsave(&rtc_lock, flags); +#ifdef CONFIG_MACH_DECSTATION + real_yrs = yrs; + leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || + !((yrs + 1900) % 400)); + yrs = 72; + + /* + * We want to keep the year set to 73 until March + * for non-leap years, so that Feb, 29th is handled + * correctly. + */ + if (!leap_yr && mon < 3) { + real_yrs--; + yrs = 73; + } +#endif + +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) { + century = (yrs + 1900) / 100; + yrs %= 100; + } +#endif + + /* These limits and adjustments are independent of + * whether the chip is in binary mode or not. + */ + if (yrs > 169) { + spin_unlock_irqrestore(&rtc_lock, flags); + return -EINVAL; + } + + if (yrs >= 100) + yrs -= 100; + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) + || RTC_ALWAYS_BCD) { + sec = bin2bcd(sec); + min = bin2bcd(min); + hrs = bin2bcd(hrs); + day = bin2bcd(day); + mon = bin2bcd(mon); + yrs = bin2bcd(yrs); + century = bin2bcd(century); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + +#ifdef CONFIG_MACH_DECSTATION + CMOS_WRITE(real_yrs, RTC_DEC_YEAR); +#endif + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + CMOS_WRITE(century, acpi_gbl_FADT.century); +#endif + + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + spin_unlock_irqrestore(&rtc_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(mc146818_set_time); diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h index e9e346b37846..a585b4b5fa0e 100644 --- a/include/linux/mc146818rtc.h +++ b/include/linux/mc146818rtc.h @@ -17,10 +17,6 @@ #include #include -#ifdef CONFIG_ACPI -#include -#endif - #ifdef __KERNEL__ #include /* spinlock_t */ extern spinlock_t rtc_lock; /* serialize CMOS RAM access */ @@ -126,192 +122,7 @@ struct cmos_rtc_board_info { #define RTC_IO_EXTENT_USED RTC_IO_EXTENT #endif /* ARCH_RTC_LOCATION */ -/* - * Returns true if a clock update is in progress - */ -static inline unsigned char mc146818_is_updating(void) -{ - unsigned char uip; - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); - uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - spin_unlock_irqrestore(&rtc_lock, flags); - return uip; -} - -static inline unsigned int mc146818_get_time(struct rtc_time *time) -{ - unsigned char ctrl; - unsigned long flags; - unsigned char century = 0; - -#ifdef CONFIG_MACH_DECSTATION - unsigned int real_year; -#endif - - /* - * read RTC once any update in progress is done. The update - * can take just over 2ms. We wait 20ms. There is no need to - * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. - * If you need to know *exactly* when a second has started, enable - * periodic update complete interrupts, (via ioctl) and then - * immediately read /dev/rtc which will block until you get the IRQ. - * Once the read clears, read the RTC time (again via ioctl). Easy. - */ - if (mc146818_is_updating()) - mdelay(20); - - /* - * Only the values that we read from the RTC are set. We leave - * tm_wday, tm_yday and tm_isdst untouched. Even though the - * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated - * by the RTC when initially set to a non-zero value. - */ - spin_lock_irqsave(&rtc_lock, flags); - time->tm_sec = CMOS_READ(RTC_SECONDS); - time->tm_min = CMOS_READ(RTC_MINUTES); - time->tm_hour = CMOS_READ(RTC_HOURS); - time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); - time->tm_mon = CMOS_READ(RTC_MONTH); - time->tm_year = CMOS_READ(RTC_YEAR); -#ifdef CONFIG_MACH_DECSTATION - real_year = CMOS_READ(RTC_DEC_YEAR); -#endif -#ifdef CONFIG_ACPI - if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && - acpi_gbl_FADT.century) - century = CMOS_READ(acpi_gbl_FADT.century); -#endif - ctrl = CMOS_READ(RTC_CONTROL); - spin_unlock_irqrestore(&rtc_lock, flags); - - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { - time->tm_sec = bcd2bin(time->tm_sec); - time->tm_min = bcd2bin(time->tm_min); - time->tm_hour = bcd2bin(time->tm_hour); - time->tm_mday = bcd2bin(time->tm_mday); - time->tm_mon = bcd2bin(time->tm_mon); - time->tm_year = bcd2bin(time->tm_year); - century = bcd2bin(century); - } - -#ifdef CONFIG_MACH_DECSTATION - time->tm_year += real_year - 72; -#endif - - if (century) - time->tm_year += (century - 19) * 100; - - /* - * Account for differences between how the RTC uses the values - * and how they are defined in a struct rtc_time; - */ - if (time->tm_year <= 69) - time->tm_year += 100; - - time->tm_mon--; - - return RTC_24H; -} - -/* Set the current date and time in the real time clock. */ -static inline int mc146818_set_time(struct rtc_time *time) -{ - unsigned long flags; - unsigned char mon, day, hrs, min, sec; - unsigned char save_control, save_freq_select; - unsigned int yrs; -#ifdef CONFIG_MACH_DECSTATION - unsigned int real_yrs, leap_yr; -#endif - unsigned char century = 0; - - yrs = time->tm_year; - mon = time->tm_mon + 1; /* tm_mon starts at zero */ - day = time->tm_mday; - hrs = time->tm_hour; - min = time->tm_min; - sec = time->tm_sec; - - if (yrs > 255) /* They are unsigned */ - return -EINVAL; - - spin_lock_irqsave(&rtc_lock, flags); -#ifdef CONFIG_MACH_DECSTATION - real_yrs = yrs; - leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || - !((yrs + 1900) % 400)); - yrs = 72; - - /* - * We want to keep the year set to 73 until March - * for non-leap years, so that Feb, 29th is handled - * correctly. - */ - if (!leap_yr && mon < 3) { - real_yrs--; - yrs = 73; - } -#endif - -#ifdef CONFIG_ACPI - if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && - acpi_gbl_FADT.century) { - century = (yrs + 1900) / 100; - yrs %= 100; - } -#endif - - /* These limits and adjustments are independent of - * whether the chip is in binary mode or not. - */ - if (yrs > 169) { - spin_unlock_irqrestore(&rtc_lock, flags); - return -EINVAL; - } - - if (yrs >= 100) - yrs -= 100; - - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) { - sec = bin2bcd(sec); - min = bin2bcd(min); - hrs = bin2bcd(hrs); - day = bin2bcd(day); - mon = bin2bcd(mon); - yrs = bin2bcd(yrs); - century = bin2bcd(century); - } - - save_control = CMOS_READ(RTC_CONTROL); - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - -#ifdef CONFIG_MACH_DECSTATION - CMOS_WRITE(real_yrs, RTC_DEC_YEAR); -#endif - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DAY_OF_MONTH); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); -#ifdef CONFIG_ACPI - if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && - acpi_gbl_FADT.century) - CMOS_WRITE(century, acpi_gbl_FADT.century); -#endif - - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - spin_unlock_irqrestore(&rtc_lock, flags); - - return 0; -} +unsigned int mc146818_get_time(struct rtc_time *time); +int mc146818_set_time(struct rtc_time *time); #endif /* _MC146818RTC_H */ -- cgit v1.2.3 From 613e97218ccbd7f33895cad4525d861810a9d5d5 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 21 Jun 2016 18:50:20 +0100 Subject: device property: Add function to search for named child of device For device nodes in both DT and ACPI, it possible to have named child nodes which contain properties (an existing example being gpio-leds). This adds a function to find a named child node for a device which can be used by drivers for property retrieval. For DT data node name matching, of_node_cmp() and similar functions are made available outside of CONFIG_OF block so the new function can reference these for DT and non-DT builds. For ACPI data node name matching, a helper function is also added which returns false if CONFIG_ACPI is not set, otherwise it performs a string comparison on the data node name. This avoids using the acpi_data_node struct for non CONFIG_ACPI builds, which would otherwise cause a build failure. Signed-off-by: Adam Thomson Acked-by: Sathyanarayana Nujella Acked-by: Rob Herring Acked-by: Rafael J. Wysocki Signed-off-by: Mark Brown --- drivers/base/property.c | 28 ++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 7 +++++++ include/linux/acpi.h | 6 ++++++ include/linux/of.h | 14 +++++++------- include/linux/property.h | 3 +++ 5 files changed, 51 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/property.c b/drivers/base/property.c index f38c21de29b7..43a36d68c3fd 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -887,6 +887,34 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev, } EXPORT_SYMBOL_GPL(device_get_next_child_node); +/** + * device_get_named_child_node - Return first matching named child node handle + * @dev: Device to find the named child node for. + * @childname: String to match child node name against. + */ +struct fwnode_handle *device_get_named_child_node(struct device *dev, + const char *childname) +{ + struct fwnode_handle *child; + + /* + * Find first matching named child node of this device. + * For ACPI this will be a data only sub-node. + */ + device_for_each_child_node(dev, child) { + if (is_of_node(child)) { + if (!of_node_cmp(to_of_node(child)->name, childname)) + return child; + } else if (is_acpi_data_node(child)) { + if (acpi_data_node_match(child, childname)) + return child; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(device_get_named_child_node); + /** * fwnode_handle_put - Drop reference to a device node * @fwnode: Pointer to the device node to drop the reference to. diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 788c6c35291a..c1a524de67c5 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -420,6 +420,13 @@ static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwn container_of(fwnode, struct acpi_data_node, fwnode) : NULL; } +static inline bool acpi_data_node_match(struct fwnode_handle *fwnode, + const char *name) +{ + return is_acpi_data_node(fwnode) ? + (!strcmp(to_acpi_data_node(fwnode)->name, name)) : false; +} + static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev) { return &adev->fwnode; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 288fac5294f5..03039c472e95 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -568,6 +568,12 @@ static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwn return NULL; } +static inline bool acpi_data_node_match(struct fwnode_handle *fwnode, + const char *name) +{ + return false; +} + static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev) { return NULL; diff --git a/include/linux/of.h b/include/linux/of.h index c7292e8ea080..8455741e313e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -238,13 +238,6 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size) #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 #endif -/* Default string compare functions, Allow arch asm/prom.h to override */ -#if !defined(of_compat_cmp) -#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) -#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) -#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) -#endif - #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) @@ -726,6 +719,13 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag #define of_match_node(_matches, _node) NULL #endif /* CONFIG_OF */ +/* Default string compare functions, Allow arch asm/prom.h to override */ +#if !defined(of_compat_cmp) +#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) +#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) +#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) +#endif + #if defined(CONFIG_OF) && defined(CONFIG_NUMA) extern int of_node_to_nid(struct device_node *np); #else diff --git a/include/linux/property.h b/include/linux/property.h index ecab11e40794..3a2f9ae25c86 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -77,6 +77,9 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev, for (child = device_get_next_child_node(dev, NULL); child; \ child = device_get_next_child_node(dev, child)) +struct fwnode_handle *device_get_named_child_node(struct device *dev, + const char *childname); + void fwnode_handle_put(struct fwnode_handle *fwnode); unsigned int device_get_child_node_count(struct device *dev); -- cgit v1.2.3 From a3aef37930713447b45b1f0f9f8841be44f7db45 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Tue, 21 Jun 2016 10:58:10 +0300 Subject: xhci: get rid of platform data No more users for it. Signed-off-by: Heikki Krogerus Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 5 +---- include/linux/usb/xhci_pdriver.h | 27 --------------------------- 2 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 include/linux/usb/xhci_pdriver.h (limited to 'include/linux') diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index d1db8bb10554..ed56bf9ed885 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "xhci.h" @@ -138,7 +137,6 @@ MODULE_DEVICE_TABLE(of, usb_xhci_of_match); static int xhci_plat_probe(struct platform_device *pdev) { - struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev); const struct of_device_id *match; const struct hc_driver *driver; struct xhci_hcd *xhci; @@ -222,8 +220,7 @@ static int xhci_plat_probe(struct platform_device *pdev) goto disable_clk; } - if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable") || - (pdata && pdata->usb3_lpm_capable)) + if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable")) xhci->quirks |= XHCI_LPM_SUPPORT; if (HCC_MAX_PSA(xhci->hcc_params) >= 4) diff --git a/include/linux/usb/xhci_pdriver.h b/include/linux/usb/xhci_pdriver.h deleted file mode 100644 index 376654b5b0f7..000000000000 --- a/include/linux/usb/xhci_pdriver.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - */ - -#ifndef __USB_CORE_XHCI_PDRIVER_H -#define __USB_CORE_XHCI_PDRIVER_H - -/** - * struct usb_xhci_pdata - platform_data for generic xhci platform driver - * - * @usb3_lpm_capable: determines if this xhci platform supports USB3 - * LPM capability - * - */ -struct usb_xhci_pdata { - unsigned usb3_lpm_capable:1; -}; - -#endif /* __USB_CORE_XHCI_PDRIVER_H */ -- cgit v1.2.3 From 0afef45654ae908536278ecb143ded5bbc713391 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 22 Jun 2016 16:40:45 -0500 Subject: staging: fsl-mc: add support for device table matching Move the definition of fsl_mc_device_id to its proper location in mod_devicetable.h, and add fsl-mc bus support to devicetable-offsets.c and file2alias.c to enable device table matching. With this patch udev based module loading of fsl-mc drivers is supported. Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fsl-mc/include/mc.h | 13 ------------- include/linux/mod_devicetable.h | 16 ++++++++++++++++ scripts/mod/devicetable-offsets.c | 4 ++++ scripts/mod/file2alias.c | 12 ++++++++++++ 4 files changed, 32 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h index bc0d45cb9b65..a9a9d23f78d5 100644 --- a/drivers/staging/fsl-mc/include/mc.h +++ b/drivers/staging/fsl-mc/include/mc.h @@ -50,19 +50,6 @@ struct fsl_mc_driver { #define to_fsl_mc_driver(_drv) \ container_of(_drv, struct fsl_mc_driver, driver) -/** - * struct fsl_mc_device_id - MC object device Id entry for driver matching - * @vendor: vendor ID - * @obj_type: MC object type - * - * Type of entries in the "device Id" table for MC object devices supported by - * a MC object device driver. The last entry of the table has vendor set to 0x0 - */ -struct fsl_mc_device_id { - u16 vendor; - const char obj_type[16]; -}; - /** * enum fsl_mc_pool_type - Types of allocatable MC bus resources * diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 6e4c645e1c0d..ed84c07f6a51 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -657,4 +657,20 @@ struct ulpi_device_id { kernel_ulong_t driver_data; }; +/** + * struct fsl_mc_device_id - MC object device identifier + * @vendor: vendor ID + * @obj_type: MC object type + * @ver_major: MC object version major number + * @ver_minor: MC object version minor number + * + * Type of entries in the "device Id" table for MC object devices supported by + * a MC object device driver. The last entry of the table has vendor set to 0x0 + */ +struct fsl_mc_device_id { + __u16 vendor; + const char obj_type[16]; +}; + + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index 840b97328b39..e4d90e50f6fe 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -202,5 +202,9 @@ int main(void) DEVID_FIELD(hda_device_id, rev_id); DEVID_FIELD(hda_device_id, api_version); + DEVID(fsl_mc_device_id); + DEVID_FIELD(fsl_mc_device_id, vendor); + DEVID_FIELD(fsl_mc_device_id, obj_type); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index fec75786f75b..29d6699d5a06 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1289,6 +1289,18 @@ static int do_hda_entry(const char *filename, void *symval, char *alias) } ADD_TO_DEVTABLE("hdaudio", hda_device_id, do_hda_entry); +/* Looks like: fsl-mc:vNdN */ +static int do_fsl_mc_entry(const char *filename, void *symval, + char *alias) +{ + DEF_FIELD(symval, fsl_mc_device_id, vendor); + DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type); + + sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type); + return 1; +} +ADD_TO_DEVTABLE("fslmc", fsl_mc_device_id, do_fsl_mc_entry); + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { -- cgit v1.2.3 From fca23e47dfdbcdacaae523f8b87d2240ce056ac1 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Tue, 21 Jun 2016 14:40:11 +0200 Subject: leds: Add no-op gpio_led_register_device when LED subsystem is disabled Some systems use 'gpio_led_register_device' to make an in-memory copy of their LED device table so the original can be removed as .init.rodata. When the LED subsystem is not enabled source in the led directory is not built and so this function may be undefined. Fix this here. Signed-off-by: Andrew F. Davis Signed-off-by: Jacek Anaszewski --- include/linux/leds.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux') diff --git a/include/linux/leds.h b/include/linux/leds.h index 0aa3701f2bf4..8a3b5d29602f 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -387,8 +387,16 @@ struct gpio_led_platform_data { unsigned long *delay_off); }; +#ifdef CONFIG_NEW_LEDS struct platform_device *gpio_led_register_device( int id, const struct gpio_led_platform_data *pdata); +#else +static inline struct platform_device *gpio_led_register_device( + int id, const struct gpio_led_platform_data *pdata) +{ + return 0; +} +#endif enum cpu_led_event { CPU_LED_IDLE_START, /* CPU enters idle */ -- cgit v1.2.3 From 1466cc5b23d18e7b6b8f1a45443d595393dbcae7 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Thu, 23 Jun 2016 17:02:37 +0300 Subject: net/mlx5: Rate limit tables support Configuring and managing HW rate limit tables. The HW holds a table of rate limits, each rate is associated with an index in that table. Later a Send Queue uses this index to set the rate limit. Multiple Send Queues can have the same rate limit, which is represented by a single entry in this table. Even though a rate can be shared, each queue is being rate limited independently of others. The SW shadow of this table holds the rate itself, the index in the HW table and the refcount (number of queues) working with this rate. The exported functions are mlx5_rl_add_rate and mlx5_rl_remove_rate. Number of different rates and their values are derived from HW capabilities. Signed-off-by: Yevgeny Petrilin Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 5 +- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 6 + drivers/net/ethernet/mellanox/mlx5/core/main.c | 10 ++ drivers/net/ethernet/mellanox/mlx5/core/rl.c | 209 +++++++++++++++++++++++ include/linux/mlx5/device.h | 4 + include/linux/mlx5/driver.h | 27 +++ 6 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/rl.c (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 9ea7b583096a..0c8a7dcea483 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -1,8 +1,9 @@ obj-$(CONFIG_MLX5_CORE) += mlx5_core.o mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ - health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ - mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o fs_counters.o + health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \ + mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \ + fs_counters.o rl.o mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o \ en_main.o en_fs.o en_ethtool.o en_tx.o en_rx.o \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 75c7ae6a5cc4..77fc1aa26114 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -151,6 +151,12 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev) return err; } + if (MLX5_CAP_GEN(dev, qos)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_QOS); + if (err) + return err; + } + return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index a19b59348dd6..08cae3485960 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1144,6 +1144,13 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv) dev_err(&pdev->dev, "Failed to init flow steering\n"); goto err_fs; } + + err = mlx5_init_rl_table(dev); + if (err) { + dev_err(&pdev->dev, "Failed to init rate limiting\n"); + goto err_rl; + } + #ifdef CONFIG_MLX5_CORE_EN err = mlx5_eswitch_init(dev); if (err) { @@ -1183,6 +1190,8 @@ err_sriov: mlx5_eswitch_cleanup(dev->priv.eswitch); #endif err_reg_dev: + mlx5_cleanup_rl_table(dev); +err_rl: mlx5_cleanup_fs(dev); err_fs: mlx5_cleanup_mkey_table(dev); @@ -1253,6 +1262,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv) mlx5_eswitch_cleanup(dev->priv.eswitch); #endif + mlx5_cleanup_rl_table(dev); mlx5_cleanup_fs(dev); mlx5_cleanup_mkey_table(dev); mlx5_cleanup_srq_table(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rl.c b/drivers/net/ethernet/mellanox/mlx5/core/rl.c new file mode 100644 index 000000000000..c07c28bd3d55 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/rl.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2013-2016, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include "mlx5_core.h" + +/* Finds an entry where we can register the given rate + * If the rate already exists, return the entry where it is registered, + * otherwise return the first available entry. + * If the table is full, return NULL + */ +static struct mlx5_rl_entry *find_rl_entry(struct mlx5_rl_table *table, + u32 rate) +{ + struct mlx5_rl_entry *ret_entry = NULL; + bool empty_found = false; + int i; + + for (i = 0; i < table->max_size; i++) { + if (table->rl_entry[i].rate == rate) + return &table->rl_entry[i]; + if (!empty_found && !table->rl_entry[i].rate) { + empty_found = true; + ret_entry = &table->rl_entry[i]; + } + } + + return ret_entry; +} + +static int mlx5_set_rate_limit_cmd(struct mlx5_core_dev *dev, + u32 rate, u16 index) +{ + u32 in[MLX5_ST_SZ_DW(set_rate_limit_in)]; + u32 out[MLX5_ST_SZ_DW(set_rate_limit_out)]; + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + + MLX5_SET(set_rate_limit_in, in, opcode, + MLX5_CMD_OP_SET_RATE_LIMIT); + MLX5_SET(set_rate_limit_in, in, rate_limit_index, index); + MLX5_SET(set_rate_limit_in, in, rate_limit, rate); + + return mlx5_cmd_exec_check_status(dev, in, sizeof(in), + out, sizeof(out)); +} + +bool mlx5_rl_is_in_range(struct mlx5_core_dev *dev, u32 rate) +{ + struct mlx5_rl_table *table = &dev->priv.rl_table; + + return (rate <= table->max_rate && rate >= table->min_rate); +} +EXPORT_SYMBOL(mlx5_rl_is_in_range); + +int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u32 rate, u16 *index) +{ + struct mlx5_rl_table *table = &dev->priv.rl_table; + struct mlx5_rl_entry *entry; + int err = 0; + + mutex_lock(&table->rl_lock); + + if (!rate || !mlx5_rl_is_in_range(dev, rate)) { + mlx5_core_err(dev, "Invalid rate: %u, should be %u to %u\n", + rate, table->min_rate, table->max_rate); + err = -EINVAL; + goto out; + } + + entry = find_rl_entry(table, rate); + if (!entry) { + mlx5_core_err(dev, "Max number of %u rates reached\n", + table->max_size); + err = -ENOSPC; + goto out; + } + if (entry->refcount) { + /* rate already configured */ + entry->refcount++; + } else { + /* new rate limit */ + err = mlx5_set_rate_limit_cmd(dev, rate, entry->index); + if (err) { + mlx5_core_err(dev, "Failed configuring rate: %u (%d)\n", + rate, err); + goto out; + } + entry->rate = rate; + entry->refcount = 1; + } + *index = entry->index; + +out: + mutex_unlock(&table->rl_lock); + return err; +} +EXPORT_SYMBOL(mlx5_rl_add_rate); + +void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, u32 rate) +{ + struct mlx5_rl_table *table = &dev->priv.rl_table; + struct mlx5_rl_entry *entry = NULL; + + /* 0 is a reserved value for unlimited rate */ + if (rate == 0) + return; + + mutex_lock(&table->rl_lock); + entry = find_rl_entry(table, rate); + if (!entry || !entry->refcount) { + mlx5_core_warn(dev, "Rate %u is not configured\n", rate); + goto out; + } + + entry->refcount--; + if (!entry->refcount) { + /* need to remove rate */ + mlx5_set_rate_limit_cmd(dev, 0, entry->index); + entry->rate = 0; + } + +out: + mutex_unlock(&table->rl_lock); +} +EXPORT_SYMBOL(mlx5_rl_remove_rate); + +int mlx5_init_rl_table(struct mlx5_core_dev *dev) +{ + struct mlx5_rl_table *table = &dev->priv.rl_table; + int i; + + mutex_init(&table->rl_lock); + if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, packet_pacing)) { + table->max_size = 0; + return 0; + } + + /* First entry is reserved for unlimited rate */ + table->max_size = MLX5_CAP_QOS(dev, packet_pacing_rate_table_size) - 1; + table->max_rate = MLX5_CAP_QOS(dev, packet_pacing_max_rate); + table->min_rate = MLX5_CAP_QOS(dev, packet_pacing_min_rate); + + table->rl_entry = kcalloc(table->max_size, sizeof(struct mlx5_rl_entry), + GFP_KERNEL); + if (!table->rl_entry) + return -ENOMEM; + + /* The index represents the index in HW rate limit table + * Index 0 is reserved for unlimited rate + */ + for (i = 0; i < table->max_size; i++) + table->rl_entry[i].index = i + 1; + + /* Index 0 is reserved */ + mlx5_core_info(dev, "Rate limit: %u rates are supported, range: %uMbps to %uMbps\n", + table->max_size, + table->min_rate >> 10, + table->max_rate >> 10); + + return 0; +} + +void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev) +{ + struct mlx5_rl_table *table = &dev->priv.rl_table; + int i; + + /* Clear all configured rates */ + for (i = 0; i < table->max_size; i++) + if (table->rl_entry[i].rate) + mlx5_set_rate_limit_cmd(dev, 0, + table->rl_entry[i].index); + + kfree(dev->priv.rl_table.rl_entry); +} diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 73a48479892d..e0a3ed758287 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -1330,6 +1330,7 @@ enum mlx5_cap_type { MLX5_CAP_ESWITCH, MLX5_CAP_RESERVED, MLX5_CAP_VECTOR_CALC, + MLX5_CAP_QOS, /* NUM OF CAP Types */ MLX5_CAP_NUM }; @@ -1414,6 +1415,9 @@ enum mlx5_cap_type { MLX5_GET(vector_calc_cap, \ mdev->hca_caps_cur[MLX5_CAP_VECTOR_CALC], cap) +#define MLX5_CAP_QOS(mdev, cap)\ + MLX5_GET(qos_cap, mdev->hca_caps_cur[MLX5_CAP_QOS], cap) + enum { MLX5_CMD_STAT_OK = 0x0, MLX5_CMD_STAT_INT_ERR = 0x1, diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 80776d0c52dc..46260fdc5305 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -481,6 +481,21 @@ struct mlx5_fc_stats { struct mlx5_eswitch; +struct mlx5_rl_entry { + u32 rate; + u16 index; + u16 refcount; +}; + +struct mlx5_rl_table { + /* protect rate limit table */ + struct mutex rl_lock; + u16 max_size; + u32 max_rate; + u32 min_rate; + struct mlx5_rl_entry *rl_entry; +}; + struct mlx5_priv { char name[MLX5_MAX_NAME_LEN]; struct mlx5_eq_table eq_table; @@ -544,6 +559,7 @@ struct mlx5_priv { struct mlx5_flow_root_namespace *esw_ingress_root_ns; struct mlx5_fc_stats fc_stats; + struct mlx5_rl_table rl_table; }; enum mlx5_device_state { @@ -861,6 +877,12 @@ int mlx5_query_odp_caps(struct mlx5_core_dev *dev, int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev, u8 port_num, void *out, size_t sz); +int mlx5_init_rl_table(struct mlx5_core_dev *dev); +void mlx5_cleanup_rl_table(struct mlx5_core_dev *dev); +int mlx5_rl_add_rate(struct mlx5_core_dev *dev, u32 rate, u16 *index); +void mlx5_rl_remove_rate(struct mlx5_core_dev *dev, u32 rate); +bool mlx5_rl_is_in_range(struct mlx5_core_dev *dev, u32 rate); + static inline int fw_initializing(struct mlx5_core_dev *dev) { return ioread32be(&dev->iseg->initializing) >> 31; @@ -938,6 +960,11 @@ static inline int mlx5_get_gid_table_len(u16 param) return 8 * (1 << param); } +static inline bool mlx5_rl_is_supported(struct mlx5_core_dev *dev) +{ + return !!(dev->priv.rl_table.max_size); +} + enum { MLX5_TRIGGERED_CMD_COMP = (u64)1 << 32, }; -- cgit v1.2.3 From 667daedaecd15b89d0ded7af49519f28d6ea2cf4 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Thu, 23 Jun 2016 17:02:42 +0300 Subject: net/mlx5e: Toggle link only after modifying port parameters Add a dedicated function to toggle port link. It should be called only after setting a port register. Toggle will set port link to down and bring it back up in case that it's admin status was up. Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c | 9 +-------- drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 7 +------ drivers/net/ethernet/mellanox/mlx5/core/port.c | 12 ++++++++++++ include/linux/mlx5/port.h | 1 + 4 files changed, 15 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c index b2db180ae2a5..e6883132b555 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c @@ -191,7 +191,6 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, { struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5_core_dev *mdev = priv->mdev; - enum mlx5_port_status ps; u8 curr_pfc_en; int ret; @@ -200,14 +199,8 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, if (pfc->pfc_en == curr_pfc_en) return 0; - mlx5_query_port_admin_status(mdev, &ps); - if (ps == MLX5_PORT_UP) - mlx5_set_port_admin_status(mdev, MLX5_PORT_DOWN); - ret = mlx5_set_port_pfc(mdev, pfc->pfc_en, pfc->pfc_en); - - if (ps == MLX5_PORT_UP) - mlx5_set_port_admin_status(mdev, MLX5_PORT_UP); + mlx5_toggle_port_link(mdev); return ret; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index c4be3941957e..d0d3dcfb4de9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -795,7 +795,6 @@ static int mlx5e_set_settings(struct net_device *netdev, u32 link_modes; u32 speed; u32 eth_proto_cap, eth_proto_admin; - enum mlx5_port_status ps; int err; speed = ethtool_cmd_speed(cmd); @@ -829,12 +828,8 @@ static int mlx5e_set_settings(struct net_device *netdev, if (link_modes == eth_proto_admin) goto out; - mlx5_query_port_admin_status(mdev, &ps); - if (ps == MLX5_PORT_UP) - mlx5_set_port_admin_status(mdev, MLX5_PORT_DOWN); mlx5_set_port_proto(mdev, link_modes, MLX5_PTYS_EN); - if (ps == MLX5_PORT_UP) - mlx5_set_port_admin_status(mdev, MLX5_PORT_UP); + mlx5_toggle_port_link(mdev); out: return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 3e35611b19c3..1562e7310f5b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -222,6 +222,18 @@ int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, } EXPORT_SYMBOL_GPL(mlx5_set_port_proto); +/* This function should be used after setting a port register only */ +void mlx5_toggle_port_link(struct mlx5_core_dev *dev) +{ + enum mlx5_port_status ps; + + mlx5_query_port_admin_status(dev, &ps); + mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN); + if (ps == MLX5_PORT_UP) + mlx5_set_port_admin_status(dev, MLX5_PORT_UP); +} +EXPORT_SYMBOL_GPL(mlx5_toggle_port_link); + int mlx5_set_port_admin_status(struct mlx5_core_dev *dev, enum mlx5_port_status status) { diff --git a/include/linux/mlx5/port.h b/include/linux/mlx5/port.h index 9851862c0ec5..4adfac15f0e9 100644 --- a/include/linux/mlx5/port.h +++ b/include/linux/mlx5/port.h @@ -67,6 +67,7 @@ int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev, u8 local_port); int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, int proto_mask); +void mlx5_toggle_port_link(struct mlx5_core_dev *dev); int mlx5_set_port_admin_status(struct mlx5_core_dev *dev, enum mlx5_port_status status); int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, -- cgit v1.2.3 From 52244d960755936fa9c8ce54d583d0ed46f24fb6 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Thu, 23 Jun 2016 17:02:46 +0300 Subject: net/mlx5e: Report correct auto negotiation and allow toggling Previous to this patch auto negotiation was reported off although it was on by default in hardware. This patch reports the correct information to ethtool and allows the user to toggle it on/off. Added another parameter to set port proto function in order to pass the auto negotiation field to the hardware. Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 42 ++++++++++++++++++---- drivers/net/ethernet/mellanox/mlx5/core/port.c | 36 ++++++++++++++++--- include/linux/mlx5/port.h | 15 ++++++-- 3 files changed, 80 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 4c560e003d56..39a4d961a58e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -702,6 +702,8 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev, u32 eth_proto_admin; u32 eth_proto_lp; u32 eth_proto_oper; + u8 an_disable_admin; + u8 an_status; int err; err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); @@ -712,10 +714,12 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev, goto err_query_ptys; } - eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); - eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); - eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); - eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); + eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); + eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); + eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); + eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); + an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); + an_status = MLX5_GET(ptys_reg, out, an_status); ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); @@ -729,6 +733,18 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev, link_ksettings->base.port = get_connector_port(eth_proto_oper); get_lp_advertising(eth_proto_lp, link_ksettings); + if (an_status == MLX5_AN_COMPLETE) + ethtool_link_ksettings_add_link_mode(link_ksettings, + lp_advertising, Autoneg); + + link_ksettings->base.autoneg = an_disable_admin ? AUTONEG_DISABLE : + AUTONEG_ENABLE; + ethtool_link_ksettings_add_link_mode(link_ksettings, supported, + Autoneg); + if (!an_disable_admin) + ethtool_link_ksettings_add_link_mode(link_ksettings, + advertising, Autoneg); + err_query_ptys: return err; } @@ -764,9 +780,14 @@ static int mlx5e_set_link_ksettings(struct net_device *netdev, { struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = priv->mdev; + u32 eth_proto_cap, eth_proto_admin; + bool an_changes = false; + u8 an_disable_admin; + u8 an_disable_cap; + bool an_disable; u32 link_modes; + u8 an_status; u32 speed; - u32 eth_proto_cap, eth_proto_admin; int err; speed = link_ksettings->base.speed; @@ -797,10 +818,17 @@ static int mlx5e_set_link_ksettings(struct net_device *netdev, goto out; } - if (link_modes == eth_proto_admin) + mlx5_query_port_autoneg(mdev, MLX5_PTYS_EN, &an_status, + &an_disable_cap, &an_disable_admin); + + an_disable = link_ksettings->base.autoneg == AUTONEG_DISABLE; + an_changes = ((!an_disable && an_disable_admin) || + (an_disable && !an_disable_admin)); + + if (!an_changes && link_modes == eth_proto_admin) goto out; - mlx5_set_port_proto(mdev, link_modes, MLX5_PTYS_EN); + mlx5_set_port_ptys(mdev, an_disable, link_modes, MLX5_PTYS_EN); mlx5_toggle_port_link(mdev); out: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 1562e7310f5b..752c08127138 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -202,15 +202,24 @@ int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev, } EXPORT_SYMBOL_GPL(mlx5_query_port_proto_oper); -int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, - int proto_mask) +int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable, + u32 proto_admin, int proto_mask) { - u32 in[MLX5_ST_SZ_DW(ptys_reg)]; u32 out[MLX5_ST_SZ_DW(ptys_reg)]; + u32 in[MLX5_ST_SZ_DW(ptys_reg)]; + u8 an_disable_admin; + u8 an_disable_cap; + u8 an_status; + + mlx5_query_port_autoneg(dev, proto_mask, &an_status, + &an_disable_cap, &an_disable_admin); + if (!an_disable_cap && an_disable) + return -EPERM; memset(in, 0, sizeof(in)); MLX5_SET(ptys_reg, in, local_port, 1); + MLX5_SET(ptys_reg, in, an_disable_admin, an_disable); MLX5_SET(ptys_reg, in, proto_mask, proto_mask); if (proto_mask == MLX5_PTYS_EN) MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin); @@ -220,7 +229,7 @@ int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, return mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out), MLX5_REG_PTYS, 0, 1); } -EXPORT_SYMBOL_GPL(mlx5_set_port_proto); +EXPORT_SYMBOL_GPL(mlx5_set_port_ptys); /* This function should be used after setting a port register only */ void mlx5_toggle_port_link(struct mlx5_core_dev *dev) @@ -530,6 +539,25 @@ int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx) } EXPORT_SYMBOL_GPL(mlx5_query_port_pfc); +void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask, + u8 *an_status, + u8 *an_disable_cap, u8 *an_disable_admin) +{ + u32 out[MLX5_ST_SZ_DW(ptys_reg)]; + + *an_status = 0; + *an_disable_cap = 0; + *an_disable_admin = 0; + + if (mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1)) + return; + + *an_status = MLX5_GET(ptys_reg, out, an_status); + *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap); + *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); +} +EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg); + int mlx5_max_tc(struct mlx5_core_dev *mdev) { u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8; diff --git a/include/linux/mlx5/port.h b/include/linux/mlx5/port.h index 4adfac15f0e9..e3012cc64b8a 100644 --- a/include/linux/mlx5/port.h +++ b/include/linux/mlx5/port.h @@ -47,6 +47,14 @@ enum mlx5_module_id { MLX5_MODULE_ID_QSFP28 = 0x11, }; +enum mlx5_an_status { + MLX5_AN_UNAVAILABLE = 0, + MLX5_AN_COMPLETE = 1, + MLX5_AN_FAILED = 2, + MLX5_AN_LINK_UP = 3, + MLX5_AN_LINK_DOWN = 4, +}; + #define MLX5_EEPROM_MAX_BYTES 32 #define MLX5_EEPROM_IDENTIFIER_BYTE_MASK 0x000000ff #define MLX5_I2C_ADDR_LOW 0x50 @@ -65,14 +73,17 @@ int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev, int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev, u8 *proto_oper, int proto_mask, u8 local_port); -int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin, - int proto_mask); +int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable, + u32 proto_admin, int proto_mask); void mlx5_toggle_port_link(struct mlx5_core_dev *dev); int mlx5_set_port_admin_status(struct mlx5_core_dev *dev, enum mlx5_port_status status); int mlx5_query_port_admin_status(struct mlx5_core_dev *dev, enum mlx5_port_status *status); int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration); +void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask, + u8 *an_status, + u8 *an_disable_cap, u8 *an_disable_admin); int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port); void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, u8 port); -- cgit v1.2.3 From d68fa32dccc136bb4e092d53606bb6f5515fa972 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 26 Jun 2016 23:20:37 +0200 Subject: rtc: ds17287: remove unused header ds17287rtc.h is unused since 15beb694c661 ("mips: ip32: add platform data hooks to use DS1685 driver"), remove it. Signed-off-by: Alexandre Belloni --- include/linux/ds17287rtc.h | 66 ---------------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 include/linux/ds17287rtc.h (limited to 'include/linux') diff --git a/include/linux/ds17287rtc.h b/include/linux/ds17287rtc.h deleted file mode 100644 index d85d3f497b96..000000000000 --- a/include/linux/ds17287rtc.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * ds17287rtc.h - register definitions for the ds1728[57] RTC / CMOS RAM - * - * 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. - * - * (C) 2003 Guido Guenther - */ -#ifndef __LINUX_DS17287RTC_H -#define __LINUX_DS17287RTC_H - -#include /* get the user-level API */ -#include - -/* Register A */ -#define DS_REGA_DV2 0x40 /* countdown chain */ -#define DS_REGA_DV1 0x20 /* oscillator enable */ -#define DS_REGA_DV0 0x10 /* bank select */ - -/* bank 1 registers */ -#define DS_B1_MODEL 0x40 /* model number byte */ -#define DS_B1_SN1 0x41 /* serial number byte 1 */ -#define DS_B1_SN2 0x42 /* serial number byte 2 */ -#define DS_B1_SN3 0x43 /* serial number byte 3 */ -#define DS_B1_SN4 0x44 /* serial number byte 4 */ -#define DS_B1_SN5 0x45 /* serial number byte 5 */ -#define DS_B1_SN6 0x46 /* serial number byte 6 */ -#define DS_B1_CRC 0x47 /* CRC byte */ -#define DS_B1_CENTURY 0x48 /* Century byte */ -#define DS_B1_DALARM 0x49 /* date alarm */ -#define DS_B1_XCTRL4A 0x4a /* extendec control register 4a */ -#define DS_B1_XCTRL4B 0x4b /* extendec control register 4b */ -#define DS_B1_RTCADDR2 0x4e /* rtc address 2 */ -#define DS_B1_RTCADDR3 0x4f /* rtc address 3 */ -#define DS_B1_RAMLSB 0x50 /* extended ram LSB */ -#define DS_B1_RAMMSB 0x51 /* extended ram MSB */ -#define DS_B1_RAMDPORT 0x53 /* extended ram data port */ - -/* register details */ -/* extended control register 4a */ -#define DS_XCTRL4A_VRT2 0x80 /* valid ram and time */ -#define DS_XCTRL4A_INCR 0x40 /* increment progress status */ -#define DS_XCTRL4A_BME 0x20 /* burst mode enable */ -#define DS_XCTRL4A_PAB 0x08 /* power active bar ctrl */ -#define DS_XCTRL4A_RF 0x04 /* ram clear flag */ -#define DS_XCTRL4A_WF 0x02 /* wake up alarm flag */ -#define DS_XCTRL4A_KF 0x01 /* kickstart flag */ - -/* interrupt causes */ -#define DS_XCTRL4A_IFS (DS_XCTRL4A_RF|DS_XCTRL4A_WF|DS_XCTRL4A_KF) - -/* extended control register 4b */ -#define DS_XCTRL4B_ABE 0x80 /* auxiliary battery enable */ -#define DS_XCTRL4B_E32K 0x40 /* enable 32.768 kHz Output */ -#define DS_XCTRL4B_CS 0x20 /* crystal select */ -#define DS_XCTRL4B_RCE 0x10 /* ram clear enable */ -#define DS_XCTRL4B_PRS 0x08 /* PAB resec select */ -#define DS_XCTRL4B_RIE 0x04 /* ram clear interrupt enable */ -#define DS_XCTRL4B_WFE 0x02 /* wake up alarm interrupt enable */ -#define DS_XCTRL4B_KFE 0x01 /* kickstart interrupt enable */ - -/* interrupt enable bits */ -#define DS_XCTRL4B_IFES (DS_XCTRL4B_RIE|DS_XCTRL4B_WFE|DS_XCTRL4B_KFE) - -#endif /* __LINUX_DS17287RTC_H */ -- cgit v1.2.3 From 10c2a2e71301deb4d7760c140606bc61841aacd3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 26 Jun 2016 23:38:44 +0200 Subject: rtc: ds2404: move rtc-ds2404.h to platform_data rtc-ds2404.h belongs to include/linux/platform_data/ Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds2404.c | 2 +- include/linux/platform_data/rtc-ds2404.h | 20 ++++++++++++++++++++ include/linux/rtc-ds2404.h | 20 -------------------- 3 files changed, 21 insertions(+), 21 deletions(-) create mode 100644 include/linux/platform_data/rtc-ds2404.h delete mode 100644 include/linux/rtc-ds2404.h (limited to 'include/linux') diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 16310fe79d76..9a1582ed7070 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/platform_data/rtc-ds2404.h b/include/linux/platform_data/rtc-ds2404.h new file mode 100644 index 000000000000..22c53825528f --- /dev/null +++ b/include/linux/platform_data/rtc-ds2404.h @@ -0,0 +1,20 @@ +/* + * ds2404.h - platform data structure for the DS2404 RTC. + * + * 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) 2012 Sven Schnelle + */ + +#ifndef __LINUX_DS2404_H +#define __LINUX_DS2404_H + +struct ds2404_platform_data { + + unsigned int gpio_rst; + unsigned int gpio_clk; + unsigned int gpio_dq; +}; +#endif diff --git a/include/linux/rtc-ds2404.h b/include/linux/rtc-ds2404.h deleted file mode 100644 index 22c53825528f..000000000000 --- a/include/linux/rtc-ds2404.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * ds2404.h - platform data structure for the DS2404 RTC. - * - * 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) 2012 Sven Schnelle - */ - -#ifndef __LINUX_DS2404_H -#define __LINUX_DS2404_H - -struct ds2404_platform_data { - - unsigned int gpio_rst; - unsigned int gpio_clk; - unsigned int gpio_dq; -}; -#endif -- cgit v1.2.3 From 7dc603c9028ea5d4354e0e317e8481df99b06d7e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 16 Jun 2016 13:29:28 +0200 Subject: sched/fair: Fix PELT integrity for new tasks Vincent and Yuyang found another few scenarios in which entity tracking goes wobbly. The scenarios are basically due to the fact that new tasks are not immediately attached and thereby differ from the normal situation -- a task is always attached to a cfs_rq load average (such that it includes its blocked contribution) and are explicitly detached/attached on migration to another cfs_rq. Scenario 1: switch to fair class p->sched_class = fair_class; if (queued) enqueue_task(p); ... enqueue_entity() enqueue_entity_load_avg() migrated = !sa->last_update_time (true) if (migrated) attach_entity_load_avg() check_class_changed() switched_from() (!fair) switched_to() (fair) switched_to_fair() attach_entity_load_avg() If @p is a new task that hasn't been fair before, it will have !last_update_time and, per the above, end up in attach_entity_load_avg() _twice_. Scenario 2: change between cgroups sched_move_group(p) if (queued) dequeue_task() task_move_group_fair() detach_task_cfs_rq() detach_entity_load_avg() set_task_rq() attach_task_cfs_rq() attach_entity_load_avg() if (queued) enqueue_task(); ... enqueue_entity() enqueue_entity_load_avg() migrated = !sa->last_update_time (true) if (migrated) attach_entity_load_avg() Similar as with scenario 1, if @p is a new task, it will have !load_update_time and we'll end up in attach_entity_load_avg() _twice_. Furthermore, notice how we do a detach_entity_load_avg() on something that wasn't attached to begin with. As stated above; the problem is that the new task isn't yet attached to the load tracking and thereby violates the invariant assumption. This patch remedies this by ensuring a new task is indeed properly attached to the load tracking on creation, through post_init_entity_util_avg(). Of course, this isn't entirely as straightforward as one might think, since the task is hashed before we call wake_up_new_task() and thus can be poked at. We avoid this by adding TASK_NEW and teaching cpu_cgroup_can_attach() to refuse such tasks. Reported-by: Yuyang Du Reported-by: Vincent Guittot Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- include/linux/sched.h | 5 +++-- kernel/sched/core.c | 28 +++++++++++++++++++++++----- kernel/sched/fair.c | 45 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 63 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index b45acfd18f4e..d99218a1e043 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -219,9 +219,10 @@ extern void proc_sched_set_task(struct task_struct *p); #define TASK_WAKING 256 #define TASK_PARKED 512 #define TASK_NOLOAD 1024 -#define TASK_STATE_MAX 2048 +#define TASK_NEW 2048 +#define TASK_STATE_MAX 4096 -#define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWPN" +#define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWPNn" extern char ___assert_task_state[1 - 2*!!( sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)]; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 3d856c46f6d8..14afa518948c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2342,11 +2342,11 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) __sched_fork(clone_flags, p); /* - * We mark the process as running here. This guarantees that + * We mark the process as NEW here. This guarantees that * nobody will actually run it, and a signal or other external * event cannot wake it up and insert it on the runqueue either. */ - p->state = TASK_RUNNING; + p->state = TASK_NEW; /* * Make sure we do not leak PI boosting priority to the child. @@ -2383,6 +2383,8 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) p->sched_class = &fair_sched_class; } + init_entity_runnable_average(&p->se); + /* * The child is not yet in the pid-hash so no cgroup attach races, * and the cgroup is pinned to this child due to cgroup_fork() @@ -2529,9 +2531,8 @@ void wake_up_new_task(struct task_struct *p) struct rq_flags rf; struct rq *rq; - /* Initialize new task's runnable average */ - init_entity_runnable_average(&p->se); raw_spin_lock_irqsave(&p->pi_lock, rf.flags); + p->state = TASK_RUNNING; #ifdef CONFIG_SMP /* * Fork balancing, do it here and not earlier because: @@ -8237,6 +8238,7 @@ static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) { struct task_struct *task; struct cgroup_subsys_state *css; + int ret = 0; cgroup_taskset_for_each(task, css, tset) { #ifdef CONFIG_RT_GROUP_SCHED @@ -8247,8 +8249,24 @@ static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) if (task->sched_class != &fair_sched_class) return -EINVAL; #endif + /* + * Serialize against wake_up_new_task() such that if its + * running, we're sure to observe its full state. + */ + raw_spin_lock_irq(&task->pi_lock); + /* + * Avoid calling sched_move_task() before wake_up_new_task() + * has happened. This would lead to problems with PELT, due to + * move wanting to detach+attach while we're not attached yet. + */ + if (task->state == TASK_NEW) + ret = -EINVAL; + raw_spin_unlock_irq(&task->pi_lock); + + if (ret) + break; } - return 0; + return ret; } static void cpu_cgroup_attach(struct cgroup_taskset *tset) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 64f26bc436eb..0c21a12c0205 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -690,6 +690,10 @@ void init_entity_runnable_average(struct sched_entity *se) /* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */ } +static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq); +static int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq); +static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se); + /* * With new tasks being created, their initial util_avgs are extrapolated * based on the cfs_rq's current util_avg: @@ -720,6 +724,7 @@ void post_init_entity_util_avg(struct sched_entity *se) struct cfs_rq *cfs_rq = cfs_rq_of(se); struct sched_avg *sa = &se->avg; long cap = (long)(SCHED_CAPACITY_SCALE - cfs_rq->avg.util_avg) / 2; + u64 now = cfs_rq_clock_task(cfs_rq); if (cap > 0) { if (cfs_rq->avg.util_avg != 0) { @@ -733,16 +738,37 @@ void post_init_entity_util_avg(struct sched_entity *se) } sa->util_sum = sa->util_avg * LOAD_AVG_MAX; } + + if (entity_is_task(se)) { + struct task_struct *p = task_of(se); + if (p->sched_class != &fair_sched_class) { + /* + * For !fair tasks do: + * + update_cfs_rq_load_avg(now, cfs_rq, false); + attach_entity_load_avg(cfs_rq, se); + switched_from_fair(rq, p); + * + * such that the next switched_to_fair() has the + * expected state. + */ + se->avg.last_update_time = now; + return; + } + } + + update_cfs_rq_load_avg(now, cfs_rq, false); + attach_entity_load_avg(cfs_rq, se); } -#else +#else /* !CONFIG_SMP */ void init_entity_runnable_average(struct sched_entity *se) { } void post_init_entity_util_avg(struct sched_entity *se) { } -#endif +#endif /* CONFIG_SMP */ /* * Update the current task's runtime statistics. @@ -2840,8 +2866,6 @@ void set_task_rq_fair(struct sched_entity *se, static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) {} #endif /* CONFIG_FAIR_GROUP_SCHED */ -static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq); - static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq) { struct rq *rq = rq_of(cfs_rq); @@ -2951,6 +2975,8 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s /* * If we got migrated (either between CPUs or between cgroups) we'll * have aged the average right before clearing @last_update_time. + * + * Or we're fresh through post_init_entity_util_avg(). */ if (se->avg.last_update_time) { __update_load_avg(cfs_rq->avg.last_update_time, cpu_of(rq_of(cfs_rq)), @@ -3056,11 +3082,14 @@ void remove_entity_load_avg(struct sched_entity *se) u64 last_update_time; /* - * Newly created task or never used group entity should not be removed - * from its (source) cfs_rq + * tasks cannot exit without having gone through wake_up_new_task() -> + * post_init_entity_util_avg() which will have added things to the + * cfs_rq, so we can remove unconditionally. + * + * Similarly for groups, they will have passed through + * post_init_entity_util_avg() before unregister_sched_fair_group() + * calls this. */ - if (se->avg.last_update_time == 0) - return; last_update_time = cfs_rq_last_update_time(cfs_rq); -- cgit v1.2.3 From 54fd11fee59e7d05287bc4eebccc8ec9742f2745 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Sat, 25 Jun 2016 08:20:25 +0100 Subject: efi: Document #define FOO_PROTOCOL_GUID layout Add a comment documenting why EFI GUIDs are laid out like they are. Ideally I'd like to change all the ", " to "," too, but right now the format is such that checkpatch won't complain with new ones, and staring at checkpatch didn't get me anywhere towards making that work. Signed-off-by: Peter Jones Signed-off-by: Matt Fleming Cc: Ard Biesheuvel Cc: Joe Perches Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-3-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- include/linux/efi.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/efi.h b/include/linux/efi.h index f196dd0b0f2f..03009695760d 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -536,7 +536,22 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, void efi_native_runtime_setup(void); /* - * EFI Configuration Table and GUID definitions + * EFI Configuration Table and GUID definitions + * + * These should be formatted roughly like the ones in the UEFI SPEC has + * them. It makes them easier to grep for, and they look the same when + * you're staring at them. Here's the guide: + * + * GUID: 12345678-1234-1234-1234-123456789012 + * Spec: + * #define EFI_SOME_PROTOCOL_GUID \ + * {0x12345678,0x1234,0x1234,\ + * {0x12,0x34,0x12,0x34,0x56,0x78,0x90,0x12}} + * Here: + * #define SOME_PROTOCOL_GUID \ + * EFI_GUID(0x12345678, 0x1234, 0x1234, \ + * 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12) + * ^ tab ^tab ^ space */ #define NULL_GUID \ EFI_GUID(0x00000000, 0x0000, 0x0000, \ -- cgit v1.2.3 From 80e75596079f0a41f905836ad0ccaac68ba33612 Mon Sep 17 00:00:00 2001 From: Alex Thorlton Date: Sat, 25 Jun 2016 08:20:27 +0100 Subject: efi: Convert efi_call_virt() to efi_call_virt_pointer() This commit makes a few slight modifications to the efi_call_virt() macro to get it to work with function pointers that are stored in locations other than efi.systab->runtime, and renames the macro to efi_call_virt_pointer(). The majority of the changes here are to pull these macros up into header files so that they can be accessed from outside of drivers/firmware/efi/runtime-wrappers.c. The most significant change not directly related to the code move is to add an extra "p" argument into the appropriate efi_call macros, and use that new argument in place of the, formerly hard-coded, efi.systab->runtime pointer. The last piece of the puzzle was to add an efi_call_virt() macro back into drivers/firmware/efi/runtime-wrappers.c to wrap around the new efi_call_virt_pointer() macro - this was mainly to keep the code from looking too cluttered by adding a bunch of extra references to efi.systab->runtime everywhere. Note that I also broke up the code in the efi_call_virt_pointer() macro a bit in the process of moving it. Signed-off-by: Alex Thorlton Signed-off-by: Matt Fleming Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: Dimitri Sivanich Cc: Linus Torvalds Cc: Mark Rutland Cc: Peter Zijlstra Cc: Roy Franz Cc: Russ Anderson Cc: Russell King Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arm-kernel@lists.infradead.org Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-5-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm/include/asm/efi.h | 4 +-- arch/arm64/include/asm/efi.h | 4 +-- arch/x86/include/asm/efi.h | 9 +++--- drivers/firmware/efi/runtime-wrappers.c | 53 +++++++-------------------------- include/linux/efi.h | 51 +++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 52 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index a708fa1f0905..766bf9b78160 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -28,10 +28,10 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); #define arch_efi_call_virt_setup() efi_virtmap_load() #define arch_efi_call_virt_teardown() efi_virtmap_unload() -#define arch_efi_call_virt(f, args...) \ +#define arch_efi_call_virt(p, f, args...) \ ({ \ efi_##f##_t *__f; \ - __f = efi.systab->runtime->f; \ + __f = p->f; \ __f(args); \ }) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 622db3c6474e..bd887663689b 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -23,10 +23,10 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); efi_virtmap_load(); \ }) -#define arch_efi_call_virt(f, args...) \ +#define arch_efi_call_virt(p, f, args...) \ ({ \ efi_##f##_t *__f; \ - __f = efi.systab->runtime->f; \ + __f = p->f; \ __f(args); \ }) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 78d1e7467eae..55b4596ef688 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -41,10 +41,9 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...); /* * Wrap all the virtual calls in a way that forces the parameters on the stack. */ -#define arch_efi_call_virt(f, args...) \ +#define arch_efi_call_virt(p, f, args...) \ ({ \ - ((efi_##f##_t __attribute__((regparm(0)))*) \ - efi.systab->runtime->f)(args); \ + ((efi_##f##_t __attribute__((regparm(0)))*) p->f)(args); \ }) #define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size) @@ -81,8 +80,8 @@ struct efi_scratch { } \ }) -#define arch_efi_call_virt(f, args...) \ - efi_call((void *)efi.systab->runtime->f, args) \ +#define arch_efi_call_virt(p, f, args...) \ + efi_call((void *)p->f, args) \ #define arch_efi_call_virt_teardown() \ ({ \ diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 23bef6bb73ee..41958774cde3 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -22,7 +22,16 @@ #include #include -static void efi_call_virt_check_flags(unsigned long flags, const char *call) +/* + * Wrap around the new efi_call_virt_generic() macros so that the + * code doesn't get too cluttered: + */ +#define efi_call_virt(f, args...) \ + efi_call_virt_pointer(efi.systab->runtime, f, args) +#define __efi_call_virt(f, args...) \ + __efi_call_virt_pointer(efi.systab->runtime, f, args) + +void efi_call_virt_check_flags(unsigned long flags, const char *call) { unsigned long cur_flags, mismatch; @@ -38,48 +47,6 @@ static void efi_call_virt_check_flags(unsigned long flags, const char *call) local_irq_restore(flags); } -/* - * Arch code can implement the following three template macros, avoiding - * reptition for the void/non-void return cases of {__,}efi_call_virt: - * - * * arch_efi_call_virt_setup - * - * Sets up the environment for the call (e.g. switching page tables, - * allowing kernel-mode use of floating point, if required). - * - * * arch_efi_call_virt - * - * Performs the call. The last expression in the macro must be the call - * itself, allowing the logic to be shared by the void and non-void - * cases. - * - * * arch_efi_call_virt_teardown - * - * Restores the usual kernel environment once the call has returned. - */ - -#define efi_call_virt(f, args...) \ -({ \ - efi_status_t __s; \ - unsigned long flags; \ - arch_efi_call_virt_setup(); \ - local_save_flags(flags); \ - __s = arch_efi_call_virt(f, args); \ - efi_call_virt_check_flags(flags, __stringify(f)); \ - arch_efi_call_virt_teardown(); \ - __s; \ -}) - -#define __efi_call_virt(f, args...) \ -({ \ - unsigned long flags; \ - arch_efi_call_virt_setup(); \ - local_save_flags(flags); \ - arch_efi_call_virt(f, args); \ - efi_call_virt_check_flags(flags, __stringify(f)); \ - arch_efi_call_virt_teardown(); \ -}) - /* * According to section 7.1 of the UEFI spec, Runtime Services are not fully * reentrant, and there are particular combinations of calls that need to be diff --git a/include/linux/efi.h b/include/linux/efi.h index 03009695760d..75d148dc9c3f 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1480,4 +1480,55 @@ efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg, unsigned long size); bool efi_runtime_disabled(void); +extern void efi_call_virt_check_flags(unsigned long flags, const char *call); + +/* + * Arch code can implement the following three template macros, avoiding + * reptition for the void/non-void return cases of {__,}efi_call_virt(): + * + * * arch_efi_call_virt_setup() + * + * Sets up the environment for the call (e.g. switching page tables, + * allowing kernel-mode use of floating point, if required). + * + * * arch_efi_call_virt() + * + * Performs the call. The last expression in the macro must be the call + * itself, allowing the logic to be shared by the void and non-void + * cases. + * + * * arch_efi_call_virt_teardown() + * + * Restores the usual kernel environment once the call has returned. + */ + +#define efi_call_virt_pointer(p, f, args...) \ +({ \ + efi_status_t __s; \ + unsigned long __flags; \ + \ + arch_efi_call_virt_setup(); \ + \ + local_save_flags(__flags); \ + __s = arch_efi_call_virt(p, f, args); \ + efi_call_virt_check_flags(__flags, __stringify(f)); \ + \ + arch_efi_call_virt_teardown(); \ + \ + __s; \ +}) + +#define __efi_call_virt_pointer(p, f, args...) \ +({ \ + unsigned long __flags; \ + \ + arch_efi_call_virt_setup(); \ + \ + local_save_flags(__flags); \ + arch_efi_call_virt(p, f, args); \ + efi_call_virt_check_flags(__flags, __stringify(f)); \ + \ + arch_efi_call_virt_teardown(); \ +}) + #endif /* _LINUX_EFI_H */ -- cgit v1.2.3 From b684e9bc750b6349ff59f1b1ab4397cae255765f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 25 Jun 2016 08:20:30 +0100 Subject: x86/efi: Remove the unused efi_get_time() function Nothing calls the efi_get_time() function on x86, but it does suffer from the 32-bit time_t overflow in 2038. This removes the function, we can always put it back in case we need it later. Signed-off-by: Arnd Bergmann Signed-off-by: Matt Fleming Acked-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/1466839230-12781-8-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/x86/platform/efi/efi.c | 15 --------------- include/linux/efi.h | 1 - 2 files changed, 16 deletions(-) (limited to 'include/linux') diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index f93545e7dc54..d898b334ff46 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -98,21 +98,6 @@ static efi_status_t __init phys_efi_set_virtual_address_map( return status; } -void efi_get_time(struct timespec *now) -{ - efi_status_t status; - efi_time_t eft; - efi_time_cap_t cap; - - status = efi.get_time(&eft, &cap); - if (status != EFI_SUCCESS) - pr_err("Oops: efitime: can't read time!\n"); - - now->tv_sec = mktime(eft.year, eft.month, eft.day, eft.hour, - eft.minute, eft.second); - now->tv_nsec = 0; -} - void __init efi_find_mirror(void) { efi_memory_desc_t *md; diff --git a/include/linux/efi.h b/include/linux/efi.h index 75d148dc9c3f..0174f28ce9b3 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -990,7 +990,6 @@ extern u64 efi_mem_desc_end(efi_memory_desc_t *md); extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md); extern void efi_initialize_iomem_resources(struct resource *code_resource, struct resource *data_resource, struct resource *bss_resource); -extern void efi_get_time(struct timespec *now); extern void efi_reserve_boot_services(void); extern int efi_get_fdt_params(struct efi_fdt_params *params); extern struct kobject *efi_kobj; -- cgit v1.2.3 From 20f7b53dfc24e0caa984087691af82e442229680 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 19:17:06 +0900 Subject: extcon: Move struct extcon_cable from header file to core This patch moves the struct extcon_cable because that should be only handled by extcon core. There are no reason to publish the internal structure. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 20 ++++++++++++++++++++ include/linux/extcon.h | 20 -------------------- 2 files changed, 20 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index b6408f015637..b5fdb5d9dbad 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -77,6 +77,26 @@ static const char *extcon_name[] = { NULL, }; +/** + * struct extcon_cable - An internal data for each cable of extcon device. + * @edev: The extcon device + * @cable_index: Index of this cable in the edev + * @attr_g: Attribute group for the cable + * @attr_name: "name" sysfs entry + * @attr_state: "state" sysfs entry + * @attrs: Array pointing to attr_name and attr_state for attr_g + */ +struct extcon_cable { + struct extcon_dev *edev; + int cable_index; + + struct attribute_group attr_g; + struct device_attribute attr_name; + struct device_attribute attr_state; + + struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ +}; + static struct class *extcon_class; #if defined(CONFIG_ANDROID) static struct class_compat *switch_class; diff --git a/include/linux/extcon.h b/include/linux/extcon.h index cec5c543afc6..1b2c8b6809cc 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -126,26 +126,6 @@ struct extcon_dev { struct device_attribute *d_attrs_muex; }; -/** - * struct extcon_cable - An internal data for each cable of extcon device. - * @edev: The extcon device - * @cable_index: Index of this cable in the edev - * @attr_g: Attribute group for the cable - * @attr_name: "name" sysfs entry - * @attr_state: "state" sysfs entry - * @attrs: Array pointing to attr_name and attr_state for attr_g - */ -struct extcon_cable { - struct extcon_dev *edev; - int cable_index; - - struct attribute_group attr_g; - struct device_attribute attr_name; - struct device_attribute attr_state; - - struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ -}; - #if IS_ENABLED(CONFIG_EXTCON) /* -- cgit v1.2.3 From 58f386560a68dd98bd6744a28fc853eef11faebe Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 20:03:39 +0900 Subject: extcon: Add resource-managed functions to register extcon notifier This patch adds the resource-managed functions for register/unregister the extcon notifier with the id of each external connector. This function will make it easy to handle the extcon notifier. - int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); - void devm_extcon_unregister_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); Signed-off-by: Chanwoo Choi --- drivers/extcon/devres.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/extcon.h | 17 ++++++++++++ 2 files changed, 90 insertions(+) (limited to 'include/linux') diff --git a/drivers/extcon/devres.c b/drivers/extcon/devres.c index 694ca85d5a70..e686acd1c459 100644 --- a/drivers/extcon/devres.c +++ b/drivers/extcon/devres.c @@ -37,6 +37,19 @@ static void devm_extcon_dev_unreg(struct device *dev, void *res) extcon_dev_unregister(*(struct extcon_dev **)res); } +struct extcon_dev_notifier_devres { + struct extcon_dev *edev; + unsigned int id; + struct notifier_block *nb; +}; + +static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res) +{ + struct extcon_dev_notifier_devres *this = res; + + extcon_unregister_notifier(this->edev, this->id, this->nb); +} + /** * devm_extcon_dev_allocate - Allocate managed extcon device * @dev: device owning the extcon device being created @@ -141,3 +154,63 @@ void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev) devm_extcon_dev_match, edev)); } EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister); + +/** + * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier() + * @dev: device to allocate extcon device + * @edev: the extcon device that has the external connecotr. + * @id: the unique id of each external connector in extcon enumeration. + * @nb: a notifier block to be registered. + * + * This function manages automatically the notifier of extcon device using + * device resource management and simplify the control of unregistering + * the notifier of extcon device. + * + * Note that the second parameter given to the callback of nb (val) is + * "old_state", not the current state. The current state can be retrieved + * by looking at the third pameter (edev pointer)'s state value. + * + * Returns 0 if success or negaive error number if failure. + */ +int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, + unsigned int id, struct notifier_block *nb) +{ + struct extcon_dev_notifier_devres *ptr; + int ret; + + ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = extcon_register_notifier(edev, id, nb); + if (ret) { + devres_free(ptr); + return ret; + } + + ptr->edev = edev; + ptr->id = id; + ptr->nb = nb; + devres_add(dev, ptr); + + return 0; +} +EXPORT_SYMBOL(devm_extcon_register_notifier); + +/** + * devm_extcon_unregister_notifier() + - Resource-managed extcon_unregister_notifier() + * @dev: device to allocate extcon device + * @edev: the extcon device that has the external connecotr. + * @id: the unique id of each external connector in extcon enumeration. + * @nb: a notifier block to be registered. + */ +void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) +{ + WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg, + devm_extcon_dev_match, edev)); +} +EXPORT_SYMBOL(devm_extcon_unregister_notifier); diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 1b2c8b6809cc..7bf530f3f4f5 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -182,6 +182,12 @@ extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); +extern int devm_extcon_register_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb); +extern void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb); /* * Following API get the extcon device from devicetree. @@ -273,6 +279,17 @@ static inline int extcon_unregister_notifier(struct extcon_dev *edev, return 0; } +static inline int devm_extcon_register_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) +{ + return -ENOSYS; +} + +static inline void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) { } + static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) { -- cgit v1.2.3 From b4bba38909c21689de21355e84259cb7b38f25ac Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Mon, 27 Jun 2016 09:58:40 -0500 Subject: fs: export __block_write_full_page gfs2 needs to be able to skip the check to see if a page is outside of the file size when writing it out. gfs2 can get into a situation where it needs to flush its in-memory log to disk while a truncate is in progress. If the file being trucated has data journaling enabled, it is possible that there are data blocks in the log that are past the end of the file. gfs can't finish the log flush without either writing these blocks out or revoking them. Otherwise, if the node crashed, it could overwrite subsequent changes made by other nodes in the cluster when it's journal was replayed. Unfortunately, there is no way to add log entries to the log during a flush. So gfs2 simply writes out the page instead. This situation can only occur when the truncate code still has the file locked exclusively, and hasn't marked this block as free in the metadata (which happens later in truc_dealloc). After gfs2 writes this page out, the truncation code will shortly invalidate it and write out any revokes if necessary. In order to make this work, gfs2 needs to be able to skip the check for writes outside the file size. Since the check exists in block_write_full_page, this patch exports __block_write_full_page, which doesn't have the check. Signed-off-by: Benjamin Marzinski Signed-off-by: Bob Peterson --- fs/buffer.c | 3 ++- include/linux/buffer_head.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/fs/buffer.c b/fs/buffer.c index 754813a6962b..6c15012a75d9 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1687,7 +1687,7 @@ static struct buffer_head *create_page_buffers(struct page *page, struct inode * * WB_SYNC_ALL, the writes are posted using WRITE_SYNC; this * causes the writes to be flagged as synchronous writes. */ -static int __block_write_full_page(struct inode *inode, struct page *page, +int __block_write_full_page(struct inode *inode, struct page *page, get_block_t *get_block, struct writeback_control *wbc, bh_end_io_t *handler) { @@ -1848,6 +1848,7 @@ recover: unlock_page(page); goto done; } +EXPORT_SYMBOL(__block_write_full_page); /* * If a page has any new buffers, zero them out here, and mark them uptodate diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index d48daa3f6f20..7e14e545c4b6 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -208,6 +208,9 @@ void block_invalidatepage(struct page *page, unsigned int offset, unsigned int length); int block_write_full_page(struct page *page, get_block_t *get_block, struct writeback_control *wbc); +int __block_write_full_page(struct inode *inode, struct page *page, + get_block_t *get_block, struct writeback_control *wbc, + bh_end_io_t *handler); int block_read_full_page(struct page*, get_block_t*); int block_is_partially_uptodate(struct page *page, unsigned long from, unsigned long count); -- cgit v1.2.3 From 86b2efbe3a390e07dbba725ef700b0d143e9a385 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Fri, 24 Jun 2016 16:35:46 -0400 Subject: audit: add fields to exclude filter by reusing user filter RFE: add additional fields for use in audit filter exclude rules https://github.com/linux-audit/audit-kernel/issues/5 Re-factor and combine audit_filter_type() with audit_filter_user() to use audit_filter_user_rules() to enable the exclude filter to additionally filter on PID, UID, GID, AUID, LOGINUID_SET, SUBJ_*. The process of combining the similar audit_filter_user() and audit_filter_type() functions, required inverting the meaning and including the ALWAYS action of the latter. Include audit_filter_user_rules() into audit_filter(), removing unneeded logic in the process. Keep the check to quit early if the list is empty. Signed-off-by: Richard Guy Briggs [PM: checkpatch.pl fixes - whitespace damage, wrapped description] Signed-off-by: Paul Moore --- include/linux/audit.h | 2 - kernel/audit.c | 4 +- kernel/audit.h | 2 + kernel/auditfilter.c | 151 ++++++++++++++++++-------------------------------- 4 files changed, 57 insertions(+), 102 deletions(-) (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index e38e3fc13ea8..9d4443f93db6 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -163,8 +163,6 @@ extern void audit_log_task_info(struct audit_buffer *ab, extern int audit_update_lsm_rules(void); /* Private API (for audit.c only) */ -extern int audit_filter_user(int type); -extern int audit_filter_type(int type); extern int audit_rule_change(int type, __u32 portid, int seq, void *data, size_t datasz); extern int audit_list_rules_send(struct sk_buff *request_skb, int seq); diff --git a/kernel/audit.c b/kernel/audit.c index 678c3f000191..994588ef9489 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -934,7 +934,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (!audit_enabled && msg_type != AUDIT_USER_AVC) return 0; - err = audit_filter_user(msg_type); + err = audit_filter(msg_type, AUDIT_FILTER_USER); if (err == 1) { /* match or error */ err = 0; if (msg_type == AUDIT_USER_TTY) { @@ -1382,7 +1382,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, if (audit_initialized != AUDIT_INITIALIZED) return NULL; - if (unlikely(audit_filter_type(type))) + if (unlikely(!audit_filter(type, AUDIT_FILTER_TYPE))) return NULL; if (gfp_mask & __GFP_DIRECT_RECLAIM) { diff --git a/kernel/audit.h b/kernel/audit.h index cbbe6bb6496e..1879f02cb2c3 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -327,6 +327,8 @@ extern pid_t audit_sig_pid; extern kuid_t audit_sig_uid; extern u32 audit_sig_sid; +extern int audit_filter(int msgtype, unsigned int listtype); + #ifdef CONFIG_AUDITSYSCALL extern int __audit_signal_info(int sig, struct task_struct *t); static inline int audit_signal_info(int sig, struct task_struct *t) diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index ff59a5eed691..85d9cac497e4 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1290,117 +1290,72 @@ int audit_compare_dname_path(const char *dname, const char *path, int parentlen) return strncmp(p, dname, dlen); } -static int audit_filter_user_rules(struct audit_krule *rule, int type, - enum audit_state *state) -{ - int i; - - for (i = 0; i < rule->field_count; i++) { - struct audit_field *f = &rule->fields[i]; - pid_t pid; - int result = 0; - u32 sid; - - switch (f->type) { - case AUDIT_PID: - pid = task_pid_nr(current); - result = audit_comparator(pid, f->op, f->val); - break; - case AUDIT_UID: - result = audit_uid_comparator(current_uid(), f->op, f->uid); - break; - case AUDIT_GID: - result = audit_gid_comparator(current_gid(), f->op, f->gid); - break; - case AUDIT_LOGINUID: - result = audit_uid_comparator(audit_get_loginuid(current), - f->op, f->uid); - break; - case AUDIT_LOGINUID_SET: - result = audit_comparator(audit_loginuid_set(current), - f->op, f->val); - break; - case AUDIT_MSGTYPE: - result = audit_comparator(type, f->op, f->val); - break; - case AUDIT_SUBJ_USER: - case AUDIT_SUBJ_ROLE: - case AUDIT_SUBJ_TYPE: - case AUDIT_SUBJ_SEN: - case AUDIT_SUBJ_CLR: - if (f->lsm_rule) { - security_task_getsecid(current, &sid); - result = security_audit_rule_match(sid, - f->type, - f->op, - f->lsm_rule, - NULL); - } - break; - } - - if (result <= 0) - return result; - } - switch (rule->action) { - case AUDIT_NEVER: - *state = AUDIT_DISABLED; - break; - case AUDIT_ALWAYS: - *state = AUDIT_RECORD_CONTEXT; - break; - } - return 1; -} - -int audit_filter_user(int type) -{ - enum audit_state state = AUDIT_DISABLED; - struct audit_entry *e; - int rc, ret; - - ret = 1; /* Audit by default */ - - rcu_read_lock(); - list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) { - rc = audit_filter_user_rules(&e->rule, type, &state); - if (rc) { - if (rc > 0 && state == AUDIT_DISABLED) - ret = 0; - break; - } - } - rcu_read_unlock(); - - return ret; -} - -int audit_filter_type(int type) +int audit_filter(int msgtype, unsigned int listtype) { struct audit_entry *e; - int result = 0; + int ret = 1; /* Audit by default */ rcu_read_lock(); - if (list_empty(&audit_filter_list[AUDIT_FILTER_TYPE])) + if (list_empty(&audit_filter_list[listtype])) goto unlock_and_return; + list_for_each_entry_rcu(e, &audit_filter_list[listtype], list) { + int i, result = 0; - list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TYPE], - list) { - int i; for (i = 0; i < e->rule.field_count; i++) { struct audit_field *f = &e->rule.fields[i]; - if (f->type == AUDIT_MSGTYPE) { - result = audit_comparator(type, f->op, f->val); - if (!result) - break; + pid_t pid; + u32 sid; + + switch (f->type) { + case AUDIT_PID: + pid = task_pid_nr(current); + result = audit_comparator(pid, f->op, f->val); + break; + case AUDIT_UID: + result = audit_uid_comparator(current_uid(), f->op, f->uid); + break; + case AUDIT_GID: + result = audit_gid_comparator(current_gid(), f->op, f->gid); + break; + case AUDIT_LOGINUID: + result = audit_uid_comparator(audit_get_loginuid(current), + f->op, f->uid); + break; + case AUDIT_LOGINUID_SET: + result = audit_comparator(audit_loginuid_set(current), + f->op, f->val); + break; + case AUDIT_MSGTYPE: + result = audit_comparator(msgtype, f->op, f->val); + break; + case AUDIT_SUBJ_USER: + case AUDIT_SUBJ_ROLE: + case AUDIT_SUBJ_TYPE: + case AUDIT_SUBJ_SEN: + case AUDIT_SUBJ_CLR: + if (f->lsm_rule) { + security_task_getsecid(current, &sid); + result = security_audit_rule_match(sid, + f->type, f->op, f->lsm_rule, NULL); + } + break; + default: + goto unlock_and_return; } + if (result < 0) /* error */ + goto unlock_and_return; + if (!result) + break; + } + if (result > 0) { + if (e->rule.action == AUDIT_NEVER || listtype == AUDIT_FILTER_TYPE) + ret = 0; + break; } - if (result) - goto unlock_and_return; } unlock_and_return: rcu_read_unlock(); - return result; + return ret; } static int update_lsm_rule(struct audit_krule *r) -- cgit v1.2.3 From 803bb30145df3132f9c8c8704d11a9e6732340c7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 26 Jun 2016 22:57:52 +0200 Subject: rtc: m48t86: move m48t86.h to platform_data m48t86.h belongs to include/linux/platform_data/ Acked-by: Jason Cooper Acked-by: H Hartley Sweeten Acked-by: Alexander Clouter Signed-off-by: Alexandre Belloni --- arch/arm/mach-ep93xx/ts72xx.c | 2 +- arch/arm/mach-orion5x/ts78xx-setup.c | 2 +- drivers/rtc/rtc-m48t86.c | 2 +- include/linux/m48t86.h | 16 ---------------- include/linux/platform_data/rtc-m48t86.h | 16 ++++++++++++++++ 5 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 include/linux/m48t86.h create mode 100644 include/linux/platform_data/rtc-m48t86.h (limited to 'include/linux') diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 45b81a2bcd4b..3b39ea353d30 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index 3a58a5d4a28a..8d597267d0c4 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index f72b91f2501f..0eeb5714c00f 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #define M48T86_REG_SEC 0x00 diff --git a/include/linux/m48t86.h b/include/linux/m48t86.h deleted file mode 100644 index 915d6b4f0f89..000000000000 --- a/include/linux/m48t86.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * ST M48T86 / Dallas DS12887 RTC driver - * Copyright (c) 2006 Tower Technologies - * - * Author: Alessandro Zummo - * - * 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. -*/ - -struct m48t86_ops -{ - void (*writebyte)(unsigned char value, unsigned long addr); - unsigned char (*readbyte)(unsigned long addr); -}; diff --git a/include/linux/platform_data/rtc-m48t86.h b/include/linux/platform_data/rtc-m48t86.h new file mode 100644 index 000000000000..915d6b4f0f89 --- /dev/null +++ b/include/linux/platform_data/rtc-m48t86.h @@ -0,0 +1,16 @@ +/* + * ST M48T86 / Dallas DS12887 RTC driver + * Copyright (c) 2006 Tower Technologies + * + * Author: Alessandro Zummo + * + * 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. +*/ + +struct m48t86_ops +{ + void (*writebyte)(unsigned char value, unsigned long addr); + unsigned char (*readbyte)(unsigned long addr); +}; -- cgit v1.2.3 From 3de56099591a4042556a2d05d4703387ad950c6f Mon Sep 17 00:00:00 2001 From: Russ Dill Date: Fri, 24 Jun 2016 13:58:07 +0530 Subject: regulator: tps65217: Enable suspend configuration The TPS65217 has a pre-defined power-up / power-down sequence which in a typical application does not need to be changed. However, it is possible to define custom sequences under I2C control. The power-up sequence is defined by strobes and delay times. Each output rail is assigned to a strobe to determine the order in which the rails are enabled. Every regulator of tps65217 PMIC has sequence registers and every regulator has a default strobe value and gets disabled when a particular power down sequence occurs. To keep a regulator on during suspend we write value 0 to strobe so that the regulator is out of all sequencers and is not impacted by any power down sequence. Hence saving the default strobe value during probe so that when we want to regulator to be enabled during suspend we write 0 to strobe and when we want it to get disabled during suspend we write the default saved strobe value. This allows platform data to specify which power rails should be on or off during RTC only suspend. This is necessary to keep DDR state while in RTC only suspend. Signed-off-by: Russ Dill [Enhanced commit log and added dynamic allocation for strobes] Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/tps65217-regulator.c | 69 +++++++++++++++++++++++++++++----- include/linux/mfd/tps65217.h | 1 + 2 files changed, 61 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index adbe4fc5cf07..2d12b9af3540 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -28,7 +28,7 @@ #include #define TPS65217_REGULATOR(_name, _id, _of_match, _ops, _n, _vr, _vm, _em, \ - _t, _lr, _nlr) \ + _t, _lr, _nlr, _sr, _sm) \ { \ .name = _name, \ .id = _id, \ @@ -45,6 +45,8 @@ .volt_table = _t, \ .linear_ranges = _lr, \ .n_linear_ranges = _nlr, \ + .bypass_reg = _sr, \ + .bypass_mask = _sm, \ } \ static const unsigned int LDO1_VSEL_table[] = { @@ -118,6 +120,35 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev, return ret; } +static int tps65217_pmic_set_suspend_enable(struct regulator_dev *dev) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + return tps65217_clear_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + TPS65217_PROTECT_L1); +} + +static int tps65217_pmic_set_suspend_disable(struct regulator_dev *dev) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + if (!tps->strobes[rid]) + return -EINVAL; + + return tps65217_set_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + tps->strobes[rid], TPS65217_PROTECT_L1); +} + /* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */ static struct regulator_ops tps65217_pmic_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -127,6 +158,8 @@ static struct regulator_ops tps65217_pmic_ops = { .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, + .set_suspend_enable = tps65217_pmic_set_suspend_enable, + .set_suspend_disable = tps65217_pmic_set_suspend_disable, }; /* Operations permitted on LDO1 */ @@ -138,41 +171,50 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = { .set_voltage_sel = tps65217_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, + .set_suspend_enable = tps65217_pmic_set_suspend_enable, + .set_suspend_disable = tps65217_pmic_set_suspend_disable, }; static const struct regulator_desc regulators[] = { TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, "dcdc1", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC1_EN, - NULL, tps65217_uv1_ranges, 2), + NULL, tps65217_uv1_ranges, 2, TPS65217_REG_SEQ1, + TPS65217_SEQ1_DC1_SEQ_MASK), TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, "dcdc2", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC2_EN, NULL, tps65217_uv1_ranges, - ARRAY_SIZE(tps65217_uv1_ranges)), + ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ1, + TPS65217_SEQ1_DC2_SEQ_MASK), TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, "dcdc3", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC3_EN, - NULL, tps65217_uv1_ranges, 1), + NULL, tps65217_uv1_ranges, 1, TPS65217_REG_SEQ2, + TPS65217_SEQ2_DC3_SEQ_MASK), TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, "ldo1", tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK, TPS65217_ENABLE_LDO1_EN, - LDO1_VSEL_table, NULL, 0), + LDO1_VSEL_table, NULL, 0, TPS65217_REG_SEQ2, + TPS65217_SEQ2_LDO1_SEQ_MASK), TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, "ldo2", tps65217_pmic_ops, 64, TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK, TPS65217_ENABLE_LDO2_EN, NULL, tps65217_uv1_ranges, - ARRAY_SIZE(tps65217_uv1_ranges)), + ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ3, + TPS65217_SEQ3_LDO2_SEQ_MASK), TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, "ldo3", tps65217_pmic_ops, 32, TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK, TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, NULL, tps65217_uv2_ranges, - ARRAY_SIZE(tps65217_uv2_ranges)), + ARRAY_SIZE(tps65217_uv2_ranges), TPS65217_REG_SEQ3, + TPS65217_SEQ3_LDO3_SEQ_MASK), TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, "ldo4", tps65217_pmic_ops, 32, TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK, TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, NULL, tps65217_uv2_ranges, - ARRAY_SIZE(tps65217_uv2_ranges)), + ARRAY_SIZE(tps65217_uv2_ranges), TPS65217_REG_SEQ4, + TPS65217_SEQ4_LDO4_SEQ_MASK), }; static int tps65217_regulator_probe(struct platform_device *pdev) @@ -181,13 +223,18 @@ static int tps65217_regulator_probe(struct platform_device *pdev) struct tps65217_board *pdata = dev_get_platdata(tps->dev); struct regulator_dev *rdev; struct regulator_config config = { }; - int i; + int i, ret; + unsigned int val; if (tps65217_chip_id(tps) != TPS65217) { dev_err(&pdev->dev, "Invalid tps chip version\n"); return -ENODEV; } + /* Allocate memory for strobes */ + tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) * + TPS65217_NUM_REGULATOR, GFP_KERNEL); + platform_set_drvdata(pdev, tps); for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { @@ -205,6 +252,10 @@ static int tps65217_regulator_probe(struct platform_device *pdev) pdev->name); return PTR_ERR(rdev); } + + /* Store default strobe info */ + ret = tps65217_reg_read(tps, regulators[i].bypass_reg, &val); + tps->strobes[i] = val & regulators[i].bypass_mask; } return 0; diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index ac7fba44d7e4..1c88231496d3 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -257,6 +257,7 @@ struct tps65217 { unsigned long id; struct regulator_desc desc[TPS65217_NUM_REGULATOR]; struct regmap *regmap; + u8 *strobes; }; static inline struct tps65217 *dev_to_tps65217(struct device *dev) -- cgit v1.2.3 From b9a0d359413d7f4e078d81cd59f9d851a6febb7a Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 24 Jun 2016 13:58:08 +0530 Subject: regulator: tps65218: Enable suspend configuration TPS65218 has a pre-defined power-up / power-down sequence which in a typical application does not need to be changed. However, it is possible to define custom sequences under I2C control. The power-up sequence is defined by strobes and delay times. Each output rail is assigned to a strobe to determine the order in which the rails are enabled. Every regulator has sequence registers and every regulator has a default strobe value and gets disabled when a particular power down sequence occurs. To keep a regulator on during suspend we write value 0 to strobe so that the regulator is out of all sequencers and is not impacted by any power down sequence. Hence saving the default strobe value during probe so that when we want to regulator to be enabled during suspend we write 0 to strobe and when we want it to get disabled during suspend we write the default saved strobe value. This allows platform data to specify which power rails should be on or off during RTC only suspend. This is necessary to keep DDR state while in RTC only suspend. Signed-off-by: Tero Kristo Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/tps65218-regulator.c | 72 ++++++++++++++++++++++++++++------ include/linux/mfd/tps65218.h | 2 + 2 files changed, 63 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index a5e5634eeb9e..8eca1eb4f219 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -31,7 +31,7 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1, LS3 }; #define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \ - _cr, _cm, _lr, _nlr, _delay, _fuv) \ + _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \ { \ .name = _name, \ .id = _id, \ @@ -49,7 +49,9 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, .linear_ranges = _lr, \ .n_linear_ranges = _nlr, \ .ramp_delay = _delay, \ - .fixed_uV = _fuv \ + .fixed_uV = _fuv, \ + .bypass_reg = _sr, \ + .bypass_mask = _sm, \ } \ #define TPS65218_INFO(_id, _nm, _min, _max) \ @@ -157,6 +159,36 @@ static int tps65218_pmic_disable(struct regulator_dev *dev) dev->desc->enable_mask, TPS65218_PROTECT_L1); } +static int tps65218_pmic_set_suspend_enable(struct regulator_dev *dev) +{ + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) + return -EINVAL; + + return tps65218_clear_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + TPS65218_PROTECT_L1); +} + +static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev) +{ + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) + return -EINVAL; + + if (!tps->info[rid]->strobe) + return -EINVAL; + + return tps65218_set_bits(tps, dev->desc->bypass_reg, + dev->desc->bypass_mask, + tps->info[rid]->strobe, + TPS65218_PROTECT_L1); +} + /* Operations permitted on DCDC1, DCDC2 */ static struct regulator_ops tps65218_dcdc12_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -167,6 +199,8 @@ static struct regulator_ops tps65218_dcdc12_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; /* Operations permitted on DCDC3, DCDC4 and LDO1 */ @@ -178,6 +212,8 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = { .set_voltage_sel = tps65218_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; static const int ls3_currents[] = { 100, 200, 500, 1000 }; @@ -247,6 +283,8 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = tps65218_pmic_enable, .disable = tps65218_pmic_disable, + .set_suspend_enable = tps65218_pmic_set_suspend_enable, + .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; static const struct regulator_desc regulators[] = { @@ -254,42 +292,47 @@ static const struct regulator_desc regulators[] = { tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1, TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges, - 2, 4000, 0), + 2, 4000, 0, TPS65218_REG_SEQ3, + TPS65218_SEQ3_DC1_SEQ_MASK), TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2, TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges, - 2, 4000, 0), + 2, 4000, 0, TPS65218_REG_SEQ3, + TPS65218_SEQ3_DC2_SEQ_MASK), TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64, TPS65218_REG_CONTROL_DCDC3, TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2, - 0, 0), + 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC3_SEQ_MASK), TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 53, TPS65218_REG_CONTROL_DCDC4, TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2, - 0, 0), + 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC4_SEQ_MASK), TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1, -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0, - NULL, 0, 0, 1000000), + NULL, 0, 0, 1000000, TPS65218_REG_SEQ5, + TPS65218_SEQ5_DC5_SEQ_MASK), TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1, -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0, - NULL, 0, 0, 1800000), + NULL, 0, 0, 1800000, TPS65218_REG_SEQ5, + TPS65218_SEQ5_DC6_SEQ_MASK), TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64, TPS65218_REG_CONTROL_LDO1, TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges, - 2, 0, 0), + 2, 0, 0, TPS65218_REG_SEQ6, + TPS65218_SEQ6_LDO1_SEQ_MASK), TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT, tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2, - TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0), + TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0), }; static int tps65218_regulator_probe(struct platform_device *pdev) @@ -300,7 +343,8 @@ static int tps65218_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; const struct of_device_id *match; struct regulator_config config = { }; - int id; + int id, ret; + unsigned int val; match = of_match_device(tps65218_of_match, &pdev->dev); if (!match) @@ -327,6 +371,12 @@ static int tps65218_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } + ret = tps65218_reg_read(tps, regulators[id].bypass_reg, &val); + if (ret) + return ret; + + tps->info[id]->strobe = val & regulators[id].bypass_mask; + return 0; } diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h index d58f3b5f585a..7fdf5326f34e 100644 --- a/include/linux/mfd/tps65218.h +++ b/include/linux/mfd/tps65218.h @@ -246,6 +246,7 @@ enum tps65218_irqs { * @name: Voltage regulator name * @min_uV: minimum micro volts * @max_uV: minimum micro volts + * @strobe: sequencing strobe value for the regulator * * This data is used to check the regualtor voltage limits while setting. */ @@ -254,6 +255,7 @@ struct tps_info { const char *name; int min_uV; int max_uV; + int strobe; }; /** -- cgit v1.2.3 From 52c44d93c26f5a76068c0a8cc83bb8f56f38043d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 15 Jun 2016 19:43:07 -0700 Subject: block: remove ->driverfs_dev Now that all drivers that specify a ->driverfs_dev have been converted to device_add_disk(), the pointer can be removed from struct gendisk. Cc: Jens Axboe Cc: Ross Zwisler Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Signed-off-by: Dan Williams --- block/genhd.c | 9 ++------- drivers/nvdimm/bus.c | 2 +- include/linux/genhd.h | 4 +--- 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/block/genhd.c b/block/genhd.c index fb2d9aeb75a5..a18d35390f1d 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -618,10 +618,6 @@ void device_add_disk(struct device *parent, struct gendisk *disk) blk_register_region(disk_devt(disk), disk->minors, NULL, exact_match, exact_lock, disk); - - /* temporary while we convert usages to use disk_to_dev(disk)->parent */ - disk->driverfs_dev = parent; - register_disk(parent, disk); blk_register_queue(disk); @@ -804,10 +800,9 @@ void __init printk_all_partitions(void) , disk_name(disk, part->partno, name_buf), part->info ? part->info->uuid : ""); if (is_part0) { - if (disk->driverfs_dev != NULL && - disk->driverfs_dev->driver != NULL) + if (dev->parent && dev->parent->driver) printk(" driver: %s\n", - disk->driverfs_dev->driver->name); + dev->parent->driver->name); else printk(" (driver?)\n"); } else diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index f085f8bceae8..5e4e5c772ea5 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -312,7 +312,7 @@ EXPORT_SYMBOL(__nd_driver_register); int nvdimm_revalidate_disk(struct gendisk *disk) { - struct device *dev = disk->driverfs_dev; + struct device *dev = disk_to_dev(disk)->parent; struct nd_region *nd_region = to_nd_region(dev->parent); const char *pol = nd_region->ro ? "only" : "write"; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index df1dabbfd388..1dbf52f9c24b 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -205,7 +205,6 @@ struct gendisk { void *private_data; int flags; - struct device *driverfs_dev; // FIXME: remove struct kobject *slave_dir; struct timer_rand_state *random; @@ -417,8 +416,7 @@ extern void part_round_stats(int cpu, struct hd_struct *part); extern void device_add_disk(struct device *parent, struct gendisk *disk); static inline void add_disk(struct gendisk *disk) { - /* temporary while we convert callers to device_add_disk */ - device_add_disk(disk->driverfs_dev, disk); + device_add_disk(NULL, disk); } extern void del_gendisk(struct gendisk *gp); -- cgit v1.2.3 From de5a3774dde2c2f3b3a9a48b880fd820142706f0 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sat, 30 Apr 2016 18:08:06 +0200 Subject: HSI: core: switch port event notifier from atomic to blocking port events should be sent from process context after irq_safe runtime pm flag is removed in omap-ssi. Signed-off-By: Sebastian Reichel Tested-by: Pavel Machek --- drivers/hsi/hsi_core.c | 8 ++++---- include/linux/hsi/hsi.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/hsi/hsi_core.c b/drivers/hsi/hsi_core.c index d7ce07ad67f3..c2a2a9795b0b 100644 --- a/drivers/hsi/hsi_core.c +++ b/drivers/hsi/hsi_core.c @@ -507,7 +507,7 @@ struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) port[i]->stop_tx = hsi_dummy_cl; port[i]->release = hsi_dummy_cl; mutex_init(&port[i]->lock); - ATOMIC_INIT_NOTIFIER_HEAD(&port[i]->n_head); + BLOCKING_INIT_NOTIFIER_HEAD(&port[i]->n_head); dev_set_name(&port[i]->device, "port%d", i); hsi->port[i]->device.release = hsi_port_release; device_initialize(&hsi->port[i]->device); @@ -689,7 +689,7 @@ int hsi_register_port_event(struct hsi_client *cl, cl->ehandler = handler; cl->nb.notifier_call = hsi_event_notifier_call; - return atomic_notifier_chain_register(&port->n_head, &cl->nb); + return blocking_notifier_chain_register(&port->n_head, &cl->nb); } EXPORT_SYMBOL_GPL(hsi_register_port_event); @@ -709,7 +709,7 @@ int hsi_unregister_port_event(struct hsi_client *cl) WARN_ON(!hsi_port_claimed(cl)); - err = atomic_notifier_chain_unregister(&port->n_head, &cl->nb); + err = blocking_notifier_chain_unregister(&port->n_head, &cl->nb); if (!err) cl->ehandler = NULL; @@ -734,7 +734,7 @@ EXPORT_SYMBOL_GPL(hsi_unregister_port_event); */ int hsi_event(struct hsi_port *port, unsigned long event) { - return atomic_notifier_call_chain(&port->n_head, event, NULL); + return blocking_notifier_call_chain(&port->n_head, event, NULL); } EXPORT_SYMBOL_GPL(hsi_event); diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h index 2790591c77cf..57402544b53f 100644 --- a/include/linux/hsi/hsi.h +++ b/include/linux/hsi/hsi.h @@ -246,7 +246,7 @@ struct hsi_port { int (*stop_tx)(struct hsi_client *cl); int (*release)(struct hsi_client *cl); /* private */ - struct atomic_notifier_head n_head; + struct blocking_notifier_head n_head; }; #define to_hsi_port(dev) container_of(dev, struct hsi_port, device) -- cgit v1.2.3 From 498b5fdd40dd3881a3119d11bff8441cfd902850 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 21 Jun 2016 11:33:25 +0100 Subject: PM / clk: Add support for adding a specific clock from device-tree Some drivers using the PM clocks framework need to add specific clocks from device-tree using a name by calling the functions of_clk_get_by_name() and then pm_clk_add_clk(). Rather than having drivers call both functions, add a helper function of_pm_clk_add_clk() that will call these functions so drivers can call a single function to add a specific clock from device-tree. Signed-off-by: Jon Hunter Signed-off-by: Rafael J. Wysocki --- drivers/base/power/clock_ops.c | 32 ++++++++++++++++++++++++++++++++ include/linux/pm_clock.h | 1 + 2 files changed, 33 insertions(+) (limited to 'include/linux') diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 761f5c21f9f0..8e2e4757adcb 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -140,6 +140,38 @@ int pm_clk_add_clk(struct device *dev, struct clk *clk) EXPORT_SYMBOL_GPL(pm_clk_add_clk); +/** + * of_pm_clk_add_clk - Start using a device clock for power management. + * @dev: Device whose clock is going to be used for power management. + * @name: Name of clock that is going to be used for power management. + * + * Add the clock described in the 'clocks' device-tree node that matches + * with the 'name' provided, to the list of clocks used for the power + * management of @dev. On success, returns 0. Returns a negative error + * code if the clock is not found or cannot be added. + */ +int of_pm_clk_add_clk(struct device *dev, const char *name) +{ + struct clk *clk; + int ret; + + if (!dev || !dev->of_node || !name) + return -EINVAL; + + clk = of_clk_get_by_name(dev->of_node, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ret = pm_clk_add_clk(dev, clk); + if (ret) { + clk_put(clk); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(of_pm_clk_add_clk); + /** * of_pm_clk_add_clks - Start using device clock(s) for power management. * @dev: Device whose clock(s) is going to be used for power management. diff --git a/include/linux/pm_clock.h b/include/linux/pm_clock.h index 308d6044f153..09779b0ae720 100644 --- a/include/linux/pm_clock.h +++ b/include/linux/pm_clock.h @@ -42,6 +42,7 @@ extern int pm_clk_create(struct device *dev); extern void pm_clk_destroy(struct device *dev); extern int pm_clk_add(struct device *dev, const char *con_id); extern int pm_clk_add_clk(struct device *dev, struct clk *clk); +extern int of_pm_clk_add_clk(struct device *dev, const char *name); extern int of_pm_clk_add_clks(struct device *dev); extern void pm_clk_remove(struct device *dev, const char *con_id); extern void pm_clk_remove_clk(struct device *dev, struct clk *clk); -- cgit v1.2.3 From 7c84f7f80d6fcea36246b793d06c3555ca53ddcd Mon Sep 17 00:00:00 2001 From: David Frey Date: Thu, 2 Jun 2016 09:59:11 +0200 Subject: hwmon: add support for Sensirion SHT3x sensors This driver implements support for the Sensirion SHT3x-DIS chip, a humidity and temperature sensor. Temperature is measured in degrees celsius, relative humidity is expressed as a percentage. In the sysfs interface, all values are scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. Signed-off-by: Pascal Sachs [groeck: Fixed 'Variable length array is used' gcc warning] Signed-off-by: Guenter Roeck --- Documentation/hwmon/sht3x | 72 ++++ drivers/hwmon/Kconfig | 11 + drivers/hwmon/Makefile | 1 + drivers/hwmon/sht3x.c | 725 ++++++++++++++++++++++++++++++++++++ include/linux/platform_data/sht3x.h | 25 ++ 5 files changed, 834 insertions(+) create mode 100644 Documentation/hwmon/sht3x create mode 100644 drivers/hwmon/sht3x.c create mode 100644 include/linux/platform_data/sht3x.h (limited to 'include/linux') diff --git a/Documentation/hwmon/sht3x b/Documentation/hwmon/sht3x new file mode 100644 index 000000000000..f5aa633ed383 --- /dev/null +++ b/Documentation/hwmon/sht3x @@ -0,0 +1,72 @@ +Kernel driver sht3x +=================== + +Supported chips: + * Sensirion SHT3x-DIS + Prefix: 'sht3x' + Addresses scanned: none + Datasheet: http://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity/Sensirion_Humidity_Datasheet_SHT3x_DIS.pdf + +Author: + David Frey + Pascal Sachs + +Description +----------- + +This driver implements support for the Sensirion SHT3x-DIS chip, a humidity +and temperature sensor. Temperature is measured in degrees celsius, relative +humidity is expressed as a percentage. In the sysfs interface, all values are +scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. + +The device communicates with the I2C protocol. Sensors can have the I2C +addresses 0x44 or 0x45, depending on the wiring. See +Documentation/i2c/instantiating-devices for methods to instantiate the device. + +There are two options configurable by means of sht3x_platform_data: +1. blocking (pull the I2C clock line down while performing the measurement) or + non-blocking mode. Blocking mode will guarantee the fastest result but + the I2C bus will be busy during that time. By default, non-blocking mode + is used. Make sure clock-stretching works properly on your device if you + want to use blocking mode. +2. high or low accuracy. High accuracy is used by default and using it is + strongly recommended. + +The sht3x sensor supports a single shot mode as well as 5 periodic measure +modes, which can be controlled with the update_interval sysfs interface. +The allowed update_interval in milliseconds are as follows: + * 0 single shot mode + * 2000 0.5 Hz periodic measurement + * 1000 1 Hz periodic measurement + * 500 2 Hz periodic measurement + * 250 4 Hz periodic measurement + * 100 10 Hz periodic measurement + +In the periodic measure mode, the sensor automatically triggers a measurement +with the configured update interval on the chip. When a temperature or humidity +reading exceeds the configured limits, the alert attribute is set to 1 and +the alert pin on the sensor is set to high. +When the temperature and humidity readings move back between the hysteresis +values, the alert bit is set to 0 and the alert pin on the sensor is set to +low. + +sysfs-Interface +--------------- + +temp1_input: temperature input +humidity1_input: humidity input +temp1_max: temperature max value +temp1_max_hyst: temperature hysteresis value for max limit +humidity1_max: humidity max value +humidity1_max_hyst: humidity hysteresis value for max limit +temp1_min: temperature min value +temp1_min_hyst: temperature hysteresis value for min limit +humidity1_min: humidity min value +humidity1_min_hyst: humidity hysteresis value for min limit +temp1_alarm: alarm flag is set to 1 if the temperature is outside the + configured limits. Alarm only works in periodic measure mode +humidity1_alarm: alarm flag is set to 1 if the humidity is outside the + configured limits. Alarm only works in periodic measure mode +update_interval: update interval, 0 for single shot, interval in msec + for periodic measurement. If the interval is not supported + by the sensor, the next faster interval is chosen diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ff940075bb90..e0be99a4615c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1265,6 +1265,17 @@ config SENSORS_SHT21 This driver can also be built as a module. If so, the module will be called sht21. +config SENSORS_SHT3x + tristate "Sensiron humidity and temperature sensors. SHT3x and compat." + depends on I2C + select CRC8 + help + If you say yes here you get support for the Sensiron SHT30 and SHT31 + humidity and temperature sensors. + + This driver can also be built as a module. If so, the module + will be called sht3x. + config SENSORS_SHTC1 tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 2ef5b7c4c54f..406b18b995b3 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -138,6 +138,7 @@ obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o +obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c new file mode 100644 index 000000000000..707a3f85385b --- /dev/null +++ b/drivers/hwmon/sht3x.c @@ -0,0 +1,725 @@ +/* Sensirion SHT3x-DIS humidity and temperature sensor driver. + * The SHT3x comes in many different versions, this driver is for the + * I2C version only. + * + * Copyright (C) 2016 Sensirion AG, Switzerland + * Author: David Frey + * Author: Pascal Sachs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* commands (high precision mode) */ +static const unsigned char sht3x_cmd_measure_blocking_hpm[] = { 0x2c, 0x06 }; +static const unsigned char sht3x_cmd_measure_nonblocking_hpm[] = { 0x24, 0x00 }; + +/* commands (low power mode) */ +static const unsigned char sht3x_cmd_measure_blocking_lpm[] = { 0x2c, 0x10 }; +static const unsigned char sht3x_cmd_measure_nonblocking_lpm[] = { 0x24, 0x16 }; + +/* commands for periodic mode */ +static const unsigned char sht3x_cmd_measure_periodic_mode[] = { 0xe0, 0x00 }; +static const unsigned char sht3x_cmd_break[] = { 0x30, 0x93 }; + +/* other commands */ +static const unsigned char sht3x_cmd_read_status_reg[] = { 0xf3, 0x2d }; +static const unsigned char sht3x_cmd_clear_status_reg[] = { 0x30, 0x41 }; + +/* delays for non-blocking i2c commands, both in us */ +#define SHT3X_NONBLOCKING_WAIT_TIME_HPM 15000 +#define SHT3X_NONBLOCKING_WAIT_TIME_LPM 4000 + +#define SHT3X_WORD_LEN 2 +#define SHT3X_CMD_LENGTH 2 +#define SHT3X_CRC8_LEN 1 +#define SHT3X_RESPONSE_LENGTH 6 +#define SHT3X_CRC8_POLYNOMIAL 0x31 +#define SHT3X_CRC8_INIT 0xFF +#define SHT3X_MIN_TEMPERATURE -45000 +#define SHT3X_MAX_TEMPERATURE 130000 +#define SHT3X_MIN_HUMIDITY 0 +#define SHT3X_MAX_HUMIDITY 100000 + +enum sht3x_chips { + sht3x, + sts3x, +}; + +enum sht3x_limits { + limit_max = 0, + limit_max_hyst, + limit_min, + limit_min_hyst, +}; + +DECLARE_CRC8_TABLE(sht3x_crc8_table); + +/* periodic measure commands (high precision mode) */ +static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = { + /* 0.5 measurements per second */ + {0x20, 0x32}, + /* 1 measurements per second */ + {0x21, 0x30}, + /* 2 measurements per second */ + {0x22, 0x36}, + /* 4 measurements per second */ + {0x23, 0x34}, + /* 10 measurements per second */ + {0x27, 0x37}, +}; + +/* periodic measure commands (low power mode) */ +static const char periodic_measure_commands_lpm[][SHT3X_CMD_LENGTH] = { + /* 0.5 measurements per second */ + {0x20, 0x2f}, + /* 1 measurements per second */ + {0x21, 0x2d}, + /* 2 measurements per second */ + {0x22, 0x2b}, + /* 4 measurements per second */ + {0x23, 0x29}, + /* 10 measurements per second */ + {0x27, 0x2a}, +}; + +struct sht3x_limit_commands { + const char read_command[SHT3X_CMD_LENGTH]; + const char write_command[SHT3X_CMD_LENGTH]; +}; + +static const struct sht3x_limit_commands limit_commands[] = { + /* temp1_max, humidity1_max */ + [limit_max] = { {0xe1, 0x1f}, {0x61, 0x1d} }, + /* temp_1_max_hyst, humidity1_max_hyst */ + [limit_max_hyst] = { {0xe1, 0x14}, {0x61, 0x16} }, + /* temp1_min, humidity1_min */ + [limit_min] = { {0xe1, 0x02}, {0x61, 0x00} }, + /* temp_1_min_hyst, humidity1_min_hyst */ + [limit_min_hyst] = { {0xe1, 0x09}, {0x61, 0x0B} }, +}; + +#define SHT3X_NUM_LIMIT_CMD ARRAY_SIZE(limit_commands) + +static const u16 mode_to_update_interval[] = { + 0, + 2000, + 1000, + 500, + 250, + 100, +}; + +struct sht3x_data { + struct i2c_client *client; + struct mutex i2c_lock; /* lock for sending i2c commands */ + struct mutex data_lock; /* lock for updating driver data */ + + u8 mode; + const unsigned char *command; + u32 wait_time; /* in us*/ + unsigned long last_update; /* last update in periodic mode*/ + + struct sht3x_platform_data setup; + + /* + * cached values for temperature and humidity and limits + * the limits arrays have the following order: + * max, max_hyst, min, min_hyst + */ + int temperature; + int temperature_limits[SHT3X_NUM_LIMIT_CMD]; + u32 humidity; + u32 humidity_limits[SHT3X_NUM_LIMIT_CMD]; +}; + +static u8 get_mode_from_update_interval(u16 value) +{ + size_t index; + u8 number_of_modes = ARRAY_SIZE(mode_to_update_interval); + + if (value == 0) + return 0; + + /* find next faster update interval */ + for (index = 1; index < number_of_modes; index++) { + if (mode_to_update_interval[index] <= value) + return index; + } + + return number_of_modes - 1; +} + +static int sht3x_read_from_command(struct i2c_client *client, + struct sht3x_data *data, + const char *command, + char *buf, int length, u32 wait_time) +{ + int ret; + + mutex_lock(&data->i2c_lock); + ret = i2c_master_send(client, command, SHT3X_CMD_LENGTH); + + if (ret != SHT3X_CMD_LENGTH) { + ret = ret < 0 ? ret : -EIO; + goto out; + } + + if (wait_time) + usleep_range(wait_time, wait_time + 1000); + + ret = i2c_master_recv(client, buf, length); + if (ret != length) { + ret = ret < 0 ? ret : -EIO; + goto out; + } + + ret = 0; +out: + mutex_unlock(&data->i2c_lock); + return ret; +} + +static int sht3x_extract_temperature(u16 raw) +{ + /* + * From datasheet: + * T = -45 + 175 * ST / 2^16 + * Adapted for integer fixed point (3 digit) arithmetic. + */ + return ((21875 * (int)raw) >> 13) - 45000; +} + +static u32 sht3x_extract_humidity(u16 raw) +{ + /* + * From datasheet: + * RH = 100 * SRH / 2^16 + * Adapted for integer fixed point (3 digit) arithmetic. + */ + return (12500 * (u32)raw) >> 13; +} + +static struct sht3x_data *sht3x_update_client(struct device *dev) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + u16 interval_ms = mode_to_update_interval[data->mode]; + unsigned long interval_jiffies = msecs_to_jiffies(interval_ms); + unsigned char buf[SHT3X_RESPONSE_LENGTH]; + u16 val; + int ret = 0; + + mutex_lock(&data->data_lock); + /* + * Only update cached readings once per update interval in periodic + * mode. In single shot mode the sensor measures values on demand, so + * every time the sysfs interface is called, a measurement is triggered. + * In periodic mode however, the measurement process is handled + * internally by the sensor and reading out sensor values only makes + * sense if a new reading is available. + */ + if (time_after(jiffies, data->last_update + interval_jiffies)) { + ret = sht3x_read_from_command(client, data, data->command, buf, + sizeof(buf), data->wait_time); + if (ret) + goto out; + + val = be16_to_cpup((__be16 *)buf); + data->temperature = sht3x_extract_temperature(val); + val = be16_to_cpup((__be16 *)(buf + 3)); + data->humidity = sht3x_extract_humidity(val); + data->last_update = jiffies; + } + +out: + mutex_unlock(&data->data_lock); + if (ret) + return ERR_PTR(ret); + + return data; +} + +/* sysfs attributes */ +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sht3x_data *data = sht3x_update_client(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->temperature); +} + +static ssize_t humidity1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sht3x_data *data = sht3x_update_client(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%u\n", data->humidity); +} + +/* + * limits_update must only be called from probe or with data_lock held + */ +static int limits_update(struct sht3x_data *data) +{ + int ret; + u8 index; + int temperature; + u32 humidity; + u16 raw; + char buffer[SHT3X_RESPONSE_LENGTH]; + const struct sht3x_limit_commands *commands; + struct i2c_client *client = data->client; + + for (index = 0; index < SHT3X_NUM_LIMIT_CMD; index++) { + commands = &limit_commands[index]; + ret = sht3x_read_from_command(client, data, + commands->read_command, buffer, + SHT3X_RESPONSE_LENGTH, 0); + + if (ret) + return ret; + + raw = be16_to_cpup((__be16 *)buffer); + temperature = sht3x_extract_temperature((raw & 0x01ff) << 7); + humidity = sht3x_extract_humidity(raw & 0xfe00); + data->temperature_limits[index] = temperature; + data->humidity_limits[index] = humidity; + } + + return ret; +} + +static ssize_t temp1_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + u8 index = to_sensor_dev_attr(attr)->index; + int temperature_limit = data->temperature_limits[index]; + + return scnprintf(buf, PAGE_SIZE, "%d\n", temperature_limit); +} + +static ssize_t humidity1_limit_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + u8 index = to_sensor_dev_attr(attr)->index; + u32 humidity_limit = data->humidity_limits[index]; + + return scnprintf(buf, PAGE_SIZE, "%u\n", humidity_limit); +} + +/* + * limit_store must only be called with data_lock held + */ +static size_t limit_store(struct device *dev, + size_t count, + u8 index, + int temperature, + u32 humidity) +{ + char buffer[SHT3X_CMD_LENGTH + SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; + char *position = buffer; + int ret; + u16 raw; + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + const struct sht3x_limit_commands *commands; + + commands = &limit_commands[index]; + + memcpy(position, commands->write_command, SHT3X_CMD_LENGTH); + position += SHT3X_CMD_LENGTH; + /* + * ST = (T + 45) / 175 * 2^16 + * SRH = RH / 100 * 2^16 + * adapted for fixed point arithmetic and packed the same as + * in limit_show() + */ + raw = ((u32)(temperature + 45000) * 24543) >> (16 + 7); + raw |= ((humidity * 42950) >> 16) & 0xfe00; + + *((__be16 *)position) = cpu_to_be16(raw); + position += SHT3X_WORD_LEN; + *position = crc8(sht3x_crc8_table, + position - SHT3X_WORD_LEN, + SHT3X_WORD_LEN, + SHT3X_CRC8_INIT); + + mutex_lock(&data->i2c_lock); + ret = i2c_master_send(client, buffer, sizeof(buffer)); + mutex_unlock(&data->i2c_lock); + + if (ret != sizeof(buffer)) + return ret < 0 ? ret : -EIO; + + data->temperature_limits[index] = temperature; + data->humidity_limits[index] = humidity; + return count; +} + +static ssize_t temp1_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int temperature; + int ret; + struct sht3x_data *data = dev_get_drvdata(dev); + u8 index = to_sensor_dev_attr(attr)->index; + + ret = kstrtoint(buf, 0, &temperature); + if (ret) + return ret; + + temperature = clamp_val(temperature, SHT3X_MIN_TEMPERATURE, + SHT3X_MAX_TEMPERATURE); + mutex_lock(&data->data_lock); + ret = limit_store(dev, count, index, temperature, + data->humidity_limits[index]); + mutex_unlock(&data->data_lock); + + return ret; +} + +static ssize_t humidity1_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + u32 humidity; + int ret; + struct sht3x_data *data = dev_get_drvdata(dev); + u8 index = to_sensor_dev_attr(attr)->index; + + ret = kstrtou32(buf, 0, &humidity); + if (ret) + return ret; + + humidity = clamp_val(humidity, SHT3X_MIN_HUMIDITY, SHT3X_MAX_HUMIDITY); + mutex_lock(&data->data_lock); + ret = limit_store(dev, count, index, data->temperature_limits[index], + humidity); + mutex_unlock(&data->data_lock); + + return ret; +} + +static void sht3x_select_command(struct sht3x_data *data) +{ + /* + * In blocking mode (clock stretching mode) the I2C bus + * is blocked for other traffic, thus the call to i2c_master_recv() + * will wait until the data is ready. For non blocking mode, we + * have to wait ourselves. + */ + if (data->mode > 0) { + data->command = sht3x_cmd_measure_periodic_mode; + data->wait_time = 0; + } else if (data->setup.blocking_io) { + data->command = data->setup.high_precision ? + sht3x_cmd_measure_blocking_hpm : + sht3x_cmd_measure_blocking_lpm; + data->wait_time = 0; + } else { + if (data->setup.high_precision) { + data->command = sht3x_cmd_measure_nonblocking_hpm; + data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_HPM; + } else { + data->command = sht3x_cmd_measure_nonblocking_lpm; + data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_LPM; + } + } +} + +static int status_register_read(struct device *dev, + struct device_attribute *attr, + char *buffer, int length) +{ + int ret; + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + ret = sht3x_read_from_command(client, data, sht3x_cmd_read_status_reg, + buffer, length, 0); + + return ret; +} + +static ssize_t temp1_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; + int ret; + + ret = status_register_read(dev, attr, buffer, + SHT3X_WORD_LEN + SHT3X_CRC8_LEN); + if (ret) + return ret; + + return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x04)); +} + +static ssize_t humidity1_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; + int ret; + + ret = status_register_read(dev, attr, buffer, + SHT3X_WORD_LEN + SHT3X_CRC8_LEN); + if (ret) + return ret; + + return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x08)); +} + +static ssize_t update_interval_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", + mode_to_update_interval[data->mode]); +} + +static ssize_t update_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + u16 update_interval; + u8 mode; + int ret; + const char *command; + struct sht3x_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + ret = kstrtou16(buf, 0, &update_interval); + if (ret) + return ret; + + mode = get_mode_from_update_interval(update_interval); + + mutex_lock(&data->data_lock); + /* mode did not change */ + if (mode == data->mode) { + mutex_unlock(&data->data_lock); + return count; + } + + mutex_lock(&data->i2c_lock); + /* + * Abort periodic measure mode. + * To do any changes to the configuration while in periodic mode, we + * have to send a break command to the sensor, which then falls back + * to single shot (mode = 0). + */ + if (data->mode > 0) { + ret = i2c_master_send(client, sht3x_cmd_break, + SHT3X_CMD_LENGTH); + if (ret != SHT3X_CMD_LENGTH) + goto out; + data->mode = 0; + } + + if (mode > 0) { + if (data->setup.high_precision) + command = periodic_measure_commands_hpm[mode - 1]; + else + command = periodic_measure_commands_lpm[mode - 1]; + + /* select mode */ + ret = i2c_master_send(client, command, SHT3X_CMD_LENGTH); + if (ret != SHT3X_CMD_LENGTH) + goto out; + } + + /* select mode and command */ + data->mode = mode; + sht3x_select_command(data); + +out: + mutex_unlock(&data->i2c_lock); + mutex_unlock(&data->data_lock); + if (ret != SHT3X_CMD_LENGTH) + return ret < 0 ? ret : -EIO; + + return count; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp1_input_show, NULL, 0); +static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, humidity1_input_show, + NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + temp1_limit_show, temp1_limit_store, + limit_max); +static SENSOR_DEVICE_ATTR(humidity1_max, S_IRUGO | S_IWUSR, + humidity1_limit_show, humidity1_limit_store, + limit_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + temp1_limit_show, temp1_limit_store, + limit_max_hyst); +static SENSOR_DEVICE_ATTR(humidity1_max_hyst, S_IRUGO | S_IWUSR, + humidity1_limit_show, humidity1_limit_store, + limit_max_hyst); +static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, + temp1_limit_show, temp1_limit_store, + limit_min); +static SENSOR_DEVICE_ATTR(humidity1_min, S_IRUGO | S_IWUSR, + humidity1_limit_show, humidity1_limit_store, + limit_min); +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO | S_IWUSR, + temp1_limit_show, temp1_limit_store, + limit_min_hyst); +static SENSOR_DEVICE_ATTR(humidity1_min_hyst, S_IRUGO | S_IWUSR, + humidity1_limit_show, humidity1_limit_store, + limit_min_hyst); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, temp1_alarm_show, NULL, 0); +static SENSOR_DEVICE_ATTR(humidity1_alarm, S_IRUGO, humidity1_alarm_show, + NULL, 0); +static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, + update_interval_show, update_interval_store, 0); + +static struct attribute *sht3x_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_humidity1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_humidity1_max.dev_attr.attr, + &sensor_dev_attr_humidity1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, + &sensor_dev_attr_humidity1_min.dev_attr.attr, + &sensor_dev_attr_humidity1_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_humidity1_alarm.dev_attr.attr, + &sensor_dev_attr_update_interval.dev_attr.attr, + NULL +}; + +static struct attribute *sts3x_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL +}; + +ATTRIBUTE_GROUPS(sht3x); +ATTRIBUTE_GROUPS(sts3x); + +static int sht3x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct sht3x_data *data; + struct device *hwmon_dev; + struct i2c_adapter *adap = client->adapter; + struct device *dev = &client->dev; + const struct attribute_group **attribute_groups; + + /* + * we require full i2c support since the sht3x uses multi-byte read and + * writes as well as multi-byte commands which are not supported by + * the smbus protocol + */ + if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) + return -ENODEV; + + ret = i2c_master_send(client, sht3x_cmd_clear_status_reg, + SHT3X_CMD_LENGTH); + if (ret != SHT3X_CMD_LENGTH) + return ret < 0 ? ret : -ENODEV; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->setup.blocking_io = false; + data->setup.high_precision = true; + data->mode = 0; + data->last_update = 0; + data->client = client; + crc8_populate_msb(sht3x_crc8_table, SHT3X_CRC8_POLYNOMIAL); + + if (client->dev.platform_data) + data->setup = *(struct sht3x_platform_data *)dev->platform_data; + + sht3x_select_command(data); + + mutex_init(&data->i2c_lock); + mutex_init(&data->data_lock); + + ret = limits_update(data); + if (ret) + return ret; + + if (id->driver_data == sts3x) + attribute_groups = sts3x_groups; + else + attribute_groups = sht3x_groups; + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, + data, + attribute_groups); + + if (IS_ERR(hwmon_dev)) + dev_dbg(dev, "unable to register hwmon device\n"); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +/* device ID table */ +static const struct i2c_device_id sht3x_ids[] = { + {"sht3x", sht3x}, + {"sts3x", sts3x}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, sht3x_ids); + +static struct i2c_driver sht3x_i2c_driver = { + .driver.name = "sht3x", + .probe = sht3x_probe, + .id_table = sht3x_ids, +}; + +module_i2c_driver(sht3x_i2c_driver); + +MODULE_AUTHOR("David Frey "); +MODULE_AUTHOR("Pascal Sachs "); +MODULE_DESCRIPTION("Sensirion SHT3x humidity and temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/sht3x.h b/include/linux/platform_data/sht3x.h new file mode 100644 index 000000000000..2e5eea358194 --- /dev/null +++ b/include/linux/platform_data/sht3x.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 Sensirion AG, Switzerland + * Author: David Frey + * Author: Pascal Sachs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SHT3X_H_ +#define __SHT3X_H_ + +struct sht3x_platform_data { + bool blocking_io; + bool high_precision; +}; +#endif /* __SHT3X_H_ */ -- cgit v1.2.3 From c35d9292fee0474a1a037f75b0b85af32200c76f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 18 Apr 2016 23:06:48 +0200 Subject: of: Add a new macro to declare_of for one parameter function returning a value The macro OF_DECLARE_1 expect a void (*func)(struct device_node *) while the OF_DECLARE_2 expect a int (*func)(struct device_node *, struct device_node *). The second one allows to pass an init function returning a value, which make possible to call the functions in the table and check the return value in order to catch at a higher level the errors and handle them from there instead of doing a panic in each driver (well at least this is the case for the clkevt). Unfortunately the OF_DECLARE_1 does not allow that and that lead to some code duplication and crappyness in the drivers. The OF_DECLARE_1 is used by all the clk drivers and the clocksource/clockevent drivers. It is not possible to do the change in one shot as we have to change all the init functions. The OF_DECLARE_2 specifies an init function prototype with two parameters with the node and its parent. The latter won't be used, ever, in the timer drivers. Introduce a OF_DECLARE_1_RET macro to be used, and hopefully we can smoothly and iteratively change the users of OF_DECLARE_1 to use the new macro instead. Signed-off-by: Daniel Lezcano Acked-by: Rob Herring --- include/linux/of.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/of.h b/include/linux/of.h index c7292e8ea080..552943d37f40 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -1009,10 +1009,13 @@ static inline int of_get_available_child_count(const struct device_node *np) #endif typedef int (*of_init_fn_2)(struct device_node *, struct device_node *); +typedef int (*of_init_fn_1_ret)(struct device_node *); typedef void (*of_init_fn_1)(struct device_node *); #define OF_DECLARE_1(table, name, compat, fn) \ _OF_DECLARE(table, name, compat, fn, of_init_fn_1) +#define OF_DECLARE_1_RET(table, name, compat, fn) \ + _OF_DECLARE(table, name, compat, fn, of_init_fn_1_ret) #define OF_DECLARE_2(table, name, compat, fn) \ _OF_DECLARE(table, name, compat, fn, of_init_fn_2) -- cgit v1.2.3 From b7c4db861683af5fc50ac3cb3751cf847d765211 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 31 May 2016 16:25:59 +0200 Subject: clocksource/drivers/clksrc-probe: Introduce init functions with return code Currently, the clksrc-probe is not able to handle any error from the init functions. There are different issues with the current code: - the code is duplicated in the init functions by writing error - every driver tends to panic in its own init function - counting the number of clocksources is not reliable This patch adds another table to store the functions returning an error. The table is temporary while we convert all the drivers to return an error and will disappear. Signed-off-by: Daniel Lezcano --- drivers/clocksource/clksrc-probe.c | 22 ++++++++++++++++++++++ include/asm-generic/vmlinux.lds.h | 2 ++ include/linux/clocksource.h | 3 +++ 3 files changed, 27 insertions(+) (limited to 'include/linux') diff --git a/drivers/clocksource/clksrc-probe.c b/drivers/clocksource/clksrc-probe.c index 7cb6c923a836..5fa6a555b35c 100644 --- a/drivers/clocksource/clksrc-probe.c +++ b/drivers/clocksource/clksrc-probe.c @@ -20,16 +20,22 @@ #include extern struct of_device_id __clksrc_of_table[]; +extern struct of_device_id __clksrc_ret_of_table[]; static const struct of_device_id __clksrc_of_table_sentinel __used __section(__clksrc_of_table_end); +static const struct of_device_id __clksrc_ret_of_table_sentinel + __used __section(__clksrc_ret_of_table_end); + void __init clocksource_probe(void) { struct device_node *np; const struct of_device_id *match; of_init_fn_1 init_func; + of_init_fn_1_ret init_func_ret; unsigned clocksources = 0; + int ret; for_each_matching_node_and_match(np, __clksrc_of_table, &match) { if (!of_device_is_available(np)) @@ -40,6 +46,22 @@ void __init clocksource_probe(void) clocksources++; } + for_each_matching_node_and_match(np, __clksrc_ret_of_table, &match) { + if (!of_device_is_available(np)) + continue; + + init_func_ret = match->data; + + ret = init_func_ret(np); + if (ret) { + pr_err("Failed to initialize '%s': %d", + of_node_full_name(np), ret); + continue; + } + + clocksources++; + } + clocksources += acpi_probe_device_table(clksrc); if (!clocksources) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6a67ab94b553..8c6c626285c0 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -173,6 +173,7 @@ *(__##name##_of_table_end) #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) +#define CLKSRC_RET_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc_ret) #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) #define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) #define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) @@ -531,6 +532,7 @@ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ CLKSRC_OF_TABLES() \ + CLKSRC_RET_OF_TABLES() \ IOMMU_OF_TABLES() \ CPU_METHOD_OF_TABLES() \ CPUIDLE_METHOD_OF_TABLES() \ diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 44a1aff22566..15c3839850f4 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -246,6 +246,9 @@ extern int clocksource_i8253_init(void); #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ OF_DECLARE_1(clksrc, name, compat, fn) +#define CLOCKSOURCE_OF_DECLARE_RET(name, compat, fn) \ + OF_DECLARE_1_RET(clksrc_ret, name, compat, fn) + #ifdef CONFIG_CLKSRC_PROBE extern void clocksource_probe(void); #else -- cgit v1.2.3 From 177cf6e52b0a1a382b9892d3cc9aafd6e7c5943f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 7 Jun 2016 00:27:44 +0200 Subject: clocksources: Switch back to the clksrc table All the clocksource drivers's init function are now converted to return an error code. CLOCKSOURCE_OF_DECLARE is no longer used as well as the clksrc-of table. Let's convert back the names: - CLOCKSOURCE_OF_DECLARE_RET => CLOCKSOURCE_OF_DECLARE - clksrc-of-ret => clksrc-of Signed-off-by: Daniel Lezcano For exynos_mct and samsung_pwm_timer: Acked-by: Krzysztof Kozlowski For arch/arc: Acked-by: Vineet Gupta For mediatek driver: Acked-by: Matthias Brugger For the Rockchip-part Acked-by: Heiko Stuebner For STi : Acked-by: Patrice Chotard For the mps2-timer.c and versatile.c changes: Acked-by: Liviu Dudau For the OXNAS part : Acked-by: Neil Armstrong For LPC32xx driver: Acked-by: Sylvain Lemieux For Broadcom Kona timer change: Acked-by: Ray Jui For Sun4i and Sun5i: Acked-by: Chen-Yu Tsai For Meson6: Acked-by: Carlo Caione For Keystone: Acked-by: Santosh Shilimkar For NPS: Acked-by: Noam Camus For bcm2835: Acked-by: Eric Anholt --- arch/arc/kernel/time.c | 6 +++--- arch/arm/kernel/smp_twd.c | 6 +++--- arch/microblaze/kernel/timer.c | 2 +- arch/mips/ralink/cevt-rt3352.c | 2 +- arch/nios2/kernel/time.c | 2 +- drivers/clocksource/arm_arch_timer.c | 6 +++--- drivers/clocksource/arm_global_timer.c | 2 +- drivers/clocksource/armv7m_systick.c | 2 +- drivers/clocksource/asm9260_timer.c | 2 +- drivers/clocksource/bcm2835_timer.c | 2 +- drivers/clocksource/bcm_kona_timer.c | 4 ++-- drivers/clocksource/cadence_ttc_timer.c | 2 +- drivers/clocksource/clksrc-dbx500-prcmu.c | 2 +- drivers/clocksource/clksrc-probe.c | 14 -------------- drivers/clocksource/clksrc_st_lpc.c | 2 +- drivers/clocksource/clps711x-timer.c | 2 +- drivers/clocksource/dw_apb_timer_of.c | 8 ++++---- drivers/clocksource/exynos_mct.c | 4 ++-- drivers/clocksource/fsl_ftm_timer.c | 2 +- drivers/clocksource/h8300_timer16.c | 2 +- drivers/clocksource/h8300_timer8.c | 2 +- drivers/clocksource/h8300_tpu.c | 2 +- drivers/clocksource/meson6_timer.c | 2 +- drivers/clocksource/mips-gic-timer.c | 2 +- drivers/clocksource/moxart_timer.c | 2 +- drivers/clocksource/mps2-timer.c | 2 +- drivers/clocksource/mtk_timer.c | 2 +- drivers/clocksource/mxs_timer.c | 2 +- drivers/clocksource/nomadik-mtu.c | 2 +- drivers/clocksource/pxa_timer.c | 2 +- drivers/clocksource/qcom-timer.c | 4 ++-- drivers/clocksource/rockchip_timer.c | 8 ++++---- drivers/clocksource/samsung_pwm_timer.c | 8 ++++---- drivers/clocksource/sun4i_timer.c | 2 +- drivers/clocksource/tango_xtal.c | 2 +- drivers/clocksource/tegra20_timer.c | 4 ++-- drivers/clocksource/time-armada-370-xp.c | 6 +++--- drivers/clocksource/time-efm32.c | 4 ++-- drivers/clocksource/time-lpc32xx.c | 2 +- drivers/clocksource/time-orion.c | 2 +- drivers/clocksource/time-pistachio.c | 2 +- drivers/clocksource/timer-atlas7.c | 2 +- drivers/clocksource/timer-atmel-pit.c | 2 +- drivers/clocksource/timer-atmel-st.c | 2 +- drivers/clocksource/timer-digicolor.c | 2 +- drivers/clocksource/timer-imx-gpt.c | 24 ++++++++++++------------ drivers/clocksource/timer-integrator-ap.c | 2 +- drivers/clocksource/timer-keystone.c | 2 +- drivers/clocksource/timer-nps.c | 4 ++-- drivers/clocksource/timer-oxnas-rps.c | 4 ++-- drivers/clocksource/timer-prima2.c | 2 +- drivers/clocksource/timer-sp804.c | 4 ++-- drivers/clocksource/timer-stm32.c | 2 +- drivers/clocksource/timer-sun5i.c | 4 ++-- drivers/clocksource/timer-ti-32k.c | 2 +- drivers/clocksource/timer-u300.c | 2 +- drivers/clocksource/versatile.c | 4 ++-- drivers/clocksource/vf_pit_timer.c | 2 +- drivers/clocksource/vt8500_timer.c | 2 +- drivers/clocksource/zevio-timer.c | 2 +- include/asm-generic/vmlinux.lds.h | 2 -- include/linux/clocksource.h | 5 +---- 62 files changed, 98 insertions(+), 117 deletions(-) (limited to 'include/linux') diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 09de669f4ff0..98f22d2eb563 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c @@ -130,7 +130,7 @@ static int __init arc_cs_setup_gfrc(struct device_node *node) return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); } -CLOCKSOURCE_OF_DECLARE_RET(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); +CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); #endif @@ -192,7 +192,7 @@ static int __init arc_cs_setup_rtc(struct device_node *node) return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); } -CLOCKSOURCE_OF_DECLARE_RET(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); +CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); #endif @@ -379,7 +379,7 @@ static int __init arc_of_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(arc_clkevt, "snps,arc-timer", arc_of_timer_init); +CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); /* * Called from start_kernel() - boot CPU only diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 2b24be41d9cc..b6ec65e68009 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -412,7 +412,7 @@ out: WARN(err, "twd_local_timer_of_register failed (%d)\n", err); return err; } -CLOCKSOURCE_OF_DECLARE_RET(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); -CLOCKSOURCE_OF_DECLARE_RET(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); -CLOCKSOURCE_OF_DECLARE_RET(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); +CLOCKSOURCE_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); #endif diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 7f35e7b50f1b..5bbf38b916ef 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -332,5 +332,5 @@ static int __init xilinx_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(xilinx_timer, "xlnx,xps-timer-1.00.a", +CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a", xilinx_timer_init); diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index f2d3c7908626..f24eee04e16a 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -150,4 +150,4 @@ static int __init ralink_systick_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(systick, "ralink,cevt-systick", ralink_systick_init); +CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c index b75e40e17963..d9563ddb337e 100644 --- a/arch/nios2/kernel/time.c +++ b/arch/nios2/kernel/time.c @@ -352,4 +352,4 @@ void __init time_init(void) clocksource_probe(); } -CLOCKSOURCE_OF_DECLARE_RET(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); +CLOCKSOURCE_OF_DECLARE(nios2_timer, ALTR_TIMER_COMPATIBLE, nios2_time_init); diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index d0cda68e2c41..9e33309ad2ea 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -784,8 +784,8 @@ static int __init arch_timer_of_init(struct device_node *np) return arch_timer_init(); } -CLOCKSOURCE_OF_DECLARE_RET(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); -CLOCKSOURCE_OF_DECLARE_RET(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); +CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); static int __init arch_timer_mem_init(struct device_node *np) { @@ -868,7 +868,7 @@ out: of_node_put(best_frame); return ret; } -CLOCKSOURCE_OF_DECLARE_RET(armv7_arch_timer_mem, "arm,armv7-timer-mem", +CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", arch_timer_mem_init); #ifdef CONFIG_ACPI diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index 40104fc93f24..2a9ceb6e93f9 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -358,5 +358,5 @@ out_unmap: } /* Only tested on r2p2 and r3p0 */ -CLOCKSOURCE_OF_DECLARE_RET(arm_gt, "arm,cortex-a9-global-timer", +CLOCKSOURCE_OF_DECLARE(arm_gt, "arm,cortex-a9-global-timer", global_timer_of_register); diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c index 2b55410edaf6..e93af1f6a36c 100644 --- a/drivers/clocksource/armv7m_systick.c +++ b/drivers/clocksource/armv7m_systick.c @@ -81,5 +81,5 @@ out_unmap: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(arm_systick, "arm,armv7m-systick", +CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick", system_timer_of_register); diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c index d113c0275d06..1ba871b7fe11 100644 --- a/drivers/clocksource/asm9260_timer.c +++ b/drivers/clocksource/asm9260_timer.c @@ -238,5 +238,5 @@ static int __init asm9260_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(asm9260_timer, "alphascale,asm9260-timer", +CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer", asm9260_timer_init); diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 2dcf896b5381..e71acf231c89 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -142,5 +142,5 @@ static int __init bcm2835_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(bcm2835, "brcm,bcm2835-system-timer", +CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer", bcm2835_timer_init); diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index c251aa68993f..86f87be3d80f 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -195,9 +195,9 @@ static int __init kona_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(brcm_kona, "brcm,kona-timer", kona_timer_init); +CLOCKSOURCE_OF_DECLARE(brcm_kona, "brcm,kona-timer", kona_timer_init); /* * bcm,kona-timer is deprecated by brcm,kona-timer * being kept here for driver compatibility */ -CLOCKSOURCE_OF_DECLARE_RET(bcm_kona, "bcm,kona-timer", kona_timer_init); +CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer", kona_timer_init); diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index e2e76311dde2..388a77bdc39a 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -539,4 +539,4 @@ static int __init ttc_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(ttc, "cdns,ttc", ttc_timer_init); +CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c index 5a59d2953388..77a365f573d7 100644 --- a/drivers/clocksource/clksrc-dbx500-prcmu.c +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c @@ -86,5 +86,5 @@ static int __init clksrc_dbx500_prcmu_init(struct device_node *node) #endif return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K); } -CLOCKSOURCE_OF_DECLARE_RET(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4", +CLOCKSOURCE_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4", clksrc_dbx500_prcmu_init); diff --git a/drivers/clocksource/clksrc-probe.c b/drivers/clocksource/clksrc-probe.c index 5fa6a555b35c..bc62be97f0a8 100644 --- a/drivers/clocksource/clksrc-probe.c +++ b/drivers/clocksource/clksrc-probe.c @@ -20,19 +20,14 @@ #include extern struct of_device_id __clksrc_of_table[]; -extern struct of_device_id __clksrc_ret_of_table[]; static const struct of_device_id __clksrc_of_table_sentinel __used __section(__clksrc_of_table_end); -static const struct of_device_id __clksrc_ret_of_table_sentinel - __used __section(__clksrc_ret_of_table_end); - void __init clocksource_probe(void) { struct device_node *np; const struct of_device_id *match; - of_init_fn_1 init_func; of_init_fn_1_ret init_func_ret; unsigned clocksources = 0; int ret; @@ -41,15 +36,6 @@ void __init clocksource_probe(void) if (!of_device_is_available(np)) continue; - init_func = match->data; - init_func(np); - clocksources++; - } - - for_each_matching_node_and_match(np, __clksrc_ret_of_table, &match) { - if (!of_device_is_available(np)) - continue; - init_func_ret = match->data; ret = init_func_ret(np); diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c index c9022a9eb593..03cc49217bb4 100644 --- a/drivers/clocksource/clksrc_st_lpc.c +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -132,4 +132,4 @@ static int __init st_clksrc_of_register(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(ddata, "st,stih407-lpc", st_clksrc_of_register); +CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c index 3b6619808442..84aed78261e4 100644 --- a/drivers/clocksource/clps711x-timer.c +++ b/drivers/clocksource/clps711x-timer.c @@ -119,5 +119,5 @@ static int __init clps711x_timer_init(struct device_node *np) return -EINVAL; } } -CLOCKSOURCE_OF_DECLARE_RET(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); +CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); #endif diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index 4985a2cadad9..aee6c0d39a7c 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -167,7 +167,7 @@ static int __init dw_apb_timer_init(struct device_node *timer) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE(pc3x2_timer, "picochip,pc3x2-timer", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE(apb_timer_osc, "snps,dw-apb-timer-osc", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE(apb_timer_sp, "snps,dw-apb-timer-sp", dw_apb_timer_init); +CLOCKSOURCE_OF_DECLARE(apb_timer, "snps,dw-apb-timer", dw_apb_timer_init); diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index f6caed0c36ae..0d18dd4b3bd2 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -627,5 +627,5 @@ static int __init mct_init_ppi(struct device_node *np) { return mct_init_dt(np, MCT_INT_PPI); } -CLOCKSOURCE_OF_DECLARE_RET(exynos4210, "samsung,exynos4210-mct", mct_init_spi); -CLOCKSOURCE_OF_DECLARE_RET(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); +CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi); +CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 9ad4ca32fb2d..738515b89073 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -369,4 +369,4 @@ err: kfree(priv); return ret; } -CLOCKSOURCE_OF_DECLARE_RET(flextimer, "fsl,ftm-timer", ftm_timer_init); +CLOCKSOURCE_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init); diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c index 9d99fc85ffad..07d9d5be9054 100644 --- a/drivers/clocksource/h8300_timer16.c +++ b/drivers/clocksource/h8300_timer16.c @@ -187,5 +187,5 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(h8300_16bit, "renesas,16bit-timer", +CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init); diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index 0292a1907619..546bb180f5a4 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -215,4 +215,4 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); +CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c index 4faf718b30f3..7bdf1991c847 100644 --- a/drivers/clocksource/h8300_tpu.c +++ b/drivers/clocksource/h8300_tpu.c @@ -154,4 +154,4 @@ free_clk: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(h8300_tpu, "renesas,tpu", h8300_tpu_init); +CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c index 3a6e78f62b19..52af591a9fc7 100644 --- a/drivers/clocksource/meson6_timer.c +++ b/drivers/clocksource/meson6_timer.c @@ -174,5 +174,5 @@ static int __init meson6_timer_init(struct device_node *node) 1, 0xfffe); return 0; } -CLOCKSOURCE_OF_DECLARE_RET(meson6, "amlogic,meson6-timer", +CLOCKSOURCE_OF_DECLARE(meson6, "amlogic,meson6-timer", meson6_timer_init); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index b164b8712f39..1572c7a778ab 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -222,5 +222,5 @@ static void __init gic_clocksource_of_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(mips_gic_timer, "mti,gic-timer", +CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c index b9c30cd035bf..841454417acd 100644 --- a/drivers/clocksource/moxart_timer.c +++ b/drivers/clocksource/moxart_timer.c @@ -178,4 +178,4 @@ static int __init moxart_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(moxart, "moxa,moxart-timer", moxart_timer_init); +CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init); diff --git a/drivers/clocksource/mps2-timer.c b/drivers/clocksource/mps2-timer.c index c303fa9ba87f..3e4431ed9aa9 100644 --- a/drivers/clocksource/mps2-timer.c +++ b/drivers/clocksource/mps2-timer.c @@ -274,4 +274,4 @@ static int __init mps2_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(mps2_timer, "arm,mps2-timer", mps2_timer_init); +CLOCKSOURCE_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init); diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index 432a2c0884a9..90659493c59c 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -265,4 +265,4 @@ err_kzalloc: return -EINVAL; } -CLOCKSOURCE_OF_DECLARE_RET(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); +CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index 17b9d1991178..630a8d3904bb 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -295,4 +295,4 @@ static int __init mxs_timer_init(struct device_node *np) return setup_irq(irq, &mxs_timer_irq); } -CLOCKSOURCE_OF_DECLARE_RET(mxs, "fsl,timrot", mxs_timer_init); +CLOCKSOURCE_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init); diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index d2be5b3e0318..3c124d1ca600 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -284,5 +284,5 @@ static int __init nmdk_timer_of_init(struct device_node *node) return nmdk_timer_init(base, irq, pclk, clk); } -CLOCKSOURCE_OF_DECLARE_RET(nomadik_mtu, "st,nomadik-mtu", +CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "st,nomadik-mtu", nmdk_timer_of_init); diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index 59af75cc4c74..937e10b84d58 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -213,7 +213,7 @@ static int __init pxa_timer_dt_init(struct device_node *np) return pxa_timer_common_init(irq, clk_get_rate(clk)); } -CLOCKSOURCE_OF_DECLARE_RET(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); +CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); /* * Legacy timer init for non device-tree boards. diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index 79f73bddc5f4..662576339049 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -273,5 +273,5 @@ static int __init msm_dt_timer_init(struct device_node *np) return msm_timer_init(freq, 32, irq, !!percpu_offset); } -CLOCKSOURCE_OF_DECLARE_RET(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(scss_timer, "qcom,scss-timer", msm_dt_timer_init); +CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); +CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index 85aee6953944..23e267acba25 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -205,7 +205,7 @@ static int __init rk3399_timer_init(struct device_node *np) return rk_timer_init(np, TIMER_CONTROL_REG3399); } -CLOCKSOURCE_OF_DECLARE_RET(rk3288_timer, "rockchip,rk3288-timer", - rk3288_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(rk3399_timer, "rockchip,rk3399-timer", - rk3399_timer_init); +CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", + rk3288_timer_init); +CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", + rk3399_timer_init); diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 27a9797e8187..54565bd0093b 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -466,7 +466,7 @@ static int __init s3c2410_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s3c24xx_variant); } -CLOCKSOURCE_OF_DECLARE_RET(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE(s3c2410_pwm, "samsung,s3c2410-pwm", s3c2410_pwm_clocksource_init); static const struct samsung_pwm_variant s3c64xx_variant = { .bits = 32, @@ -479,7 +479,7 @@ static int __init s3c64xx_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s3c64xx_variant); } -CLOCKSOURCE_OF_DECLARE_RET(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE(s3c6400_pwm, "samsung,s3c6400-pwm", s3c64xx_pwm_clocksource_init); static const struct samsung_pwm_variant s5p64x0_variant = { .bits = 32, @@ -492,7 +492,7 @@ static int __init s5p64x0_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s5p64x0_variant); } -CLOCKSOURCE_OF_DECLARE_RET(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE(s5p6440_pwm, "samsung,s5p6440-pwm", s5p64x0_pwm_clocksource_init); static const struct samsung_pwm_variant s5p_variant = { .bits = 32, @@ -505,5 +505,5 @@ static int __init s5p_pwm_clocksource_init(struct device_node *np) { return samsung_pwm_alloc(np, &s5p_variant); } -CLOCKSOURCE_OF_DECLARE_RET(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); +CLOCKSOURCE_OF_DECLARE(s5pc100_pwm, "samsung,s5pc100-pwm", s5p_pwm_clocksource_init); #endif diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 445373091fe8..97669ee4df2a 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -226,5 +226,5 @@ static int __init sun4i_timer_init(struct device_node *node) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(sun4i, "allwinner,sun4i-a10-timer", +CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer", sun4i_timer_init); diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c index 7dc716cc976f..12fcef8cf2d3 100644 --- a/drivers/clocksource/tango_xtal.c +++ b/drivers/clocksource/tango_xtal.c @@ -53,4 +53,4 @@ static int __init tango_clocksource_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(tango, "sigma,tick-counter", tango_clocksource_init); +CLOCKSOURCE_OF_DECLARE(tango, "sigma,tick-counter", tango_clocksource_init); diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 543c37e3a62c..f960891aa04e 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -237,7 +237,7 @@ static int __init tegra20_init_timer(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); +CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); static int __init tegra20_init_rtc(struct device_node *np) { @@ -261,4 +261,4 @@ static int __init tegra20_init_rtc(struct device_node *np) return register_persistent_clock(NULL, tegra_read_persistent_clock64); } -CLOCKSOURCE_OF_DECLARE_RET(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); +CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index bc4ab48d4048..a4e59239f28e 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -371,7 +371,7 @@ static int __init armada_xp_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE_RET(armada_xp, "marvell,armada-xp-timer", +CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", armada_xp_timer_init); static int __init armada_375_timer_init(struct device_node *np) @@ -409,7 +409,7 @@ static int __init armada_375_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE_RET(armada_375, "marvell,armada-375-timer", +CLOCKSOURCE_OF_DECLARE(armada_375, "marvell,armada-375-timer", armada_375_timer_init); static int __init armada_370_timer_init(struct device_node *np) @@ -432,5 +432,5 @@ static int __init armada_370_timer_init(struct device_node *np) return armada_370_xp_timer_common_init(np); } -CLOCKSOURCE_OF_DECLARE_RET(armada_370, "marvell,armada-370-timer", +CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", armada_370_timer_init); diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/time-efm32.c index 6e2f79fd6ad0..5ac344b383e1 100644 --- a/drivers/clocksource/time-efm32.c +++ b/drivers/clocksource/time-efm32.c @@ -283,5 +283,5 @@ static int __init efm32_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(efm32compat, "efm32,timer", efm32_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(efm32, "energymicro,efm32-timer", efm32_timer_init); +CLOCKSOURCE_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init); +CLOCKSOURCE_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init); diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c index cb5b8665ff82..9649cfdb9213 100644 --- a/drivers/clocksource/time-lpc32xx.c +++ b/drivers/clocksource/time-lpc32xx.c @@ -311,4 +311,4 @@ static int __init lpc32xx_timer_init(struct device_node *np) return ret; } -CLOCKSOURCE_OF_DECLARE_RET(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); +CLOCKSOURCE_OF_DECLARE(lpc32xx_timer, "nxp,lpc3220-timer", lpc32xx_timer_init); diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index 5fdeb5dcc4cf..a28f496e97cf 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c @@ -167,4 +167,4 @@ static int __init orion_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(orion_timer, "marvell,orion-timer", orion_timer_init); +CLOCKSOURCE_OF_DECLARE(orion_timer, "marvell,orion-timer", orion_timer_init); diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c index adaaec5e9abd..a7d9a08e4b0e 100644 --- a/drivers/clocksource/time-pistachio.c +++ b/drivers/clocksource/time-pistachio.c @@ -214,5 +214,5 @@ static int __init pistachio_clksrc_of_init(struct device_node *node) sched_clock_register(pistachio_read_sched_clock, 32, rate); return clocksource_register_hz(&pcs_gpt.cs, rate); } -CLOCKSOURCE_OF_DECLARE_RET(pistachio_gptimer, "img,pistachio-gptimer", +CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", pistachio_clksrc_of_init); diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c index 7b1a0071a211..90f8fbc154a4 100644 --- a/drivers/clocksource/timer-atlas7.c +++ b/drivers/clocksource/timer-atlas7.c @@ -304,4 +304,4 @@ static int __init sirfsoc_of_timer_init(struct device_node *np) return sirfsoc_atlas7_timer_init(np); } -CLOCKSOURCE_OF_DECLARE_RET(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); +CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init); diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index ffaca7c2c996..1ffac0cb0cb7 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -270,5 +270,5 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) return at91sam926x_pit_common_init(data); } -CLOCKSOURCE_OF_DECLARE_RET(at91sam926x_pit, "atmel,at91sam9260-pit", +CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit", at91sam926x_pit_dt_init); diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c index e9331d36965b..e90ab5b63a90 100644 --- a/drivers/clocksource/timer-atmel-st.c +++ b/drivers/clocksource/timer-atmel-st.c @@ -260,5 +260,5 @@ static int __init atmel_st_timer_init(struct device_node *node) /* register clocksource */ return clocksource_register_hz(&clk32k, sclk_rate); } -CLOCKSOURCE_OF_DECLARE_RET(atmel_st_timer, "atmel,at91rm9200-st", +CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st", atmel_st_timer_init); diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c index b929061ebe56..10318cc99c0e 100644 --- a/drivers/clocksource/timer-digicolor.c +++ b/drivers/clocksource/timer-digicolor.c @@ -202,5 +202,5 @@ static int __init digicolor_timer_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(conexant_digicolor, "cnxt,cx92755-timer", +CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer", digicolor_timer_init); diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index d5640a747078..f595460bfc58 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -545,15 +545,15 @@ static int __init imx6dl_timer_init_dt(struct device_node *np) return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); } -CLOCKSOURCE_OF_DECLARE_RET(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); -CLOCKSOURCE_OF_DECLARE_RET(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt); +CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt); diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index 675faceab5d6..df6e672afc04 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -232,5 +232,5 @@ static int __init integrator_ap_timer_init_of(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(integrator_ap_timer, "arm,integrator-timer", +CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", integrator_ap_timer_init_of); diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c index 4199823b2ec9..ab68a47ab3b4 100644 --- a/drivers/clocksource/timer-keystone.c +++ b/drivers/clocksource/timer-keystone.c @@ -226,5 +226,5 @@ err: return error; } -CLOCKSOURCE_OF_DECLARE_RET(keystone_timer, "ti,keystone-timer", +CLOCKSOURCE_OF_DECLARE(keystone_timer, "ti,keystone-timer", keystone_timer_init); diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c index b5c7b2bd77bd..70c149af8ee0 100644 --- a/drivers/clocksource/timer-nps.c +++ b/drivers/clocksource/timer-nps.c @@ -96,5 +96,5 @@ static int __init nps_timer_init(struct device_node *node) return nps_setup_clocksource(node, clk); } -CLOCKSOURCE_OF_DECLARE_RET(ezchip_nps400_clksrc, "ezchip,nps400-timer", - nps_timer_init); +CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", + nps_timer_init); diff --git a/drivers/clocksource/timer-oxnas-rps.c b/drivers/clocksource/timer-oxnas-rps.c index 0d99f40ee757..bd887e2a8cf8 100644 --- a/drivers/clocksource/timer-oxnas-rps.c +++ b/drivers/clocksource/timer-oxnas-rps.c @@ -293,5 +293,5 @@ err_alloc: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(ox810se_rps, - "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); +CLOCKSOURCE_OF_DECLARE(ox810se_rps, + "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index 7b1084d0b45e..dae8a66301d7 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -246,5 +246,5 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(sirfsoc_prima2_timer, +CLOCKSOURCE_OF_DECLARE(sirfsoc_prima2_timer, "sirf,prima2-tick", sirfsoc_prima2_timer_init); diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index 3dc47efc9298..d07863388e05 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -287,7 +287,7 @@ err: iounmap(base); return ret; } -CLOCKSOURCE_OF_DECLARE_RET(sp804, "arm,sp804", sp804_of_init); +CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); static int __init integrator_cp_of_init(struct device_node *np) { @@ -335,4 +335,4 @@ err: iounmap(base); return ret; } -CLOCKSOURCE_OF_DECLARE_RET(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); +CLOCKSOURCE_OF_DECLARE(intcp, "arm,integrator-cp-timer", integrator_cp_of_init); diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index d5bf352905c8..1b2574c4fb97 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -187,4 +187,4 @@ err_clk_get: return ret; } -CLOCKSOURCE_OF_DECLARE_RET(stm32, "st,stm32-timer", stm32_clockevent_init); +CLOCKSOURCE_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init); diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index f0a3ffbab431..c184eb84101e 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -346,7 +346,7 @@ static int __init sun5i_timer_init(struct device_node *node) return sun5i_setup_clockevent(node, timer_base, clk, irq); } -CLOCKSOURCE_OF_DECLARE_RET(sun5i_a13, "allwinner,sun5i-a13-hstimer", +CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer", sun5i_timer_init); -CLOCKSOURCE_OF_DECLARE_RET(sun7i_a20, "allwinner,sun7i-a20-hstimer", +CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer", sun5i_timer_init); diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c index e4ad3c6e03f9..92b7e390f6c8 100644 --- a/drivers/clocksource/timer-ti-32k.c +++ b/drivers/clocksource/timer-ti-32k.c @@ -124,5 +124,5 @@ static int __init ti_32k_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(ti_32k_timer, "ti,omap-counter32k", +CLOCKSOURCE_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k", ti_32k_timer_init); diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c index a6a0dec41faa..704e40c6f151 100644 --- a/drivers/clocksource/timer-u300.c +++ b/drivers/clocksource/timer-u300.c @@ -458,5 +458,5 @@ static int __init u300_timer_init_of(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(u300_timer, "stericsson,u300-apptimer", +CLOCKSOURCE_OF_DECLARE(u300_timer, "stericsson,u300-apptimer", u300_timer_init_of); diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c index 8daeffac300b..220b490a8142 100644 --- a/drivers/clocksource/versatile.c +++ b/drivers/clocksource/versatile.c @@ -38,7 +38,7 @@ static int __init versatile_sched_clock_init(struct device_node *node) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(vexpress, "arm,vexpress-sysreg", +CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg", versatile_sched_clock_init); -CLOCKSOURCE_OF_DECLARE_RET(versatile, "arm,versatile-sysreg", +CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg", versatile_sched_clock_init); diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c index ca4dff4d5684..55d8d8402d90 100644 --- a/drivers/clocksource/vf_pit_timer.c +++ b/drivers/clocksource/vf_pit_timer.c @@ -201,4 +201,4 @@ static int __init pit_timer_init(struct device_node *np) return pit_clockevent_init(clk_rate, irq); } -CLOCKSOURCE_OF_DECLARE_RET(vf610, "fsl,vf610-pit", pit_timer_init); +CLOCKSOURCE_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 1bc8707b4f9d..b15069483fbd 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -165,4 +165,4 @@ static int __init vt8500_timer_init(struct device_node *np) return 0; } -CLOCKSOURCE_OF_DECLARE_RET(vt8500, "via,vt8500-timer", vt8500_timer_init); +CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c index cb4cf056d56d..9a53f5ef6157 100644 --- a/drivers/clocksource/zevio-timer.c +++ b/drivers/clocksource/zevio-timer.c @@ -215,4 +215,4 @@ static int __init zevio_timer_init(struct device_node *node) return zevio_timer_add(node); } -CLOCKSOURCE_OF_DECLARE_RET(zevio_timer, "lsi,zevio-timer", zevio_timer_init); +CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_init); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 8c6c626285c0..6a67ab94b553 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -173,7 +173,6 @@ *(__##name##_of_table_end) #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) -#define CLKSRC_RET_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc_ret) #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) #define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) #define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) @@ -532,7 +531,6 @@ CLK_OF_TABLES() \ RESERVEDMEM_OF_TABLES() \ CLKSRC_OF_TABLES() \ - CLKSRC_RET_OF_TABLES() \ IOMMU_OF_TABLES() \ CPU_METHOD_OF_TABLES() \ CPUIDLE_METHOD_OF_TABLES() \ diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 15c3839850f4..08398182f56e 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -244,10 +244,7 @@ extern int clocksource_mmio_init(void __iomem *, const char *, extern int clocksource_i8253_init(void); #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ - OF_DECLARE_1(clksrc, name, compat, fn) - -#define CLOCKSOURCE_OF_DECLARE_RET(name, compat, fn) \ - OF_DECLARE_1_RET(clksrc_ret, name, compat, fn) + OF_DECLARE_1_RET(clksrc, name, compat, fn) #ifdef CONFIG_CLKSRC_PROBE extern void clocksource_probe(void); -- cgit v1.2.3 From b81ea968706bdb5c2f2af62c5700573a32ab310a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Thu, 2 Jun 2016 22:44:49 +0200 Subject: clk: Add missing clk_get_sys() stub When compiling with the COMPILE_TEST option set, the clps711x does not compile because of the clk_get_sys() noop stub missing. Signed-off-by: Daniel Lezcano Reviewed-by: Michael Turquette --- include/linux/clk.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/clk.h b/include/linux/clk.h index 0df4a51e1a78..834179f3fa72 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -461,6 +461,10 @@ static inline struct clk *clk_get_parent(struct clk *clk) return NULL; } +static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) +{ + return NULL; +} #endif /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ -- cgit v1.2.3 From a5e4bd991362223346e1d3561e61d7a25797fe25 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 24 Jun 2016 11:24:08 +0200 Subject: of_mdio: select fixed phy support unconditionally Calling the fixed-phy functions when CONFIG_FIXED_PHY=m as a previous change tried cannot work if the caller is in built-in code: drivers/of/built-in.o: In function `of_phy_register_fixed_link': of_reserved_mem.c:(.text+0x85e0): undefined reference to `fixed_phy_register' Making of_mdio depend on 'FIXED_PHY || !FIXED_PHY' would solve this dependency by enforcing that OF_MDIO itself becomes a loadable module when FIXED_PHY=y, but that creates a different dependency as it breaks any built-in ethernet driver that uses of_mdio. Making FIXED_PHY a bool option also cannot work, since it depends on PHYLIB, which again is tristate. This version now uses 'select FIXED_PHY' to ensure that the fixed-phy portion of of_mdio is not optional. The main downside of this is a small increase in code size for cases that do not need fixed phy support, but it should avoid all of the link-time problems. Signed-off-by: Arnd Bergmann Fixes: d1bd330a229f ("of_mdio: Enable fixed PHY support if driver is a module") Acked-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/of/Kconfig | 1 + drivers/of/of_mdio.c | 2 -- include/linux/of_mdio.h | 8 ++------ 3 files changed, 3 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index b3bec3aaa45d..bc07ad30c9bf 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -74,6 +74,7 @@ config OF_NET config OF_MDIO def_tristate PHYLIB depends on PHYLIB + select FIXED_PHY help OpenFirmware MDIO bus (Ethernet PHY) accessors diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index de68707a99c7..e2b50bc12f23 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -361,7 +361,6 @@ struct phy_device *of_phy_attach(struct net_device *dev, } EXPORT_SYMBOL(of_phy_attach); -#if IS_ENABLED(CONFIG_FIXED_PHY) /* * of_phy_is_fixed_link() and of_phy_register_fixed_link() must * support two DT bindings: @@ -451,4 +450,3 @@ int of_phy_register_fixed_link(struct device_node *np) return -ENODEV; } EXPORT_SYMBOL(of_phy_register_fixed_link); -#endif diff --git a/include/linux/of_mdio.h b/include/linux/of_mdio.h index 6c8cb9aa4c00..4b04587d0441 100644 --- a/include/linux/of_mdio.h +++ b/include/linux/of_mdio.h @@ -25,6 +25,8 @@ struct phy_device *of_phy_attach(struct net_device *dev, extern struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np); extern int of_mdio_parse_addr(struct device *dev, const struct device_node *np); +extern int of_phy_register_fixed_link(struct device_node *np); +extern bool of_phy_is_fixed_link(struct device_node *np); #else /* CONFIG_OF */ static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) @@ -67,12 +69,6 @@ static inline int of_mdio_parse_addr(struct device *dev, { return -ENOSYS; } -#endif /* CONFIG_OF */ - -#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_FIXED_PHY) -extern int of_phy_register_fixed_link(struct device_node *np); -extern bool of_phy_is_fixed_link(struct device_node *np); -#else static inline int of_phy_register_fixed_link(struct device_node *np) { return -ENOSYS; -- cgit v1.2.3 From ebaac1736245e78109cd47d453a86a18dcfc94b8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 15 Jun 2016 15:09:28 +0200 Subject: context_tracking: move rcu_virt_note_context_switch out of kvm_host.h Make kvm_guest_{enter,exit} and __kvm_guest_{enter,exit} trivial wrappers around the code in context_tracking.h. Name the context_tracking.h functions consistently with what those for kernel<->user switch. Cc: Andy Lutomirski Cc: Peter Zijlstra Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Thomas Gleixner Reviewed-by: Rik van Riel Signed-off-by: Paolo Bonzini --- include/linux/context_tracking.h | 38 ++++++++++++++++++++++++++++++++++---- include/linux/kvm_host.h | 25 ++++--------------------- 2 files changed, 38 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h index d259274238db..ff4a32d24d56 100644 --- a/include/linux/context_tracking.h +++ b/include/linux/context_tracking.h @@ -84,7 +84,8 @@ static inline void context_tracking_init(void) { } #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN -static inline void guest_enter(void) +/* must be called with irqs disabled */ +static inline void guest_enter_irqoff(void) { if (vtime_accounting_cpu_enabled()) vtime_guest_enter(current); @@ -93,9 +94,19 @@ static inline void guest_enter(void) if (context_tracking_is_enabled()) __context_tracking_enter(CONTEXT_GUEST); + + /* KVM does not hold any references to rcu protected data when it + * switches CPU into a guest mode. In fact switching to a guest mode + * is very similar to exiting to userspace from rcu point of view. In + * addition CPU may stay in a guest mode for quite a long time (up to + * one time slice). Lets treat guest mode as quiescent state, just like + * we do with user-mode execution. + */ + if (!context_tracking_cpu_is_enabled()) + rcu_virt_note_context_switch(smp_processor_id()); } -static inline void guest_exit(void) +static inline void guest_exit_irqoff(void) { if (context_tracking_is_enabled()) __context_tracking_exit(CONTEXT_GUEST); @@ -107,7 +118,7 @@ static inline void guest_exit(void) } #else -static inline void guest_enter(void) +static inline void guest_enter_irqoff(void) { /* * This is running in ioctl context so its safe @@ -116,9 +127,10 @@ static inline void guest_enter(void) */ vtime_account_system(current); current->flags |= PF_VCPU; + rcu_virt_note_context_switch(smp_processor_id()); } -static inline void guest_exit(void) +static inline void guest_exit_irqoff(void) { /* Flush the guest cputime we spent on the guest */ vtime_account_system(current); @@ -126,4 +138,22 @@ static inline void guest_exit(void) } #endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */ +static inline void guest_enter(void) +{ + unsigned long flags; + + local_irq_save(flags); + guest_enter_irqoff(); + local_irq_restore(flags); +} + +static inline void guest_exit(void) +{ + unsigned long flags; + + local_irq_save(flags); + guest_exit_irqoff(); + local_irq_restore(flags); +} + #endif diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 0640ee92b978..ffff40522688 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -878,40 +878,23 @@ static inline void kvm_iommu_unmap_pages(struct kvm *kvm, /* must be called with irqs disabled */ static inline void __kvm_guest_enter(void) { - guest_enter(); - /* KVM does not hold any references to rcu protected data when it - * switches CPU into a guest mode. In fact switching to a guest mode - * is very similar to exiting to userspace from rcu point of view. In - * addition CPU may stay in a guest mode for quite a long time (up to - * one time slice). Lets treat guest mode as quiescent state, just like - * we do with user-mode execution. - */ - if (!context_tracking_cpu_is_enabled()) - rcu_virt_note_context_switch(smp_processor_id()); + guest_enter_irqoff(); } /* must be called with irqs disabled */ static inline void __kvm_guest_exit(void) { - guest_exit(); + guest_exit_irqoff(); } static inline void kvm_guest_enter(void) { - unsigned long flags; - - local_irq_save(flags); - __kvm_guest_enter(); - local_irq_restore(flags); + guest_enter(); } static inline void kvm_guest_exit(void) { - unsigned long flags; - - local_irq_save(flags); - __kvm_guest_exit(); - local_irq_restore(flags); + guest_exit(); } /* -- cgit v1.2.3 From 02e57b9d7c8ce9e403f15f48fb91dd6549aaf465 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Fri, 24 Jun 2016 15:16:26 +0200 Subject: drivers: net: stmmac: add port selection programming In case of SGMII more, for example when a MAC2MAC connection is needed, the port selection bits (inside the MAC configuration registers) have to be programmed according to the link selected. So the patch adds a new DT parameter to pass the port selection and to programmed related PCS and CORE to use it. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/stmmac.txt | 3 +++ drivers/net/ethernet/stmicro/stmmac/common.h | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c | 15 +++++++++++++++ drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 15 +++++++++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 3 ++- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 15 ++++++++++++++- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 2 ++ include/linux/stmmac.h | 1 + 8 files changed, 53 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt index 95816c5fc589..41b49e6075f5 100644 --- a/Documentation/devicetree/bindings/net/stmmac.txt +++ b/Documentation/devicetree/bindings/net/stmmac.txt @@ -47,6 +47,9 @@ Optional properties: supported by this device instance - snps,perfect-filter-entries: Number of perfect filter entries supported by this device instance +- snps,ps-speed: port selection speed that can be passed to the core when + PCS is supported. For example, this is used in case of SGMII + and MAC2MAC connection. - AXI BUS Mode parameters: below the list of all the parameters to program the AXI register inside the DMA module: - snps,lpi_en: enable Low Power Interface diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 51077a8dc1f5..2533b91f1421 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -531,6 +531,7 @@ struct mac_device_info { unsigned int rx_csum; unsigned int pcs; unsigned int pmt; + unsigned int ps; }; struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 0d31f2f80d07..cbefe9e2207c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -46,6 +46,21 @@ static void dwmac1000_core_init(struct mac_device_info *hw, int mtu) if (mtu > 2000) value |= GMAC_CONTROL_JE; + if (hw->ps) { + value |= GMAC_CONTROL_TE; + + if (hw->ps == SPEED_1000) { + value &= ~GMAC_CONTROL_PS; + } else { + value |= GMAC_CONTROL_PS; + + if (hw->ps == SPEED_10) + value &= ~GMAC_CONTROL_FES; + else + value |= GMAC_CONTROL_FES; + } + } + writel(value, ioaddr + GMAC_CONTROL); /* Mask GMAC interrupts */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 747f3cf1e20b..df5580dcdfed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -32,6 +32,21 @@ static void dwmac4_core_init(struct mac_device_info *hw, int mtu) if (mtu > 2000) value |= GMAC_CONFIG_JE; + if (hw->ps) { + value |= GMAC_CONFIG_TE; + + if (hw->ps == SPEED_1000) { + value &= ~GMAC_CONFIG_PS; + } else { + value |= GMAC_CONFIG_PS; + + if (hw->ps == SPEED_10) + value &= ~GMAC_CONFIG_FES; + else + value |= GMAC_CONFIG_FES; + } + } + writel(value, ioaddr + GMAC_CONFIG); /* Mask GMAC interrupts */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index da2d9b5b740a..1e06173fc9d7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -380,7 +380,8 @@ static int stmmac_ethtool_setsettings(struct net_device *dev, spin_lock(&priv->lock); if (priv->hw->mac->pcs_ctrl_ane) - priv->hw->mac->pcs_ctrl_ane(priv->ioaddr, 1, 0, 0); + priv->hw->mac->pcs_ctrl_ane(priv->ioaddr, 1, + priv->hw->ps, 0); spin_unlock(&priv->lock); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 6142fce9ffac..aab777c1ba33 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1666,6 +1666,19 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) if (priv->plat->bus_setup) priv->plat->bus_setup(priv->ioaddr); + /* PS and related bits will be programmed according to the speed */ + if (priv->hw->pcs) { + int speed = priv->plat->mac_port_sel_speed; + + if ((speed == SPEED_10) || (speed == SPEED_100) || + (speed == SPEED_1000)) { + priv->hw->ps = speed; + } else { + dev_warn(priv->device, "invalid port speed\n"); + priv->hw->ps = 0; + } + } + /* Initialize the MAC Core */ priv->hw->mac->core_init(priv->hw, dev->mtu); @@ -1716,7 +1729,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) } if (priv->hw->pcs && priv->hw->mac->pcs_ctrl_ane) - priv->hw->mac->pcs_ctrl_ane(priv->hw, 1, 0, 0); + priv->hw->mac->pcs_ctrl_ane(priv->hw, 1, priv->hw->ps, 0); /* set TX ring length */ if (priv->hw->dma->set_tx_ring_len) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index a96714d34560..f7dfc0ae8e9c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -319,6 +319,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set."); } + of_property_read_u32(np, "snps,ps-speed", &plat->mac_port_sel_speed); + plat->axi = stmmac_axi_setup(pdev); return plat; diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 0507dbfbf63c..705840e0438f 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -141,5 +141,6 @@ struct plat_stmmacenet_data { struct stmmac_axi *axi; int has_gmac4; bool tso_en; + int mac_port_sel_speed; }; #endif -- cgit v1.2.3 From 3132583e5bd7cb56dffb2c04128ec4db12c32027 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jun 2016 09:17:57 -0300 Subject: [media] cec.h: add cec header This header contains the CEC public API. Since the CEC framework will initially be part of staging this header is kept out of include/uapi for the time being until the CEC framework will be moved out of staging. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec.h | 993 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 993 insertions(+) create mode 100644 include/linux/cec.h (limited to 'include/linux') diff --git a/include/linux/cec.h b/include/linux/cec.h new file mode 100644 index 000000000000..40924e79465d --- /dev/null +++ b/include/linux/cec.h @@ -0,0 +1,993 @@ +/* + * cec - HDMI Consumer Electronics Control public header + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Note: this framework is still in staging and it is likely the API + * will change before it goes out of staging. + * + * Once it is moved out of staging this header will move to uapi. + */ +#ifndef _CEC_UAPI_H +#define _CEC_UAPI_H + +#include + +#define CEC_MAX_MSG_SIZE 16 + +/** + * struct cec_msg - CEC message structure. + * @ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the + * driver. It is set when the message transmission has finished + * and it is set when a message was received. + * @len: Length in bytes of the message. + * @timeout: The timeout (in ms) that is used to timeout CEC_RECEIVE. + * Set to 0 if you want to wait forever. This timeout can also be + * used with CEC_TRANSMIT as the timeout for waiting for a reply. + * If 0, then it will use a 1 second timeout instead of waiting + * forever as is done with CEC_RECEIVE. + * @sequence: The framework assigns a sequence number to messages that are + * sent. This can be used to track replies to previously sent + * messages. + * @flags: Set to 0. + * @rx_status: The message receive status bits. Set by the driver. + * @tx_status: The message transmit status bits. Set by the driver. + * @msg: The message payload. + * @reply: This field is ignored with CEC_RECEIVE and is only used by + * CEC_TRANSMIT. If non-zero, then wait for a reply with this + * opcode. Set to CEC_MSG_FEATURE_ABORT if you want to wait for + * a possible ABORT reply. If there was an error when sending the + * msg or FeatureAbort was returned, then reply is set to 0. + * If reply is non-zero upon return, then len/msg are set to + * the received message. + * If reply is zero upon return and status has the + * CEC_TX_STATUS_FEATURE_ABORT bit set, then len/msg are set to + * the received feature abort message. + * If reply is zero upon return and status has the + * CEC_TX_STATUS_MAX_RETRIES bit set, then no reply was seen at + * all. If reply is non-zero for CEC_TRANSMIT and the message is a + * broadcast, then -EINVAL is returned. + * if reply is non-zero, then timeout is set to 1000 (the required + * maximum response time). + * @tx_arb_lost_cnt: The number of 'Arbitration Lost' events. Set by the driver. + * @tx_nack_cnt: The number of 'Not Acknowledged' events. Set by the driver. + * @tx_low_drive_cnt: The number of 'Low Drive Detected' events. Set by the + * driver. + * @tx_error_cnt: The number of 'Error' events. Set by the driver. + */ +struct cec_msg { + __u64 ts; + __u32 len; + __u32 timeout; + __u32 sequence; + __u32 flags; + __u8 rx_status; + __u8 tx_status; + __u8 msg[CEC_MAX_MSG_SIZE]; + __u8 reply; + __u8 tx_arb_lost_cnt; + __u8 tx_nack_cnt; + __u8 tx_low_drive_cnt; + __u8 tx_error_cnt; +}; + +/** + * cec_msg_initiator - return the initiator's logical address. + * @msg: the message structure + */ +static inline __u8 cec_msg_initiator(const struct cec_msg *msg) +{ + return msg->msg[0] >> 4; +} + +/** + * cec_msg_destination - return the destination's logical address. + * @msg: the message structure + */ +static inline __u8 cec_msg_destination(const struct cec_msg *msg) +{ + return msg->msg[0] & 0xf; +} + +/** + * cec_msg_opcode - return the opcode of the message, -1 for poll + * @msg: the message structure + */ +static inline int cec_msg_opcode(const struct cec_msg *msg) +{ + return msg->len > 1 ? msg->msg[1] : -1; +} + +/** + * cec_msg_is_broadcast - return true if this is a broadcast message. + * @msg: the message structure + */ +static inline bool cec_msg_is_broadcast(const struct cec_msg *msg) +{ + return (msg->msg[0] & 0xf) == 0xf; +} + +/** + * cec_msg_init - initialize the message structure. + * @msg: the message structure + * @initiator: the logical address of the initiator + * @destination:the logical address of the destination (0xf for broadcast) + * + * The whole structure is zeroed, the len field is set to 1 (i.e. a poll + * message) and the initiator and destination are filled in. + */ +static inline void cec_msg_init(struct cec_msg *msg, + __u8 initiator, __u8 destination) +{ + memset(msg, 0, sizeof(*msg)); + msg->msg[0] = (initiator << 4) | destination; + msg->len = 1; +} + +/** + * cec_msg_set_reply_to - fill in destination/initiator in a reply message. + * @msg: the message structure for the reply + * @orig: the original message structure + * + * Set the msg destination to the orig initiator and the msg initiator to the + * orig destination. Note that msg and orig may be the same pointer, in which + * case the change is done in place. + */ +static inline void cec_msg_set_reply_to(struct cec_msg *msg, + struct cec_msg *orig) +{ + /* The destination becomes the initiator and vice versa */ + msg->msg[0] = (cec_msg_destination(orig) << 4) | + cec_msg_initiator(orig); + msg->reply = msg->timeout = 0; +} + +/* cec status field */ +#define CEC_TX_STATUS_OK (1 << 0) +#define CEC_TX_STATUS_ARB_LOST (1 << 1) +#define CEC_TX_STATUS_NACK (1 << 2) +#define CEC_TX_STATUS_LOW_DRIVE (1 << 3) +#define CEC_TX_STATUS_ERROR (1 << 4) +#define CEC_TX_STATUS_MAX_RETRIES (1 << 5) + +#define CEC_RX_STATUS_OK (1 << 0) +#define CEC_RX_STATUS_TIMEOUT (1 << 1) +#define CEC_RX_STATUS_FEATURE_ABORT (1 << 2) + +static inline bool cec_msg_status_is_ok(const struct cec_msg *msg) +{ + if (msg->tx_status && !(msg->tx_status & CEC_TX_STATUS_OK)) + return false; + if (msg->rx_status && !(msg->rx_status & CEC_RX_STATUS_OK)) + return false; + if (!msg->tx_status && !msg->rx_status) + return false; + return !(msg->rx_status & CEC_RX_STATUS_FEATURE_ABORT); +} + +#define CEC_LOG_ADDR_INVALID 0xff +#define CEC_PHYS_ADDR_INVALID 0xffff + +/* + * The maximum number of logical addresses one device can be assigned to. + * The CEC 2.0 spec allows for only 2 logical addresses at the moment. The + * Analog Devices CEC hardware supports 3. So let's go wild and go for 4. + */ +#define CEC_MAX_LOG_ADDRS 4 + +/* The logical addresses defined by CEC 2.0 */ +#define CEC_LOG_ADDR_TV 0 +#define CEC_LOG_ADDR_RECORD_1 1 +#define CEC_LOG_ADDR_RECORD_2 2 +#define CEC_LOG_ADDR_TUNER_1 3 +#define CEC_LOG_ADDR_PLAYBACK_1 4 +#define CEC_LOG_ADDR_AUDIOSYSTEM 5 +#define CEC_LOG_ADDR_TUNER_2 6 +#define CEC_LOG_ADDR_TUNER_3 7 +#define CEC_LOG_ADDR_PLAYBACK_2 8 +#define CEC_LOG_ADDR_RECORD_3 9 +#define CEC_LOG_ADDR_TUNER_4 10 +#define CEC_LOG_ADDR_PLAYBACK_3 11 +#define CEC_LOG_ADDR_BACKUP_1 12 +#define CEC_LOG_ADDR_BACKUP_2 13 +#define CEC_LOG_ADDR_SPECIFIC 14 +#define CEC_LOG_ADDR_UNREGISTERED 15 /* as initiator address */ +#define CEC_LOG_ADDR_BROADCAST 15 /* ad destination address */ + +/* The logical address types that the CEC device wants to claim */ +#define CEC_LOG_ADDR_TYPE_TV 0 +#define CEC_LOG_ADDR_TYPE_RECORD 1 +#define CEC_LOG_ADDR_TYPE_TUNER 2 +#define CEC_LOG_ADDR_TYPE_PLAYBACK 3 +#define CEC_LOG_ADDR_TYPE_AUDIOSYSTEM 4 +#define CEC_LOG_ADDR_TYPE_SPECIFIC 5 +#define CEC_LOG_ADDR_TYPE_UNREGISTERED 6 +/* + * Switches should use UNREGISTERED. + * Processors should use SPECIFIC. + */ + +#define CEC_LOG_ADDR_MASK_TV (1 << CEC_LOG_ADDR_TV) +#define CEC_LOG_ADDR_MASK_RECORD ((1 << CEC_LOG_ADDR_RECORD_1) | \ + (1 << CEC_LOG_ADDR_RECORD_2) | \ + (1 << CEC_LOG_ADDR_RECORD_3)) +#define CEC_LOG_ADDR_MASK_TUNER ((1 << CEC_LOG_ADDR_TUNER_1) | \ + (1 << CEC_LOG_ADDR_TUNER_2) | \ + (1 << CEC_LOG_ADDR_TUNER_3) | \ + (1 << CEC_LOG_ADDR_TUNER_4)) +#define CEC_LOG_ADDR_MASK_PLAYBACK ((1 << CEC_LOG_ADDR_PLAYBACK_1) | \ + (1 << CEC_LOG_ADDR_PLAYBACK_2) | \ + (1 << CEC_LOG_ADDR_PLAYBACK_3)) +#define CEC_LOG_ADDR_MASK_AUDIOSYSTEM (1 << CEC_LOG_ADDR_AUDIOSYSTEM) +#define CEC_LOG_ADDR_MASK_BACKUP ((1 << CEC_LOG_ADDR_BACKUP_1) | \ + (1 << CEC_LOG_ADDR_BACKUP_2)) +#define CEC_LOG_ADDR_MASK_SPECIFIC (1 << CEC_LOG_ADDR_SPECIFIC) +#define CEC_LOG_ADDR_MASK_UNREGISTERED (1 << CEC_LOG_ADDR_UNREGISTERED) + +static inline bool cec_has_tv(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_TV; +} + +static inline bool cec_has_record(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_RECORD; +} + +static inline bool cec_has_tuner(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_TUNER; +} + +static inline bool cec_has_playback(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_PLAYBACK; +} + +static inline bool cec_has_audiosystem(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_AUDIOSYSTEM; +} + +static inline bool cec_has_backup(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_BACKUP; +} + +static inline bool cec_has_specific(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_SPECIFIC; +} + +static inline bool cec_is_unregistered(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_UNREGISTERED; +} + +static inline bool cec_is_unconfigured(__u16 log_addr_mask) +{ + return log_addr_mask == 0; +} + +/* + * Use this if there is no vendor ID (CEC_G_VENDOR_ID) or if the vendor ID + * should be disabled (CEC_S_VENDOR_ID) + */ +#define CEC_VENDOR_ID_NONE 0xffffffff + +/* The message handling modes */ +/* Modes for initiator */ +#define CEC_MODE_NO_INITIATOR (0x0 << 0) +#define CEC_MODE_INITIATOR (0x1 << 0) +#define CEC_MODE_EXCL_INITIATOR (0x2 << 0) +#define CEC_MODE_INITIATOR_MSK 0x0f + +/* Modes for follower */ +#define CEC_MODE_NO_FOLLOWER (0x0 << 4) +#define CEC_MODE_FOLLOWER (0x1 << 4) +#define CEC_MODE_EXCL_FOLLOWER (0x2 << 4) +#define CEC_MODE_EXCL_FOLLOWER_PASSTHRU (0x3 << 4) +#define CEC_MODE_MONITOR (0xe << 4) +#define CEC_MODE_MONITOR_ALL (0xf << 4) +#define CEC_MODE_FOLLOWER_MSK 0xf0 + +/* Userspace has to configure the physical address */ +#define CEC_CAP_PHYS_ADDR (1 << 0) +/* Userspace has to configure the logical addresses */ +#define CEC_CAP_LOG_ADDRS (1 << 1) +/* Userspace can transmit messages (and thus become follower as well) */ +#define CEC_CAP_TRANSMIT (1 << 2) +/* + * Passthrough all messages instead of processing them. + */ +#define CEC_CAP_PASSTHROUGH (1 << 3) +/* Supports remote control */ +#define CEC_CAP_RC (1 << 4) +/* Hardware can monitor all messages, not just directed and broadcast. */ +#define CEC_CAP_MONITOR_ALL (1 << 5) + +/** + * struct cec_caps - CEC capabilities structure. + * @driver: name of the CEC device driver. + * @name: name of the CEC device. @driver + @name must be unique. + * @available_log_addrs: number of available logical addresses. + * @capabilities: capabilities of the CEC adapter. + * @version: version of the CEC adapter framework. + */ +struct cec_caps { + char driver[32]; + char name[32]; + __u32 available_log_addrs; + __u32 capabilities; + __u32 version; +}; + +/** + * struct cec_log_addrs - CEC logical addresses structure. + * @log_addr: the claimed logical addresses. Set by the driver. + * @log_addr_mask: current logical address mask. Set by the driver. + * @cec_version: the CEC version that the adapter should implement. Set by the + * caller. + * @num_log_addrs: how many logical addresses should be claimed. Set by the + * caller. + * @vendor_id: the vendor ID of the device. Set by the caller. + * @flags: set to 0. + * @osd_name: the OSD name of the device. Set by the caller. + * @primary_device_type: the primary device type for each logical address. + * Set by the caller. + * @log_addr_type: the logical address types. Set by the caller. + * @all_device_types: CEC 2.0: all device types represented by the logical + * address. Set by the caller. + * @features: CEC 2.0: The logical address features. Set by the caller. + */ +struct cec_log_addrs { + __u8 log_addr[CEC_MAX_LOG_ADDRS]; + __u16 log_addr_mask; + __u8 cec_version; + __u8 num_log_addrs; + __u32 vendor_id; + __u32 flags; + char osd_name[15]; + __u8 primary_device_type[CEC_MAX_LOG_ADDRS]; + __u8 log_addr_type[CEC_MAX_LOG_ADDRS]; + + /* CEC 2.0 */ + __u8 all_device_types[CEC_MAX_LOG_ADDRS]; + __u8 features[CEC_MAX_LOG_ADDRS][12]; +}; + +/* Events */ + +/* Event that occurs when the adapter state changes */ +#define CEC_EVENT_STATE_CHANGE 1 +/* + * This event is sent when messages are lost because the application + * didn't empty the message queue in time + */ +#define CEC_EVENT_LOST_MSGS 2 + +#define CEC_EVENT_FL_INITIAL_STATE (1 << 0) + +/** + * struct cec_event_state_change - used when the CEC adapter changes state. + * @phys_addr: the current physical address + * @log_addr_mask: the current logical address mask + */ +struct cec_event_state_change { + __u16 phys_addr; + __u16 log_addr_mask; +}; + +/** + * struct cec_event_lost_msgs - tells you how many messages were lost due. + * @lost_msgs: how many messages were lost. + */ +struct cec_event_lost_msgs { + __u32 lost_msgs; +}; + +/** + * struct cec_event - CEC event structure + * @ts: the timestamp of when the event was sent. + * @event: the event. + * array. + * @state_change: the event payload for CEC_EVENT_STATE_CHANGE. + * @lost_msgs: the event payload for CEC_EVENT_LOST_MSGS. + * @raw: array to pad the union. + */ +struct cec_event { + __u64 ts; + __u32 event; + __u32 flags; + union { + struct cec_event_state_change state_change; + struct cec_event_lost_msgs lost_msgs; + __u32 raw[16]; + }; +}; + +/* ioctls */ + +/* Adapter capabilities */ +#define CEC_ADAP_G_CAPS _IOWR('a', 0, struct cec_caps) + +/* + * phys_addr is either 0 (if this is the CEC root device) + * or a valid physical address obtained from the sink's EDID + * as read by this CEC device (if this is a source device) + * or a physical address obtained and modified from a sink + * EDID and used for a sink CEC device. + * If nothing is connected, then phys_addr is 0xffff. + * See HDMI 1.4b, section 8.7 (Physical Address). + * + * The CEC_ADAP_S_PHYS_ADDR ioctl may not be available if that is handled + * internally. + */ +#define CEC_ADAP_G_PHYS_ADDR _IOR('a', 1, __u16) +#define CEC_ADAP_S_PHYS_ADDR _IOW('a', 2, __u16) + +/* + * Configure the CEC adapter. It sets the device type and which + * logical types it will try to claim. It will return which + * logical addresses it could actually claim. + * An error is returned if the adapter is disabled or if there + * is no physical address assigned. + */ + +#define CEC_ADAP_G_LOG_ADDRS _IOR('a', 3, struct cec_log_addrs) +#define CEC_ADAP_S_LOG_ADDRS _IOWR('a', 4, struct cec_log_addrs) + +/* Transmit/receive a CEC command */ +#define CEC_TRANSMIT _IOWR('a', 5, struct cec_msg) +#define CEC_RECEIVE _IOWR('a', 6, struct cec_msg) + +/* Dequeue CEC events */ +#define CEC_DQEVENT _IOWR('a', 7, struct cec_event) + +/* + * Get and set the message handling mode for this filehandle. + */ +#define CEC_G_MODE _IOR('a', 8, __u32) +#define CEC_S_MODE _IOW('a', 9, __u32) + +/* + * The remainder of this header defines all CEC messages and operands. + * The format matters since it the cec-ctl utility parses it to generate + * code for implementing all these messages. + * + * Comments ending with 'Feature' group messages for each feature. + * If messages are part of multiple features, then the "Has also" + * comment is used to list the previously defined messages that are + * supported by the feature. + * + * Before operands are defined a comment is added that gives the + * name of the operand and in brackets the variable name of the + * corresponding argument in the cec-funcs.h function. + */ + +/* Messages */ + +/* One Touch Play Feature */ +#define CEC_MSG_ACTIVE_SOURCE 0x82 +#define CEC_MSG_IMAGE_VIEW_ON 0x04 +#define CEC_MSG_TEXT_VIEW_ON 0x0d + + +/* Routing Control Feature */ + +/* + * Has also: + * CEC_MSG_ACTIVE_SOURCE + */ + +#define CEC_MSG_INACTIVE_SOURCE 0x9d +#define CEC_MSG_REQUEST_ACTIVE_SOURCE 0x85 +#define CEC_MSG_ROUTING_CHANGE 0x80 +#define CEC_MSG_ROUTING_INFORMATION 0x81 +#define CEC_MSG_SET_STREAM_PATH 0x86 + + +/* Standby Feature */ +#define CEC_MSG_STANDBY 0x36 + + +/* One Touch Record Feature */ +#define CEC_MSG_RECORD_OFF 0x0b +#define CEC_MSG_RECORD_ON 0x09 +/* Record Source Type Operand (rec_src_type) */ +#define CEC_OP_RECORD_SRC_OWN 1 +#define CEC_OP_RECORD_SRC_DIGITAL 2 +#define CEC_OP_RECORD_SRC_ANALOG 3 +#define CEC_OP_RECORD_SRC_EXT_PLUG 4 +#define CEC_OP_RECORD_SRC_EXT_PHYS_ADDR 5 +/* Service Identification Method Operand (service_id_method) */ +#define CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID 0 +#define CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL 1 +/* Digital Service Broadcast System Operand (dig_bcast_system) */ +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN 0x00 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN 0x01 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN 0x02 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS 0x08 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS 0x09 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T 0x0a +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE 0x10 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT 0x11 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T 0x12 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C 0x18 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S 0x19 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2 0x1a +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T 0x1b +/* Analogue Broadcast Type Operand (ana_bcast_type) */ +#define CEC_OP_ANA_BCAST_TYPE_CABLE 0 +#define CEC_OP_ANA_BCAST_TYPE_SATELLITE 1 +#define CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL 2 +/* Broadcast System Operand (bcast_system) */ +#define CEC_OP_BCAST_SYSTEM_PAL_BG 0x00 +#define CEC_OP_BCAST_SYSTEM_SECAM_LQ 0x01 /* SECAM L' */ +#define CEC_OP_BCAST_SYSTEM_PAL_M 0x02 +#define CEC_OP_BCAST_SYSTEM_NTSC_M 0x03 +#define CEC_OP_BCAST_SYSTEM_PAL_I 0x04 +#define CEC_OP_BCAST_SYSTEM_SECAM_DK 0x05 +#define CEC_OP_BCAST_SYSTEM_SECAM_BG 0x06 +#define CEC_OP_BCAST_SYSTEM_SECAM_L 0x07 +#define CEC_OP_BCAST_SYSTEM_PAL_DK 0x08 +#define CEC_OP_BCAST_SYSTEM_OTHER 0x1f +/* Channel Number Format Operand (channel_number_fmt) */ +#define CEC_OP_CHANNEL_NUMBER_FMT_1_PART 0x01 +#define CEC_OP_CHANNEL_NUMBER_FMT_2_PART 0x02 + +#define CEC_MSG_RECORD_STATUS 0x0a +/* Record Status Operand (rec_status) */ +#define CEC_OP_RECORD_STATUS_CUR_SRC 0x01 +#define CEC_OP_RECORD_STATUS_DIG_SERVICE 0x02 +#define CEC_OP_RECORD_STATUS_ANA_SERVICE 0x03 +#define CEC_OP_RECORD_STATUS_EXT_INPUT 0x04 +#define CEC_OP_RECORD_STATUS_NO_DIG_SERVICE 0x05 +#define CEC_OP_RECORD_STATUS_NO_ANA_SERVICE 0x06 +#define CEC_OP_RECORD_STATUS_NO_SERVICE 0x07 +#define CEC_OP_RECORD_STATUS_INVALID_EXT_PLUG 0x09 +#define CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR 0x0a +#define CEC_OP_RECORD_STATUS_UNSUP_CA 0x0b +#define CEC_OP_RECORD_STATUS_NO_CA_ENTITLEMENTS 0x0c +#define CEC_OP_RECORD_STATUS_CANT_COPY_SRC 0x0d +#define CEC_OP_RECORD_STATUS_NO_MORE_COPIES 0x0e +#define CEC_OP_RECORD_STATUS_NO_MEDIA 0x10 +#define CEC_OP_RECORD_STATUS_PLAYING 0x11 +#define CEC_OP_RECORD_STATUS_ALREADY_RECORDING 0x12 +#define CEC_OP_RECORD_STATUS_MEDIA_PROT 0x13 +#define CEC_OP_RECORD_STATUS_NO_SIGNAL 0x14 +#define CEC_OP_RECORD_STATUS_MEDIA_PROBLEM 0x15 +#define CEC_OP_RECORD_STATUS_NO_SPACE 0x16 +#define CEC_OP_RECORD_STATUS_PARENTAL_LOCK 0x17 +#define CEC_OP_RECORD_STATUS_TERMINATED_OK 0x1a +#define CEC_OP_RECORD_STATUS_ALREADY_TERM 0x1b +#define CEC_OP_RECORD_STATUS_OTHER 0x1f + +#define CEC_MSG_RECORD_TV_SCREEN 0x0f + + +/* Timer Programming Feature */ +#define CEC_MSG_CLEAR_ANALOGUE_TIMER 0x33 +/* Recording Sequence Operand (recording_seq) */ +#define CEC_OP_REC_SEQ_SUNDAY 0x01 +#define CEC_OP_REC_SEQ_MONDAY 0x02 +#define CEC_OP_REC_SEQ_TUESDAY 0x04 +#define CEC_OP_REC_SEQ_WEDNESDAY 0x08 +#define CEC_OP_REC_SEQ_THURSDAY 0x10 +#define CEC_OP_REC_SEQ_FRIDAY 0x20 +#define CEC_OP_REC_SEQ_SATERDAY 0x40 +#define CEC_OP_REC_SEQ_ONCE_ONLY 0x00 + +#define CEC_MSG_CLEAR_DIGITAL_TIMER 0x99 + +#define CEC_MSG_CLEAR_EXT_TIMER 0xa1 +/* External Source Specifier Operand (ext_src_spec) */ +#define CEC_OP_EXT_SRC_PLUG 0x04 +#define CEC_OP_EXT_SRC_PHYS_ADDR 0x05 + +#define CEC_MSG_SET_ANALOGUE_TIMER 0x34 +#define CEC_MSG_SET_DIGITAL_TIMER 0x97 +#define CEC_MSG_SET_EXT_TIMER 0xa2 + +#define CEC_MSG_SET_TIMER_PROGRAM_TITLE 0x67 +#define CEC_MSG_TIMER_CLEARED_STATUS 0x43 +/* Timer Cleared Status Data Operand (timer_cleared_status) */ +#define CEC_OP_TIMER_CLR_STAT_RECORDING 0x00 +#define CEC_OP_TIMER_CLR_STAT_NO_MATCHING 0x01 +#define CEC_OP_TIMER_CLR_STAT_NO_INFO 0x02 +#define CEC_OP_TIMER_CLR_STAT_CLEARED 0x80 + +#define CEC_MSG_TIMER_STATUS 0x35 +/* Timer Overlap Warning Operand (timer_overlap_warning) */ +#define CEC_OP_TIMER_OVERLAP_WARNING_NO_OVERLAP 0 +#define CEC_OP_TIMER_OVERLAP_WARNING_OVERLAP 1 +/* Media Info Operand (media_info) */ +#define CEC_OP_MEDIA_INFO_UNPROT_MEDIA 0 +#define CEC_OP_MEDIA_INFO_PROT_MEDIA 1 +#define CEC_OP_MEDIA_INFO_NO_MEDIA 2 +/* Programmed Indicator Operand (prog_indicator) */ +#define CEC_OP_PROG_IND_NOT_PROGRAMMED 0 +#define CEC_OP_PROG_IND_PROGRAMMED 1 +/* Programmed Info Operand (prog_info) */ +#define CEC_OP_PROG_INFO_ENOUGH_SPACE 0x08 +#define CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE 0x09 +#define CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE 0x0b +#define CEC_OP_PROG_INFO_NONE_AVAILABLE 0x0a +/* Not Programmed Error Info Operand (prog_error) */ +#define CEC_OP_PROG_ERROR_NO_FREE_TIMER 0x01 +#define CEC_OP_PROG_ERROR_DATE_OUT_OF_RANGE 0x02 +#define CEC_OP_PROG_ERROR_REC_SEQ_ERROR 0x03 +#define CEC_OP_PROG_ERROR_INV_EXT_PLUG 0x04 +#define CEC_OP_PROG_ERROR_INV_EXT_PHYS_ADDR 0x05 +#define CEC_OP_PROG_ERROR_CA_UNSUPP 0x06 +#define CEC_OP_PROG_ERROR_INSUF_CA_ENTITLEMENTS 0x07 +#define CEC_OP_PROG_ERROR_RESOLUTION_UNSUPP 0x08 +#define CEC_OP_PROG_ERROR_PARENTAL_LOCK 0x09 +#define CEC_OP_PROG_ERROR_CLOCK_FAILURE 0x0a +#define CEC_OP_PROG_ERROR_DUPLICATE 0x0e + + +/* System Information Feature */ +#define CEC_MSG_CEC_VERSION 0x9e +/* CEC Version Operand (cec_version) */ +#define CEC_OP_CEC_VERSION_1_3A 4 +#define CEC_OP_CEC_VERSION_1_4 5 +#define CEC_OP_CEC_VERSION_2_0 6 + +#define CEC_MSG_GET_CEC_VERSION 0x9f +#define CEC_MSG_GIVE_PHYSICAL_ADDR 0x83 +#define CEC_MSG_GET_MENU_LANGUAGE 0x91 +#define CEC_MSG_REPORT_PHYSICAL_ADDR 0x84 +/* Primary Device Type Operand (prim_devtype) */ +#define CEC_OP_PRIM_DEVTYPE_TV 0 +#define CEC_OP_PRIM_DEVTYPE_RECORD 1 +#define CEC_OP_PRIM_DEVTYPE_TUNER 3 +#define CEC_OP_PRIM_DEVTYPE_PLAYBACK 4 +#define CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM 5 +#define CEC_OP_PRIM_DEVTYPE_SWITCH 6 +#define CEC_OP_PRIM_DEVTYPE_PROCESSOR 7 + +#define CEC_MSG_SET_MENU_LANGUAGE 0x32 +#define CEC_MSG_REPORT_FEATURES 0xa6 /* HDMI 2.0 */ +/* All Device Types Operand (all_device_types) */ +#define CEC_OP_ALL_DEVTYPE_TV 0x80 +#define CEC_OP_ALL_DEVTYPE_RECORD 0x40 +#define CEC_OP_ALL_DEVTYPE_TUNER 0x20 +#define CEC_OP_ALL_DEVTYPE_PLAYBACK 0x10 +#define CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM 0x08 +#define CEC_OP_ALL_DEVTYPE_SWITCH 0x04 +/* + * And if you wondering what happened to PROCESSOR devices: those should + * be mapped to a SWITCH. + */ + +/* Valid for RC Profile and Device Feature operands */ +#define CEC_OP_FEAT_EXT 0x80 /* Extension bit */ +/* RC Profile Operand (rc_profile) */ +#define CEC_OP_FEAT_RC_TV_PROFILE_NONE 0x00 +#define CEC_OP_FEAT_RC_TV_PROFILE_1 0x02 +#define CEC_OP_FEAT_RC_TV_PROFILE_2 0x06 +#define CEC_OP_FEAT_RC_TV_PROFILE_3 0x0a +#define CEC_OP_FEAT_RC_TV_PROFILE_4 0x0e +#define CEC_OP_FEAT_RC_SRC_HAS_DEV_ROOT_MENU 0x50 +#define CEC_OP_FEAT_RC_SRC_HAS_DEV_SETUP_MENU 0x48 +#define CEC_OP_FEAT_RC_SRC_HAS_CONTENTS_MENU 0x44 +#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_TOP_MENU 0x42 +#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU 0x41 +/* Device Feature Operand (dev_features) */ +#define CEC_OP_FEAT_DEV_HAS_RECORD_TV_SCREEN 0x40 +#define CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING 0x20 +#define CEC_OP_FEAT_DEV_HAS_DECK_CONTROL 0x10 +#define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE 0x08 +#define CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX 0x04 +#define CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX 0x02 + +#define CEC_MSG_GIVE_FEATURES 0xa5 /* HDMI 2.0 */ + + +/* Deck Control Feature */ +#define CEC_MSG_DECK_CONTROL 0x42 +/* Deck Control Mode Operand (deck_control_mode) */ +#define CEC_OP_DECK_CTL_MODE_SKIP_FWD 1 +#define CEC_OP_DECK_CTL_MODE_SKIP_REV 2 +#define CEC_OP_DECK_CTL_MODE_STOP 3 +#define CEC_OP_DECK_CTL_MODE_EJECT 4 + +#define CEC_MSG_DECK_STATUS 0x1b +/* Deck Info Operand (deck_info) */ +#define CEC_OP_DECK_INFO_PLAY 0x11 +#define CEC_OP_DECK_INFO_RECORD 0x12 +#define CEC_OP_DECK_INFO_PLAY_REV 0x13 +#define CEC_OP_DECK_INFO_STILL 0x14 +#define CEC_OP_DECK_INFO_SLOW 0x15 +#define CEC_OP_DECK_INFO_SLOW_REV 0x16 +#define CEC_OP_DECK_INFO_FAST_FWD 0x17 +#define CEC_OP_DECK_INFO_FAST_REV 0x18 +#define CEC_OP_DECK_INFO_NO_MEDIA 0x19 +#define CEC_OP_DECK_INFO_STOP 0x1a +#define CEC_OP_DECK_INFO_SKIP_FWD 0x1b +#define CEC_OP_DECK_INFO_SKIP_REV 0x1c +#define CEC_OP_DECK_INFO_INDEX_SEARCH_FWD 0x1d +#define CEC_OP_DECK_INFO_INDEX_SEARCH_REV 0x1e +#define CEC_OP_DECK_INFO_OTHER 0x1f + +#define CEC_MSG_GIVE_DECK_STATUS 0x1a +/* Status Request Operand (status_req) */ +#define CEC_OP_STATUS_REQ_ON 1 +#define CEC_OP_STATUS_REQ_OFF 2 +#define CEC_OP_STATUS_REQ_ONCE 3 + +#define CEC_MSG_PLAY 0x41 +/* Play Mode Operand (play_mode) */ +#define CEC_OP_PLAY_MODE_PLAY_FWD 0x24 +#define CEC_OP_PLAY_MODE_PLAY_REV 0x20 +#define CEC_OP_PLAY_MODE_PLAY_STILL 0x25 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN 0x05 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED 0x06 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX 0x07 +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN 0x09 +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED 0x0a +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX 0x0b +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN 0x15 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED 0x16 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX 0x17 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN 0x19 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED 0x1a +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX 0x1b + + +/* Tuner Control Feature */ +#define CEC_MSG_GIVE_TUNER_DEVICE_STATUS 0x08 +#define CEC_MSG_SELECT_ANALOGUE_SERVICE 0x92 +#define CEC_MSG_SELECT_DIGITAL_SERVICE 0x93 +#define CEC_MSG_TUNER_DEVICE_STATUS 0x07 +/* Recording Flag Operand (rec_flag) */ +#define CEC_OP_REC_FLAG_USED 0 +#define CEC_OP_REC_FLAG_NOT_USED 1 +/* Tuner Display Info Operand (tuner_display_info) */ +#define CEC_OP_TUNER_DISPLAY_INFO_DIGITAL 0 +#define CEC_OP_TUNER_DISPLAY_INFO_NONE 1 +#define CEC_OP_TUNER_DISPLAY_INFO_ANALOGUE 2 + +#define CEC_MSG_TUNER_STEP_DECREMENT 0x06 +#define CEC_MSG_TUNER_STEP_INCREMENT 0x05 + + +/* Vendor Specific Commands Feature */ + +/* + * Has also: + * CEC_MSG_CEC_VERSION + * CEC_MSG_GET_CEC_VERSION + */ +#define CEC_MSG_DEVICE_VENDOR_ID 0x87 +#define CEC_MSG_GIVE_DEVICE_VENDOR_ID 0x8c +#define CEC_MSG_VENDOR_COMMAND 0x89 +#define CEC_MSG_VENDOR_COMMAND_WITH_ID 0xa0 +#define CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN 0x8a +#define CEC_MSG_VENDOR_REMOTE_BUTTON_UP 0x8b + + +/* OSD Display Feature */ +#define CEC_MSG_SET_OSD_STRING 0x64 +/* Display Control Operand (disp_ctl) */ +#define CEC_OP_DISP_CTL_DEFAULT 0x00 +#define CEC_OP_DISP_CTL_UNTIL_CLEARED 0x40 +#define CEC_OP_DISP_CTL_CLEAR 0x80 + + +/* Device OSD Transfer Feature */ +#define CEC_MSG_GIVE_OSD_NAME 0x46 +#define CEC_MSG_SET_OSD_NAME 0x47 + + +/* Device Menu Control Feature */ +#define CEC_MSG_MENU_REQUEST 0x8d +/* Menu Request Type Operand (menu_req) */ +#define CEC_OP_MENU_REQUEST_ACTIVATE 0x00 +#define CEC_OP_MENU_REQUEST_DEACTIVATE 0x01 +#define CEC_OP_MENU_REQUEST_QUERY 0x02 + +#define CEC_MSG_MENU_STATUS 0x8e +/* Menu State Operand (menu_state) */ +#define CEC_OP_MENU_STATE_ACTIVATED 0x00 +#define CEC_OP_MENU_STATE_DEACTIVATED 0x01 + +#define CEC_MSG_USER_CONTROL_PRESSED 0x44 +/* UI Broadcast Type Operand (ui_bcast_type) */ +#define CEC_OP_UI_BCAST_TYPE_TOGGLE_ALL 0x00 +#define CEC_OP_UI_BCAST_TYPE_TOGGLE_DIG_ANA 0x01 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE 0x10 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_T 0x20 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_CABLE 0x30 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_SAT 0x40 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL 0x50 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_T 0x60 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_CABLE 0x70 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_SAT 0x80 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT 0x90 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT2 0x91 +#define CEC_OP_UI_BCAST_TYPE_IP 0xa0 +/* UI Sound Presentation Control Operand (ui_snd_pres_ctl) */ +#define CEC_OP_UI_SND_PRES_CTL_DUAL_MONO 0x10 +#define CEC_OP_UI_SND_PRES_CTL_KARAOKE 0x20 +#define CEC_OP_UI_SND_PRES_CTL_DOWNMIX 0x80 +#define CEC_OP_UI_SND_PRES_CTL_REVERB 0x90 +#define CEC_OP_UI_SND_PRES_CTL_EQUALIZER 0xa0 +#define CEC_OP_UI_SND_PRES_CTL_BASS_UP 0xb1 +#define CEC_OP_UI_SND_PRES_CTL_BASS_NEUTRAL 0xb2 +#define CEC_OP_UI_SND_PRES_CTL_BASS_DOWN 0xb3 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_UP 0xc1 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_NEUTRAL 0xc2 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_DOWN 0xc3 + +#define CEC_MSG_USER_CONTROL_RELEASED 0x45 + + +/* Remote Control Passthrough Feature */ + +/* + * Has also: + * CEC_MSG_USER_CONTROL_PRESSED + * CEC_MSG_USER_CONTROL_RELEASED + */ + + +/* Power Status Feature */ +#define CEC_MSG_GIVE_DEVICE_POWER_STATUS 0x8f +#define CEC_MSG_REPORT_POWER_STATUS 0x90 +/* Power Status Operand (pwr_state) */ +#define CEC_OP_POWER_STATUS_ON 0 +#define CEC_OP_POWER_STATUS_STANDBY 1 +#define CEC_OP_POWER_STATUS_TO_ON 2 +#define CEC_OP_POWER_STATUS_TO_STANDBY 3 + + +/* General Protocol Messages */ +#define CEC_MSG_FEATURE_ABORT 0x00 +/* Abort Reason Operand (reason) */ +#define CEC_OP_ABORT_UNRECOGNIZED_OP 0 +#define CEC_OP_ABORT_INCORRECT_MODE 1 +#define CEC_OP_ABORT_NO_SOURCE 2 +#define CEC_OP_ABORT_INVALID_OP 3 +#define CEC_OP_ABORT_REFUSED 4 +#define CEC_OP_ABORT_UNDETERMINED 5 + +#define CEC_MSG_ABORT 0xff + + +/* System Audio Control Feature */ + +/* + * Has also: + * CEC_MSG_USER_CONTROL_PRESSED + * CEC_MSG_USER_CONTROL_RELEASED + */ +#define CEC_MSG_GIVE_AUDIO_STATUS 0x71 +#define CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS 0x7d +#define CEC_MSG_REPORT_AUDIO_STATUS 0x7a +/* Audio Mute Status Operand (aud_mute_status) */ +#define CEC_OP_AUD_MUTE_STATUS_OFF 0 +#define CEC_OP_AUD_MUTE_STATUS_ON 1 + +#define CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR 0xa3 +#define CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR 0xa4 +#define CEC_MSG_SET_SYSTEM_AUDIO_MODE 0x72 +/* System Audio Status Operand (sys_aud_status) */ +#define CEC_OP_SYS_AUD_STATUS_OFF 0 +#define CEC_OP_SYS_AUD_STATUS_ON 1 + +#define CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST 0x70 +#define CEC_MSG_SYSTEM_AUDIO_MODE_STATUS 0x7e +/* Audio Format ID Operand (audio_format_id) */ +#define CEC_OP_AUD_FMT_ID_CEA861 0 +#define CEC_OP_AUD_FMT_ID_CEA861_CXT 1 + + +/* Audio Rate Control Feature */ +#define CEC_MSG_SET_AUDIO_RATE 0x9a +/* Audio Rate Operand (audio_rate) */ +#define CEC_OP_AUD_RATE_OFF 0 +#define CEC_OP_AUD_RATE_WIDE_STD 1 +#define CEC_OP_AUD_RATE_WIDE_FAST 2 +#define CEC_OP_AUD_RATE_WIDE_SLOW 3 +#define CEC_OP_AUD_RATE_NARROW_STD 4 +#define CEC_OP_AUD_RATE_NARROW_FAST 5 +#define CEC_OP_AUD_RATE_NARROW_SLOW 6 + + +/* Audio Return Channel Control Feature */ +#define CEC_MSG_INITIATE_ARC 0xc0 +#define CEC_MSG_REPORT_ARC_INITIATED 0xc1 +#define CEC_MSG_REPORT_ARC_TERMINATED 0xc2 +#define CEC_MSG_REQUEST_ARC_INITIATION 0xc3 +#define CEC_MSG_REQUEST_ARC_TERMINATION 0xc4 +#define CEC_MSG_TERMINATE_ARC 0xc5 + + +/* Dynamic Audio Lipsync Feature */ +/* Only for CEC 2.0 and up */ +#define CEC_MSG_REQUEST_CURRENT_LATENCY 0xa7 +#define CEC_MSG_REPORT_CURRENT_LATENCY 0xa8 +/* Low Latency Mode Operand (low_latency_mode) */ +#define CEC_OP_LOW_LATENCY_MODE_OFF 0 +#define CEC_OP_LOW_LATENCY_MODE_ON 1 +/* Audio Output Compensated Operand (audio_out_compensated) */ +#define CEC_OP_AUD_OUT_COMPENSATED_NA 0 +#define CEC_OP_AUD_OUT_COMPENSATED_DELAY 1 +#define CEC_OP_AUD_OUT_COMPENSATED_NO_DELAY 2 +#define CEC_OP_AUD_OUT_COMPENSATED_PARTIAL_DELAY 3 + + +/* Capability Discovery and Control Feature */ +#define CEC_MSG_CDC_MESSAGE 0xf8 +/* Ethernet-over-HDMI: nobody ever does this... */ +#define CEC_MSG_CDC_HEC_INQUIRE_STATE 0x00 +#define CEC_MSG_CDC_HEC_REPORT_STATE 0x01 +/* HEC Functionality State Operand (hec_func_state) */ +#define CEC_OP_HEC_FUNC_STATE_NOT_SUPPORTED 0 +#define CEC_OP_HEC_FUNC_STATE_INACTIVE 1 +#define CEC_OP_HEC_FUNC_STATE_ACTIVE 2 +#define CEC_OP_HEC_FUNC_STATE_ACTIVATION_FIELD 3 +/* Host Functionality State Operand (host_func_state) */ +#define CEC_OP_HOST_FUNC_STATE_NOT_SUPPORTED 0 +#define CEC_OP_HOST_FUNC_STATE_INACTIVE 1 +#define CEC_OP_HOST_FUNC_STATE_ACTIVE 2 +/* ENC Functionality State Operand (enc_func_state) */ +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED 0 +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_INACTIVE 1 +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_ACTIVE 2 +/* CDC Error Code Operand (cdc_errcode) */ +#define CEC_OP_CDC_ERROR_CODE_NONE 0 +#define CEC_OP_CDC_ERROR_CODE_CAP_UNSUPPORTED 1 +#define CEC_OP_CDC_ERROR_CODE_WRONG_STATE 2 +#define CEC_OP_CDC_ERROR_CODE_OTHER 3 +/* HEC Support Operand (hec_support) */ +#define CEC_OP_HEC_SUPPORT_NO 0 +#define CEC_OP_HEC_SUPPORT_YES 1 +/* HEC Activation Operand (hec_activation) */ +#define CEC_OP_HEC_ACTIVATION_ON 0 +#define CEC_OP_HEC_ACTIVATION_OFF 1 + +#define CEC_MSG_CDC_HEC_SET_STATE_ADJACENT 0x02 +#define CEC_MSG_CDC_HEC_SET_STATE 0x03 +/* HEC Set State Operand (hec_set_state) */ +#define CEC_OP_HEC_SET_STATE_DEACTIVATE 0 +#define CEC_OP_HEC_SET_STATE_ACTIVATE 1 + +#define CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION 0x04 +#define CEC_MSG_CDC_HEC_NOTIFY_ALIVE 0x05 +#define CEC_MSG_CDC_HEC_DISCOVER 0x06 +/* Hotplug Detect messages */ +#define CEC_MSG_CDC_HPD_SET_STATE 0x10 +/* HPD State Operand (hpd_state) */ +#define CEC_OP_HPD_STATE_CP_EDID_DISABLE 0 +#define CEC_OP_HPD_STATE_CP_EDID_ENABLE 1 +#define CEC_OP_HPD_STATE_CP_EDID_DISABLE_ENABLE 2 +#define CEC_OP_HPD_STATE_EDID_DISABLE 3 +#define CEC_OP_HPD_STATE_EDID_ENABLE 4 +#define CEC_OP_HPD_STATE_EDID_DISABLE_ENABLE 5 +#define CEC_MSG_CDC_HPD_REPORT_STATE 0x11 +/* HPD Error Code Operand (hpd_error) */ +#define CEC_OP_HPD_ERROR_NONE 0 +#define CEC_OP_HPD_ERROR_INITIATOR_NOT_CAPABLE 1 +#define CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE 2 +#define CEC_OP_HPD_ERROR_OTHER 3 +#define CEC_OP_HPD_ERROR_NONE_NO_VIDEO 4 + +#endif -- cgit v1.2.3 From 50f7d5a65e5a31e92a9d46663770cd9509f939a2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jun 2016 09:20:52 -0300 Subject: [media] cec-funcs.h: static inlines to pack/unpack CEC messages This public header contains static inlines to pack and unpack CEC messages. It is for use in both the kernel and in userspace. Since the CEC framework will initially be in staging this header is not yet in include/uapi. Once the framework is moved out of staging this header should be moved to uapi at the same time. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 1881 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1881 insertions(+) create mode 100644 include/linux/cec-funcs.h (limited to 'include/linux') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h new file mode 100644 index 000000000000..8ee1029b9b74 --- /dev/null +++ b/include/linux/cec-funcs.h @@ -0,0 +1,1881 @@ +/* + * cec - HDMI Consumer Electronics Control message functions + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Note: this framework is still in staging and it is likely the API + * will change before it goes out of staging. + * + * Once it is moved out of staging this header will move to uapi. + */ +#ifndef _CEC_UAPI_FUNCS_H +#define _CEC_UAPI_FUNCS_H + +#include + +/* One Touch Play Feature */ +static inline void cec_msg_active_source(struct cec_msg *msg, __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ACTIVE_SOURCE; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_active_source(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_image_view_on(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_IMAGE_VIEW_ON; +} + +static inline void cec_msg_text_view_on(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TEXT_VIEW_ON; +} + + +/* Routing Control Feature */ +static inline void cec_msg_inactive_source(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_INACTIVE_SOURCE; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_inactive_source(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_request_active_source(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REQUEST_ACTIVE_SOURCE; + msg->reply = reply ? CEC_MSG_ACTIVE_SOURCE : 0; +} + +static inline void cec_msg_routing_information(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ROUTING_INFORMATION; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_routing_information(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_routing_change(struct cec_msg *msg, + bool reply, + __u16 orig_phys_addr, + __u16 new_phys_addr) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ROUTING_CHANGE; + msg->msg[2] = orig_phys_addr >> 8; + msg->msg[3] = orig_phys_addr & 0xff; + msg->msg[4] = new_phys_addr >> 8; + msg->msg[5] = new_phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_ROUTING_INFORMATION : 0; +} + +static inline void cec_ops_routing_change(const struct cec_msg *msg, + __u16 *orig_phys_addr, + __u16 *new_phys_addr) +{ + *orig_phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *new_phys_addr = (msg->msg[4] << 8) | msg->msg[5]; +} + +static inline void cec_msg_set_stream_path(struct cec_msg *msg, __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_SET_STREAM_PATH; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_set_stream_path(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + + +/* Standby Feature */ +static inline void cec_msg_standby(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_STANDBY; +} + + +/* One Touch Record Feature */ +static inline void cec_msg_record_off(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_RECORD_OFF; +} + +struct cec_op_arib_data { + __u16 transport_id; + __u16 service_id; + __u16 orig_network_id; +}; + +struct cec_op_atsc_data { + __u16 transport_id; + __u16 program_number; +}; + +struct cec_op_dvb_data { + __u16 transport_id; + __u16 service_id; + __u16 orig_network_id; +}; + +struct cec_op_channel_data { + __u8 channel_number_fmt; + __u16 major; + __u16 minor; +}; + +struct cec_op_digital_service_id { + __u8 service_id_method; + __u8 dig_bcast_system; + union { + struct cec_op_arib_data arib; + struct cec_op_atsc_data atsc; + struct cec_op_dvb_data dvb; + struct cec_op_channel_data channel; + }; +}; + +struct cec_op_record_src { + __u8 type; + union { + struct cec_op_digital_service_id digital; + struct { + __u8 ana_bcast_type; + __u16 ana_freq; + __u8 bcast_system; + } analog; + struct { + __u8 plug; + } ext_plug; + struct { + __u16 phys_addr; + } ext_phys_addr; + }; +}; + +static inline void cec_set_digital_service_id(__u8 *msg, + const struct cec_op_digital_service_id *digital) +{ + *msg++ = (digital->service_id_method << 7) | digital->dig_bcast_system; + if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) { + *msg++ = (digital->channel.channel_number_fmt << 2) | + (digital->channel.major >> 8); + *msg++ = digital->channel.major && 0xff; + *msg++ = digital->channel.minor >> 8; + *msg++ = digital->channel.minor & 0xff; + *msg++ = 0; + *msg++ = 0; + return; + } + switch (digital->dig_bcast_system) { + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T: + *msg++ = digital->atsc.transport_id >> 8; + *msg++ = digital->atsc.transport_id & 0xff; + *msg++ = digital->atsc.program_number >> 8; + *msg++ = digital->atsc.program_number & 0xff; + *msg++ = 0; + *msg++ = 0; + break; + default: + *msg++ = digital->dvb.transport_id >> 8; + *msg++ = digital->dvb.transport_id & 0xff; + *msg++ = digital->dvb.service_id >> 8; + *msg++ = digital->dvb.service_id & 0xff; + *msg++ = digital->dvb.orig_network_id >> 8; + *msg++ = digital->dvb.orig_network_id & 0xff; + break; + } +} + +static inline void cec_get_digital_service_id(const __u8 *msg, + struct cec_op_digital_service_id *digital) +{ + digital->service_id_method = msg[0] >> 7; + digital->dig_bcast_system = msg[0] & 0x7f; + if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) { + digital->channel.channel_number_fmt = msg[1] >> 2; + digital->channel.major = ((msg[1] & 3) << 6) | msg[2]; + digital->channel.minor = (msg[3] << 8) | msg[4]; + return; + } + digital->dvb.transport_id = (msg[1] << 8) | msg[2]; + digital->dvb.service_id = (msg[3] << 8) | msg[4]; + digital->dvb.orig_network_id = (msg[5] << 8) | msg[6]; +} + +static inline void cec_msg_record_on_own(struct cec_msg *msg) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_OWN; +} + +static inline void cec_msg_record_on_digital(struct cec_msg *msg, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 10; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_DIGITAL; + cec_set_digital_service_id(msg->msg + 3, digital); +} + +static inline void cec_msg_record_on_analog(struct cec_msg *msg, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 7; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_ANALOG; + msg->msg[3] = ana_bcast_type; + msg->msg[4] = ana_freq >> 8; + msg->msg[5] = ana_freq & 0xff; + msg->msg[6] = bcast_system; +} + +static inline void cec_msg_record_on_plug(struct cec_msg *msg, + __u8 plug) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PLUG; + msg->msg[3] = plug; +} + +static inline void cec_msg_record_on_phys_addr(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 5; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PHYS_ADDR; + msg->msg[3] = phys_addr >> 8; + msg->msg[4] = phys_addr & 0xff; +} + +static inline void cec_msg_record_on(struct cec_msg *msg, + const struct cec_op_record_src *rec_src) +{ + switch (rec_src->type) { + case CEC_OP_RECORD_SRC_OWN: + cec_msg_record_on_own(msg); + break; + case CEC_OP_RECORD_SRC_DIGITAL: + cec_msg_record_on_digital(msg, &rec_src->digital); + break; + case CEC_OP_RECORD_SRC_ANALOG: + cec_msg_record_on_analog(msg, + rec_src->analog.ana_bcast_type, + rec_src->analog.ana_freq, + rec_src->analog.bcast_system); + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + cec_msg_record_on_plug(msg, rec_src->ext_plug.plug); + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + cec_msg_record_on_phys_addr(msg, + rec_src->ext_phys_addr.phys_addr); + break; + } +} + +static inline void cec_ops_record_on(const struct cec_msg *msg, + struct cec_op_record_src *rec_src) +{ + rec_src->type = msg->msg[2]; + switch (rec_src->type) { + case CEC_OP_RECORD_SRC_OWN: + break; + case CEC_OP_RECORD_SRC_DIGITAL: + cec_get_digital_service_id(msg->msg + 3, &rec_src->digital); + break; + case CEC_OP_RECORD_SRC_ANALOG: + rec_src->analog.ana_bcast_type = msg->msg[3]; + rec_src->analog.ana_freq = + (msg->msg[4] << 8) | msg->msg[5]; + rec_src->analog.bcast_system = msg->msg[6]; + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + rec_src->ext_plug.plug = msg->msg[3]; + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + rec_src->ext_phys_addr.phys_addr = + (msg->msg[3] << 8) | msg->msg[4]; + break; + } +} + +static inline void cec_msg_record_status(struct cec_msg *msg, __u8 rec_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_RECORD_STATUS; + msg->msg[2] = rec_status; +} + +static inline void cec_ops_record_status(const struct cec_msg *msg, + __u8 *rec_status) +{ + *rec_status = msg->msg[2]; +} + +static inline void cec_msg_record_tv_screen(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_RECORD_TV_SCREEN; + msg->reply = reply ? CEC_MSG_RECORD_ON : 0; +} + + +/* Timer Programming Feature */ +static inline void cec_msg_timer_status(struct cec_msg *msg, + __u8 timer_overlap_warning, + __u8 media_info, + __u8 prog_info, + __u8 prog_error, + __u8 duration_hr, + __u8 duration_min) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_TIMER_STATUS; + msg->msg[2] = (timer_overlap_warning << 7) | + (media_info << 5) | + (prog_info ? 0x10 : 0) | + (prog_info ? prog_info : prog_error); + if (prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE || + prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE || + prog_error == CEC_OP_PROG_ERROR_DUPLICATE) { + msg->len += 2; + msg->msg[3] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[4] = ((duration_min / 10) << 4) | (duration_min % 10); + } +} + +static inline void cec_ops_timer_status(struct cec_msg *msg, + __u8 *timer_overlap_warning, + __u8 *media_info, + __u8 *prog_info, + __u8 *prog_error, + __u8 *duration_hr, + __u8 *duration_min) +{ + *timer_overlap_warning = msg->msg[2] >> 7; + *media_info = (msg->msg[2] >> 5) & 3; + if (msg->msg[2] & 0x10) { + *prog_info = msg->msg[2] & 0xf; + *prog_error = 0; + } else { + *prog_info = 0; + *prog_error = msg->msg[2] & 0xf; + } + if (*prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE || + *prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE || + *prog_error == CEC_OP_PROG_ERROR_DUPLICATE) { + *duration_hr = (msg->msg[3] >> 4) * 10 + (msg->msg[3] & 0xf); + *duration_min = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + } else { + *duration_hr = *duration_min = 0; + } +} + +static inline void cec_msg_timer_cleared_status(struct cec_msg *msg, + __u8 timer_cleared_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_TIMER_CLEARED_STATUS; + msg->msg[2] = timer_cleared_status; +} + +static inline void cec_ops_timer_cleared_status(struct cec_msg *msg, + __u8 *timer_cleared_status) +{ + *timer_cleared_status = msg->msg[2]; +} + +static inline void cec_msg_clear_analogue_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_CLEAR_ANALOGUE_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ana_bcast_type; + msg->msg[10] = ana_freq >> 8; + msg->msg[11] = ana_freq & 0xff; + msg->msg[12] = bcast_system; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; +} + +static inline void cec_ops_clear_analogue_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ana_bcast_type = msg->msg[9]; + *ana_freq = (msg->msg[10] << 8) | msg->msg[11]; + *bcast_system = msg->msg[12]; +} + +static inline void cec_msg_clear_digital_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 16; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; + msg->msg[1] = CEC_MSG_CLEAR_DIGITAL_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + cec_set_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_ops_clear_digital_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + struct cec_op_digital_service_id *digital) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + cec_get_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_msg_clear_ext_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ext_src_spec, + __u8 plug, + __u16 phys_addr) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_CLEAR_EXT_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ext_src_spec; + msg->msg[10] = plug; + msg->msg[11] = phys_addr >> 8; + msg->msg[12] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; +} + +static inline void cec_ops_clear_ext_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ext_src_spec, + __u8 *plug, + __u16 *phys_addr) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ext_src_spec = msg->msg[9]; + *plug = msg->msg[10]; + *phys_addr = (msg->msg[11] << 8) | msg->msg[12]; +} + +static inline void cec_msg_set_analogue_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_SET_ANALOGUE_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ana_bcast_type; + msg->msg[10] = ana_freq >> 8; + msg->msg[11] = ana_freq & 0xff; + msg->msg[12] = bcast_system; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; +} + +static inline void cec_ops_set_analogue_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ana_bcast_type = msg->msg[9]; + *ana_freq = (msg->msg[10] << 8) | msg->msg[11]; + *bcast_system = msg->msg[12]; +} + +static inline void cec_msg_set_digital_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 16; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; + msg->msg[1] = CEC_MSG_SET_DIGITAL_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + cec_set_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_ops_set_digital_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + struct cec_op_digital_service_id *digital) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + cec_get_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_msg_set_ext_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ext_src_spec, + __u8 plug, + __u16 phys_addr) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_SET_EXT_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ext_src_spec; + msg->msg[10] = plug; + msg->msg[11] = phys_addr >> 8; + msg->msg[12] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; +} + +static inline void cec_ops_set_ext_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ext_src_spec, + __u8 *plug, + __u16 *phys_addr) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ext_src_spec = msg->msg[9]; + *plug = msg->msg[10]; + *phys_addr = (msg->msg[11] << 8) | msg->msg[12]; +} + +static inline void cec_msg_set_timer_program_title(struct cec_msg *msg, + const char *prog_title) +{ + unsigned int len = strlen(prog_title); + + if (len > 14) + len = 14; + msg->len = 2 + len; + msg->msg[1] = CEC_MSG_SET_TIMER_PROGRAM_TITLE; + memcpy(msg->msg + 2, prog_title, len); +} + +static inline void cec_ops_set_timer_program_title(const struct cec_msg *msg, + char *prog_title) +{ + unsigned int len = msg->len - 2; + + if (len > 14) + len = 14; + memcpy(prog_title, msg->msg + 2, len); + prog_title[len] = '\0'; +} + +/* System Information Feature */ +static inline void cec_msg_cec_version(struct cec_msg *msg, __u8 cec_version) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_CEC_VERSION; + msg->msg[2] = cec_version; +} + +static inline void cec_ops_cec_version(const struct cec_msg *msg, + __u8 *cec_version) +{ + *cec_version = msg->msg[2]; +} + +static inline void cec_msg_get_cec_version(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GET_CEC_VERSION; + msg->reply = reply ? CEC_MSG_CEC_VERSION : 0; +} + +static inline void cec_msg_report_physical_addr(struct cec_msg *msg, + __u16 phys_addr, __u8 prim_devtype) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_PHYSICAL_ADDR; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->msg[4] = prim_devtype; +} + +static inline void cec_ops_report_physical_addr(const struct cec_msg *msg, + __u16 *phys_addr, __u8 *prim_devtype) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *prim_devtype = msg->msg[4]; +} + +static inline void cec_msg_give_physical_addr(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_PHYSICAL_ADDR; + msg->reply = reply ? CEC_MSG_REPORT_PHYSICAL_ADDR : 0; +} + +static inline void cec_msg_set_menu_language(struct cec_msg *msg, + const char *language) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_SET_MENU_LANGUAGE; + memcpy(msg->msg + 2, language, 3); +} + +static inline void cec_ops_set_menu_language(struct cec_msg *msg, + char *language) +{ + memcpy(language, msg->msg + 2, 3); + language[3] = '\0'; +} + +static inline void cec_msg_get_menu_language(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GET_MENU_LANGUAGE; + msg->reply = reply ? CEC_MSG_SET_MENU_LANGUAGE : 0; +} + +/* + * Assumes a single RC Profile byte and a single Device Features byte, + * i.e. no extended features are supported by this helper function. + * + * As of CEC 2.0 no extended features are defined, should those be added + * in the future, then this function needs to be adapted or a new function + * should be added. + */ +static inline void cec_msg_report_features(struct cec_msg *msg, + __u8 cec_version, __u8 all_device_types, + __u8 rc_profile, __u8 dev_features) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_FEATURES; + msg->msg[2] = cec_version; + msg->msg[3] = all_device_types; + msg->msg[4] = rc_profile; + msg->msg[5] = dev_features; +} + +static inline void cec_ops_report_features(const struct cec_msg *msg, + __u8 *cec_version, __u8 *all_device_types, + const __u8 **rc_profile, const __u8 **dev_features) +{ + const __u8 *p = &msg->msg[4]; + + *cec_version = msg->msg[2]; + *all_device_types = msg->msg[3]; + *rc_profile = p; + while (p < &msg->msg[14] && (*p & CEC_OP_FEAT_EXT)) + p++; + if (!(*p & CEC_OP_FEAT_EXT)) { + *dev_features = p + 1; + while (p < &msg->msg[15] && (*p & CEC_OP_FEAT_EXT)) + p++; + } + if (*p & CEC_OP_FEAT_EXT) + *rc_profile = *dev_features = NULL; +} + +static inline void cec_msg_give_features(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_FEATURES; + msg->reply = reply ? CEC_MSG_REPORT_FEATURES : 0; +} + +/* Deck Control Feature */ +static inline void cec_msg_deck_control(struct cec_msg *msg, + __u8 deck_control_mode) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_DECK_CONTROL; + msg->msg[2] = deck_control_mode; +} + +static inline void cec_ops_deck_control(struct cec_msg *msg, + __u8 *deck_control_mode) +{ + *deck_control_mode = msg->msg[2]; +} + +static inline void cec_msg_deck_status(struct cec_msg *msg, + __u8 deck_info) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_DECK_STATUS; + msg->msg[2] = deck_info; +} + +static inline void cec_ops_deck_status(struct cec_msg *msg, + __u8 *deck_info) +{ + *deck_info = msg->msg[2]; +} + +static inline void cec_msg_give_deck_status(struct cec_msg *msg, + bool reply, + __u8 status_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_GIVE_DECK_STATUS; + msg->msg[2] = status_req; + msg->reply = reply ? CEC_MSG_DECK_STATUS : 0; +} + +static inline void cec_ops_give_deck_status(struct cec_msg *msg, + __u8 *status_req) +{ + *status_req = msg->msg[2]; +} + +static inline void cec_msg_play(struct cec_msg *msg, + __u8 play_mode) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_PLAY; + msg->msg[2] = play_mode; +} + +static inline void cec_ops_play(struct cec_msg *msg, + __u8 *play_mode) +{ + *play_mode = msg->msg[2]; +} + + +/* Tuner Control Feature */ +struct cec_op_tuner_device_info { + __u8 rec_flag; + __u8 tuner_display_info; + bool is_analog; + union { + struct cec_op_digital_service_id digital; + struct { + __u8 ana_bcast_type; + __u16 ana_freq; + __u8 bcast_system; + } analog; + }; +}; + +static inline void cec_msg_tuner_device_status_analog(struct cec_msg *msg, + __u8 rec_flag, + __u8 tuner_display_info, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 7; + msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS; + msg->msg[2] = (rec_flag << 7) | tuner_display_info; + msg->msg[3] = ana_bcast_type; + msg->msg[4] = ana_freq >> 8; + msg->msg[5] = ana_freq & 0xff; + msg->msg[6] = bcast_system; +} + +static inline void cec_msg_tuner_device_status_digital(struct cec_msg *msg, + __u8 rec_flag, __u8 tuner_display_info, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 10; + msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS; + msg->msg[2] = (rec_flag << 7) | tuner_display_info; + cec_set_digital_service_id(msg->msg + 3, digital); +} + +static inline void cec_msg_tuner_device_status(struct cec_msg *msg, + const struct cec_op_tuner_device_info *tuner_dev_info) +{ + if (tuner_dev_info->is_analog) + cec_msg_tuner_device_status_analog(msg, + tuner_dev_info->rec_flag, + tuner_dev_info->tuner_display_info, + tuner_dev_info->analog.ana_bcast_type, + tuner_dev_info->analog.ana_freq, + tuner_dev_info->analog.bcast_system); + else + cec_msg_tuner_device_status_digital(msg, + tuner_dev_info->rec_flag, + tuner_dev_info->tuner_display_info, + &tuner_dev_info->digital); +} + +static inline void cec_ops_tuner_device_status(struct cec_msg *msg, + struct cec_op_tuner_device_info *tuner_dev_info) +{ + tuner_dev_info->is_analog = msg->len < 10; + tuner_dev_info->rec_flag = msg->msg[2] >> 7; + tuner_dev_info->tuner_display_info = msg->msg[2] & 0x7f; + if (tuner_dev_info->is_analog) { + tuner_dev_info->analog.ana_bcast_type = msg->msg[3]; + tuner_dev_info->analog.ana_freq = (msg->msg[4] << 8) | msg->msg[5]; + tuner_dev_info->analog.bcast_system = msg->msg[6]; + return; + } + cec_get_digital_service_id(msg->msg + 3, &tuner_dev_info->digital); +} + +static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg, + bool reply, + __u8 status_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS; + msg->msg[2] = status_req; + msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0; +} + +static inline void cec_ops_give_tuner_device_status(struct cec_msg *msg, + __u8 *status_req) +{ + *status_req = msg->msg[2]; +} + +static inline void cec_msg_select_analogue_service(struct cec_msg *msg, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 6; + msg->msg[1] = CEC_MSG_SELECT_ANALOGUE_SERVICE; + msg->msg[2] = ana_bcast_type; + msg->msg[3] = ana_freq >> 8; + msg->msg[4] = ana_freq & 0xff; + msg->msg[5] = bcast_system; +} + +static inline void cec_ops_select_analogue_service(struct cec_msg *msg, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *ana_bcast_type = msg->msg[2]; + *ana_freq = (msg->msg[3] << 8) | msg->msg[4]; + *bcast_system = msg->msg[5]; +} + +static inline void cec_msg_select_digital_service(struct cec_msg *msg, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 9; + msg->msg[1] = CEC_MSG_SELECT_DIGITAL_SERVICE; + cec_set_digital_service_id(msg->msg + 2, digital); +} + +static inline void cec_ops_select_digital_service(struct cec_msg *msg, + struct cec_op_digital_service_id *digital) +{ + cec_get_digital_service_id(msg->msg + 2, digital); +} + +static inline void cec_msg_tuner_step_decrement(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TUNER_STEP_DECREMENT; +} + +static inline void cec_msg_tuner_step_increment(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TUNER_STEP_INCREMENT; +} + + +/* Vendor Specific Commands Feature */ +static inline void cec_msg_device_vendor_id(struct cec_msg *msg, __u32 vendor_id) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_DEVICE_VENDOR_ID; + msg->msg[2] = vendor_id >> 16; + msg->msg[3] = (vendor_id >> 8) & 0xff; + msg->msg[4] = vendor_id & 0xff; +} + +static inline void cec_ops_device_vendor_id(const struct cec_msg *msg, + __u32 *vendor_id) +{ + *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4]; +} + +static inline void cec_msg_give_device_vendor_id(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_DEVICE_VENDOR_ID; + msg->reply = reply ? CEC_MSG_DEVICE_VENDOR_ID : 0; +} + +static inline void cec_msg_vendor_remote_button_up(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_UP; +} + + +/* OSD Display Feature */ +static inline void cec_msg_set_osd_string(struct cec_msg *msg, + __u8 disp_ctl, + const char *osd) +{ + unsigned int len = strlen(osd); + + if (len > 13) + len = 13; + msg->len = 3 + len; + msg->msg[1] = CEC_MSG_SET_OSD_STRING; + msg->msg[2] = disp_ctl; + memcpy(msg->msg + 3, osd, len); +} + +static inline void cec_ops_set_osd_string(const struct cec_msg *msg, + __u8 *disp_ctl, + char *osd) +{ + unsigned int len = msg->len - 3; + + *disp_ctl = msg->msg[2]; + if (len > 13) + len = 13; + memcpy(osd, msg->msg + 3, len); + osd[len] = '\0'; +} + + +/* Device OSD Transfer Feature */ +static inline void cec_msg_set_osd_name(struct cec_msg *msg, const char *name) +{ + unsigned int len = strlen(name); + + if (len > 14) + len = 14; + msg->len = 2 + len; + msg->msg[1] = CEC_MSG_SET_OSD_NAME; + memcpy(msg->msg + 2, name, len); +} + +static inline void cec_ops_set_osd_name(const struct cec_msg *msg, + char *name) +{ + unsigned int len = msg->len - 2; + + if (len > 14) + len = 14; + memcpy(name, msg->msg + 2, len); + name[len] = '\0'; +} + +static inline void cec_msg_give_osd_name(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_OSD_NAME; + msg->reply = reply ? CEC_MSG_SET_OSD_NAME : 0; +} + + +/* Device Menu Control Feature */ +static inline void cec_msg_menu_status(struct cec_msg *msg, + __u8 menu_state) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_MENU_STATUS; + msg->msg[2] = menu_state; +} + +static inline void cec_ops_menu_status(struct cec_msg *msg, + __u8 *menu_state) +{ + *menu_state = msg->msg[2]; +} + +static inline void cec_msg_menu_request(struct cec_msg *msg, + bool reply, + __u8 menu_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_MENU_REQUEST; + msg->msg[2] = menu_req; + msg->reply = reply ? CEC_MSG_MENU_STATUS : 0; +} + +static inline void cec_ops_menu_request(struct cec_msg *msg, + __u8 *menu_req) +{ + *menu_req = msg->msg[2]; +} + +struct cec_op_ui_command { + __u8 ui_cmd; + bool has_opt_arg; + union { + struct cec_op_channel_data channel_identifier; + __u8 ui_broadcast_type; + __u8 ui_sound_presentation_control; + __u8 play_mode; + __u8 ui_function_media; + __u8 ui_function_select_av_input; + __u8 ui_function_select_audio_input; + }; +}; + +static inline void cec_msg_user_control_pressed(struct cec_msg *msg, + const struct cec_op_ui_command *ui_cmd) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_USER_CONTROL_PRESSED; + msg->msg[2] = ui_cmd->ui_cmd; + if (!ui_cmd->has_opt_arg) + return; + switch (ui_cmd->ui_cmd) { + case 0x56: + case 0x57: + case 0x60: + case 0x68: + case 0x69: + case 0x6a: + /* The optional operand is one byte for all these ui commands */ + msg->len++; + msg->msg[3] = ui_cmd->play_mode; + break; + case 0x67: + msg->len += 4; + msg->msg[3] = (ui_cmd->channel_identifier.channel_number_fmt << 2) | + (ui_cmd->channel_identifier.major >> 8); + msg->msg[4] = ui_cmd->channel_identifier.major && 0xff; + msg->msg[5] = ui_cmd->channel_identifier.minor >> 8; + msg->msg[6] = ui_cmd->channel_identifier.minor & 0xff; + break; + } +} + +static inline void cec_ops_user_control_pressed(struct cec_msg *msg, + struct cec_op_ui_command *ui_cmd) +{ + ui_cmd->ui_cmd = msg->msg[2]; + ui_cmd->has_opt_arg = false; + if (msg->len == 3) + return; + switch (ui_cmd->ui_cmd) { + case 0x56: + case 0x57: + case 0x60: + case 0x68: + case 0x69: + case 0x6a: + /* The optional operand is one byte for all these ui commands */ + ui_cmd->play_mode = msg->msg[3]; + ui_cmd->has_opt_arg = true; + break; + case 0x67: + if (msg->len < 7) + break; + ui_cmd->has_opt_arg = true; + ui_cmd->channel_identifier.channel_number_fmt = msg->msg[3] >> 2; + ui_cmd->channel_identifier.major = ((msg->msg[3] & 3) << 6) | msg->msg[4]; + ui_cmd->channel_identifier.minor = (msg->msg[5] << 8) | msg->msg[6]; + break; + } +} + +static inline void cec_msg_user_control_released(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_USER_CONTROL_RELEASED; +} + +/* Remote Control Passthrough Feature */ + +/* Power Status Feature */ +static inline void cec_msg_report_power_status(struct cec_msg *msg, + __u8 pwr_state) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_REPORT_POWER_STATUS; + msg->msg[2] = pwr_state; +} + +static inline void cec_ops_report_power_status(const struct cec_msg *msg, + __u8 *pwr_state) +{ + *pwr_state = msg->msg[2]; +} + +static inline void cec_msg_give_device_power_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_DEVICE_POWER_STATUS; + msg->reply = reply ? CEC_MSG_REPORT_POWER_STATUS : 0; +} + +/* General Protocol Messages */ +static inline void cec_msg_feature_abort(struct cec_msg *msg, + __u8 abort_msg, __u8 reason) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_FEATURE_ABORT; + msg->msg[2] = abort_msg; + msg->msg[3] = reason; +} + +static inline void cec_ops_feature_abort(const struct cec_msg *msg, + __u8 *abort_msg, __u8 *reason) +{ + *abort_msg = msg->msg[2]; + *reason = msg->msg[3]; +} + +/* This changes the current message into a feature abort message */ +static inline void cec_msg_reply_feature_abort(struct cec_msg *msg, __u8 reason) +{ + cec_msg_set_reply_to(msg, msg); + msg->len = 4; + msg->msg[2] = msg->msg[1]; + msg->msg[3] = reason; + msg->msg[1] = CEC_MSG_FEATURE_ABORT; +} + +static inline void cec_msg_abort(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_ABORT; +} + + +/* System Audio Control Feature */ +static inline void cec_msg_report_audio_status(struct cec_msg *msg, + __u8 aud_mute_status, + __u8 aud_vol_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_REPORT_AUDIO_STATUS; + msg->msg[2] = (aud_mute_status << 7) | (aud_vol_status & 0x7f); +} + +static inline void cec_ops_report_audio_status(const struct cec_msg *msg, + __u8 *aud_mute_status, + __u8 *aud_vol_status) +{ + *aud_mute_status = msg->msg[2] >> 7; + *aud_vol_status = msg->msg[2] & 0x7f; +} + +static inline void cec_msg_give_audio_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_AUDIO_STATUS; + msg->reply = reply ? CEC_MSG_REPORT_AUDIO_STATUS : 0; +} + +static inline void cec_msg_set_system_audio_mode(struct cec_msg *msg, + __u8 sys_aud_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SET_SYSTEM_AUDIO_MODE; + msg->msg[2] = sys_aud_status; +} + +static inline void cec_ops_set_system_audio_mode(const struct cec_msg *msg, + __u8 *sys_aud_status) +{ + *sys_aud_status = msg->msg[2]; +} + +static inline void cec_msg_system_audio_mode_request(struct cec_msg *msg, + bool reply, + __u16 phys_addr) +{ + msg->len = phys_addr == 0xffff ? 2 : 4; + msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_SET_SYSTEM_AUDIO_MODE : 0; + +} + +static inline void cec_ops_system_audio_mode_request(const struct cec_msg *msg, + __u16 *phys_addr) +{ + if (msg->len < 4) + *phys_addr = 0xffff; + else + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_system_audio_mode_status(struct cec_msg *msg, + __u8 sys_aud_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_STATUS; + msg->msg[2] = sys_aud_status; +} + +static inline void cec_ops_system_audio_mode_status(const struct cec_msg *msg, + __u8 *sys_aud_status) +{ + *sys_aud_status = msg->msg[2]; +} + +static inline void cec_msg_give_system_audio_mode_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS; + msg->reply = reply ? CEC_MSG_SYSTEM_AUDIO_MODE_STATUS : 0; +} + +static inline void cec_msg_report_short_audio_descriptor(struct cec_msg *msg, + __u8 num_descriptors, + const __u32 *descriptors) +{ + unsigned int i; + + if (num_descriptors > 4) + num_descriptors = 4; + msg->len = 2 + num_descriptors * 3; + msg->msg[1] = CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR; + for (i = 0; i < num_descriptors; i++) { + msg->msg[2 + i * 3] = (descriptors[i] >> 16) & 0xff; + msg->msg[3 + i * 3] = (descriptors[i] >> 8) & 0xff; + msg->msg[4 + i * 3] = descriptors[i] & 0xff; + } +} + +static inline void cec_ops_report_short_audio_descriptor(const struct cec_msg *msg, + __u8 *num_descriptors, + __u32 *descriptors) +{ + unsigned int i; + + *num_descriptors = (msg->len - 2) / 3; + if (*num_descriptors > 4) + *num_descriptors = 4; + for (i = 0; i < *num_descriptors; i++) + descriptors[i] = (msg->msg[2 + i * 3] << 16) | + (msg->msg[3 + i * 3] << 8) | + msg->msg[4 + i * 3]; +} + +static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg, + __u8 num_descriptors, + const __u8 *audio_format_id, + const __u8 *audio_format_code) +{ + unsigned int i; + + if (num_descriptors > 4) + num_descriptors = 4; + msg->len = 2 + num_descriptors; + msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR; + for (i = 0; i < num_descriptors; i++) + msg->msg[2 + i] = (audio_format_id[i] << 6) | + (audio_format_code[i] & 0x3f); +} + +static inline void cec_ops_request_short_audio_descriptor(const struct cec_msg *msg, + __u8 *num_descriptors, + __u8 *audio_format_id, + __u8 *audio_format_code) +{ + unsigned int i; + + *num_descriptors = msg->len - 2; + if (*num_descriptors > 4) + *num_descriptors = 4; + for (i = 0; i < *num_descriptors; i++) { + audio_format_id[i] = msg->msg[2 + i] >> 6; + audio_format_code[i] = msg->msg[2 + i] & 0x3f; + } +} + + +/* Audio Rate Control Feature */ +static inline void cec_msg_set_audio_rate(struct cec_msg *msg, + __u8 audio_rate) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SET_AUDIO_RATE; + msg->msg[2] = audio_rate; +} + +static inline void cec_ops_set_audio_rate(const struct cec_msg *msg, + __u8 *audio_rate) +{ + *audio_rate = msg->msg[2]; +} + + +/* Audio Return Channel Control Feature */ +static inline void cec_msg_report_arc_initiated(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REPORT_ARC_INITIATED; +} + +static inline void cec_msg_initiate_arc(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_INITIATE_ARC; + msg->reply = reply ? CEC_MSG_REPORT_ARC_INITIATED : 0; +} + +static inline void cec_msg_request_arc_initiation(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REQUEST_ARC_INITIATION; + msg->reply = reply ? CEC_MSG_INITIATE_ARC : 0; +} + +static inline void cec_msg_report_arc_terminated(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REPORT_ARC_TERMINATED; +} + +static inline void cec_msg_terminate_arc(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TERMINATE_ARC; + msg->reply = reply ? CEC_MSG_REPORT_ARC_TERMINATED : 0; +} + +static inline void cec_msg_request_arc_termination(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REQUEST_ARC_TERMINATION; + msg->reply = reply ? CEC_MSG_TERMINATE_ARC : 0; +} + + +/* Dynamic Audio Lipsync Feature */ +/* Only for CEC 2.0 and up */ +static inline void cec_msg_report_current_latency(struct cec_msg *msg, + __u16 phys_addr, + __u8 video_latency, + __u8 low_latency_mode, + __u8 audio_out_compensated, + __u8 audio_out_delay) +{ + msg->len = 7; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_CURRENT_LATENCY; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->msg[4] = video_latency; + msg->msg[5] = (low_latency_mode << 2) | audio_out_compensated; + msg->msg[6] = audio_out_delay; +} + +static inline void cec_ops_report_current_latency(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *video_latency, + __u8 *low_latency_mode, + __u8 *audio_out_compensated, + __u8 *audio_out_delay) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *video_latency = msg->msg[4]; + *low_latency_mode = (msg->msg[5] >> 2) & 1; + *audio_out_compensated = msg->msg[5] & 3; + *audio_out_delay = msg->msg[6]; +} + +static inline void cec_msg_request_current_latency(struct cec_msg *msg, + bool reply, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REQUEST_CURRENT_LATENCY; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_REPORT_CURRENT_LATENCY : 0; +} + +static inline void cec_ops_request_current_latency(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + + +/* Capability Discovery and Control Feature */ +static inline void cec_msg_cdc_hec_inquire_state(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2) +{ + msg->len = 9; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; +} + +static inline void cec_ops_cdc_hec_inquire_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; +} + +static inline void cec_msg_cdc_hec_report_state(struct cec_msg *msg, + __u16 target_phys_addr, + __u8 hec_func_state, + __u8 host_func_state, + __u8 enc_func_state, + __u8 cdc_errcode, + __u8 has_field, + __u16 hec_field) +{ + msg->len = has_field ? 10 : 8; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_REPORT_STATE; + msg->msg[5] = target_phys_addr >> 8; + msg->msg[6] = target_phys_addr & 0xff; + msg->msg[7] = (hec_func_state << 6) | + (host_func_state << 4) | + (enc_func_state << 2) | + cdc_errcode; + if (has_field) { + msg->msg[8] = hec_field >> 8; + msg->msg[9] = hec_field & 0xff; + } +} + +static inline void cec_ops_cdc_hec_report_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *target_phys_addr, + __u8 *hec_func_state, + __u8 *host_func_state, + __u8 *enc_func_state, + __u8 *cdc_errcode, + __u8 *has_field, + __u16 *hec_field) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *target_phys_addr = (msg->msg[5] << 8) | msg->msg[6]; + *hec_func_state = msg->msg[7] >> 6; + *host_func_state = (msg->msg[7] >> 4) & 3; + *enc_func_state = (msg->msg[7] >> 4) & 3; + *cdc_errcode = msg->msg[7] & 3; + *has_field = msg->len >= 10; + *hec_field = *has_field ? ((msg->msg[8] << 8) | msg->msg[9]) : 0; +} + +static inline void cec_msg_cdc_hec_set_state(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2, + __u8 hec_set_state, + __u16 phys_addr3, + __u16 phys_addr4, + __u16 phys_addr5) +{ + msg->len = 10; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; + msg->msg[9] = hec_set_state; + if (phys_addr3 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr3 >> 8; + msg->msg[msg->len++] = phys_addr3 & 0xff; + if (phys_addr4 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr4 >> 8; + msg->msg[msg->len++] = phys_addr4 & 0xff; + if (phys_addr5 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr5 >> 8; + msg->msg[msg->len++] = phys_addr5 & 0xff; + } + } + } +} + +static inline void cec_ops_cdc_hec_set_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2, + __u8 *hec_set_state, + __u16 *phys_addr3, + __u16 *phys_addr4, + __u16 *phys_addr5) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; + *hec_set_state = msg->msg[9]; + *phys_addr3 = *phys_addr4 = *phys_addr5 = CEC_PHYS_ADDR_INVALID; + if (msg->len >= 12) + *phys_addr3 = (msg->msg[10] << 8) | msg->msg[11]; + if (msg->len >= 14) + *phys_addr4 = (msg->msg[12] << 8) | msg->msg[13]; + if (msg->len >= 16) + *phys_addr5 = (msg->msg[14] << 8) | msg->msg[15]; +} + +static inline void cec_msg_cdc_hec_set_state_adjacent(struct cec_msg *msg, + __u16 phys_addr1, + __u8 hec_set_state) +{ + msg->len = 8; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_SET_STATE_ADJACENT; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = hec_set_state; +} + +static inline void cec_ops_cdc_hec_set_state_adjacent(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u8 *hec_set_state) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *hec_set_state = msg->msg[7]; +} + +static inline void cec_msg_cdc_hec_request_deactivation(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2, + __u16 phys_addr3) +{ + msg->len = 11; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; + msg->msg[9] = phys_addr3 >> 8; + msg->msg[10] = phys_addr3 & 0xff; +} + +static inline void cec_ops_cdc_hec_request_deactivation(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2, + __u16 *phys_addr3) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; + *phys_addr3 = (msg->msg[9] << 8) | msg->msg[10]; +} + +static inline void cec_msg_cdc_hec_notify_alive(struct cec_msg *msg) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_NOTIFY_ALIVE; +} + +static inline void cec_ops_cdc_hec_notify_alive(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_cdc_hec_discover(struct cec_msg *msg) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_DISCOVER; +} + +static inline void cec_ops_cdc_hec_discover(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_cdc_hpd_set_state(struct cec_msg *msg, + __u8 input_port, + __u8 hpd_state) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HPD_SET_STATE; + msg->msg[5] = (input_port << 4) | hpd_state; +} + +static inline void cec_ops_cdc_hpd_set_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *input_port, + __u8 *hpd_state) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *input_port = msg->msg[5] >> 4; + *hpd_state = msg->msg[5] & 0xf; +} + +static inline void cec_msg_cdc_hpd_report_state(struct cec_msg *msg, + __u8 hpd_state, + __u8 hpd_error) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HPD_REPORT_STATE; + msg->msg[5] = (hpd_state << 4) | hpd_error; +} + +static inline void cec_ops_cdc_hpd_report_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *hpd_state, + __u8 *hpd_error) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *hpd_state = msg->msg[5] >> 4; + *hpd_error = msg->msg[5] & 0xf; +} + +#endif -- cgit v1.2.3 From 9828c2c6c1048c61034a8b94e6376aeff6d2284f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 28 Jun 2016 09:03:59 +0200 Subject: block: Convert fifo_time from ulong to u64 Currently rq->fifo_time is unsigned long but CFQ stores nanosecond timestamp in it which would overflow on 32-bit archs. Convert it to u64 to avoid the overflow. Since the rq->fifo_time is unioned with struct call_single_data(), this does not change the size of struct request in any way. We have to slightly fixup block/deadline-iosched.c so that comparison happens in the right types. Fixes: 9a7f38c42c2b92391d9dabaf9f51df7cfe5608e4 Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- block/deadline-iosched.c | 5 +++-- include/linux/blkdev.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index d0dd7882d8c7..26a9d3c8057a 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -173,7 +173,8 @@ deadline_merged_requests(struct request_queue *q, struct request *req, * and move into next position (next will be deleted) in fifo */ if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) { - if (time_before(next->fifo_time, req->fifo_time)) { + if (time_before((unsigned long)next->fifo_time, + (unsigned long)req->fifo_time)) { list_move(&req->queuelist, &next->queuelist); req->fifo_time = next->fifo_time; } @@ -227,7 +228,7 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir) /* * rq is expired! */ - if (time_after_eq(jiffies, rq->fifo_time)) + if (time_after_eq(jiffies, (unsigned long)rq->fifo_time)) return 1; return 0; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 9746d223494c..d116d3b52c73 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -90,7 +90,7 @@ struct request { struct list_head queuelist; union { struct call_single_data csd; - unsigned long fifo_time; + u64 fifo_time; }; struct request_queue *q; -- cgit v1.2.3 From cbf9077e586b9c0db1a1ce5690552ae268c15848 Mon Sep 17 00:00:00 2001 From: Chris Lapa Date: Fri, 24 Jun 2016 12:26:08 +1000 Subject: max8903: cleans up confusing relationship between dc_valid, dok and dcm. The max8903_charger.h file indicated that dcm and dok were not optional when dc_valid is set. It makes sense to have dok as a compulsory pin when dc_valid is given. However dcm can be optionally wired to a fixed level especially when the circuit is configured for dc power exclusively. The previous implementation already allowed for this somewhat, however no error was given if dok wasn't given whilst dc_valid was. The new implementation enforces dok presence when dc_valid is given. Whilst allowing dcm to be optional. Signed-off-by: Chris Lapa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/max8903_charger.c | 22 +++++++++------------- include/linux/power/max8903_charger.h | 6 +++--- 2 files changed, 12 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 0a5b0e142788..6ec705f7a9d9 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -211,27 +211,23 @@ static int max8903_probe(struct platform_device *pdev) } if (pdata->dc_valid) { - if (pdata->dok && gpio_is_valid(pdata->dok) && - pdata->dcm && gpio_is_valid(pdata->dcm)) { + if (pdata->dok && gpio_is_valid(pdata->dok)) { gpio = pdata->dok; /* PULL_UPed Interrupt */ ta_in = gpio_get_value(gpio) ? 0 : 1; + } else { + dev_err(dev, "When DC is wired, DOK should be wired as well.\n"); + return -EINVAL; + } + } + if (pdata->dcm) { + if (gpio_is_valid(pdata->dcm)) { gpio = pdata->dcm; /* Output */ gpio_set_value(gpio, ta_in); } else { - dev_err(dev, "When DC is wired, DOK and DCM should" - " be wired as well.\n"); + dev_err(dev, "Invalid pin: dcm.\n"); return -EINVAL; } - } else { - if (pdata->dcm) { - if (gpio_is_valid(pdata->dcm)) - gpio_set_value(pdata->dcm, 0); - else { - dev_err(dev, "Invalid pin: dcm.\n"); - return -EINVAL; - } - } } if (pdata->usb_valid) { diff --git a/include/linux/power/max8903_charger.h b/include/linux/power/max8903_charger.h index 24f51db8a83f..89d3f1cb3433 100644 --- a/include/linux/power/max8903_charger.h +++ b/include/linux/power/max8903_charger.h @@ -26,8 +26,8 @@ struct max8903_pdata { /* * GPIOs - * cen, chg, flt, and usus are optional. - * dok, dcm, and uok are not optional depending on the status of + * cen, chg, flt, dcm and usus are optional. + * dok and uok are not optional depending on the status of * dc_valid and usb_valid. */ int cen; /* Charger Enable input */ @@ -41,7 +41,7 @@ struct max8903_pdata { /* * DC(Adapter/TA) is wired * When dc_valid is true, - * dok and dcm should be valid. + * dok should be valid. * * At least one of dc_valid or usb_valid should be true. */ -- cgit v1.2.3 From e81b87d22a8fed6bac24197972c9c394a2b92b5d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 28 Jun 2016 13:25:04 +0200 Subject: clk: Provide notifier stubs when !COMMON_CLK The clk notifier symbols are hidden by COMMON_CLK. However on some platforms HAVE_CLK might be set while COMMON_CLK not which leads to compile test build errors like: $ make.cross ARCH=sh drivers/devfreq/tegra-devfreq.c: In function 'tegra_actmon_rate_notify_cb': >> drivers/devfreq/tegra-devfreq.c:391:16: error: 'POST_RATE_CHANGE' undeclared (first use in this function) if (action != POST_RATE_CHANGE) ^ drivers/devfreq/tegra-devfreq.c: In function 'tegra_devfreq_probe': >> drivers/devfreq/tegra-devfreq.c:654:8: error: implicit declaration of function 'clk_notifier_register' [-Werror=implicit-function-declaration] err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb); ^ Export the macros and data type declarations outside of COMMON_CLK ifdef and provide stubs to fix the compile testing. Reported-by: kbuild test robot Signed-off-by: Krzysztof Kozlowski Tested-by: Bartlomiej Zolnierkiewicz Signed-off-by: Stephen Boyd --- include/linux/clk.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/clk.h b/include/linux/clk.h index 0df4a51e1a78..a89ba4e7af7a 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -20,8 +20,6 @@ struct device; struct clk; -#ifdef CONFIG_COMMON_CLK - /** * DOC: clk notifier callback types * @@ -78,6 +76,8 @@ struct clk_notifier_data { unsigned long new_rate; }; +#ifdef CONFIG_COMMON_CLK + /** * clk_notifier_register: register a clock rate-change notifier callback * @clk: clock whose rate we are interested in @@ -140,6 +140,18 @@ bool clk_is_match(const struct clk *p, const struct clk *q); #else +static inline int clk_notifier_register(struct clk *clk, + struct notifier_block *nb) +{ + return -ENOTSUPP; +} + +static inline int clk_notifier_unregister(struct clk *clk, + struct notifier_block *nb) +{ + return -ENOTSUPP; +} + static inline long clk_get_accuracy(struct clk *clk) { return -ENOTSUPP; -- cgit v1.2.3 From 7eb231c337e00735d4b553ed4ae7f9441598f028 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 17 Jun 2016 12:27:52 +0200 Subject: PM / Domains: Convert pm_genpd_init() to return an error code The are already cases when pm_genpd_init() can fail. Currently we hide the failures instead of propagating an error code, which is a better method. Moreover, to prepare for future changes like moving away from using a fixed array-size of the struct genpd_power_state, to instead dynamically allocate data for it, the pm_genpd_init() API needs to be able to return an error code, as allocation can fail. Current users of the pm_genpd_init() is thus requested to start dealing with error codes. In the transition phase, users will have to live with only error messages being printed to log. Signed-off-by: Ulf Hansson Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 10 +++++++--- include/linux/pm_domain.h | 9 +++++---- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 9193aacf7b1b..a1f2aff33997 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1258,12 +1258,14 @@ EXPORT_SYMBOL_GPL(pm_genpd_remove_subdomain); * @genpd: PM domain object to initialize. * @gov: PM domain governor to associate with the domain (may be NULL). * @is_off: Initial value of the domain's power_is_off field. + * + * Returns 0 on successful initialization, else a negative error code. */ -void pm_genpd_init(struct generic_pm_domain *genpd, - struct dev_power_governor *gov, bool is_off) +int pm_genpd_init(struct generic_pm_domain *genpd, + struct dev_power_governor *gov, bool is_off) { if (IS_ERR_OR_NULL(genpd)) - return; + return -EINVAL; INIT_LIST_HEAD(&genpd->master_links); INIT_LIST_HEAD(&genpd->slave_links); @@ -1321,6 +1323,8 @@ void pm_genpd_init(struct generic_pm_domain *genpd, mutex_lock(&gpd_list_lock); list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); + + return 0; } EXPORT_SYMBOL_GPL(pm_genpd_init); diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index dd5b0447d572..31fec858088c 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -127,8 +127,8 @@ extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *new_subdomain); extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *target); -extern void pm_genpd_init(struct generic_pm_domain *genpd, - struct dev_power_governor *gov, bool is_off); +extern int pm_genpd_init(struct generic_pm_domain *genpd, + struct dev_power_governor *gov, bool is_off); extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; @@ -163,9 +163,10 @@ static inline int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, { return -ENOSYS; } -static inline void pm_genpd_init(struct generic_pm_domain *genpd, - struct dev_power_governor *gov, bool is_off) +static inline int pm_genpd_init(struct generic_pm_domain *genpd, + struct dev_power_governor *gov, bool is_off) { + return -ENOSYS; } #endif -- cgit v1.2.3 From a99ab50dbbb1f982d076d19e0a9959fe2efa3126 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 28 Jun 2016 22:53:19 -0700 Subject: mfd: rn5t618: Add Ricoh RN5T567 PMIC support The Ricoh RN5T567 is from the same family as the Ricoh RN5T618 is, the differences are: + DCDC4 + Slightly different output voltage/currents + 32kHz Output - ADC/Charger capabilities Signed-off-by: Stefan Agner Reviewed-by: Marcel Ziswiler Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/rn5t618.txt | 19 +++++++++-------- drivers/mfd/Kconfig | 7 ++++--- drivers/mfd/rn5t618.c | 25 ++++++++++++++++------- include/linux/mfd/rn5t618.h | 12 +++++++++++ 4 files changed, 45 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/mfd/rn5t618.txt b/Documentation/devicetree/bindings/mfd/rn5t618.txt index 937785a3eddc..9e6770b105c9 100644 --- a/Documentation/devicetree/bindings/mfd/rn5t618.txt +++ b/Documentation/devicetree/bindings/mfd/rn5t618.txt @@ -1,18 +1,21 @@ -* Ricoh RN5T618 PMIC +* Ricoh RN5T567/RN5T618 PMIC -Ricoh RN5T618 is a power management IC which integrates 3 step-down -DCDC converters, 7 low-dropout regulators, a Li-ion battery charger, -fuel gauge, ADC, GPIOs and a watchdog timer. It can be controlled -through a I2C interface. +Ricoh RN5T567/RN5T618 is a power management IC family which integrates +3 to 4 step-down DCDC converters, 7 low-dropout regulators, GPIOs and +a watchdog timer. The RN5T618 provides additionally a Li-ion battery +charger, fuel gauge and an ADC. It can be controlled through an I2C +interface. Required properties: - - compatible: should be "ricoh,rn5t618" + - compatible: must be one of + "ricoh,rn5t567" + "ricoh,rn5t618" - reg: the I2C slave address of the device Sub-nodes: - regulators: the node is required if the regulator functionality is - needed. The valid regulator names are: DCDC1, DCDC2, DCDC3, LDO1, - LDO2, LDO3, LDO4, LDO5, LDORTC1 and LDORTC2. + needed. The valid regulator names are: DCDC1, DCDC2, DCDC3, DCDC4 + (RN5T567), LDO1, LDO2, LDO3, LDO4, LDO5, LDORTC1 and LDORTC2. The common bindings for each individual regulator can be found in: Documentation/devicetree/bindings/regulator/regulator.txt diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1bcf601de5bc..ff031a7735a5 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -852,13 +852,14 @@ config MFD_RK808 including interrupts, RTC, LDO & DCDC regulators, and onkey. config MFD_RN5T618 - tristate "Ricoh RN5T5618 PMIC" + tristate "Ricoh RN5T567/618 PMIC" depends on I2C + depends on OF select MFD_CORE select REGMAP_I2C help - Say yes here to add support for the Ricoh RN5T618 PMIC. This - driver provides common support for accessing the device, + Say yes here to add support for the Ricoh RN5T567 or R5T618 PMIC. + This driver provides common support for accessing the device, additional drivers must be enabled in order to use the functionality of the device. diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index 0ad51d792feb..c86160d3a773 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -2,6 +2,7 @@ * MFD core driver for Ricoh RN5T618 PMIC * * Copyright (C) 2014 Beniamino Galvani + * Copyright (C) 2016 Toradex AG * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,6 +16,7 @@ #include #include #include +#include #include static const struct mfd_cell rn5t618_cells[] = { @@ -59,17 +61,32 @@ static void rn5t618_power_off(void) RN5T618_SLPCNT_SWPWROFF, RN5T618_SLPCNT_SWPWROFF); } +static const struct of_device_id rn5t618_of_match[] = { + { .compatible = "ricoh,rn5t567", .data = (void *)RN5T567 }, + { .compatible = "ricoh,rn5t618", .data = (void *)RN5T618 }, + { } +}; +MODULE_DEVICE_TABLE(of, rn5t618_of_match); + static int rn5t618_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + const struct of_device_id *of_id; struct rn5t618 *priv; int ret; + of_id = of_match_device(rn5t618_of_match, &i2c->dev); + if (!of_id) { + dev_err(&i2c->dev, "Failed to find matching DT ID\n"); + return -EINVAL; + } + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; i2c_set_clientdata(i2c, priv); + priv->variant = (long)of_id->data; priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config); if (IS_ERR(priv->regmap)) { @@ -105,12 +122,6 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c) return 0; } -static const struct of_device_id rn5t618_of_match[] = { - { .compatible = "ricoh,rn5t618" }, - { } -}; -MODULE_DEVICE_TABLE(of, rn5t618_of_match); - static const struct i2c_device_id rn5t618_i2c_id[] = { { } }; @@ -129,5 +140,5 @@ static struct i2c_driver rn5t618_i2c_driver = { module_i2c_driver(rn5t618_i2c_driver); MODULE_AUTHOR("Beniamino Galvani "); -MODULE_DESCRIPTION("Ricoh RN5T618 MFD driver"); +MODULE_DESCRIPTION("Ricoh RN5T567/618 MFD driver"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/rn5t618.h b/include/linux/mfd/rn5t618.h index c72d5344f3b3..54179c2577ae 100644 --- a/include/linux/mfd/rn5t618.h +++ b/include/linux/mfd/rn5t618.h @@ -20,6 +20,7 @@ #define RN5T618_OTPVER 0x01 #define RN5T618_IODAC 0x02 #define RN5T618_VINDAC 0x03 +#define RN5T618_OUT32KEN 0x05 #define RN5T618_CPUCNT 0x06 #define RN5T618_PSWR 0x07 #define RN5T618_PONHIS 0x09 @@ -38,6 +39,7 @@ #define RN5T618_DC1_SLOT 0x16 #define RN5T618_DC2_SLOT 0x17 #define RN5T618_DC3_SLOT 0x18 +#define RN5T618_DC4_SLOT 0x19 #define RN5T618_LDO1_SLOT 0x1b #define RN5T618_LDO2_SLOT 0x1c #define RN5T618_LDO3_SLOT 0x1d @@ -54,12 +56,16 @@ #define RN5T618_DC2CTL2 0x2f #define RN5T618_DC3CTL 0x30 #define RN5T618_DC3CTL2 0x31 +#define RN5T618_DC4CTL 0x32 +#define RN5T618_DC4CTL2 0x33 #define RN5T618_DC1DAC 0x36 #define RN5T618_DC2DAC 0x37 #define RN5T618_DC3DAC 0x38 +#define RN5T618_DC4DAC 0x39 #define RN5T618_DC1DAC_SLP 0x3b #define RN5T618_DC2DAC_SLP 0x3c #define RN5T618_DC3DAC_SLP 0x3d +#define RN5T618_DC4DAC_SLP 0x3e #define RN5T618_DCIREN 0x40 #define RN5T618_DCIRQ 0x41 #define RN5T618_DCIRMON 0x42 @@ -221,8 +227,14 @@ enum { RN5T618_REG_NUM, }; +enum { + RN5T567 = 0, + RN5T618, +}; + struct rn5t618 { struct regmap *regmap; + long variant; }; #endif /* __LINUX_MFD_RN5T618_H */ -- cgit v1.2.3 From ed6d362d8dbc3494cd98cd771737ea8b1407ed61 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 28 Jun 2016 22:53:20 -0700 Subject: regulator: rn5t618: Add RN5T567 PMIC support Extend the driver to support Ricoh RN5T567. Support the additional DCDC and slightly different voltage range of LDORTC1. Signed-off-by: Stefan Agner Reviewed-by: Marcel Ziswiler Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/regulator/Kconfig | 5 +++-- drivers/regulator/rn5t618-regulator.c | 40 +++++++++++++++++++++++++++++++---- include/linux/mfd/rn5t618.h | 1 + 3 files changed, 40 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 144cbf5b3e5a..547269416950 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -636,10 +636,11 @@ config REGULATOR_RK808 outputs which can be controlled by i2c communication. config REGULATOR_RN5T618 - tristate "Ricoh RN5T618 voltage regulators" + tristate "Ricoh RN5T567/618 voltage regulators" depends on MFD_RN5T618 help - Say y here to support the regulators found on Ricoh RN5T618 PMIC. + Say y here to support the regulators found on Ricoh RN5T567 or + RN5T618 PMIC. config REGULATOR_RT5033 tristate "Richtek RT5033 Regulators" diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c index b85ceb8ff911..9c930eb68cda 100644 --- a/drivers/regulator/rn5t618-regulator.c +++ b/drivers/regulator/rn5t618-regulator.c @@ -46,6 +46,23 @@ static struct regulator_ops rn5t618_reg_ops = { .vsel_mask = (vmask), \ } +static struct regulator_desc rn5t567_regulators[] = { + /* DCDC */ + REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC2, DC2CTL, BIT(0), DC2DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC3, DC3CTL, BIT(0), DC3DAC, 0xff, 600000, 3500000, 12500), + REG(DCDC4, DC4CTL, BIT(0), DC4DAC, 0xff, 600000, 3500000, 12500), + /* LDO */ + REG(LDO1, LDOEN1, BIT(0), LDO1DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO2, LDOEN1, BIT(1), LDO2DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO3, LDOEN1, BIT(2), LDO3DAC, 0x7f, 600000, 3500000, 25000), + REG(LDO4, LDOEN1, BIT(3), LDO4DAC, 0x7f, 900000, 3500000, 25000), + REG(LDO5, LDOEN1, BIT(4), LDO5DAC, 0x7f, 900000, 3500000, 25000), + /* LDO RTC */ + REG(LDORTC1, LDOEN2, BIT(4), LDORTCDAC, 0x7f, 1200000, 3500000, 25000), + REG(LDORTC2, LDOEN2, BIT(5), LDORTC2DAC, 0x7f, 900000, 3500000, 25000), +}; + static struct regulator_desc rn5t618_regulators[] = { /* DCDC */ REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500), @@ -67,18 +84,33 @@ static int rn5t618_regulator_probe(struct platform_device *pdev) struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct regulator_dev *rdev; + struct regulator_desc *regulators; int i; + switch (rn5t618->variant) { + case RN5T567: + regulators = rn5t567_regulators; + break; + case RN5T618: + regulators = rn5t618_regulators; + break; + default: + return -EINVAL; + } + + config.dev = pdev->dev.parent; + config.regmap = rn5t618->regmap; + for (i = 0; i < RN5T618_REG_NUM; i++) { - config.dev = pdev->dev.parent; - config.regmap = rn5t618->regmap; + if (!regulators[i].name) + continue; rdev = devm_regulator_register(&pdev->dev, - &rn5t618_regulators[i], + ®ulators[i], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", - rn5t618_regulators[i].name); + regulators[i].name); return PTR_ERR(rdev); } } diff --git a/include/linux/mfd/rn5t618.h b/include/linux/mfd/rn5t618.h index 54179c2577ae..cadc6543909d 100644 --- a/include/linux/mfd/rn5t618.h +++ b/include/linux/mfd/rn5t618.h @@ -217,6 +217,7 @@ enum { RN5T618_DCDC1, RN5T618_DCDC2, RN5T618_DCDC3, + RN5T618_DCDC4, RN5T618_LDO1, RN5T618_LDO2, RN5T618_LDO3, -- cgit v1.2.3 From 9787f5e28b50774f1d5672e33b277ba1e9aa0753 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Thu, 2 Jun 2016 12:52:23 -0500 Subject: mfd: altr_a10sr: Add Altera Arria10 DevKit System Resource Chip Add support for the Altera Arria10 Development Kit System Resource chip which is implemented using a MAX5 as a external gpio extender with the regmap framework over a SPI bus. Signed-off-by: Thor Thayer Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 11 +++ drivers/mfd/Makefile | 2 + drivers/mfd/altera-a10sr.c | 169 +++++++++++++++++++++++++++++++++++++++ include/linux/mfd/altera-a10sr.h | 85 ++++++++++++++++++++ 4 files changed, 267 insertions(+) create mode 100644 drivers/mfd/altera-a10sr.c create mode 100644 include/linux/mfd/altera-a10sr.h (limited to 'include/linux') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ff031a7735a5..9402399bb3d6 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -18,6 +18,17 @@ config MFD_CS5535 This is the core driver for CS5535/CS5536 MFD functions. This is necessary for using the board's GPIO and MFGPT functionality. +config MFD_ALTERA_A10SR + bool "Altera Arria10 DevKit System Resource chip" + depends on ARCH_SOCFPGA && SPI_MASTER=y && OF + select REGMAP_SPI + select MFD_CORE + help + Support for the Altera Arria10 DevKit MAX5 System Resource chip + using the SPI interface. This driver provides common support for + accessing the external gpio extender (LEDs & buttons) and + power supply alarms (hwmon). + config MFD_ACT8945A tristate "Active-semi ACT8945A" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 42a66e19e191..2ba3ba35f745 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -205,3 +205,5 @@ intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o + +obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c new file mode 100644 index 000000000000..c05aa4ff57fd --- /dev/null +++ b/drivers/mfd/altera-a10sr.c @@ -0,0 +1,169 @@ +/* + * Copyright Intel Corporation (C) 2014-2016. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * SPI access for Altera Arria10 MAX5 System Resource Chip + * + * Adapted from DA9052 + */ + +#include +#include +#include +#include +#include + +static const struct mfd_cell altr_a10sr_subdev_info[] = { + { + .name = "altr_a10sr_gpio", + .of_compatible = "altr,a10sr-gpio", + }, +}; + +static bool altr_a10sr_reg_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ALTR_A10SR_VERSION_READ: + case ALTR_A10SR_LED_REG: + case ALTR_A10SR_PBDSW_REG: + case ALTR_A10SR_PBDSW_IRQ_REG: + case ALTR_A10SR_PWR_GOOD1_REG: + case ALTR_A10SR_PWR_GOOD2_REG: + case ALTR_A10SR_PWR_GOOD3_REG: + case ALTR_A10SR_FMCAB_REG: + case ALTR_A10SR_HPS_RST_REG: + case ALTR_A10SR_USB_QSPI_REG: + case ALTR_A10SR_SFPA_REG: + case ALTR_A10SR_SFPB_REG: + case ALTR_A10SR_I2C_M_REG: + case ALTR_A10SR_WARM_RST_REG: + case ALTR_A10SR_WR_KEY_REG: + case ALTR_A10SR_PMBUS_REG: + return true; + default: + return false; + } +} + +static bool altr_a10sr_reg_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ALTR_A10SR_LED_REG: + case ALTR_A10SR_PBDSW_IRQ_REG: + case ALTR_A10SR_FMCAB_REG: + case ALTR_A10SR_HPS_RST_REG: + case ALTR_A10SR_USB_QSPI_REG: + case ALTR_A10SR_SFPA_REG: + case ALTR_A10SR_SFPB_REG: + case ALTR_A10SR_WARM_RST_REG: + case ALTR_A10SR_WR_KEY_REG: + case ALTR_A10SR_PMBUS_REG: + return true; + default: + return false; + } +} + +static bool altr_a10sr_reg_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ALTR_A10SR_PBDSW_REG: + case ALTR_A10SR_PBDSW_IRQ_REG: + case ALTR_A10SR_PWR_GOOD1_REG: + case ALTR_A10SR_PWR_GOOD2_REG: + case ALTR_A10SR_PWR_GOOD3_REG: + case ALTR_A10SR_HPS_RST_REG: + case ALTR_A10SR_I2C_M_REG: + case ALTR_A10SR_WARM_RST_REG: + case ALTR_A10SR_WR_KEY_REG: + case ALTR_A10SR_PMBUS_REG: + return true; + default: + return false; + } +} + +const struct regmap_config altr_a10sr_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .cache_type = REGCACHE_NONE, + + .use_single_rw = true, + .read_flag_mask = 1, + .write_flag_mask = 0, + + .max_register = ALTR_A10SR_WR_KEY_REG, + .readable_reg = altr_a10sr_reg_readable, + .writeable_reg = altr_a10sr_reg_writeable, + .volatile_reg = altr_a10sr_reg_volatile, + +}; + +static int altr_a10sr_spi_probe(struct spi_device *spi) +{ + int ret; + struct altr_a10sr *a10sr; + + a10sr = devm_kzalloc(&spi->dev, sizeof(*a10sr), + GFP_KERNEL); + if (!a10sr) + return -ENOMEM; + + spi->mode = SPI_MODE_3; + spi->bits_per_word = 8; + spi_setup(spi); + + a10sr->dev = &spi->dev; + + spi_set_drvdata(spi, a10sr); + + a10sr->regmap = devm_regmap_init_spi(spi, &altr_a10sr_regmap_config); + if (IS_ERR(a10sr->regmap)) { + ret = PTR_ERR(a10sr->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = devm_mfd_add_devices(a10sr->dev, PLATFORM_DEVID_AUTO, + altr_a10sr_subdev_info, + ARRAY_SIZE(altr_a10sr_subdev_info), + NULL, 0, NULL); + if (ret) + dev_err(a10sr->dev, "Failed to register sub-devices: %d\n", + ret); + + return ret; +} + +static const struct of_device_id altr_a10sr_spi_of_match[] = { + { .compatible = "altr,a10sr" }, + { }, +}; +MODULE_DEVICE_TABLE(of, altr_a10sr_spi_of_match); + +static struct spi_driver altr_a10sr_spi_driver = { + .probe = altr_a10sr_spi_probe, + .driver = { + .name = "altr_a10sr", + .of_match_table = of_match_ptr(altr_a10sr_spi_of_match), + }, +}; + +module_spi_driver(altr_a10sr_spi_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Thor Thayer "); +MODULE_DESCRIPTION("Altera Arria10 DevKit System Resource MFD Driver"); diff --git a/include/linux/mfd/altera-a10sr.h b/include/linux/mfd/altera-a10sr.h new file mode 100644 index 000000000000..45a5e6e7db54 --- /dev/null +++ b/include/linux/mfd/altera-a10sr.h @@ -0,0 +1,85 @@ +/* + * Copyright Intel Corporation (C) 2014-2016. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * Declarations for Altera Arria10 MAX5 System Resource Chip + * + * Adapted from DA9052 + */ + +#ifndef __MFD_ALTERA_A10SR_H +#define __MFD_ALTERA_A10SR_H + +#include +#include +#include +#include +#include + +/* Write registers are always on even addresses */ +#define WRITE_REG_MASK 0xFE +/* Odd registers are always on odd addresses */ +#define READ_REG_MASK 0x01 + +#define ALTR_A10SR_BITS_PER_REGISTER 8 +/* + * To find the correct register, we divide the input GPIO by + * the number of GPIO in each register. We then need to multiply + * by 2 because the reads are at odd addresses. + */ +#define ALTR_A10SR_REG_OFFSET(X) (((X) / ALTR_A10SR_BITS_PER_REGISTER) << 1) +#define ALTR_A10SR_REG_BIT(X) ((X) % ALTR_A10SR_BITS_PER_REGISTER) +#define ALTR_A10SR_REG_BIT_CHG(X, Y) ((X) << ALTR_A10SR_REG_BIT(Y)) +#define ALTR_A10SR_REG_BIT_MASK(X) (1 << ALTR_A10SR_REG_BIT(X)) + +/* Arria10 System Controller Register Defines */ +#define ALTR_A10SR_NOP 0x00 /* No Change */ +#define ALTR_A10SR_VERSION_READ 0x00 /* MAX5 Version Read */ + +#define ALTR_A10SR_LED_REG 0x02 /* LED - Upper 4 bits */ +/* LED register Bit Definitions */ +#define ALTR_A10SR_LED_VALID_SHIFT 4 /* LED - Upper 4 bits valid */ +#define ALTR_A10SR_OUT_VALID_RANGE_LO ALTR_A10SR_LED_VALID_SHIFT +#define ALTR_A10SR_OUT_VALID_RANGE_HI 7 + +#define ALTR_A10SR_PBDSW_REG 0x04 /* PB & DIP SW - Input only */ +#define ALTR_A10SR_PBDSW_IRQ_REG 0x06 /* PB & DIP SW Flag Clear */ +/* Pushbutton & DIP Switch Bit Definitions */ +#define ALTR_A10SR_IN_VALID_RANGE_LO 8 +#define ALTR_A10SR_IN_VALID_RANGE_HI 15 + +#define ALTR_A10SR_PWR_GOOD1_REG 0x08 /* Power Good1 Read */ +#define ALTR_A10SR_PWR_GOOD2_REG 0x0A /* Power Good2 Read */ +#define ALTR_A10SR_PWR_GOOD3_REG 0x0C /* Power Good3 Read */ +#define ALTR_A10SR_FMCAB_REG 0x0E /* FMCA/B & PCIe Pwr Enable */ +#define ALTR_A10SR_HPS_RST_REG 0x10 /* HPS Reset */ +#define ALTR_A10SR_USB_QSPI_REG 0x12 /* USB, BQSPI, FILE Reset */ +#define ALTR_A10SR_SFPA_REG 0x14 /* SFPA Control Reg */ +#define ALTR_A10SR_SFPB_REG 0x16 /* SFPB Control Reg */ +#define ALTR_A10SR_I2C_M_REG 0x18 /* I2C Master Select */ +#define ALTR_A10SR_WARM_RST_REG 0x1A /* HPS Warm Reset */ +#define ALTR_A10SR_WR_KEY_REG 0x1C /* HPS Warm Reset Key */ +#define ALTR_A10SR_PMBUS_REG 0x1E /* HPS PM Bus */ + +/** + * struct altr_a10sr - Altera Max5 MFD device private data structure + * @dev: : this device + * @regmap: the regmap assigned to the parent device. + */ +struct altr_a10sr { + struct device *dev; + struct regmap *regmap; +}; + +#endif /* __MFD_ALTERA_A10SR_H */ -- cgit v1.2.3 From 0d3a7cce3e8bc5c060b1f038984c10cb70289e1d Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 8 Jun 2016 10:54:35 -0500 Subject: mfd: ti_am335x_tscadc: Rename regmap_tscadc to regmap The regmap structure pointer is named regmap_tscadc, this is not consistent with other drivers and is redundant, it also contributes to several checkpatch warnings involving long lines. Rename this. Signed-off-by: Andrew F. Davis Signed-off-by: Lee Jones --- drivers/mfd/ti_am335x_tscadc.c | 36 ++++++++++++++++++------------------ include/linux/mfd/ti_am335x_tscadc.h | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index e71f6092be61..c8f027b4ea4c 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -43,7 +43,7 @@ void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tscadc, u32 val) if (tscadc->adc_waiting) wake_up(&tscadc->reg_se_wait); else if (!tscadc->adc_in_use) - regmap_write(tscadc->regmap_tscadc, REG_SE, tscadc->reg_se_cache); + regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache); spin_unlock_irqrestore(&tscadc->reg_lock, flags); } @@ -54,7 +54,7 @@ static void am335x_tscadc_need_adc(struct ti_tscadc_dev *tscadc) DEFINE_WAIT(wait); u32 reg; - regmap_read(tscadc->regmap_tscadc, REG_ADCFSM, ®); + regmap_read(tscadc->regmap, REG_ADCFSM, ®); if (reg & SEQ_STATUS) { tscadc->adc_waiting = true; prepare_to_wait(&tscadc->reg_se_wait, &wait, @@ -70,7 +70,7 @@ static void am335x_tscadc_need_adc(struct ti_tscadc_dev *tscadc) * Sequencer should either be idle or * busy applying the charge step. */ - regmap_read(tscadc->regmap_tscadc, REG_ADCFSM, ®); + regmap_read(tscadc->regmap, REG_ADCFSM, ®); WARN_ON((reg & SEQ_STATUS) && !(reg & CHARGE_STEP)); tscadc->adc_waiting = false; } @@ -82,7 +82,7 @@ void am335x_tsc_se_set_once(struct ti_tscadc_dev *tscadc, u32 val) spin_lock_irq(&tscadc->reg_lock); am335x_tscadc_need_adc(tscadc); - regmap_write(tscadc->regmap_tscadc, REG_SE, val); + regmap_write(tscadc->regmap, REG_SE, val); spin_unlock_irq(&tscadc->reg_lock); } EXPORT_SYMBOL_GPL(am335x_tsc_se_set_once); @@ -93,7 +93,7 @@ void am335x_tsc_se_adc_done(struct ti_tscadc_dev *tscadc) spin_lock_irqsave(&tscadc->reg_lock, flags); tscadc->adc_in_use = false; - regmap_write(tscadc->regmap_tscadc, REG_SE, tscadc->reg_se_cache); + regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache); spin_unlock_irqrestore(&tscadc->reg_lock, flags); } EXPORT_SYMBOL_GPL(am335x_tsc_se_adc_done); @@ -104,7 +104,7 @@ void am335x_tsc_se_clr(struct ti_tscadc_dev *tscadc, u32 val) spin_lock_irqsave(&tscadc->reg_lock, flags); tscadc->reg_se_cache &= ~val; - regmap_write(tscadc->regmap_tscadc, REG_SE, tscadc->reg_se_cache); + regmap_write(tscadc->regmap, REG_SE, tscadc->reg_se_cache); spin_unlock_irqrestore(&tscadc->reg_lock, flags); } EXPORT_SYMBOL_GPL(am335x_tsc_se_clr); @@ -116,7 +116,7 @@ static void tscadc_idle_config(struct ti_tscadc_dev *tscadc) idleconfig = STEPCONFIG_YNN | STEPCONFIG_INM_ADCREFM | STEPCONFIG_INP_ADCREFM | STEPCONFIG_YPN; - regmap_write(tscadc->regmap_tscadc, REG_IDLECONFIG, idleconfig); + regmap_write(tscadc->regmap, REG_IDLECONFIG, idleconfig); } static int ti_tscadc_probe(struct platform_device *pdev) @@ -187,11 +187,11 @@ static int ti_tscadc_probe(struct platform_device *pdev) if (IS_ERR(tscadc->tscadc_base)) return PTR_ERR(tscadc->tscadc_base); - tscadc->regmap_tscadc = devm_regmap_init_mmio(&pdev->dev, + tscadc->regmap = devm_regmap_init_mmio(&pdev->dev, tscadc->tscadc_base, &tscadc_regmap_config); - if (IS_ERR(tscadc->regmap_tscadc)) { + if (IS_ERR(tscadc->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); - err = PTR_ERR(tscadc->regmap_tscadc); + err = PTR_ERR(tscadc->regmap); goto ret; } @@ -221,11 +221,11 @@ static int ti_tscadc_probe(struct platform_device *pdev) /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ tscadc->clk_div--; - regmap_write(tscadc->regmap_tscadc, REG_CLKDIV, tscadc->clk_div); + regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div); /* Set the control register bits */ ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; - regmap_write(tscadc->regmap_tscadc, REG_CTRL, ctrl); + regmap_write(tscadc->regmap, REG_CTRL, ctrl); /* Set register bits for Idle Config Mode */ if (tsc_wires > 0) { @@ -239,7 +239,7 @@ static int ti_tscadc_probe(struct platform_device *pdev) /* Enable the TSC module enable bit */ ctrl |= CNTRLREG_TSCSSENB; - regmap_write(tscadc->regmap_tscadc, REG_CTRL, ctrl); + regmap_write(tscadc->regmap, REG_CTRL, ctrl); tscadc->used_cells = 0; tscadc->tsc_cell = -1; @@ -285,7 +285,7 @@ static int ti_tscadc_remove(struct platform_device *pdev) { struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev); - regmap_write(tscadc->regmap_tscadc, REG_SE, 0x00); + regmap_write(tscadc->regmap, REG_SE, 0x00); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -299,7 +299,7 @@ static int __maybe_unused tscadc_suspend(struct device *dev) { struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev); - regmap_write(tscadc->regmap_tscadc, REG_SE, 0x00); + regmap_write(tscadc->regmap, REG_SE, 0x00); pm_runtime_put_sync(dev); return 0; @@ -314,7 +314,7 @@ static int __maybe_unused tscadc_resume(struct device *dev) /* context restore */ ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; - regmap_write(tscadc->regmap_tscadc, REG_CTRL, ctrl); + regmap_write(tscadc->regmap, REG_CTRL, ctrl); if (tscadc->tsc_cell != -1) { if (tscadc->tsc_wires == 5) @@ -324,9 +324,9 @@ static int __maybe_unused tscadc_resume(struct device *dev) tscadc_idle_config(tscadc); } ctrl |= CNTRLREG_TSCSSENB; - regmap_write(tscadc->regmap_tscadc, REG_CTRL, ctrl); + regmap_write(tscadc->regmap, REG_CTRL, ctrl); - regmap_write(tscadc->regmap_tscadc, REG_CLKDIV, tscadc->clk_div); + regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div); return 0; } diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index 1fd50dcfe47c..2567a87872b0 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -153,7 +153,7 @@ struct ti_tscadc_dev { struct device *dev; - struct regmap *regmap_tscadc; + struct regmap *regmap; void __iomem *tscadc_base; int irq; int used_cells; /* 1-2 */ -- cgit v1.2.3 From 9e3d5c996b340c1572afabe5ff2f0dd8ced1583a Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 14 Jun 2016 15:43:31 -0700 Subject: mfd: hi655x-pmic: Rename some interrupt macro names Currently the hi655x-pmic driver has names for interrupt mask values, but not for the interrupt numbers themselves. So to allow for interrupt numbers to have sane names, rename the mask values with the _MASK postfix and use the existing names as the interrupt name Signed-off-by: John Stultz Signed-off-by: Lee Jones --- drivers/mfd/hi655x-pmic.c | 16 ++++++++-------- include/linux/mfd/hi655x-pmic.h | 25 +++++++++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index 68ab3701cbf3..072e6feab6e9 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -29,14 +29,14 @@ static const struct mfd_cell hi655x_pmic_devs[] = { }; static const struct regmap_irq hi655x_irqs[] = { - { .reg_offset = 0, .mask = OTMP_D1R_INT }, - { .reg_offset = 0, .mask = VSYS_2P5_R_INT }, - { .reg_offset = 0, .mask = VSYS_UV_D3R_INT }, - { .reg_offset = 0, .mask = VSYS_6P0_D200UR_INT }, - { .reg_offset = 0, .mask = PWRON_D4SR_INT }, - { .reg_offset = 0, .mask = PWRON_D20F_INT }, - { .reg_offset = 0, .mask = PWRON_D20R_INT }, - { .reg_offset = 0, .mask = RESERVE_INT }, + { .reg_offset = 0, .mask = OTMP_D1R_INT_MASK }, + { .reg_offset = 0, .mask = VSYS_2P5_R_INT_MASK }, + { .reg_offset = 0, .mask = VSYS_UV_D3R_INT_MASK }, + { .reg_offset = 0, .mask = VSYS_6P0_D200UR_INT_MASK }, + { .reg_offset = 0, .mask = PWRON_D4SR_INT_MASK }, + { .reg_offset = 0, .mask = PWRON_D20F_INT_MASK }, + { .reg_offset = 0, .mask = PWRON_D20R_INT_MASK }, + { .reg_offset = 0, .mask = RESERVE_INT_MASK }, }; static const struct regmap_irq_chip hi655x_irq_chip = { diff --git a/include/linux/mfd/hi655x-pmic.h b/include/linux/mfd/hi655x-pmic.h index dbbe9a644622..62f03c2b1bb0 100644 --- a/include/linux/mfd/hi655x-pmic.h +++ b/include/linux/mfd/hi655x-pmic.h @@ -34,14 +34,23 @@ #define PMU_VER_START 0x10 #define PMU_VER_END 0x38 -#define RESERVE_INT BIT(7) -#define PWRON_D20R_INT BIT(6) -#define PWRON_D20F_INT BIT(5) -#define PWRON_D4SR_INT BIT(4) -#define VSYS_6P0_D200UR_INT BIT(3) -#define VSYS_UV_D3R_INT BIT(2) -#define VSYS_2P5_R_INT BIT(1) -#define OTMP_D1R_INT BIT(0) +#define RESERVE_INT 7 +#define PWRON_D20R_INT 6 +#define PWRON_D20F_INT 5 +#define PWRON_D4SR_INT 4 +#define VSYS_6P0_D200UR_INT 3 +#define VSYS_UV_D3R_INT 2 +#define VSYS_2P5_R_INT 1 +#define OTMP_D1R_INT 0 + +#define RESERVE_INT_MASK BIT(RESERVE_INT) +#define PWRON_D20R_INT_MASK BIT(PWRON_D20R_INT) +#define PWRON_D20F_INT_MASK BIT(PWRON_D20F_INT) +#define PWRON_D4SR_INT_MASK BIT(PWRON_D4SR_INT) +#define VSYS_6P0_D200UR_INT_MASK BIT(VSYS_6P0_D200UR_INT) +#define VSYS_UV_D3R_INT_MASK BIT(VSYS_UV_D3R_INT) +#define VSYS_2P5_R_INT_MASK BIT(VSYS_2P5_R_INT) +#define OTMP_D1R_INT_MASK BIT(OTMP_D1R_INT) struct hi655x_pmic { struct resource *res; -- cgit v1.2.3 From 698adfc968f3625a50853157ee5dbd208b6408a8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 13 Jun 2016 13:37:51 +0100 Subject: mfd: arizona: Remove some duplicate defines Some duplicate defines seem to have snuck into the registers file, this patch simply removes them. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- include/linux/mfd/arizona/registers.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index cd7e78eae006..0d06c5d0af93 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -856,12 +856,6 @@ #define ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE 0xB38 #define ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE 0xB40 #define ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE 0xB48 -#define ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE 0xB60 -#define ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE 0xB68 -#define ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE 0xB30 -#define ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE 0xB38 -#define ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE 0xB40 -#define ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE 0xB48 #define ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE 0xB50 #define ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE 0xB58 #define ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE 0xB60 -- cgit v1.2.3 From fc1882dcb5031953169a38260a0e653910825e46 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 25 May 2016 14:22:02 +0200 Subject: mfd: stmpe: Move platform data into MFD driver The STMPE platform data is only populated from the device tree in all existing users, so push the struct and make the OF case the norm. Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/stmpe.c | 40 ++++++++++++++++++++++++++++------------ include/linux/mfd/stmpe.h | 22 +--------------------- 2 files changed, 29 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index fb8f9e8b75df..94c7cc02fdab 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -23,6 +23,27 @@ #include #include "stmpe.h" +/** + * struct stmpe_platform_data - STMPE platform data + * @id: device id to distinguish between multiple STMPEs on the same board + * @blocks: bitmask of blocks to enable (use STMPE_BLOCK_*) + * @irq_trigger: IRQ trigger to use for the interrupt to the host + * @autosleep: bool to enable/disable stmpe autosleep + * @autosleep_timeout: inactivity timeout in milliseconds for autosleep + * @irq_over_gpio: true if gpio is used to get irq + * @irq_gpio: gpio number over which irq will be requested (significant only if + * irq_over_gpio is true) + */ +struct stmpe_platform_data { + int id; + unsigned int blocks; + unsigned int irq_trigger; + bool autosleep; + bool irq_over_gpio; + int irq_gpio; + int autosleep_timeout; +}; + static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) { return stmpe->variant->enable(stmpe, blocks, true); @@ -1187,24 +1208,19 @@ static void stmpe_of_probe(struct stmpe_platform_data *pdata, /* Called from client specific probe routines */ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum) { - struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev); + struct stmpe_platform_data *pdata; struct device_node *np = ci->dev->of_node; struct stmpe *stmpe; int ret; - if (!pdata) { - if (!np) - return -EINVAL; - - pdata = devm_kzalloc(ci->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; + pdata = devm_kzalloc(ci->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; - stmpe_of_probe(pdata, np); + stmpe_of_probe(pdata, np); - if (of_find_property(np, "interrupts", NULL) == NULL) - ci->irq = -1; - } + if (of_find_property(np, "interrupts", NULL) == NULL) + ci->irq = -1; stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); if (!stmpe) diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index cb83883918a7..de748bc7525e 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h @@ -62,6 +62,7 @@ enum { struct stmpe_variant_info; struct stmpe_client_info; +struct stmpe_platform_data; /** * struct stmpe - STMPE MFD structure @@ -117,25 +118,4 @@ extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks); #define STMPE_GPIO_NOREQ_811_TOUCH (0xf0) -/** - * struct stmpe_platform_data - STMPE platform data - * @id: device id to distinguish between multiple STMPEs on the same board - * @blocks: bitmask of blocks to enable (use STMPE_BLOCK_*) - * @irq_trigger: IRQ trigger to use for the interrupt to the host - * @autosleep: bool to enable/disable stmpe autosleep - * @autosleep_timeout: inactivity timeout in milliseconds for autosleep - * @irq_over_gpio: true if gpio is used to get irq - * @irq_gpio: gpio number over which irq will be requested (significant only if - * irq_over_gpio is true) - */ -struct stmpe_platform_data { - int id; - unsigned int blocks; - unsigned int irq_trigger; - bool autosleep; - bool irq_over_gpio; - int irq_gpio; - int autosleep_timeout; -}; - #endif -- cgit v1.2.3 From 0a58da1e2f25f213fb72d7d6a18dff9562621215 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 20 Jun 2016 17:07:18 +0300 Subject: mfd: twl6040: Handle mclk used for HPPLL and optional internal clock source On some boards, like omap5-uevm the MCLK is gated by default and in order to be able to use the High performance modes of twl6040 it need to be enabled by SW. Add support for handling the MCLK source clock via CCF. At the same time lower the print priority of the notification that the 32K clock is not provided and it is not going to be handled by the driver. Signed-off-by: Peter Ujfalusi Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/twl6040.txt | 4 +-- drivers/mfd/twl6040.c | 41 ++++++++++++++++------- include/linux/mfd/twl6040.h | 5 +-- 3 files changed, 34 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/mfd/twl6040.txt b/Documentation/devicetree/bindings/mfd/twl6040.txt index a41157b5d930..e6afdfa3543d 100644 --- a/Documentation/devicetree/bindings/mfd/twl6040.txt +++ b/Documentation/devicetree/bindings/mfd/twl6040.txt @@ -19,8 +19,8 @@ Required properties: Optional properties, nodes: - enable-active-high: To power on the twl6040 during boot. -- clocks: phandle to the clk32k clock provider -- clock-names: Must be "clk32k" +- clocks: phandle to the clk32k and/or to mclk clock provider +- clock-names: Must be "clk32k" for the 32K clock and "mclk" for the MCLK. Vibra functionality Required properties: diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 852d5874aabb..ab328ec49353 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -323,8 +323,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) /* Default PLL configuration after power up */ twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; - twl6040->sysclk = 19200000; - twl6040->mclk = 32768; + twl6040->sysclk_rate = 19200000; } else { /* already powered-down */ if (!twl6040->power_count) { @@ -352,8 +351,12 @@ int twl6040_power(struct twl6040 *twl6040, int on) regcache_cache_only(twl6040->regmap, true); regcache_mark_dirty(twl6040->regmap); - twl6040->sysclk = 0; - twl6040->mclk = 0; + twl6040->sysclk_rate = 0; + + if (twl6040->pll == TWL6040_SYSCLK_SEL_HPPLL) { + clk_disable_unprepare(twl6040->mclk); + twl6040->mclk_rate = 0; + } clk_disable_unprepare(twl6040->clk32k); } @@ -377,15 +380,15 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, /* Force full reconfiguration when switching between PLL */ if (pll_id != twl6040->pll) { - twl6040->sysclk = 0; - twl6040->mclk = 0; + twl6040->sysclk_rate = 0; + twl6040->mclk_rate = 0; } switch (pll_id) { case TWL6040_SYSCLK_SEL_LPPLL: /* low-power PLL divider */ /* Change the sysclk configuration only if it has been canged */ - if (twl6040->sysclk != freq_out) { + if (twl6040->sysclk_rate != freq_out) { switch (freq_out) { case 17640000: lppllctl |= TWL6040_LPLLFIN; @@ -427,6 +430,8 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, ret = -EINVAL; goto pll_out; } + + clk_disable_unprepare(twl6040->mclk); break; case TWL6040_SYSCLK_SEL_HPPLL: /* high-performance PLL can provide only 19.2 MHz */ @@ -437,7 +442,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, goto pll_out; } - if (twl6040->mclk != freq_in) { + if (twl6040->mclk_rate != freq_in) { hppllctl &= ~TWL6040_MCLK_MSK; switch (freq_in) { @@ -468,6 +473,9 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, goto pll_out; } + /* When switching to HPPLL, enable the mclk first */ + if (pll_id != twl6040->pll) + clk_prepare_enable(twl6040->mclk); /* * enable clock slicer to ensure input waveform is * square @@ -483,6 +491,8 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, lppllctl &= ~TWL6040_LPLLENA; twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); + + twl6040->mclk_rate = freq_in; } break; default: @@ -491,8 +501,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, goto pll_out; } - twl6040->sysclk = freq_out; - twl6040->mclk = freq_in; + twl6040->sysclk_rate = freq_out; twl6040->pll = pll_id; pll_out: @@ -512,7 +521,7 @@ EXPORT_SYMBOL(twl6040_get_pll); unsigned int twl6040_get_sysclk(struct twl6040 *twl6040) { - return twl6040->sysclk; + return twl6040->sysclk_rate; } EXPORT_SYMBOL(twl6040_get_sysclk); @@ -655,10 +664,18 @@ static int twl6040_probe(struct i2c_client *client, if (IS_ERR(twl6040->clk32k)) { if (PTR_ERR(twl6040->clk32k) == -EPROBE_DEFER) return -EPROBE_DEFER; - dev_info(&client->dev, "clk32k is not handled\n"); + dev_dbg(&client->dev, "clk32k is not handled\n"); twl6040->clk32k = NULL; } + twl6040->mclk = devm_clk_get(&client->dev, "mclk"); + if (IS_ERR(twl6040->mclk)) { + if (PTR_ERR(twl6040->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(&client->dev, "mclk is not handled\n"); + twl6040->mclk = NULL; + } + twl6040->supplies[0].supply = "vio"; twl6040->supplies[1].supply = "v2v1"; ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h index 8e95cd87cd74..36795a1be479 100644 --- a/include/linux/mfd/twl6040.h +++ b/include/linux/mfd/twl6040.h @@ -226,6 +226,7 @@ struct twl6040 { struct regmap_irq_chip_data *irq_data; struct regulator_bulk_data supplies[2]; /* supplies for vio, v2v1 */ struct clk *clk32k; + struct clk *mclk; struct mutex mutex; struct mutex irq_mutex; struct mfd_cell cells[TWL6040_CELLS]; @@ -237,8 +238,8 @@ struct twl6040 { /* PLL configuration */ int pll; - unsigned int sysclk; - unsigned int mclk; + unsigned int sysclk_rate; + unsigned int mclk_rate; unsigned int irq; unsigned int irq_ready; -- cgit v1.2.3 From bc92126012c8c84988eebbbf9c8a246949b07462 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 21:09:04 +0900 Subject: extcon: Fix the wrong description about extcon_set/get_cable_state_() This patch fixes the wrong description about extcon_set/get_cable_state_() because they use the unique id of external connector instead of legacy name. Signed-off-by: Chanwoo Choi --- include/linux/extcon.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 7bf530f3f4f5..61004413dc64 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -165,7 +165,7 @@ extern int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state); /* * get/set_cable_state access each bit of the 32b encoded state value. - * They are used to access the status of each cable based on the cable_name. + * They are used to access the status of each cable based on the cable id. */ extern int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id); extern int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, -- cgit v1.2.3 From 053239987f89f9a6299e78610bad010764bccd71 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Jun 2016 16:10:33 +0200 Subject: soc: renesas: rcar-sysc: Move SYSC interrupt config to rcar-sysc driver On R-Car H1 and Gen2, the SYSC interrupt registers are always configured using hardcoded values in platform code. For R-Car Gen2, values are provided for H2 and M2-W only, other SoCs are not yet supported, and never will be. Move this configuration from SoC-specific platform code to the rcar_sysc_init() wrapper, so it can be skipped if the SYSC is configured from DT. This would be the case not only for H1, H2, and M2-W using a modern DTS, but also for other R-Car Gen2 SoCs not supported by the platform code, relying purely on DT. There is no longer a need to return the mapped register block, hence make the function return void. Signed-off-by: Geert Uytterhoeven Reviewed-by: Ulrich Hecht Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/pm-r8a7779.c | 6 +----- arch/arm/mach-shmobile/pm-rcar-gen2.c | 6 +----- drivers/soc/renesas/rcar-sysc.c | 12 ++++++++---- include/linux/soc/renesas/rcar-sysc.h | 2 +- 4 files changed, 11 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c index 4174cbcbc467..5c9a93f5e650 100644 --- a/arch/arm/mach-shmobile/pm-r8a7779.c +++ b/arch/arm/mach-shmobile/pm-r8a7779.c @@ -23,11 +23,7 @@ static void __init r8a7779_sysc_init(void) { - void __iomem *base = rcar_sysc_init(0xffd85000); - - /* enable all interrupt sources, but do not use interrupt handler */ - iowrite32(0x0131000e, base + SYSCIER); - iowrite32(0, base + SYSCIMR); + rcar_sysc_init(0xffd85000, 0x0131000e); } #else /* CONFIG_PM || CONFIG_SMP */ diff --git a/arch/arm/mach-shmobile/pm-rcar-gen2.c b/arch/arm/mach-shmobile/pm-rcar-gen2.c index 691ac166a277..7768fd1bce65 100644 --- a/arch/arm/mach-shmobile/pm-rcar-gen2.c +++ b/arch/arm/mach-shmobile/pm-rcar-gen2.c @@ -37,11 +37,7 @@ static void __init rcar_gen2_sysc_init(u32 syscier) { - void __iomem *base = rcar_sysc_init(0xe6180000); - - /* enable all interrupt sources, but do not use interrupt handler */ - iowrite32(syscier, base + SYSCIER); - iowrite32(0, base + SYSCIMR); + rcar_sysc_init(0xe6180000, syscier); } #else /* CONFIG_SMP */ diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 68d6856c9d3c..22f0d646225c 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -400,10 +400,14 @@ out_put: } early_initcall(rcar_sysc_pd_init); -void __iomem * __init rcar_sysc_init(phys_addr_t base) +void __init rcar_sysc_init(phys_addr_t base, u32 syscier) { - if (rcar_sysc_pd_init()) - rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE); + if (!rcar_sysc_pd_init()) + return; - return rcar_sysc_base; + rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE); + + /* enable all interrupt sources, but do not use interrupt handler */ + iowrite32(syscier, rcar_sysc_base + SYSCIER); + iowrite32(0, rcar_sysc_base + SYSCIMR); } diff --git a/include/linux/soc/renesas/rcar-sysc.h b/include/linux/soc/renesas/rcar-sysc.h index 92fc613ab23d..7b8b280c181b 100644 --- a/include/linux/soc/renesas/rcar-sysc.h +++ b/include/linux/soc/renesas/rcar-sysc.h @@ -11,6 +11,6 @@ struct rcar_sysc_ch { int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch); int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch); -void __iomem *rcar_sysc_init(phys_addr_t base); +void rcar_sysc_init(phys_addr_t base, u32 syscier); #endif /* __LINUX_SOC_RENESAS_RCAR_SYSC_H__ */ -- cgit v1.2.3 From 7524c1cebc0a4e2ab186fcb5f87116f3d9018ee4 Mon Sep 17 00:00:00 2001 From: James Ban Date: Wed, 29 Jun 2016 16:49:32 +0900 Subject: regulator: da9211: add descriptions for da9212/da9214 This is a patch for adding description for da9212/da9214. Signed-off-by: James Ban Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/da9211.txt | 47 +++++++++++++++++++--- drivers/regulator/da9211-regulator.c | 13 ++++-- drivers/regulator/da9211-regulator.h | 3 +- include/linux/regulator/da9211.h | 5 ++- 4 files changed, 57 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/regulator/da9211.txt b/Documentation/devicetree/bindings/regulator/da9211.txt index c620493e8dbe..0f2a6f8fcafd 100644 --- a/Documentation/devicetree/bindings/regulator/da9211.txt +++ b/Documentation/devicetree/bindings/regulator/da9211.txt @@ -1,7 +1,8 @@ -* Dialog Semiconductor DA9211/DA9213/DA9215 Voltage Regulator +* Dialog Semiconductor DA9211/DA9212/DA9213/DA9214/DA9215 Voltage Regulator Required properties: -- compatible: "dlg,da9211" or "dlg,da9213" or "dlg,da9215" +- compatible: "dlg,da9211" or "dlg,da9212" or "dlg,da9213" + or "dlg,da9214" or "dlg,da9215" - reg: I2C slave address, usually 0x68. - interrupts: the interrupt outputs of the controller - regulators: A node that houses a sub-node for each regulator within the @@ -21,6 +22,25 @@ Example 1) DA9211 reg = <0x68>; interrupts = <3 27>; + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <2000000>; + regulator-max-microamp = <5000000>; + enable-gpios = <&gpio 27 0>; + }; + }; + }; + +Example 2) DA9212 + + pmic: da9212@68 { + compatible = "dlg,da9212"; + reg = <0x68>; + interrupts = <3 27>; + regulators { BUCKA { regulator-name = "VBUCKA"; @@ -41,12 +61,30 @@ Example 1) DA9211 }; }; -Example 2) DA9213 +Example 3) DA9213 pmic: da9213@68 { compatible = "dlg,da9213"; reg = <0x68>; interrupts = <3 27>; + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 27 0>; + }; + }; + }; + +Example 4) DA9214 + pmic: da9214@68 { + compatible = "dlg,da9214"; + reg = <0x68>; + interrupts = <3 27>; + regulators { BUCKA { regulator-name = "VBUCKA"; @@ -67,8 +105,7 @@ Example 2) DA9213 }; }; - -Example 3) DA9215 +Example 5) DA9215 pmic: da9215@68 { compatible = "dlg,da9215"; reg = <0x68>; diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 236abf473db5..aa47280efd32 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -1,5 +1,6 @@ /* - * da9211-regulator.c - Regulator device driver for DA9211/DA9213/DA9215 + * da9211-regulator.c - Regulator device driver for DA9211/DA9212 + * /DA9213/DA9214/DA9215 * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or @@ -493,7 +494,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c, static const struct i2c_device_id da9211_i2c_id[] = { {"da9211", DA9211}, + {"da9212", DA9212}, {"da9213", DA9213}, + {"da9214", DA9214}, {"da9215", DA9215}, {}, }; @@ -502,8 +505,10 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); #ifdef CONFIG_OF static const struct of_device_id da9211_dt_ids[] = { { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, - { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, - { .compatible = "dlg,da9215", .data = &da9211_i2c_id[2] }, + { .compatible = "dlg,da9212", .data = &da9211_i2c_id[1] }, + { .compatible = "dlg,da9213", .data = &da9211_i2c_id[2] }, + { .compatible = "dlg,da9214", .data = &da9211_i2c_id[3] }, + { .compatible = "dlg,da9215", .data = &da9211_i2c_id[4] }, {}, }; MODULE_DEVICE_TABLE(of, da9211_dt_ids); @@ -521,5 +526,5 @@ static struct i2c_driver da9211_regulator_driver = { module_i2c_driver(da9211_regulator_driver); MODULE_AUTHOR("James Ban "); -MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213/DA9215"); +MODULE_DESCRIPTION("DA9211/DA9212/DA9213/DA9214/DA9215 regulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h index d6ad96fc64d3..b841bbf330cc 100644 --- a/drivers/regulator/da9211-regulator.h +++ b/drivers/regulator/da9211-regulator.h @@ -1,5 +1,6 @@ /* - * da9211-regulator.h - Regulator definitions for DA9211/DA9213/DA9215 + * da9211-regulator.h - Regulator definitions for DA9211/DA9212 + * /DA9213/DA9214/DA9215 * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This program is free software; you can redistribute it and/or diff --git a/include/linux/regulator/da9211.h b/include/linux/regulator/da9211.h index a43a5ca1167b..80cb40b7c88d 100644 --- a/include/linux/regulator/da9211.h +++ b/include/linux/regulator/da9211.h @@ -1,5 +1,6 @@ /* - * da9211.h - Regulator device driver for DA9211/DA9213/DA9215 + * da9211.h - Regulator device driver for DA9211/DA9212 + * /DA9213/DA9214/DA9215 * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This program is free software; you can redistribute it and/or @@ -22,7 +23,9 @@ enum da9211_chip_id { DA9211, + DA9212, DA9213, + DA9214, DA9215, }; -- cgit v1.2.3 From a92e7c3d82a1313ab1954e5cdfd8f04efdb4ca78 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Tue, 28 Jun 2016 11:41:12 +0900 Subject: spi: s3c64xx: consider the case when the CS line is not connected When the CS line is not connected, it is not needed to enable or disable the chip selection functionality from the s3c64xx devices in order to perform a transfer. Set the CS controller logically always enabled already during initialization (by writing '0' in the S3C64XX_SPI_SLAVE_SEL register) and never disable it. Signed-off-by: Andi Shyti Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-samsung.txt | 3 +++ drivers/spi/spi-s3c64xx.c | 9 ++++++++- include/linux/platform_data/spi-s3c64xx.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/spi/spi-samsung.txt b/Documentation/devicetree/bindings/spi/spi-samsung.txt index 6dbdeb3c361a..930bc7349271 100644 --- a/Documentation/devicetree/bindings/spi/spi-samsung.txt +++ b/Documentation/devicetree/bindings/spi/spi-samsung.txt @@ -40,6 +40,9 @@ Optional Board Specific Properties: - cs-gpios: should specify GPIOs used for chipselects (see spi-bus.txt) +- no-cs-readback: the CS line is disconnected, therefore the device should not + operate based on CS signalling. + SPI Controller specific data in SPI slave nodes: - The spi slave nodes should provide the following information which is required diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 972367d5c7f2..14269b07804c 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -315,6 +315,9 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable) struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi->master); + if (sdd->cntrlr_info->no_cs) + return; + if (enable) { if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) { writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); @@ -960,7 +963,9 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) sdd->cur_speed = 0; - if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) + if (sci->no_cs) + writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + else if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); /* Disable Interrupts - we use Polling if not DMA mode */ @@ -1015,6 +1020,8 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) sci->num_cs = temp; } + sci->no_cs = of_property_read_bool(dev->of_node, "broken-cs"); + return sci; } #else diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h index fb5625bcca9a..5c1e21c87270 100644 --- a/include/linux/platform_data/spi-s3c64xx.h +++ b/include/linux/platform_data/spi-s3c64xx.h @@ -38,6 +38,7 @@ struct s3c64xx_spi_csinfo { struct s3c64xx_spi_info { int src_clk_nr; int num_cs; + bool no_cs; int (*cfg_gpio)(void); dma_filter_fn filter; void *dma_tx; -- cgit v1.2.3 From 3fdd1526e6c5ceadd4e91906d223e2d382fb72ca Mon Sep 17 00:00:00 2001 From: Ivaylo Dimitrov Date: Wed, 22 Jun 2016 22:22:19 +0300 Subject: ir-rx51: use PWM framework instead of OMAP dmtimer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert driver to use PWM framework instead of calling dmtimer functions directly for PWM timer. Remove paragraph about writing to the Free Software Foundation's mailing address while at it. Signed-off-by: Ivaylo Dimitrov Acked-by: Pali Rohár Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-rx51-peripherals.c | 1 - arch/arm/mach-omap2/pdata-quirks.c | 1 - drivers/media/rc/ir-rx51.c | 85 ++++++++++++++-------------- include/linux/platform_data/media/ir-rx51.h | 2 - 4 files changed, 44 insertions(+), 45 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 9a7073949d1d..e487575a86ca 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -1242,7 +1242,6 @@ static struct pwm_omap_dmtimer_pdata __maybe_unused pwm_dmtimer_pdata = { #if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE) static struct lirc_rx51_platform_data rx51_lirc_data = { .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat, - .pwm_timer = 9, /* Use GPT 9 for CIR */ #if IS_ENABLED(CONFIG_OMAP_DM_TIMER) .dmtimer = &pwm_dmtimer_pdata, #endif diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 6571ad959908..278bb8f3b77b 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -491,7 +491,6 @@ static struct pwm_omap_dmtimer_pdata pwm_dmtimer_pdata = { static struct lirc_rx51_platform_data __maybe_unused rx51_lirc_data = { .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat, - .pwm_timer = 9, /* Use GPT 9 for CIR */ #if IS_ENABLED(CONFIG_OMAP_DM_TIMER) .dmtimer = &pwm_dmtimer_pdata, #endif diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index da839c3a8c8b..5096ef3108d9 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -12,13 +12,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ - #include #include #include @@ -26,6 +20,7 @@ #include #include #include +#include #include #include @@ -43,7 +38,7 @@ #define TIMER_MAX_VALUE 0xffffffff struct lirc_rx51 { - pwm_omap_dmtimer *pwm_timer; + struct pwm_device *pwm; pwm_omap_dmtimer *pulse_timer; struct pwm_omap_dmtimer_pdata *dmtimer; struct device *dev; @@ -58,32 +53,28 @@ struct lirc_rx51 { int wbuf[WBUF_LEN]; int wbuf_index; unsigned long device_is_open; - int pwm_timer_num; }; static void lirc_rx51_on(struct lirc_rx51 *lirc_rx51) { - lirc_rx51->dmtimer->set_pwm(lirc_rx51->pwm_timer, 0, 1, - PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE); + pwm_enable(lirc_rx51->pwm); } static void lirc_rx51_off(struct lirc_rx51 *lirc_rx51) { - lirc_rx51->dmtimer->set_pwm(lirc_rx51->pwm_timer, 0, 1, - PWM_OMAP_DMTIMER_TRIGGER_NONE); + pwm_disable(lirc_rx51->pwm); } static int init_timing_params(struct lirc_rx51 *lirc_rx51) { - u32 load, match; - - load = -(lirc_rx51->fclk_khz * 1000 / lirc_rx51->freq); - match = -(lirc_rx51->duty_cycle * -load / 100); - lirc_rx51->dmtimer->set_load(lirc_rx51->pwm_timer, 1, load); - lirc_rx51->dmtimer->set_match(lirc_rx51->pwm_timer, 1, match); - lirc_rx51->dmtimer->write_counter(lirc_rx51->pwm_timer, TIMER_MAX_VALUE - 2); - lirc_rx51->dmtimer->start(lirc_rx51->pwm_timer); + struct pwm_device *pwm = lirc_rx51->pwm; + int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, lirc_rx51->freq); + + duty = DIV_ROUND_CLOSEST(lirc_rx51->duty_cycle * period, 100); lirc_rx51->dmtimer->set_int_enable(lirc_rx51->pulse_timer, 0); + + pwm_config(pwm, duty, period); + lirc_rx51->dmtimer->start(lirc_rx51->pulse_timer); lirc_rx51->match = 0; @@ -165,7 +156,7 @@ end: /* Stop TX here */ lirc_rx51_off(lirc_rx51); lirc_rx51->wbuf_index = -1; - lirc_rx51->dmtimer->stop(lirc_rx51->pwm_timer); + lirc_rx51->dmtimer->stop(lirc_rx51->pulse_timer); lirc_rx51->dmtimer->set_int_enable(lirc_rx51->pulse_timer, 0); wake_up_interruptible(&lirc_rx51->wqueue); @@ -176,13 +167,13 @@ end: static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51) { struct clk *clk_fclk; - int retval, pwm_timer = lirc_rx51->pwm_timer_num; + int retval; - lirc_rx51->pwm_timer = lirc_rx51->dmtimer->request_specific(pwm_timer); - if (lirc_rx51->pwm_timer == NULL) { - dev_err(lirc_rx51->dev, ": Error requesting GPT%d timer\n", - pwm_timer); - return -EBUSY; + lirc_rx51->pwm = pwm_get(lirc_rx51->dev, NULL); + if (IS_ERR(lirc_rx51->pwm)) { + retval = PTR_ERR(lirc_rx51->pwm); + dev_err(lirc_rx51->dev, ": pwm_get failed: %d\n", retval); + return retval; } lirc_rx51->pulse_timer = lirc_rx51->dmtimer->request(); @@ -192,15 +183,11 @@ static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51) goto err1; } - lirc_rx51->dmtimer->set_source(lirc_rx51->pwm_timer, - PWM_OMAP_DMTIMER_SRC_SYS_CLK); lirc_rx51->dmtimer->set_source(lirc_rx51->pulse_timer, PWM_OMAP_DMTIMER_SRC_SYS_CLK); - - lirc_rx51->dmtimer->enable(lirc_rx51->pwm_timer); lirc_rx51->dmtimer->enable(lirc_rx51->pulse_timer); - - lirc_rx51->irq_num = lirc_rx51->dmtimer->get_irq(lirc_rx51->pulse_timer); + lirc_rx51->irq_num = + lirc_rx51->dmtimer->get_irq(lirc_rx51->pulse_timer); retval = request_irq(lirc_rx51->irq_num, lirc_rx51_interrupt_handler, IRQF_SHARED, "lirc_pulse_timer", lirc_rx51); if (retval) { @@ -208,7 +195,7 @@ static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51) goto err2; } - clk_fclk = lirc_rx51->dmtimer->get_fclk(lirc_rx51->pwm_timer); + clk_fclk = lirc_rx51->dmtimer->get_fclk(lirc_rx51->pulse_timer); lirc_rx51->fclk_khz = clk_get_rate(clk_fclk) / 1000; return 0; @@ -216,7 +203,7 @@ static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51) err2: lirc_rx51->dmtimer->free(lirc_rx51->pulse_timer); err1: - lirc_rx51->dmtimer->free(lirc_rx51->pwm_timer); + pwm_put(lirc_rx51->pwm); return retval; } @@ -226,11 +213,10 @@ static int lirc_rx51_free_port(struct lirc_rx51 *lirc_rx51) lirc_rx51->dmtimer->set_int_enable(lirc_rx51->pulse_timer, 0); free_irq(lirc_rx51->irq_num, lirc_rx51); lirc_rx51_off(lirc_rx51); - lirc_rx51->dmtimer->disable(lirc_rx51->pwm_timer); lirc_rx51->dmtimer->disable(lirc_rx51->pulse_timer); - lirc_rx51->dmtimer->free(lirc_rx51->pwm_timer); lirc_rx51->dmtimer->free(lirc_rx51->pulse_timer); lirc_rx51->wbuf_index = -1; + pwm_put(lirc_rx51->pwm); return 0; } @@ -387,7 +373,6 @@ static int lirc_rx51_release(struct inode *inode, struct file *file) } static struct lirc_rx51 lirc_rx51 = { - .freq = 38000, .duty_cycle = 50, .wbuf_index = -1, }; @@ -445,14 +430,34 @@ static int lirc_rx51_resume(struct platform_device *dev) static int lirc_rx51_probe(struct platform_device *dev) { + struct pwm_device *pwm; + lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES; lirc_rx51.pdata = dev->dev.platform_data; + + if (!lirc_rx51.pdata) { + dev_err(&dev->dev, "Platform Data is missing\n"); + return -ENXIO; + } + if (!lirc_rx51.pdata->dmtimer) { dev_err(&dev->dev, "no dmtimer?\n"); return -ENODEV; } - lirc_rx51.pwm_timer_num = lirc_rx51.pdata->pwm_timer; + pwm = pwm_get(&dev->dev, NULL); + if (IS_ERR(pwm)) { + int err = PTR_ERR(pwm); + + if (err != -EPROBE_DEFER) + dev_err(&dev->dev, "pwm_get failed: %d\n", err); + return err; + } + + /* Use default, in case userspace does not set the carrier */ + lirc_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC); + pwm_put(pwm); + lirc_rx51.dmtimer = lirc_rx51.pdata->dmtimer; lirc_rx51.dev = &dev->dev; lirc_rx51_driver.dev = &dev->dev; @@ -464,8 +469,6 @@ static int lirc_rx51_probe(struct platform_device *dev) lirc_rx51_driver.minor); return lirc_rx51_driver.minor; } - dev_info(lirc_rx51.dev, "registration ok, minor: %d, pwm: %d\n", - lirc_rx51_driver.minor, lirc_rx51.pwm_timer_num); return 0; } diff --git a/include/linux/platform_data/media/ir-rx51.h b/include/linux/platform_data/media/ir-rx51.h index 3038120ca46e..6acf22d497f7 100644 --- a/include/linux/platform_data/media/ir-rx51.h +++ b/include/linux/platform_data/media/ir-rx51.h @@ -2,8 +2,6 @@ #define _LIRC_RX51_H struct lirc_rx51_platform_data { - int pwm_timer; - int(*set_max_mpu_wakeup_lat)(struct device *dev, long t); struct pwm_omap_dmtimer_pdata *dmtimer; }; -- cgit v1.2.3 From 79cdad3635b3a253d712aba115fa274ef94a8c6b Mon Sep 17 00:00:00 2001 From: Ivaylo Dimitrov Date: Wed, 22 Jun 2016 22:22:21 +0300 Subject: ir-rx51: use hrtimer instead of dmtimer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop dmtimer usage for pulse timer in favor of hrtimer. That allows removing PWM dmitimer platform data usage. Signed-off-by: Ivaylo Dimitrov Acked-by: Pali Rohár Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-rx51-peripherals.c | 4 - arch/arm/mach-omap2/pdata-quirks.c | 3 - drivers/media/rc/ir-rx51.c | 166 ++++++--------------------- include/linux/platform_data/media/ir-rx51.h | 1 - 4 files changed, 37 insertions(+), 137 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index e487575a86ca..a5ab712c1a59 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -1242,10 +1242,6 @@ static struct pwm_omap_dmtimer_pdata __maybe_unused pwm_dmtimer_pdata = { #if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE) static struct lirc_rx51_platform_data rx51_lirc_data = { .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat, -#if IS_ENABLED(CONFIG_OMAP_DM_TIMER) - .dmtimer = &pwm_dmtimer_pdata, -#endif - }; static struct platform_device rx51_lirc_device = { diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 0d7b05a36b99..7cc672b33e0c 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -486,9 +486,6 @@ static struct pwm_omap_dmtimer_pdata pwm_dmtimer_pdata = { static struct lirc_rx51_platform_data __maybe_unused rx51_lirc_data = { .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat, -#if IS_ENABLED(CONFIG_OMAP_DM_TIMER) - .dmtimer = &pwm_dmtimer_pdata, -#endif }; static struct platform_device __maybe_unused rx51_lirc_device = { diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index 1cbb43d0a350..82fb6f2ca011 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -22,10 +22,10 @@ #include #include #include +#include #include #include -#include #include #define LIRC_RX51_DRIVER_FEATURES (LIRC_CAN_SET_SEND_DUTY_CYCLE | \ @@ -36,32 +36,26 @@ #define WBUF_LEN 256 -#define TIMER_MAX_VALUE 0xffffffff - struct lirc_rx51 { struct pwm_device *pwm; - pwm_omap_dmtimer *pulse_timer; - struct pwm_omap_dmtimer_pdata *dmtimer; + struct hrtimer timer; struct device *dev; struct lirc_rx51_platform_data *pdata; wait_queue_head_t wqueue; - unsigned long fclk_khz; unsigned int freq; /* carrier frequency */ unsigned int duty_cycle; /* carrier duty cycle */ - unsigned int irq_num; - unsigned int match; int wbuf[WBUF_LEN]; int wbuf_index; unsigned long device_is_open; }; -static void lirc_rx51_on(struct lirc_rx51 *lirc_rx51) +static inline void lirc_rx51_on(struct lirc_rx51 *lirc_rx51) { pwm_enable(lirc_rx51->pwm); } -static void lirc_rx51_off(struct lirc_rx51 *lirc_rx51) +static inline void lirc_rx51_off(struct lirc_rx51 *lirc_rx51) { pwm_disable(lirc_rx51->pwm); } @@ -72,61 +66,21 @@ static int init_timing_params(struct lirc_rx51 *lirc_rx51) int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, lirc_rx51->freq); duty = DIV_ROUND_CLOSEST(lirc_rx51->duty_cycle * period, 100); - lirc_rx51->dmtimer->set_int_enable(lirc_rx51->pulse_timer, 0); pwm_config(pwm, duty, period); - lirc_rx51->dmtimer->start(lirc_rx51->pulse_timer); - - lirc_rx51->match = 0; - return 0; } -#define tics_after(a, b) ((long)(b) - (long)(a) < 0) - -static int pulse_timer_set_timeout(struct lirc_rx51 *lirc_rx51, int usec) +static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer) { - int counter; - - BUG_ON(usec < 0); - - if (lirc_rx51->match == 0) - counter = lirc_rx51->dmtimer->read_counter(lirc_rx51->pulse_timer); - else - counter = lirc_rx51->match; - - counter += (u32)(lirc_rx51->fclk_khz * usec / (1000)); - lirc_rx51->dmtimer->set_match(lirc_rx51->pulse_timer, 1, counter); - lirc_rx51->dmtimer->set_int_enable(lirc_rx51->pulse_timer, - PWM_OMAP_DMTIMER_INT_MATCH); - if (tics_after(lirc_rx51->dmtimer->read_counter(lirc_rx51->pulse_timer), - counter)) { - return 1; - } - return 0; -} + struct lirc_rx51 *lirc_rx51 = + container_of(timer, struct lirc_rx51, timer); + ktime_t now; -static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr) -{ - unsigned int retval; - struct lirc_rx51 *lirc_rx51 = ptr; - - retval = lirc_rx51->dmtimer->read_status(lirc_rx51->pulse_timer); - if (!retval) - return IRQ_NONE; - - if (retval & ~PWM_OMAP_DMTIMER_INT_MATCH) - dev_err_ratelimited(lirc_rx51->dev, - ": Unexpected interrupt source: %x\n", retval); - - lirc_rx51->dmtimer->write_status(lirc_rx51->pulse_timer, - PWM_OMAP_DMTIMER_INT_MATCH | - PWM_OMAP_DMTIMER_INT_OVERFLOW | - PWM_OMAP_DMTIMER_INT_CAPTURE); if (lirc_rx51->wbuf_index < 0) { dev_err_ratelimited(lirc_rx51->dev, - ": BUG wbuf_index has value of %i\n", + "BUG wbuf_index has value of %i\n", lirc_rx51->wbuf_index); goto end; } @@ -136,6 +90,8 @@ static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr) * pulses until we catch up. */ do { + u64 ns; + if (lirc_rx51->wbuf_index >= WBUF_LEN) goto end; if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1) @@ -146,80 +102,24 @@ static irqreturn_t lirc_rx51_interrupt_handler(int irq, void *ptr) else lirc_rx51_on(lirc_rx51); - retval = pulse_timer_set_timeout(lirc_rx51, - lirc_rx51->wbuf[lirc_rx51->wbuf_index]); + ns = 1000 * lirc_rx51->wbuf[lirc_rx51->wbuf_index]; + hrtimer_add_expires_ns(timer, ns); + lirc_rx51->wbuf_index++; - } while (retval); + now = timer->base->get_time(); + + } while (hrtimer_get_expires_tv64(timer) < now.tv64); - return IRQ_HANDLED; + return HRTIMER_RESTART; end: /* Stop TX here */ lirc_rx51_off(lirc_rx51); lirc_rx51->wbuf_index = -1; - lirc_rx51->dmtimer->stop(lirc_rx51->pulse_timer); - lirc_rx51->dmtimer->set_int_enable(lirc_rx51->pulse_timer, 0); wake_up_interruptible(&lirc_rx51->wqueue); - return IRQ_HANDLED; -} - -static int lirc_rx51_init_port(struct lirc_rx51 *lirc_rx51) -{ - struct clk *clk_fclk; - int retval; - - lirc_rx51->pwm = pwm_get(lirc_rx51->dev, NULL); - if (IS_ERR(lirc_rx51->pwm)) { - retval = PTR_ERR(lirc_rx51->pwm); - dev_err(lirc_rx51->dev, ": pwm_get failed: %d\n", retval); - return retval; - } - - lirc_rx51->pulse_timer = lirc_rx51->dmtimer->request(); - if (lirc_rx51->pulse_timer == NULL) { - dev_err(lirc_rx51->dev, ": Error requesting pulse timer\n"); - retval = -EBUSY; - goto err1; - } - - lirc_rx51->dmtimer->set_source(lirc_rx51->pulse_timer, - PWM_OMAP_DMTIMER_SRC_SYS_CLK); - lirc_rx51->dmtimer->enable(lirc_rx51->pulse_timer); - lirc_rx51->irq_num = - lirc_rx51->dmtimer->get_irq(lirc_rx51->pulse_timer); - retval = request_irq(lirc_rx51->irq_num, lirc_rx51_interrupt_handler, - IRQF_SHARED, "lirc_pulse_timer", lirc_rx51); - if (retval) { - dev_err(lirc_rx51->dev, ": Failed to request interrupt line\n"); - goto err2; - } - - clk_fclk = lirc_rx51->dmtimer->get_fclk(lirc_rx51->pulse_timer); - lirc_rx51->fclk_khz = clk_get_rate(clk_fclk) / 1000; - - return 0; - -err2: - lirc_rx51->dmtimer->free(lirc_rx51->pulse_timer); -err1: - pwm_put(lirc_rx51->pwm); - - return retval; -} - -static int lirc_rx51_free_port(struct lirc_rx51 *lirc_rx51) -{ - lirc_rx51->dmtimer->set_int_enable(lirc_rx51->pulse_timer, 0); - free_irq(lirc_rx51->irq_num, lirc_rx51); - lirc_rx51_off(lirc_rx51); - lirc_rx51->dmtimer->disable(lirc_rx51->pulse_timer); - lirc_rx51->dmtimer->free(lirc_rx51->pulse_timer); - lirc_rx51->wbuf_index = -1; - pwm_put(lirc_rx51->pwm); - - return 0; + return HRTIMER_NORESTART; } static ssize_t lirc_rx51_write(struct file *file, const char *buf, @@ -258,8 +158,9 @@ static ssize_t lirc_rx51_write(struct file *file, const char *buf, lirc_rx51_on(lirc_rx51); lirc_rx51->wbuf_index = 1; - pulse_timer_set_timeout(lirc_rx51, lirc_rx51->wbuf[0]); - + hrtimer_start(&lirc_rx51->timer, + ns_to_ktime(1000 * lirc_rx51->wbuf[0]), + HRTIMER_MODE_REL); /* * Don't return back to the userspace until the transfer has * finished @@ -359,14 +260,24 @@ static int lirc_rx51_open(struct inode *inode, struct file *file) if (test_and_set_bit(1, &lirc_rx51->device_is_open)) return -EBUSY; - return lirc_rx51_init_port(lirc_rx51); + lirc_rx51->pwm = pwm_get(lirc_rx51->dev, NULL); + if (IS_ERR(lirc_rx51->pwm)) { + int res = PTR_ERR(lirc_rx51->pwm); + + dev_err(lirc_rx51->dev, "pwm_get failed: %d\n", res); + return res; + } + + return 0; } static int lirc_rx51_release(struct inode *inode, struct file *file) { struct lirc_rx51 *lirc_rx51 = file->private_data; - lirc_rx51_free_port(lirc_rx51); + hrtimer_cancel(&lirc_rx51->timer); + lirc_rx51_off(lirc_rx51); + pwm_put(lirc_rx51->pwm); clear_bit(1, &lirc_rx51->device_is_open); @@ -441,11 +352,6 @@ static int lirc_rx51_probe(struct platform_device *dev) return -ENXIO; } - if (!lirc_rx51.pdata->dmtimer) { - dev_err(&dev->dev, "no dmtimer?\n"); - return -ENODEV; - } - pwm = pwm_get(&dev->dev, NULL); if (IS_ERR(pwm)) { int err = PTR_ERR(pwm); @@ -459,7 +365,9 @@ static int lirc_rx51_probe(struct platform_device *dev) lirc_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC); pwm_put(pwm); - lirc_rx51.dmtimer = lirc_rx51.pdata->dmtimer; + hrtimer_init(&lirc_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + lirc_rx51.timer.function = lirc_rx51_timer_cb; + lirc_rx51.dev = &dev->dev; lirc_rx51_driver.dev = &dev->dev; lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver); diff --git a/include/linux/platform_data/media/ir-rx51.h b/include/linux/platform_data/media/ir-rx51.h index 6acf22d497f7..812d87307877 100644 --- a/include/linux/platform_data/media/ir-rx51.h +++ b/include/linux/platform_data/media/ir-rx51.h @@ -3,7 +3,6 @@ struct lirc_rx51_platform_data { int(*set_max_mpu_wakeup_lat)(struct device *dev, long t); - struct pwm_omap_dmtimer_pdata *dmtimer; }; #endif -- cgit v1.2.3 From 2d902671ce1cd98cdc88d78c481889a1b2996101 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 30 Jun 2016 08:53:27 +0200 Subject: vfs: merge .d_select_inode() into .d_real() The two methods essentially do the same: find the real dentry/inode belonging to an overlay dentry. The difference is in the usage: vfs_open() uses ->d_select_inode() and expects the function to perform copy-up if necessary based on the open flags argument. file_dentry() uses ->d_real() passing in the overlay dentry as well as the underlying inode. vfs_rename() uses ->d_select_inode() but passes zero flags. ->d_real() with a zero inode would have worked just as well here. This patch merges the functionality of ->d_select_inode() into ->d_real() by adding an 'open_flags' argument to the latter. [Al Viro] Make the signature of d_real() match that of ->d_real() again. And constify the inode argument, while we are at it. Signed-off-by: Miklos Szeredi --- fs/dcache.c | 3 --- fs/namei.c | 2 +- fs/open.c | 8 ++++---- fs/overlayfs/inode.c | 31 ++++++++++--------------------- fs/overlayfs/overlayfs.h | 2 +- fs/overlayfs/super.c | 20 ++++++++++++++------ include/linux/dcache.h | 28 ++++++++-------------------- include/linux/fs.h | 7 +------ 8 files changed, 39 insertions(+), 62 deletions(-) (limited to 'include/linux') diff --git a/fs/dcache.c b/fs/dcache.c index d6847d7b123d..5405b89fe8ec 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1729,7 +1729,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_DELETE | - DCACHE_OP_SELECT_INODE | DCACHE_OP_REAL)); dentry->d_op = op; if (!op) @@ -1746,8 +1745,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) dentry->d_flags |= DCACHE_OP_DELETE; if (op->d_prune) dentry->d_flags |= DCACHE_OP_PRUNE; - if (op->d_select_inode) - dentry->d_flags |= DCACHE_OP_SELECT_INODE; if (op->d_real) dentry->d_flags |= DCACHE_OP_REAL; diff --git a/fs/namei.c b/fs/namei.c index 70580ab1445c..bb7a2e0b959c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4328,7 +4328,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, * Check source == target. * On overlayfs need to look at underlying inodes. */ - if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0)) + if (d_real_inode(old_dentry) == d_real_inode(new_dentry)) return 0; error = may_delete(old_dir, old_dentry, is_dir); diff --git a/fs/open.c b/fs/open.c index 93ae3cdee4ab..bf66cf1a9f5c 100644 --- a/fs/open.c +++ b/fs/open.c @@ -840,13 +840,13 @@ EXPORT_SYMBOL(file_path); int vfs_open(const struct path *path, struct file *file, const struct cred *cred) { - struct inode *inode = vfs_select_inode(path->dentry, file->f_flags); + struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags); - if (IS_ERR(inode)) - return PTR_ERR(inode); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); file->f_path = *path; - return do_dentry_open(file, inode, NULL, cred); + return do_dentry_open(file, d_backing_inode(dentry), NULL, cred); } struct file *dentry_open(const struct path *path, int flags, diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 1dbeab6cf96e..e08cd94d7b26 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -325,36 +325,25 @@ static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, return true; } -struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags) +int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags) { - int err; + int err = 0; struct path realpath; enum ovl_path_type type; - if (d_is_dir(dentry)) - return d_backing_inode(dentry); - type = ovl_path_real(dentry, &realpath); if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) { err = ovl_want_write(dentry); - if (err) - return ERR_PTR(err); - - if (file_flags & O_TRUNC) - err = ovl_copy_up_truncate(dentry); - else - err = ovl_copy_up(dentry); - ovl_drop_write(dentry); - if (err) - return ERR_PTR(err); - - ovl_path_upper(dentry, &realpath); + if (!err) { + if (file_flags & O_TRUNC) + err = ovl_copy_up_truncate(dentry); + else + err = ovl_copy_up(dentry); + ovl_drop_write(dentry); + } } - if (realpath.dentry->d_flags & DCACHE_OP_SELECT_INODE) - return realpath.dentry->d_op->d_select_inode(realpath.dentry, file_flags); - - return d_backing_inode(realpath.dentry); + return err; } static const struct inode_operations ovl_file_inode_operations = { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 4bd9b5ba8f42..6b9fd25c5ad4 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -179,7 +179,7 @@ ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode, const char *name, void *value, size_t size); ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); int ovl_removexattr(struct dentry *dentry, const char *name); -struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags); +int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags); struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, struct ovl_entry *oe); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index ce02f46029da..035c176edf00 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -304,7 +304,9 @@ static void ovl_dentry_release(struct dentry *dentry) } } -static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode) +static struct dentry *ovl_d_real(struct dentry *dentry, + const struct inode *inode, + unsigned int open_flags) { struct dentry *real; @@ -314,6 +316,16 @@ static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode) goto bug; } + if (d_is_negative(dentry)) + return dentry; + + if (open_flags) { + int err = ovl_open_maybe_copy_up(dentry, open_flags); + + if (err) + return ERR_PTR(err); + } + real = ovl_dentry_upper(dentry); if (real && (!inode || inode == d_inode(real))) return real; @@ -326,9 +338,7 @@ static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode) return real; /* Handle recursion */ - if (real->d_flags & DCACHE_OP_REAL) - return real->d_op->d_real(real, inode); - + return d_real(real, inode, open_flags); bug: WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry, inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0); @@ -378,13 +388,11 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags) static const struct dentry_operations ovl_dentry_operations = { .d_release = ovl_dentry_release, - .d_select_inode = ovl_d_select_inode, .d_real = ovl_d_real, }; static const struct dentry_operations ovl_reval_dentry_operations = { .d_release = ovl_dentry_release, - .d_select_inode = ovl_d_select_inode, .d_real = ovl_d_real, .d_revalidate = ovl_dentry_revalidate, .d_weak_revalidate = ovl_dentry_weak_revalidate, diff --git a/include/linux/dcache.h b/include/linux/dcache.h index f53fa055021a..45b22de15ede 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -139,8 +139,7 @@ struct dentry_operations { char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); - struct inode *(*d_select_inode)(struct dentry *, unsigned); - struct dentry *(*d_real)(struct dentry *, struct inode *); + struct dentry *(*d_real)(struct dentry *, const struct inode *, unsigned int); } ____cacheline_aligned; /* @@ -206,10 +205,8 @@ struct dentry_operations { #define DCACHE_MAY_FREE 0x00800000 #define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ -#define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ - -#define DCACHE_ENCRYPTED_WITH_KEY 0x04000000 /* dir is encrypted with a valid key */ -#define DCACHE_OP_REAL 0x08000000 +#define DCACHE_ENCRYPTED_WITH_KEY 0x02000000 /* dir is encrypted with a valid key */ +#define DCACHE_OP_REAL 0x04000000 #define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */ #define DCACHE_DENTRY_CURSOR 0x20000000 @@ -557,25 +554,16 @@ static inline struct dentry *d_backing_dentry(struct dentry *upper) return upper; } -static inline struct dentry *d_real(struct dentry *dentry) +static inline struct dentry *d_real(struct dentry *dentry, + const struct inode *inode, + unsigned int flags) { if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) - return dentry->d_op->d_real(dentry, NULL); + return dentry->d_op->d_real(dentry, inode, flags); else return dentry; } -static inline struct inode *vfs_select_inode(struct dentry *dentry, - unsigned open_flags) -{ - struct inode *inode = d_inode(dentry); - - if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE)) - inode = dentry->d_op->d_select_inode(dentry, open_flags); - - return inode; -} - /** * d_real_inode - Return the real inode * @dentry: The dentry to query @@ -585,7 +573,7 @@ static inline struct inode *vfs_select_inode(struct dentry *dentry, */ static inline struct inode *d_real_inode(struct dentry *dentry) { - return d_backing_inode(d_real(dentry)); + return d_backing_inode(d_real(dentry, NULL, 0)); } diff --git a/include/linux/fs.h b/include/linux/fs.h index dd288148a6b1..bacc0733663c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1272,12 +1272,7 @@ static inline struct inode *file_inode(const struct file *f) static inline struct dentry *file_dentry(const struct file *file) { - struct dentry *dentry = file->f_path.dentry; - - if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) - return dentry->d_op->d_real(dentry, file_inode(file)); - else - return dentry; + return d_real(file->f_path.dentry, file_inode(file), 0); } static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) -- cgit v1.2.3 From e698b8a43659f9ece192fcab215abcadac8f88d7 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 30 Jun 2016 08:53:27 +0200 Subject: vfs: document ->d_real() Add missing documentation for the d_op->d_real() method and d_real() helper. Signed-off-by: Miklos Szeredi --- Documentation/filesystems/Locking | 3 +++ Documentation/filesystems/vfs.txt | 20 ++++++++++++++++++++ include/linux/dcache.h | 14 +++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 75eea7ce3d7c..898d3cecd8a6 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -20,6 +20,8 @@ prototypes: char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen); struct vfsmount *(*d_automount)(struct path *path); int (*d_manage)(struct dentry *, bool); + struct dentry *(*d_real)(struct dentry *, const struct inode *, + unsigned int); locking rules: rename_lock ->d_lock may block rcu-walk @@ -34,6 +36,7 @@ d_iput: no no yes no d_dname: no no no no d_automount: no no yes no d_manage: no no yes (ref-walk) maybe +d_real no no yes no --------------------------- inode_operations --------------------------- prototypes: diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index c61a223ef3ff..1c934dd2c47d 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -938,6 +938,8 @@ struct dentry_operations { char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); + struct dentry *(*d_real)(struct dentry *, const struct inode *, + unsigned int); }; d_revalidate: called when the VFS needs to revalidate a dentry. This @@ -1060,6 +1062,24 @@ struct dentry_operations { This function is only used if DCACHE_MANAGE_TRANSIT is set on the dentry being transited from. + d_real: overlay/union type filesystems implement this method to return one of + the underlying dentries hidden by the overlay. It is used in three + different modes: + + Called from open it may need to copy-up the file depending on the + supplied open flags. This mode is selected with a non-zero flags + argument. In this mode the d_real method can return an error. + + Called from file_dentry() it returns the real dentry matching the inode + argument. The real dentry may be from a lower layer already copied up, + but still referenced from the file. This mode is selected with a + non-NULL inode argument. This will always succeed. + + With NULL inode and zero flags the topmost real underlying dentry is + returned. This will always succeed. + + This method is never called with both non-NULL inode and non-zero flags. + Example : static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 45b22de15ede..14df83609c7f 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -139,7 +139,8 @@ struct dentry_operations { char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); - struct dentry *(*d_real)(struct dentry *, const struct inode *, unsigned int); + struct dentry *(*d_real)(struct dentry *, const struct inode *, + unsigned int); } ____cacheline_aligned; /* @@ -554,6 +555,17 @@ static inline struct dentry *d_backing_dentry(struct dentry *upper) return upper; } +/** + * d_real - Return the real dentry + * @dentry: the dentry to query + * @inode: inode to select the dentry from multiple layers (can be NULL) + * @flags: open flags to control copy-up behavior + * + * If dentry is on an union/overlay, then return the underlying, real dentry. + * Otherwise return the dentry itself. + * + * See also: Documentation/filesystems/vfs.txt + */ static inline struct dentry *d_real(struct dentry *dentry, const struct inode *inode, unsigned int flags) -- cgit v1.2.3 From e98e915e11ad1efb11147122bd4932ec6b3425da Mon Sep 17 00:00:00 2001 From: Masashi Honma Date: Wed, 22 Jun 2016 20:23:03 +0900 Subject: wireless: Use macro instead of number Use IEEE80211_MIN_ACTION_SIZE macro for robust management frame check. Signed-off-by: Masashi Honma Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index b118744d3382..1daebb307e6e 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2464,7 +2464,7 @@ static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr) */ static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb) { - if (skb->len < 25) + if (skb->len < IEEE80211_MIN_ACTION_SIZE) return false; return _ieee80211_is_robust_mgmt_frame((void *)skb->data); } -- cgit v1.2.3 From 46f6b06050b736dab4d41494dae27b883cddc365 Mon Sep 17 00:00:00 2001 From: Masashi Honma Date: Wed, 22 Jun 2016 19:55:20 +0900 Subject: mac80211: Encrypt "Group addressed privacy" action frames Previously, the action frames to group address was not encrypted. But [1] "Table 8-38 Category values" indicates "Mesh" and "Multihop" category action frames should be encrypted (Group addressed privacy == yes). And the encyption key should be MGTK ([1] 10.13 Group addressed robust management frame procedures). So this patch modifies the code to make it suitable for spec. [1] IEEE Std 802.11-2012 Signed-off-by: Masashi Honma Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 30 ++++++++++++++++++++++++++++++ net/mac80211/rx.c | 7 ++++++- net/mac80211/tx.c | 6 +++++- 3 files changed, 41 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 1daebb307e6e..a80516fd65c8 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -2486,6 +2487,35 @@ static inline bool ieee80211_is_public_action(struct ieee80211_hdr *hdr, return mgmt->u.action.category == WLAN_CATEGORY_PUBLIC; } +/** + * _ieee80211_is_group_privacy_action - check if frame is a group addressed + * privacy action frame + * @hdr: the frame + */ +static inline bool _ieee80211_is_group_privacy_action(struct ieee80211_hdr *hdr) +{ + struct ieee80211_mgmt *mgmt = (void *)hdr; + + if (!ieee80211_is_action(hdr->frame_control) || + !is_multicast_ether_addr(hdr->addr1)) + return false; + + return mgmt->u.action.category == WLAN_CATEGORY_MESH_ACTION || + mgmt->u.action.category == WLAN_CATEGORY_MULTIHOP_ACTION; +} + +/** + * ieee80211_is_group_privacy_action - check if frame is a group addressed + * privacy action frame + * @skb: the skb containing the frame, length will be checked + */ +static inline bool ieee80211_is_group_privacy_action(struct sk_buff *skb) +{ + if (skb->len < IEEE80211_MIN_ACTION_SIZE) + return false; + return _ieee80211_is_group_privacy_action((void *)skb->data); +} + /** * ieee80211_tu_to_usec - convert time units (TU) to microseconds * @tu: the TUs diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9a1eb70cb120..2e8a9024625a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1624,8 +1624,13 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (mmie_keyidx < NUM_DEFAULT_KEYS || mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) return RX_DROP_MONITOR; /* unexpected BIP keyidx */ - if (rx->sta) + if (rx->sta) { + if (ieee80211_is_group_privacy_action(skb) && + test_sta_flag(rx->sta, WLAN_STA_MFP)) + return RX_DROP_MONITOR; + rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]); + } if (!rx->key) rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); } else if (!ieee80211_has_protected(fc)) { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 44ec605a5682..fa8d38eb9236 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -593,6 +593,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) else if (tx->sta && (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]))) tx->key = key; + else if (ieee80211_is_group_privacy_action(tx->skb) && + (key = rcu_dereference(tx->sdata->default_multicast_key))) + tx->key = key; else if (ieee80211_is_mgmt(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && ieee80211_is_robust_mgmt_frame(tx->skb) && @@ -625,7 +628,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) case WLAN_CIPHER_SUITE_GCMP_256: if (!ieee80211_is_data_present(hdr->frame_control) && !ieee80211_use_mfp(hdr->frame_control, tx->sta, - tx->skb)) + tx->skb) && + !ieee80211_is_group_privacy_action(tx->skb)) tx->key = NULL; else skip_hw = (tx->key->conf.flags & -- cgit v1.2.3 From ab714aff4f744f52f0beae93ed441f2f5585eb7a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 30 Jun 2016 11:39:38 -0400 Subject: jbd2: move lockdep tracking to journal_s Currently lockdep map is tracked in each journal handle. To be able to expand lockdep support to cover also other cases where we depend on transaction commit and where handle is not available, move lockdep map into struct journal_s. Since this makes the lockdep map shared for all handles, we have to use rwsem_acquire_read() for acquisitions now. Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o --- fs/jbd2/journal.c | 4 ++++ fs/jbd2/transaction.c | 11 +++-------- include/linux/jbd2.h | 17 +++++++++++++---- 3 files changed, 20 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index b31852f76f46..208e4058040b 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1091,6 +1091,7 @@ static void jbd2_stats_proc_exit(journal_t *journal) static journal_t * journal_init_common (void) { + static struct lock_class_key jbd2_trans_commit_key; journal_t *journal; int err; @@ -1126,6 +1127,9 @@ static journal_t * journal_init_common (void) spin_lock_init(&journal->j_history_lock); + lockdep_init_map(&journal->j_trans_commit_map, "jbd2_handle", + &jbd2_trans_commit_key, 0); + return journal; } diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 41249538c047..c0065040c5be 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -382,13 +382,11 @@ repeat: read_unlock(&journal->j_state_lock); current->journal_info = handle; - lock_map_acquire(&handle->h_lockdep_map); + rwsem_acquire_read(&journal->j_trans_commit_map, 0, 0, _THIS_IP_); jbd2_journal_free_transaction(new_transaction); return 0; } -static struct lock_class_key jbd2_handle_key; - /* Allocate a new handle. This should probably be in a slab... */ static handle_t *new_handle(int nblocks) { @@ -398,9 +396,6 @@ static handle_t *new_handle(int nblocks) handle->h_buffer_credits = nblocks; handle->h_ref = 1; - lockdep_init_map(&handle->h_lockdep_map, "jbd2_handle", - &jbd2_handle_key, 0); - return handle; } @@ -672,7 +667,7 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask) if (need_to_start) jbd2_log_start_commit(journal, tid); - lock_map_release(&handle->h_lockdep_map); + rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_); handle->h_buffer_credits = nblocks; ret = start_this_handle(journal, handle, gfp_mask); return ret; @@ -1750,7 +1745,7 @@ int jbd2_journal_stop(handle_t *handle) wake_up(&journal->j_wait_transaction_locked); } - lock_map_release(&handle->h_lockdep_map); + rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_); if (wait_for_commit) err = jbd2_log_wait_commit(journal, tid); diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index efb232c5f668..3d210cbe4e1b 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -491,10 +491,6 @@ struct jbd2_journal_handle unsigned long h_start_jiffies; unsigned int h_requested_credits; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map h_lockdep_map; -#endif }; @@ -793,6 +789,7 @@ jbd2_time_diff(unsigned long start, unsigned long end) * @j_proc_entry: procfs entry for the jbd statistics directory * @j_stats: Overall statistics * @j_private: An opaque pointer to fs-private information. + * @j_trans_commit_map: Lockdep entity to track transaction commit dependencies */ struct journal_s @@ -1035,6 +1032,18 @@ struct journal_s /* Precomputed journal UUID checksum for seeding other checksums */ __u32 j_csum_seed; + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + /* + * Lockdep entity to track transaction commit dependencies. Handles + * hold this "lock" for read, when we wait for commit, we acquire the + * "lock" for writing. This matches the properties of jbd2 journalling + * where the running transaction has to wait for all handles to be + * dropped to commit that transaction and also acquiring a handle may + * require transaction commit to finish. + */ + struct lockdep_map j_trans_commit_map; +#endif }; /* journal feature predicate functions */ -- cgit v1.2.3 From 1eaa566d368b214d99cbb973647c1b0b8102a9ae Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 30 Jun 2016 11:40:54 -0400 Subject: jbd2: track more dependencies on transaction commit So far we were tracking only dependency on transaction commit due to starting a new handle (which may require commit to start a new transaction). Now add tracking also for other cases where we wait for transaction commit. This way lockdep can catch deadlocks e. g. because we call jbd2_journal_stop() for a synchronous handle with some locks held which rank below transaction start. Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o --- fs/jbd2/journal.c | 1 + fs/jbd2/transaction.c | 4 ++++ include/linux/jbd2.h | 6 ++++++ 3 files changed, 11 insertions(+) (limited to 'include/linux') diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 208e4058040b..fc1d7a39b082 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -691,6 +691,7 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid) { int err = 0; + jbd2_might_wait_for_commit(journal); read_lock(&journal->j_state_lock); #ifdef CONFIG_JBD2_DEBUG if (!tid_geq(journal->j_commit_request, tid)) { diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index c0065040c5be..b5bc3e249163 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -182,6 +182,8 @@ static int add_transaction_credits(journal_t *journal, int blocks, int needed; int total = blocks + rsv_blocks; + jbd2_might_wait_for_commit(journal); + /* * If the current transaction is locked down for commit, wait * for the lock to be released. @@ -695,6 +697,8 @@ void jbd2_journal_lock_updates(journal_t *journal) { DEFINE_WAIT(wait); + jbd2_might_wait_for_commit(journal); + write_lock(&journal->j_state_lock); ++journal->j_barrier_count; diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 3d210cbe4e1b..dfaa1f4dcb0c 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -1046,6 +1046,12 @@ struct journal_s #endif }; +#define jbd2_might_wait_for_commit(j) \ + do { \ + rwsem_acquire(&j->j_trans_commit_map, 0, 0, _THIS_IP_); \ + rwsem_release(&j->j_trans_commit_map, 1, _THIS_IP_); \ + } while (0) + /* journal feature predicate functions */ #define JBD2_FEATURE_COMPAT_FUNCS(name, flagname) \ static inline bool jbd2_has_feature_##name(journal_t *j) \ -- cgit v1.2.3 From bc2b7dab629a51e8beb5fda4222c62a23b729f26 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Wed, 9 Mar 2016 19:05:49 +0100 Subject: iio:core: timestamping clock selection support Adds a new per-device sysfs attribute "current_timestamp_clock" to allow userspace to select a particular POSIX clock for buffered samples and events timestamping. Following clocks, as listed in clock_gettime(2), are supported: CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_COARSE, CLOCK_BOOTTIME and CLOCK_TAI. Signed-off-by: Gregor Boirie Acked-by: Sanchayan Maity Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 7 + Documentation/DocBook/iio.tmpl | 2 +- drivers/iio/accel/bma180.c | 2 +- drivers/iio/accel/bmc150-accel-core.c | 4 +- drivers/iio/accel/kxcjk-1013.c | 2 +- drivers/iio/accel/mma7455_core.c | 3 +- drivers/iio/accel/mma8452.c | 4 +- drivers/iio/accel/mma9551.c | 2 +- drivers/iio/accel/mma9553.c | 2 +- drivers/iio/adc/ad7291.c | 2 +- drivers/iio/adc/ad7298.c | 2 +- drivers/iio/adc/ad7476.c | 2 +- drivers/iio/adc/ad7887.c | 2 +- drivers/iio/adc/ad7923.c | 2 +- drivers/iio/adc/ad799x.c | 4 +- drivers/iio/adc/cc10001_adc.c | 2 +- drivers/iio/adc/hi8435.c | 2 +- drivers/iio/adc/ina2xx-adc.c | 6 +- drivers/iio/adc/max1363.c | 5 +- drivers/iio/adc/ti-adc081c.c | 3 +- drivers/iio/adc/ti-ads1015.c | 3 +- drivers/iio/adc/vf610_adc.c | 3 +- drivers/iio/adc/xilinx-xadc-events.c | 4 +- drivers/iio/chemical/atlas-ph-sensor.c | 2 +- drivers/iio/common/st_sensors/st_sensors_buffer.c | 2 +- drivers/iio/common/st_sensors/st_sensors_trigger.c | 2 +- drivers/iio/dac/ad5421.c | 6 +- drivers/iio/dac/ad5504.c | 2 +- drivers/iio/dummy/iio_simple_dummy_buffer.c | 3 +- drivers/iio/dummy/iio_simple_dummy_events.c | 2 +- drivers/iio/gyro/bmg160_core.c | 30 ++-- drivers/iio/iio_core.h | 3 + drivers/iio/imu/bmi160/bmi160_core.c | 3 +- drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 2 +- drivers/iio/industrialio-core.c | 179 ++++++++++++++++++++- drivers/iio/industrialio-event.c | 19 ++- drivers/iio/industrialio-trigger.c | 2 +- drivers/iio/light/acpi-als.c | 2 +- drivers/iio/light/adjd_s311.c | 2 +- drivers/iio/light/apds9300.c | 2 +- drivers/iio/light/apds9960.c | 4 +- drivers/iio/light/cm36651.c | 2 +- drivers/iio/light/gp2ap020a00f.c | 8 +- drivers/iio/light/isl29125.c | 2 +- drivers/iio/light/lm3533-als.c | 2 +- drivers/iio/light/ltr501.c | 7 +- drivers/iio/light/max44000.c | 3 +- drivers/iio/light/opt3001.c | 4 +- drivers/iio/light/stk3310.c | 2 +- drivers/iio/light/tcs3414.c | 2 +- drivers/iio/light/tcs3472.c | 2 +- drivers/iio/light/tsl2563.c | 2 +- drivers/iio/light/us5182d.c | 2 +- drivers/iio/magnetometer/ak8975.c | 3 +- drivers/iio/magnetometer/hmc5843_core.c | 2 +- drivers/iio/magnetometer/mag3110.c | 2 +- drivers/iio/pressure/mpl3115.c | 2 +- drivers/iio/pressure/ms5611_core.c | 3 +- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 2 +- drivers/iio/proximity/sx9500.c | 4 +- drivers/staging/iio/accel/lis3l02dq_core.c | 2 +- drivers/staging/iio/accel/sca3000_core.c | 2 +- drivers/staging/iio/adc/ad7280a.c | 8 +- drivers/staging/iio/adc/ad7606_ring.c | 3 +- drivers/staging/iio/adc/ad7816.c | 3 +- drivers/staging/iio/addac/adt7316.c | 4 +- drivers/staging/iio/cdc/ad7150.c | 2 +- drivers/staging/iio/light/tsl2x7x_core.c | 2 +- include/linux/iio/iio.h | 22 ++- 69 files changed, 327 insertions(+), 114 deletions(-) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index e7f590c6ef8e..fee35c00cc4e 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -32,6 +32,13 @@ Description: Description of the physical chip / device for device X. Typically a part number. +What: /sys/bus/iio/devices/iio:deviceX/timestamp_clock +KernelVersion: 4.5 +Contact: linux-iio@vger.kernel.org +Description: + String identifying current posix clock used to timestamp + buffered samples and events for device X. + What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency What: /sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency What: /sys/bus/iio/devices/triggerX/sampling_frequency diff --git a/Documentation/DocBook/iio.tmpl b/Documentation/DocBook/iio.tmpl index f525bf56d1dd..e2ab6a1f223e 100644 --- a/Documentation/DocBook/iio.tmpl +++ b/Documentation/DocBook/iio.tmpl @@ -594,7 +594,7 @@ irqreturn_t sensor_iio_pollfunc(int irq, void *p) { - pf->timestamp = iio_get_time_ns(); + pf->timestamp = iio_get_time_ns((struct indio_dev *)p); return IRQ_WAKE_THREAD; } diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index f04b88406995..e3f88ba5faf3 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -654,7 +654,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bma180_data *data = iio_priv(indio_dev); - int64_t time_ns = iio_get_time_ns(); + s64 time_ns = iio_get_time_ns(indio_dev); int bit, ret, i = 0; mutex_lock(&data->mutex); diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 197e693e7e7b..bf17aae66145 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -901,7 +901,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, */ if (!irq) { data->old_timestamp = data->timestamp; - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); } /* @@ -1303,7 +1303,7 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) int i; data->old_timestamp = data->timestamp; - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { if (data->triggers[i].enabled) { diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index bfe219a8bea2..765a72362dc6 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1129,7 +1129,7 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private) struct iio_dev *indio_dev = private; struct kxcjk1013_data *data = iio_priv(indio_dev); - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); if (data->dready_trigger_on) iio_trigger_poll(data->dready_trig); diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c index c902f54c23f5..6551085bedd7 100644 --- a/drivers/iio/accel/mma7455_core.c +++ b/drivers/iio/accel/mma7455_core.c @@ -97,7 +97,8 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p) if (ret) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 799fe64fc286..c0df28328368 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -917,7 +917,7 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev, static void mma8452_transient_interrupt(struct iio_dev *indio_dev) { struct mma8452_data *data = iio_priv(indio_dev); - s64 ts = iio_get_time_ns(); + s64 ts = iio_get_time_ns(indio_dev); int src; src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src); @@ -997,7 +997,7 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index d899a4d4307f..bf2704435629 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -391,7 +391,7 @@ static irqreturn_t mma9551_event_handler(int irq, void *private) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1), IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); out: mutex_unlock(&data->mutex); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index bb05f3efddca..36bf19733be0 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1001,7 +1001,7 @@ static irqreturn_t mma9553_irq_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct mma9553_data *data = iio_priv(indio_dev); - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); /* * Since we only configure the interrupt pin when an * event is enabled, we are sure we have at least diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index c0eabf156702..037630932749 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -115,7 +115,7 @@ static irqreturn_t ad7291_event_handler(int irq, void *private) u16 t_status, v_status; u16 command; int i; - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status)) return IRQ_HANDLED; diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 62bb8f7ce4a0..5dd0742da75a 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -163,7 +163,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 810c9a9fa62f..a819be288577 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -70,7 +70,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->data, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index ee2ccc19fab6..1bc363b0a4c1 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -122,7 +122,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->data, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index ff444c19d749..133711680e55 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index ec0200dd52cb..54284766d2ef 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -212,7 +212,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) goto out; iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); @@ -502,7 +502,7 @@ static irqreturn_t ad799x_event_handler(int irq, void *private) (i >> 1), IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } done: diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c index 8254f529b2a9..91636c0ba5b5 100644 --- a/drivers/iio/adc/cc10001_adc.c +++ b/drivers/iio/adc/cc10001_adc.c @@ -186,7 +186,7 @@ done: if (!sample_invalid) iio_push_to_buffers_with_timestamp(indio_dev, data, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index c73c6c62a6ac..c62bdb0a809e 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -400,7 +400,7 @@ static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val) iio_push_event(idev, IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i, IIO_EV_TYPE_THRESH, dir), - iio_get_time_ns()); + iio_get_time_ns(idev)); } } diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 502f2fbe8aef..b95ce5d7ee2c 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -465,7 +465,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) s64 time_a, time_b; unsigned int alert; - time_a = iio_get_time_ns(); + time_a = iio_get_time_ns(indio_dev); /* * Because the timer thread and the chip conversion clock @@ -504,7 +504,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) data[i++] = val; } - time_b = iio_get_time_ns(); + time_b = iio_get_time_ns(indio_dev); iio_push_to_buffers_with_timestamp(indio_dev, (unsigned int *)data, time_a); @@ -554,7 +554,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) dev_dbg(&indio_dev->dev, "Async readout mode: %d\n", chip->allow_async_readout); - chip->prev_ns = iio_get_time_ns(); + chip->prev_ns = iio_get_time_ns(indio_dev); chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev, "%s:%d-%uus", indio_dev->name, indio_dev->id, diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 998dc3caad4c..73af30684657 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -788,7 +788,7 @@ static irqreturn_t max1363_event_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct max1363_state *st = iio_priv(indio_dev); - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); unsigned long mask, loc; u8 rx; u8 tx[2] = { st->setupbyte, @@ -1506,7 +1506,8 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) if (b_sent < 0) goto done_free; - iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, + iio_get_time_ns(indio_dev)); done_free: kfree(rxbuf); diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index f8807adc08c4..283d2a12b6da 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -139,7 +139,8 @@ static irqreturn_t adc081c_trigger_handler(int irq, void *p) if (ret < 0) goto out; buf[0] = ret; - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); out: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 8be192a84893..c9574af09882 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -288,7 +288,8 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p) buf[0] = res; mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 653bf1379d2e..228a003adeed 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -594,7 +594,8 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id) if (iio_buffer_enabled(indio_dev)) { info->buffer[0] = info->value; iio_push_to_buffers_with_timestamp(indio_dev, - info->buffer, iio_get_time_ns()); + info->buffer, + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); } else complete(&info->completion); diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c index edcf3aabd70d..6d5c2a6f4e6e 100644 --- a/drivers/iio/adc/xilinx-xadc-events.c +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -46,7 +46,7 @@ static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event) iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } else { /* * For other channels we don't know whether it is a upper or @@ -56,7 +56,7 @@ static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event) iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } } diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index 02e85db5d31f..ae038a59d256 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c @@ -343,7 +343,7 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private) if (!ret) iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 50afc0f8f16b..7c84e90d8ce8 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -62,7 +62,7 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) if (sdata->hw_irq_trigger) timestamp = sdata->hw_timestamp; else - timestamp = iio_get_time_ns(); + timestamp = iio_get_time_ns(indio_dev); len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data); if (len < 0) diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 296e4ff19ae8..fab494d71951 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -29,7 +29,7 @@ irqreturn_t st_sensors_irq_handler(int irq, void *p) struct st_sensor_data *sdata = iio_priv(indio_dev); /* Get the time stamp as close in time as possible */ - sdata->hw_timestamp = iio_get_time_ns(); + sdata->hw_timestamp = iio_get_time_ns(indio_dev); return IRQ_WAKE_THREAD; } diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 968712be967f..559061ab1982 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -242,7 +242,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } if (events & AD5421_FAULT_UNDER_CURRENT) { @@ -251,7 +251,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } if (events & AD5421_FAULT_TEMP_OVER_140) { @@ -260,7 +260,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data) 0, IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } old_fault = fault; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 4e4c20d6d8b5..788b3d6fd1cc 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -223,7 +223,7 @@ static irqreturn_t ad5504_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns((struct iio_dev *)private)); return IRQ_HANDLED; } diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c index cf44a6f79431..b383892a5193 100644 --- a/drivers/iio/dummy/iio_simple_dummy_buffer.c +++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c @@ -85,7 +85,8 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) } } - iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, data, + iio_get_time_ns(indio_dev)); kfree(data); diff --git a/drivers/iio/dummy/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c index 6eb600ff7056..ed63ffd849f8 100644 --- a/drivers/iio/dummy/iio_simple_dummy_events.c +++ b/drivers/iio/dummy/iio_simple_dummy_events.c @@ -158,7 +158,7 @@ static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private) struct iio_dev *indio_dev = private; struct iio_dummy_state *st = iio_priv(indio_dev); - st->event_timestamp = iio_get_time_ns(); + st->event_timestamp = iio_get_time_ns(indio_dev); return IRQ_WAKE_THREAD; } diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 7ccc044063f6..8155251d9984 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -885,25 +885,25 @@ static irqreturn_t bmg160_event_handler(int irq, void *private) if (val & BMG160_ANY_MOTION_BIT_X) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_ROC, - dir), - iio_get_time_ns()); + 0, + IIO_MOD_X, + IIO_EV_TYPE_ROC, + dir), + iio_get_time_ns(indio_dev)); if (val & BMG160_ANY_MOTION_BIT_Y) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_ROC, - dir), - iio_get_time_ns()); + 0, + IIO_MOD_Y, + IIO_EV_TYPE_ROC, + dir), + iio_get_time_ns(indio_dev)); if (val & BMG160_ANY_MOTION_BIT_Z) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_ROC, - dir), - iio_get_time_ns()); + 0, + IIO_MOD_Z, + IIO_EV_TYPE_ROC, + dir), + iio_get_time_ns(indio_dev)); ack_intr_status: if (!data->dready_trigger_on) { diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 359883525ab7..4c45488e3a7f 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -79,4 +79,7 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev); void iio_device_wakeup_eventset(struct iio_dev *indio_dev); int iio_event_getfd(struct iio_dev *indio_dev); +struct iio_event_interface; +bool iio_event_enabled(const struct iio_event_interface *ev_int); + #endif diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 97928d558a15..e0251b8c1a52 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -411,7 +411,8 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p) buf[j++] = sample; } - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index d0700628ee6d..3a9f3eac91ab 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -107,7 +107,7 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p) struct inv_mpu6050_state *st = iio_priv(indio_dev); s64 timestamp; - timestamp = iio_get_time_ns(); + timestamp = iio_get_time_ns(indio_dev); kfifo_in_spinlocked(&st->timestamps, ×tamp, 1, &st->time_stamp_lock); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2a85bd888619..f914d5d140e4 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -178,6 +178,86 @@ ssize_t iio_read_const_attr(struct device *dev, } EXPORT_SYMBOL(iio_read_const_attr); +static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id) +{ + int ret; + const struct iio_event_interface *ev_int = indio_dev->event_interface; + + ret = mutex_lock_interruptible(&indio_dev->mlock); + if (ret) + return ret; + if ((ev_int && iio_event_enabled(ev_int)) || + iio_buffer_enabled(indio_dev)) { + mutex_unlock(&indio_dev->mlock); + return -EBUSY; + } + indio_dev->clock_id = clock_id; + mutex_unlock(&indio_dev->mlock); + + return 0; +} + +/** + * iio_get_time_ns() - utility function to get a time stamp for events etc + * @indio_dev: device + */ +s64 iio_get_time_ns(const struct iio_dev *indio_dev) +{ + struct timespec tp; + + switch (iio_device_get_clock(indio_dev)) { + case CLOCK_REALTIME: + ktime_get_real_ts(&tp); + break; + case CLOCK_MONOTONIC: + ktime_get_ts(&tp); + break; + case CLOCK_MONOTONIC_RAW: + getrawmonotonic(&tp); + break; + case CLOCK_REALTIME_COARSE: + tp = current_kernel_time(); + break; + case CLOCK_MONOTONIC_COARSE: + tp = get_monotonic_coarse(); + break; + case CLOCK_BOOTTIME: + get_monotonic_boottime(&tp); + break; + case CLOCK_TAI: + timekeeping_clocktai(&tp); + break; + default: + BUG(); + } + + return timespec_to_ns(&tp); +} +EXPORT_SYMBOL(iio_get_time_ns); + +/** + * iio_get_time_res() - utility function to get time stamp clock resolution in + * nano seconds. + * @indio_dev: device + */ +unsigned int iio_get_time_res(const struct iio_dev *indio_dev) +{ + switch (iio_device_get_clock(indio_dev)) { + case CLOCK_REALTIME: + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_RAW: + case CLOCK_BOOTTIME: + case CLOCK_TAI: + return hrtimer_resolution; + case CLOCK_REALTIME_COARSE: + case CLOCK_MONOTONIC_COARSE: + return LOW_RES_NSEC; + default: + BUG(); + } +} +EXPORT_SYMBOL(iio_get_time_res); + static int __init iio_init(void) { int ret; @@ -990,11 +1070,91 @@ static ssize_t iio_show_dev_name(struct device *dev, static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); +static ssize_t iio_show_timestamp_clock(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct iio_dev *indio_dev = dev_to_iio_dev(dev); + const clockid_t clk = iio_device_get_clock(indio_dev); + const char *name; + ssize_t sz; + + switch (clk) { + case CLOCK_REALTIME: + name = "realtime\n"; + sz = sizeof("realtime\n"); + break; + case CLOCK_MONOTONIC: + name = "monotonic\n"; + sz = sizeof("monotonic\n"); + break; + case CLOCK_MONOTONIC_RAW: + name = "monotonic_raw\n"; + sz = sizeof("monotonic_raw\n"); + break; + case CLOCK_REALTIME_COARSE: + name = "realtime_coarse\n"; + sz = sizeof("realtime_coarse\n"); + break; + case CLOCK_MONOTONIC_COARSE: + name = "monotonic_coarse\n"; + sz = sizeof("monotonic_coarse\n"); + break; + case CLOCK_BOOTTIME: + name = "boottime\n"; + sz = sizeof("boottime\n"); + break; + case CLOCK_TAI: + name = "tai\n"; + sz = sizeof("tai\n"); + break; + default: + BUG(); + } + + memcpy(buf, name, sz); + return sz; +} + +static ssize_t iio_store_timestamp_clock(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + clockid_t clk; + int ret; + + if (sysfs_streq(buf, "realtime")) + clk = CLOCK_REALTIME; + else if (sysfs_streq(buf, "monotonic")) + clk = CLOCK_MONOTONIC; + else if (sysfs_streq(buf, "monotonic_raw")) + clk = CLOCK_MONOTONIC_RAW; + else if (sysfs_streq(buf, "realtime_coarse")) + clk = CLOCK_REALTIME_COARSE; + else if (sysfs_streq(buf, "monotonic_coarse")) + clk = CLOCK_MONOTONIC_COARSE; + else if (sysfs_streq(buf, "boottime")) + clk = CLOCK_BOOTTIME; + else if (sysfs_streq(buf, "tai")) + clk = CLOCK_TAI; + else + return -EINVAL; + + ret = iio_device_set_clock(dev_to_iio_dev(dev), clk); + if (ret) + return ret; + + return len; +} + +static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR, + iio_show_timestamp_clock, iio_store_timestamp_clock); + static int iio_device_register_sysfs(struct iio_dev *indio_dev) { int i, ret = 0, attrcount, attrn, attrcount_orig = 0; struct iio_dev_attr *p; - struct attribute **attr; + struct attribute **attr, *clk = NULL; /* First count elements in any existing group */ if (indio_dev->info->attrs) { @@ -1009,16 +1169,25 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) */ if (indio_dev->channels) for (i = 0; i < indio_dev->num_channels; i++) { - ret = iio_device_add_channel_sysfs(indio_dev, - &indio_dev - ->channels[i]); + const struct iio_chan_spec *chan = + &indio_dev->channels[i]; + + if (chan->type == IIO_TIMESTAMP) + clk = &dev_attr_current_timestamp_clock.attr; + + ret = iio_device_add_channel_sysfs(indio_dev, chan); if (ret < 0) goto error_clear_attrs; attrcount += ret; } + if (indio_dev->event_interface) + clk = &dev_attr_current_timestamp_clock.attr; + if (indio_dev->name) attrcount++; + if (clk) + attrcount++; indio_dev->chan_attr_group.attrs = kcalloc(attrcount + 1, sizeof(indio_dev->chan_attr_group.attrs[0]), @@ -1039,6 +1208,8 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr; if (indio_dev->name) indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr; + if (clk) + indio_dev->chan_attr_group.attrs[attrn++] = clk; indio_dev->groups[indio_dev->groupcounter++] = &indio_dev->chan_attr_group; diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index cae332b1d7ea..0ebfc923a997 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -44,6 +44,11 @@ struct iio_event_interface { struct mutex read_lock; }; +bool iio_event_enabled(const struct iio_event_interface *ev_int) +{ + return !!test_bit(IIO_BUSY_BIT_POS, &ev_int->flags); +} + /** * iio_push_event() - try to add event to the list for userspace reading * @indio_dev: IIO device structure @@ -60,7 +65,7 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) int copied; /* Does anyone care? */ - if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { + if (iio_event_enabled(ev_int)) { ev.id = ev_code; ev.timestamp = timestamp; @@ -180,8 +185,14 @@ int iio_event_getfd(struct iio_dev *indio_dev) if (ev_int == NULL) return -ENODEV; - if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) - return -EBUSY; + fd = mutex_lock_interruptible(&indio_dev->mlock); + if (fd) + return fd; + + if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { + fd = -EBUSY; + goto unlock; + } iio_device_get(indio_dev); @@ -194,6 +205,8 @@ int iio_event_getfd(struct iio_dev *indio_dev) kfifo_reset_out(&ev_int->det_events); } +unlock: + mutex_unlock(&indio_dev->mlock); return fd; } diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 98457f044aa5..7ad82fdd3e5b 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -289,7 +289,7 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig, irqreturn_t iio_pollfunc_store_time(int irq, void *p) { struct iio_poll_func *pf = p; - pf->timestamp = iio_get_time_ns(); + pf->timestamp = iio_get_time_ns(pf->indio_dev); return IRQ_WAKE_THREAD; } EXPORT_SYMBOL(iio_pollfunc_store_time); diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 53201d99a16c..f0b47c501f4e 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -118,7 +118,7 @@ static void acpi_als_notify(struct acpi_device *device, u32 event) struct iio_dev *indio_dev = acpi_driver_data(device); struct acpi_als *als = iio_priv(indio_dev); s32 *buffer = als->evt_buffer; - s64 time_ns = iio_get_time_ns(); + s64 time_ns = iio_get_time_ns(indio_dev); s32 val; int ret; diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 09ad5f1ce539..0113fc843a81 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -118,7 +118,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adjd_s311_data *data = iio_priv(indio_dev); - s64 time_ns = iio_get_time_ns(); + s64 time_ns = iio_get_time_ns(indio_dev); int i, j = 0; int ret = adjd_s311_req_data(indio_dev); diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index e1b9fa5a7e91..649b26f67813 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -396,7 +396,7 @@ static irqreturn_t apds9300_interrupt_handler(int irq, void *private) IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(dev_info)); apds9300_clear_intr(data); diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 651d57b8abbf..a4304edc3e0f 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -807,7 +807,7 @@ static irqreturn_t apds9960_interrupt_handler(int irq, void *private) IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1); } @@ -816,7 +816,7 @@ static irqreturn_t apds9960_interrupt_handler(int irq, void *private) IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1); } diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index c8d7b5ea7e78..9d66e89c57ef 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -268,7 +268,7 @@ static irqreturn_t cm36651_irq_handler(int irq, void *data) CM36651_CMD_READ_RAW_PROXIMITY, IIO_EV_TYPE_THRESH, ev_dir); - iio_push_event(indio_dev, ev_code, iio_get_time_ns()); + iio_push_event(indio_dev, ev_code, iio_get_time_ns(indio_dev)); return IRQ_HANDLED; } diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index af73af3586a9..6ada9149f142 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -851,7 +851,7 @@ static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data) GP2AP020A00F_SCAN_MODE_PROXIMITY, IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } else { iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE( @@ -859,7 +859,7 @@ static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data) GP2AP020A00F_SCAN_MODE_PROXIMITY, IIO_EV_TYPE_ROC, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } } @@ -925,7 +925,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) IIO_MOD_LIGHT_CLEAR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &priv->flags)) { @@ -939,7 +939,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data) IIO_MOD_LIGHT_CLEAR, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } } diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index a6b9d66233d5..f48b9e5bdb0e 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -188,7 +188,7 @@ static irqreturn_t isl29125_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index e56937c40a18..f409c2047c05 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -267,7 +267,7 @@ static irqreturn_t lm3533_als_isr(int irq, void *dev_id) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); out: return IRQ_HANDLED; } diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 6bf89d8f3741..3afc53a3d0b6 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1256,7 +1256,8 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p) buf[j++] = psdata & LTR501_PS_DATA_MASK; } - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); @@ -1282,14 +1283,14 @@ static irqreturn_t ltr501_interrupt_handler(int irq, void *private) IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); if (status & LTR501_STATUS_PS_INTR) iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); return IRQ_HANDLED; } diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index f17cb2ea18f5..6511b20a2a29 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -511,7 +511,8 @@ static irqreturn_t max44000_trigger_handler(int irq, void *p) } mutex_unlock(&data->lock); - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index b776c8ed4387..78c9b3a6453a 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -713,13 +713,13 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(iio)); if (ret & OPT3001_CONFIGURATION_FL) iio_push_event(iio, IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(iio)); } else if (ret & OPT3001_CONFIGURATION_CRF) { ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); if (ret < 0) { diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 9e847f8f4f0c..45cf8b0a4363 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -528,7 +528,7 @@ static irqreturn_t stk3310_irq_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct stk3310_data *data = iio_priv(indio_dev); - data->timestamp = iio_get_time_ns(); + data->timestamp = iio_get_time_ns(indio_dev); return IRQ_WAKE_THREAD; } diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 8a15fb541dc3..a795afb7667b 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -216,7 +216,7 @@ static irqreturn_t tcs3414_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index b29312f99077..3aa71e34ae28 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -202,7 +202,7 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 57b108c30e98..04598ae993d4 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -630,7 +630,7 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), - iio_get_time_ns()); + iio_get_time_ns(dev_info)); /* clear the interrupt and push the event */ i2c_smbus_write_byte(chip->client, TSL2563_CMD | TSL2563_CLEARINT); diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index 45bc2f742f46..20c40f780964 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -833,7 +833,7 @@ static irqreturn_t us5182d_irq_thread_handler(int irq, void *private) dir = ret & US5182D_CFG0_PROX ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING; ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, IIO_EV_TYPE_THRESH, dir); - iio_push_event(indio_dev, ev, iio_get_time_ns()); + iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev)); ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret & ~US5182D_CFG0_PX_IRQ); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 57d3654d7caf..2121b50ab9b3 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -829,7 +829,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) buff[1] = clamp_t(s16, le16_to_cpu(buff[1]), -def->range, def->range); buff[2] = clamp_t(s16, le16_to_cpu(buff[2]), -def->range, def->range); - iio_push_to_buffers_with_timestamp(indio_dev, buff, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buff, + iio_get_time_ns(indio_dev)); return; unlock: diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index 77882b466e0f..ba3e2a374ee5 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -451,7 +451,7 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p) goto done; iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index 261d517428e4..f2be4a049056 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -261,7 +261,7 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p) } iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index 01b2e0b18878..6392d7b62841 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -171,7 +171,7 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p) mutex_unlock(&data->lock); iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index 76578b07bb6e..feb41f82c64a 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -224,7 +224,8 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p) if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); err: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index c0b0e82abf94..3141c3c161bb 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -238,7 +238,7 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private) ret = lidar_get_measurement(data, data->buffer); if (!ret) { iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } else if (ret != -EINVAL) { dev_err(&data->client->dev, "cannot read LIDAR measurement"); } diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 66cd09a18786..1d74b3aafeed 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -492,7 +492,7 @@ static void sx9500_push_events(struct iio_dev *indio_dev) dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, IIO_EV_TYPE_THRESH, dir); - iio_push_event(indio_dev, ev, iio_get_time_ns()); + iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev)); data->prox_stat[chan] = new_prox; } } @@ -669,7 +669,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private) } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); out: mutex_unlock(&data->mutex); diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 7a6fed3f2d3f..5c3410a74fdb 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -451,7 +451,7 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private) struct iio_dev *indio_dev = private; u8 t; - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); lis3l02dq_spi_read_reg_8(indio_dev, LIS3L02DQ_REG_WAKE_UP_SRC_ADDR, diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 53c5425d02b3..aacf643e87d3 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -774,7 +774,7 @@ static irqreturn_t sca3000_event_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct sca3000_state *st = iio_priv(indio_dev); int ret, val; - s64 last_timestamp = iio_get_time_ns(); + s64 last_timestamp = iio_get_time_ns(indio_dev); /* * Could lead if badly timed to an extra read of status reg, diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index a06b46cb81ca..2177f1dd2b5d 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -705,7 +705,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) IIO_EV_DIR_RISING, IIO_EV_TYPE_THRESH, 0, 0, 0), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); else if (((channels[i] >> 11) & 0xFFF) <= st->cell_threshlow) iio_push_event(indio_dev, @@ -715,7 +715,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) IIO_EV_DIR_FALLING, IIO_EV_TYPE_THRESH, 0, 0, 0), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } else { if (((channels[i] >> 11) & 0xFFF) >= st->aux_threshhigh) iio_push_event(indio_dev, @@ -724,7 +724,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); else if (((channels[i] >> 11) & 0xFFF) <= st->aux_threshlow) iio_push_event(indio_dev, @@ -733,7 +733,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } } diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index a6f8eb11242c..0572df9aad85 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -77,7 +77,8 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) goto done; } - iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); done: gpio_set_value(st->pdata->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index ac3735c7f4a9..5e8115b01011 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -253,7 +253,8 @@ static const struct attribute_group ad7816_attribute_group = { static irqreturn_t ad7816_event_handler(int irq, void *private) { - iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI, iio_get_time_ns()); + iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI, + iio_get_time_ns((struct iio_dev *)private)); return IRQ_HANDLED; } diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index a10e7d8e6002..3faffe59c933 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -1752,7 +1752,7 @@ static irqreturn_t adt7316_event_handler(int irq, void *private) if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX) stat1 &= 0x1F; - time = iio_get_time_ns(); + time = iio_get_time_ns(indio_dev); if (stat1 & BIT(0)) iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, @@ -1804,7 +1804,7 @@ static irqreturn_t adt7316_event_handler(int irq, void *private) 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), - iio_get_time_ns()); + iio_get_time_ns(indio_dev)); } return IRQ_HANDLED; diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index f6b9a10326ea..5578a077fcfb 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -493,7 +493,7 @@ static irqreturn_t ad7150_event_handler(int irq, void *private) struct iio_dev *indio_dev = private; struct ad7150_chip_info *chip = iio_priv(indio_dev); u8 int_status; - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); int ret; ret = i2c_smbus_read_byte_data(chip->client, AD7150_STATUS); diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index d553c8e18fcc..ea15bc1c300c 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -1554,7 +1554,7 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct tsl2X7X_chip *chip = iio_priv(indio_dev); - s64 timestamp = iio_get_time_ns(); + s64 timestamp = iio_get_time_ns(indio_dev); int ret; u8 value; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 7c29cb0124ae..854e2dad1e0d 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -312,13 +312,8 @@ static inline bool iio_channel_has_info(const struct iio_chan_spec *chan, }, \ } -/** - * iio_get_time_ns() - utility function to get a time stamp for events etc - **/ -static inline s64 iio_get_time_ns(void) -{ - return ktime_get_real_ns(); -} +s64 iio_get_time_ns(const struct iio_dev *indio_dev); +unsigned int iio_get_time_res(const struct iio_dev *indio_dev); /* Device operating modes */ #define INDIO_DIRECT_MODE 0x01 @@ -497,6 +492,7 @@ struct iio_buffer_setup_ops { * @chan_attr_group: [INTERN] group for all attrs in base directory * @name: [DRIVER] name of the device. * @info: [DRIVER] callbacks and constant info from driver + * @clock_id: [INTERN] timestamping clock posix identifier * @info_exist_lock: [INTERN] lock to prevent use during removal * @setup_ops: [DRIVER] callbacks to call before and after buffer * enable/disable @@ -537,6 +533,7 @@ struct iio_dev { struct attribute_group chan_attr_group; const char *name; const struct iio_info *info; + clockid_t clock_id; struct mutex info_exist_lock; const struct iio_buffer_setup_ops *setup_ops; struct cdev chrdev; @@ -565,7 +562,7 @@ extern struct bus_type iio_bus_type; /** * iio_device_put() - reference counted deallocation of struct device - * @indio_dev: IIO device structure containing the device + * @indio_dev: IIO device structure containing the device **/ static inline void iio_device_put(struct iio_dev *indio_dev) { @@ -573,6 +570,15 @@ static inline void iio_device_put(struct iio_dev *indio_dev) put_device(&indio_dev->dev); } +/** + * iio_device_get_clock() - Retrieve current timestamping clock for the device + * @indio_dev: IIO device structure containing the device + */ +static inline clockid_t iio_device_get_clock(const struct iio_dev *indio_dev) +{ + return indio_dev->clock_id; +} + /** * dev_to_iio_dev() - Get IIO device struct from a device struct * @dev: The device embedded in the IIO device -- cgit v1.2.3 From 5c6e5b60aae4347223f176966455010a5715b863 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2016 14:13:12 -0400 Subject: NFS: Fix an Oops in the pNFS files and flexfiles connection setup to the DS Chris Worley reports: RIP: 0010:[] [] rpc_new_client+0x2a0/0x2e0 [sunrpc] RSP: 0018:ffff880158f6f548 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff880234f8bc00 RCX: 000000000000ea60 RDX: 0000000000074cc0 RSI: 000000000000ea60 RDI: ffff880234f8bcf0 RBP: ffff880158f6f588 R08: 000000000001ac80 R09: ffff880237003300 R10: ffff880201171000 R11: ffffea0000d75200 R12: ffffffffa03afc60 R13: ffff880230c18800 R14: 0000000000000000 R15: ffff880158f6f680 FS: 00007f0e32673740(0000) GS:ffff88023fc40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000008 CR3: 0000000234886000 CR4: 00000000001406e0 Stack: ffffffffa047a680 0000000000000000 ffff880158f6f598 ffff880158f6f680 ffff880158f6f680 ffff880234d11d00 ffff88023357f800 ffff880158f6f7d0 ffff880158f6f5b8 ffffffffa024660a ffff880158f6f5b8 ffffffffa02492ec Call Trace: [] rpc_create_xprt+0x1a/0xb0 [sunrpc] [] ? xprt_create_transport+0x13c/0x240 [sunrpc] [] rpc_create+0xc6/0x1a0 [sunrpc] [] nfs_create_rpc_client+0xf5/0x140 [nfs] [] nfs_init_client+0x3a/0xd0 [nfs] [] nfs_get_client+0x25f/0x310 [nfs] [] ? rpc_ntop+0xe8/0x100 [sunrpc] [] nfs3_set_ds_client+0xcc/0x100 [nfsv3] [] nfs4_pnfs_ds_connect+0x120/0x400 [nfsv4] [] nfs4_ff_layout_prepare_ds+0xe7/0x330 [nfs_layout_flexfiles] [] ff_layout_pg_init_write+0xcb/0x280 [nfs_layout_flexfiles] [] __nfs_pageio_add_request+0x12c/0x490 [nfs] [] nfs_pageio_add_request+0xc2/0x2a0 [nfs] [] ? nfs_pageio_init+0x75/0x120 [nfs] [] nfs_do_writepage+0x120/0x270 [nfs] [] nfs_writepage_locked+0x61/0xc0 [nfs] [] ? __percpu_counter_add+0x55/0x70 [] nfs_wb_single_page+0xef/0x1c0 [nfs] [] ? __dec_zone_page_state+0x33/0x40 [] nfs_launder_page+0x41/0x90 [nfs] [] invalidate_inode_pages2_range+0x340/0x3a0 [] invalidate_inode_pages2+0x17/0x20 [] nfs_release+0x9e/0xb0 [nfs] [] ? nfs_open+0x60/0x60 [nfs] [] nfs_file_release+0x3d/0x60 [nfs] [] __fput+0xdc/0x1e0 [] ____fput+0xe/0x10 [] task_work_run+0xc4/0xe0 [] do_exit+0x2e8/0xb30 [] ? do_audit_syscall_entry+0x6c/0x70 [] ? __audit_syscall_exit+0x1e6/0x280 [] do_group_exit+0x3f/0xa0 [] SyS_exit_group+0x14/0x20 [] system_call_fastpath+0x12/0x71 Which seems to be due to a call to utsname() when in a task exit context in order to determine the hostname to set in rpc_new_client(). In reality, what we want here is not the hostname of the current task, but the hostname that was used to set up the metadata server. Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 22 ++++++++++------------ fs/nfs/internal.h | 16 ++++++++-------- fs/nfs/nfs3client.c | 8 +++++--- fs/nfs/nfs4client.c | 20 ++++++++++++-------- include/linux/nfs_xdr.h | 5 ++--- 5 files changed, 37 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 0c96528db94a..4849d0f778dc 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -367,8 +367,6 @@ nfs_found_client(const struct nfs_client_initdata *cl_init, */ struct nfs_client * nfs_get_client(const struct nfs_client_initdata *cl_init, - const struct rpc_timeout *timeparms, - const char *ip_addr, rpc_authflavor_t authflavour) { struct nfs_client *clp, *new = NULL; @@ -399,7 +397,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, &nn->nfs_client_list); spin_unlock(&nn->nfs_client_lock); new->cl_flags = cl_init->init_flags; - return rpc_ops->init_client(new, timeparms, ip_addr); + return rpc_ops->init_client(new, cl_init); } spin_unlock(&nn->nfs_client_lock); @@ -470,7 +468,7 @@ EXPORT_SYMBOL_GPL(nfs_init_timeout_values); * Create an RPC client handle */ int nfs_create_rpc_client(struct nfs_client *clp, - const struct rpc_timeout *timeparms, + const struct nfs_client_initdata *cl_init, rpc_authflavor_t flavor) { struct rpc_clnt *clnt = NULL; @@ -479,8 +477,9 @@ int nfs_create_rpc_client(struct nfs_client *clp, .protocol = clp->cl_proto, .address = (struct sockaddr *)&clp->cl_addr, .addrsize = clp->cl_addrlen, - .timeout = timeparms, + .timeout = cl_init->timeparms, .servername = clp->cl_hostname, + .nodename = cl_init->nodename, .program = &nfs_program, .version = clp->rpc_ops->version, .authflavor = flavor, @@ -591,14 +590,12 @@ EXPORT_SYMBOL_GPL(nfs_init_server_rpcclient); * nfs_init_client - Initialise an NFS2 or NFS3 client * * @clp: nfs_client to initialise - * @timeparms: timeout parameters for underlying RPC transport - * @ip_addr: IP presentation address (not used) + * @cl_init: Initialisation parameters * * Returns pointer to an NFS client, or an ERR_PTR value. */ struct nfs_client *nfs_init_client(struct nfs_client *clp, - const struct rpc_timeout *timeparms, - const char *ip_addr) + const struct nfs_client_initdata *cl_init) { int error; @@ -612,7 +609,7 @@ struct nfs_client *nfs_init_client(struct nfs_client *clp, * Create a client RPC handle for doing FSSTAT with UNIX auth only * - RFC 2623, sec 2.3.2 */ - error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); + error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX); if (error < 0) goto error; nfs_mark_client_ready(clp, NFS_CS_READY); @@ -633,6 +630,7 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_parsed_mount_data *data, struct nfs_subversion *nfs_mod) { + struct rpc_timeout timeparms; struct nfs_client_initdata cl_init = { .hostname = data->nfs_server.hostname, .addr = (const struct sockaddr *)&data->nfs_server.address, @@ -640,8 +638,8 @@ static int nfs_init_server(struct nfs_server *server, .nfs_mod = nfs_mod, .proto = data->nfs_server.protocol, .net = data->net, + .timeparms = &timeparms, }; - struct rpc_timeout timeparms; struct nfs_client *clp; int error; @@ -653,7 +651,7 @@ static int nfs_init_server(struct nfs_server *server, set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); /* Allocate or find a client reference we can use */ - clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX); + clp = nfs_get_client(&cl_init, RPC_AUTH_UNIX); if (IS_ERR(clp)) { dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); return PTR_ERR(clp); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 5154fa65a2f2..fa88609f85e3 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -66,13 +66,16 @@ struct nfs_clone_mount { struct nfs_client_initdata { unsigned long init_flags; - const char *hostname; - const struct sockaddr *addr; + const char *hostname; /* Hostname of the server */ + const struct sockaddr *addr; /* Address of the server */ + const char *nodename; /* Hostname of the client */ + const char *ip_addr; /* IP address of the client */ size_t addrlen; struct nfs_subversion *nfs_mod; int proto; u32 minorversion; struct net *net; + const struct rpc_timeout *timeparms; }; /* @@ -147,9 +150,8 @@ extern void nfs_umount(const struct nfs_mount_request *info); extern const struct rpc_program nfs_program; extern void nfs_clients_init(struct net *net); extern struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *); -int nfs_create_rpc_client(struct nfs_client *, const struct rpc_timeout *, rpc_authflavor_t); +int nfs_create_rpc_client(struct nfs_client *, const struct nfs_client_initdata *, rpc_authflavor_t); struct nfs_client *nfs_get_client(const struct nfs_client_initdata *, - const struct rpc_timeout *, const char *, rpc_authflavor_t); int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *); void nfs_server_insert_lists(struct nfs_server *); @@ -338,8 +340,7 @@ nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src) /* proc.c */ void nfs_close_context(struct nfs_open_context *ctx, int is_sync); extern struct nfs_client *nfs_init_client(struct nfs_client *clp, - const struct rpc_timeout *timeparms, - const char *ip_addr); + const struct nfs_client_initdata *); /* dir.c */ extern void nfs_force_use_readdirplus(struct inode *dir); @@ -521,8 +522,7 @@ extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); /* nfs4proc.c */ extern void __nfs4_read_done_cb(struct nfs_pgio_header *); extern struct nfs_client *nfs4_init_client(struct nfs_client *clp, - const struct rpc_timeout *timeparms, - const char *ip_addr); + const struct nfs_client_initdata *); extern int nfs40_walk_client_list(struct nfs_client *clp, struct nfs_client **result, struct rpc_cred *cred); diff --git a/fs/nfs/nfs3client.c b/fs/nfs/nfs3client.c index 9e9fa347a948..0457b4129421 100644 --- a/fs/nfs/nfs3client.c +++ b/fs/nfs/nfs3client.c @@ -81,14 +81,17 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_client *mds_clp, int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans, rpc_authflavor_t au_flavor) { + struct rpc_timeout ds_timeout; struct nfs_client_initdata cl_init = { .addr = ds_addr, .addrlen = ds_addrlen, + .nodename = mds_clp->cl_rpcclient->cl_nodename, + .ip_addr = mds_clp->cl_ipaddr, .nfs_mod = &nfs_v3, .proto = ds_proto, .net = mds_clp->cl_net, + .timeparms = &ds_timeout, }; - struct rpc_timeout ds_timeout; struct nfs_client *clp; char buf[INET6_ADDRSTRLEN + 1]; @@ -99,8 +102,7 @@ struct nfs_client *nfs3_set_ds_client(struct nfs_client *mds_clp, /* Use the MDS nfs_client cl_ipaddr. */ nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans); - clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, - au_flavor); + clp = nfs_get_client(&cl_init, au_flavor); return clp; } diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 10410e8b5853..5fc7fbbfdcef 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -349,10 +349,10 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) * Returns pointer to an NFS client, or an ERR_PTR value. */ struct nfs_client *nfs4_init_client(struct nfs_client *clp, - const struct rpc_timeout *timeparms, - const char *ip_addr) + const struct nfs_client_initdata *cl_init) { char buf[INET6_ADDRSTRLEN + 1]; + const char *ip_addr = cl_init->ip_addr; struct nfs_client *old; int error; @@ -370,9 +370,9 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags); - error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I); + error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_GSS_KRB5I); if (error == -EINVAL) - error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); + error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX); if (error < 0) goto error; @@ -793,10 +793,12 @@ static int nfs4_set_client(struct nfs_server *server, .hostname = hostname, .addr = addr, .addrlen = addrlen, + .ip_addr = ip_addr, .nfs_mod = &nfs_v4, .proto = proto, .minorversion = minorversion, .net = net, + .timeparms = timeparms, }; struct nfs_client *clp; int error; @@ -809,7 +811,7 @@ static int nfs4_set_client(struct nfs_server *server, set_bit(NFS_CS_MIGRATION, &cl_init.init_flags); /* Allocate or find a client reference we can use */ - clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour); + clp = nfs_get_client(&cl_init, authflavour); if (IS_ERR(clp)) { error = PTR_ERR(clp); goto error; @@ -847,15 +849,18 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans, u32 minor_version, rpc_authflavor_t au_flavor) { + struct rpc_timeout ds_timeout; struct nfs_client_initdata cl_init = { .addr = ds_addr, .addrlen = ds_addrlen, + .nodename = mds_clp->cl_rpcclient->cl_nodename, + .ip_addr = mds_clp->cl_ipaddr, .nfs_mod = &nfs_v4, .proto = ds_proto, .minorversion = minor_version, .net = mds_clp->cl_net, + .timeparms = &ds_timeout, }; - struct rpc_timeout ds_timeout; struct nfs_client *clp; char buf[INET6_ADDRSTRLEN + 1]; @@ -869,8 +874,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, * (section 13.1 RFC 5661). */ nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans); - clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, - au_flavor); + clp = nfs_get_client(&cl_init, au_flavor); dprintk("<-- %s %p\n", __func__, clp); return clp; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index c304a11b5b1a..82b81a1c2438 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1596,9 +1596,8 @@ struct nfs_rpc_ops { int (*have_delegation)(struct inode *, fmode_t); int (*return_delegation)(struct inode *); struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *); - struct nfs_client * - (*init_client) (struct nfs_client *, const struct rpc_timeout *, - const char *); + struct nfs_client *(*init_client) (struct nfs_client *, + const struct nfs_client_initdata *); void (*free_client) (struct nfs_client *); struct nfs_server *(*create_server)(struct nfs_mount_info *, struct nfs_subversion *); struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *, -- cgit v1.2.3 From 52445637371e5a30c0320eae75970c28f982d914 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 22 May 2016 14:33:35 +0900 Subject: clk: fixed-rate: add clk_hw_unregister_fixed_rate() This will be used to migrate to the clk_hw APIs. Signed-off-by: Masahiro Yamada Signed-off-by: Stephen Boyd --- drivers/clk/clk-fixed-rate.c | 11 +++++++++++ include/linux/clk-provider.h | 1 + 2 files changed, 12 insertions(+) (limited to 'include/linux') diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index 8e4453eb54e8..2edb39342a02 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -145,6 +145,17 @@ void clk_unregister_fixed_rate(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_unregister_fixed_rate); +void clk_hw_unregister_fixed_rate(struct clk_hw *hw) +{ + struct clk_fixed_rate *fixed; + + fixed = to_clk_fixed_rate(hw); + + clk_hw_unregister(hw); + kfree(fixed); +} +EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate); + #ifdef CONFIG_OF /** * of_fixed_clk_setup() - Setup function for simple fixed rate clock diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 0c72204c75fc..94e00fe976f5 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -293,6 +293,7 @@ void clk_unregister_fixed_rate(struct clk *clk); struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned long fixed_rate, unsigned long fixed_accuracy); +void clk_hw_unregister_fixed_rate(struct clk_hw *hw); void of_fixed_clk_setup(struct device_node *np); -- cgit v1.2.3 From 37b11804ed1725dc2ea97be2236150210a69e9d5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 27 Jun 2016 15:52:48 -0500 Subject: userns: Handle -1 in k[ug]id_has_mapping when !CONFIG_USER_NS Refuse to admit any user namespace has a mapping of the INVALID_UID and the INVALID_GID when !CONFIG_USER_NS. Acked-by: Seth Forshee Signed-off-by: "Eric W. Biederman" --- include/linux/uidgid.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index 03835522dfcb..25e9d9216340 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -177,12 +177,12 @@ static inline gid_t from_kgid_munged(struct user_namespace *to, kgid_t kgid) static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid) { - return true; + return uid_valid(uid); } static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) { - return true; + return gid_valid(gid); } #endif /* CONFIG_USER_NS */ -- cgit v1.2.3 From 0d4d717f25834134bb6f43284f84c8ccee5bbf2a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 27 Jun 2016 16:04:06 -0500 Subject: vfs: Verify acls are valid within superblock's s_user_ns. Update posix_acl_valid to verify that an acl is within a user namespace. Update the callers of posix_acl_valid to pass in an appropriate user namespace. For posix_acl_xattr_set and v9fs_xattr_set_acl pass in inode->i_sb->s_user_ns to posix_acl_valid. For md_unpack_acl pass in &init_user_ns as no inode or superblock is in sight. Acked-by: Seth Forshee Signed-off-by: "Eric W. Biederman" --- drivers/staging/lustre/lustre/mdc/mdc_request.c | 2 +- fs/9p/acl.c | 2 +- fs/posix_acl.c | 8 ++++---- include/linux/posix_acl.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 86b7445365f4..40cf57fad581 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -434,7 +434,7 @@ static int mdc_unpack_acl(struct ptlrpc_request *req, struct lustre_md *md) return rc; } - rc = posix_acl_valid(acl); + rc = posix_acl_valid(&init_user_ns, acl); if (rc) { CERROR("validate acl: %d\n", rc); posix_acl_release(acl); diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 0576eaeb60b9..5b6a1743ea17 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -266,7 +266,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler, if (IS_ERR(acl)) return PTR_ERR(acl); else if (acl) { - retval = posix_acl_valid(acl); + retval = posix_acl_valid(inode->i_sb->s_user_ns, acl); if (retval) goto err_out; } diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 8a4a266beff3..647c28180675 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -205,7 +205,7 @@ posix_acl_clone(const struct posix_acl *acl, gfp_t flags) * Check if an acl is valid. Returns 0 if it is, or -E... otherwise. */ int -posix_acl_valid(const struct posix_acl *acl) +posix_acl_valid(struct user_namespace *user_ns, const struct posix_acl *acl) { const struct posix_acl_entry *pa, *pe; int state = ACL_USER_OBJ; @@ -225,7 +225,7 @@ posix_acl_valid(const struct posix_acl *acl) case ACL_USER: if (state != ACL_USER) return -EINVAL; - if (!uid_valid(pa->e_uid)) + if (!kuid_has_mapping(user_ns, pa->e_uid)) return -EINVAL; needs_mask = 1; break; @@ -240,7 +240,7 @@ posix_acl_valid(const struct posix_acl *acl) case ACL_GROUP: if (state != ACL_GROUP) return -EINVAL; - if (!gid_valid(pa->e_gid)) + if (!kgid_has_mapping(user_ns, pa->e_gid)) return -EINVAL; needs_mask = 1; break; @@ -845,7 +845,7 @@ posix_acl_xattr_set(const struct xattr_handler *handler, return PTR_ERR(acl); if (acl) { - ret = posix_acl_valid(acl); + ret = posix_acl_valid(inode->i_sb->s_user_ns, acl); if (ret) goto out; } diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 5b5a80cc5926..1af6438fde3e 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -81,7 +81,7 @@ posix_acl_release(struct posix_acl *acl) extern void posix_acl_init(struct posix_acl *, int); extern struct posix_acl *posix_acl_alloc(int, gfp_t); -extern int posix_acl_valid(const struct posix_acl *); +extern int posix_acl_valid(struct user_namespace *, const struct posix_acl *); extern int posix_acl_permission(struct inode *, const struct posix_acl *, int); extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); -- cgit v1.2.3 From 6edaa5307f3f51e4e56dc4c63f68a69d88c6ddf5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 15 Jun 2016 15:18:26 +0200 Subject: KVM: remove kvm_guest_enter/exit wrappers Use the functions from context_tracking.h directly. Cc: Andy Lutomirski Cc: Peter Zijlstra Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Thomas Gleixner Reviewed-by: Rik van Riel Signed-off-by: Paolo Bonzini --- arch/arm/kvm/arm.c | 8 ++++---- arch/mips/kvm/mips.c | 4 ++-- arch/powerpc/kvm/book3s_hv.c | 4 ++-- arch/powerpc/kvm/book3s_pr.c | 4 ++-- arch/powerpc/kvm/booke.c | 4 ++-- arch/powerpc/kvm/powerpc.c | 2 +- arch/s390/kvm/kvm-s390.c | 4 ++-- arch/s390/kvm/vsie.c | 4 ++-- arch/x86/kvm/x86.c | 4 ++-- include/linux/kvm_host.h | 22 ---------------------- 10 files changed, 19 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index f20ca84537f5..9ac4970882fe 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -615,7 +615,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) * Enter the guest */ trace_kvm_entry(*vcpu_pc(vcpu)); - __kvm_guest_enter(); + guest_enter_irqoff(); vcpu->mode = IN_GUEST_MODE; ret = kvm_call_hyp(__kvm_vcpu_run, vcpu); @@ -641,14 +641,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) local_irq_enable(); /* - * We do local_irq_enable() before calling kvm_guest_exit() so + * We do local_irq_enable() before calling guest_exit() so * that if a timer interrupt hits while running the guest we * account that tick as being spent in the guest. We enable - * preemption after calling kvm_guest_exit() so that if we get + * preemption after calling guest_exit() so that if we get * preempted we make sure ticks after that is not counted as * guest time. */ - kvm_guest_exit(); + guest_exit(); trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu)); /* diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 5a2b9034a05c..5f1163653b50 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -406,7 +406,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) kvm_mips_deliver_interrupts(vcpu, kvm_read_c0_guest_cause(vcpu->arch.cop0)); - __kvm_guest_enter(); + guest_enter_irqoff(); /* Disable hardware page table walking while in guest */ htw_stop(); @@ -418,7 +418,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) /* Re-enable HTW before enabling interrupts */ htw_start(); - __kvm_guest_exit(); + guest_exit_irqoff(); local_irq_enable(); if (vcpu->sigset_active) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index e20beae5ca7a..6b2859c12ae8 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -2522,7 +2522,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) list_for_each_entry(pvc, &core_info.vcs[sub], preempt_list) spin_unlock(&pvc->lock); - kvm_guest_enter(); + guest_enter(); srcu_idx = srcu_read_lock(&vc->kvm->srcu); @@ -2570,7 +2570,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) /* make sure updates to secondary vcpu structs are visible now */ smp_mb(); - kvm_guest_exit(); + guest_exit(); for (sub = 0; sub < core_info.n_subcores; ++sub) list_for_each_entry_safe(pvc, vcnext, &core_info.vcs[sub], diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 8e4f64f0b774..6a66c5ff0827 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -914,7 +914,7 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu, /* We get here with MSR.EE=1 */ trace_kvm_exit(exit_nr, vcpu); - kvm_guest_exit(); + guest_exit(); switch (exit_nr) { case BOOK3S_INTERRUPT_INST_STORAGE: @@ -1531,7 +1531,7 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) kvmppc_clear_debug(vcpu); - /* No need for kvm_guest_exit. It's done in handle_exit. + /* No need for guest_exit. It's done in handle_exit. We also get here with interrupts enabled. */ /* Make sure we save the guest FPU/Altivec/VSX state */ diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 4afae695899a..02b4672f7347 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -776,7 +776,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) ret = __kvmppc_vcpu_run(kvm_run, vcpu); - /* No need for kvm_guest_exit. It's done in handle_exit. + /* No need for guest_exit. It's done in handle_exit. We also get here with interrupts enabled. */ /* Switch back to user space debug context */ @@ -1012,7 +1012,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, } trace_kvm_exit(exit_nr, vcpu); - __kvm_guest_exit(); + guest_exit_irqoff(); local_irq_enable(); diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 02416fea7653..1ac036e45ed4 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -119,7 +119,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) continue; } - __kvm_guest_enter(); + guest_enter_irqoff(); return 1; } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 03eeeb0ded24..d42428c11794 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2623,14 +2623,14 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) * guest_enter and guest_exit should be no uaccess. */ local_irq_disable(); - __kvm_guest_enter(); + guest_enter_irqoff(); __disable_cpu_timer_accounting(vcpu); local_irq_enable(); exit_reason = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs); local_irq_disable(); __enable_cpu_timer_accounting(vcpu); - __kvm_guest_exit(); + guest_exit_irqoff(); local_irq_enable(); vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 6895e7b3be12..c106488b4137 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -765,13 +765,13 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); local_irq_disable(); - kvm_guest_enter(); + guest_enter_irqoff(); local_irq_enable(); rc = sie64a(scb_s, vcpu->run->s.regs.gprs); local_irq_disable(); - kvm_guest_exit(); + guest_exit_irqoff(); local_irq_enable(); vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 9e50e2ad6d08..618463abeec5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6658,7 +6658,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) trace_kvm_entry(vcpu->vcpu_id); wait_lapic_expire(vcpu); - __kvm_guest_enter(); + guest_enter_irqoff(); if (unlikely(vcpu->arch.switch_db_regs)) { set_debugreg(0, 7); @@ -6717,7 +6717,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) */ barrier(); - kvm_guest_exit(); + guest_exit(); preempt_enable(); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index ffff40522688..66b2f6159aad 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -875,28 +875,6 @@ static inline void kvm_iommu_unmap_pages(struct kvm *kvm, } #endif -/* must be called with irqs disabled */ -static inline void __kvm_guest_enter(void) -{ - guest_enter_irqoff(); -} - -/* must be called with irqs disabled */ -static inline void __kvm_guest_exit(void) -{ - guest_exit_irqoff(); -} - -static inline void kvm_guest_enter(void) -{ - guest_enter(); -} - -static inline void kvm_guest_exit(void) -{ - guest_exit(); -} - /* * search_memslots() and __gfn_to_memslot() are here because they are * used in non-modular code in arch/powerpc/kvm/book3s_hv_rm_mmu.c. -- cgit v1.2.3 From 982fb490c298896d15e9323a882f34a57c11ff56 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 30 Jun 2016 14:45:31 +0800 Subject: ptr_ring: support zero length ring Sometimes, we need zero length ring. But current code will crash since we don't do any check before accessing the ring. This patch fixes this. Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- include/linux/ptr_ring.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h index 562a65e8bcc0..d78b8b89c707 100644 --- a/include/linux/ptr_ring.h +++ b/include/linux/ptr_ring.h @@ -102,7 +102,7 @@ static inline bool ptr_ring_full_bh(struct ptr_ring *r) */ static inline int __ptr_ring_produce(struct ptr_ring *r, void *ptr) { - if (r->queue[r->producer]) + if (unlikely(!r->size) || r->queue[r->producer]) return -ENOSPC; r->queue[r->producer++] = ptr; @@ -164,7 +164,9 @@ static inline int ptr_ring_produce_bh(struct ptr_ring *r, void *ptr) */ static inline void *__ptr_ring_peek(struct ptr_ring *r) { - return r->queue[r->consumer]; + if (likely(r->size)) + return r->queue[r->consumer]; + return NULL; } /* Note: callers invoking this in a loop must use a compiler barrier, -- cgit v1.2.3 From fd68adec9de3104c236ffbcb3bd829d3e635a444 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 30 Jun 2016 14:45:32 +0800 Subject: skb_array: minor tweak Signed-off-by: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- include/linux/skb_array.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skb_array.h b/include/linux/skb_array.h index 678bfbf78ac4..2dd0d1e4ee7e 100644 --- a/include/linux/skb_array.h +++ b/include/linux/skb_array.h @@ -151,12 +151,12 @@ static inline int skb_array_init(struct skb_array *a, int size, gfp_t gfp) return ptr_ring_init(&a->ring, size, gfp); } -void __skb_array_destroy_skb(void *ptr) +static void __skb_array_destroy_skb(void *ptr) { kfree_skb(ptr); } -int skb_array_resize(struct skb_array *a, int size, gfp_t gfp) +static inline int skb_array_resize(struct skb_array *a, int size, gfp_t gfp) { return ptr_ring_resize(&a->ring, size, gfp, __skb_array_destroy_skb); } -- cgit v1.2.3 From 59e6ae53248a72d83cec77dd704b6990b2394479 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 30 Jun 2016 14:45:33 +0800 Subject: ptr_ring: support resizing multiple queues Sometimes, we need support resizing multiple queues at once. This is because it was not easy to recover to recover from a partial failure of multiple queues resizing. Signed-off-by: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- include/linux/ptr_ring.h | 71 +++++++++++++++++++++++++++++++++++----- tools/virtio/ringtest/ptr_ring.c | 5 +++ 2 files changed, 67 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h index d78b8b89c707..2052011bf9fb 100644 --- a/include/linux/ptr_ring.h +++ b/include/linux/ptr_ring.h @@ -349,20 +349,14 @@ static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp) return 0; } -static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp, - void (*destroy)(void *)) +static inline void **__ptr_ring_swap_queue(struct ptr_ring *r, void **queue, + int size, gfp_t gfp, + void (*destroy)(void *)) { - unsigned long flags; int producer = 0; - void **queue = __ptr_ring_init_queue_alloc(size, gfp); void **old; void *ptr; - if (!queue) - return -ENOMEM; - - spin_lock_irqsave(&(r)->producer_lock, flags); - while ((ptr = ptr_ring_consume(r))) if (producer < size) queue[producer++] = ptr; @@ -375,6 +369,23 @@ static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp, old = r->queue; r->queue = queue; + return old; +} + +static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp, + void (*destroy)(void *)) +{ + unsigned long flags; + void **queue = __ptr_ring_init_queue_alloc(size, gfp); + void **old; + + if (!queue) + return -ENOMEM; + + spin_lock_irqsave(&(r)->producer_lock, flags); + + old = __ptr_ring_swap_queue(r, queue, size, gfp, destroy); + spin_unlock_irqrestore(&(r)->producer_lock, flags); kfree(old); @@ -382,6 +393,48 @@ static inline int ptr_ring_resize(struct ptr_ring *r, int size, gfp_t gfp, return 0; } +static inline int ptr_ring_resize_multiple(struct ptr_ring **rings, int nrings, + int size, + gfp_t gfp, void (*destroy)(void *)) +{ + unsigned long flags; + void ***queues; + int i; + + queues = kmalloc(nrings * sizeof *queues, gfp); + if (!queues) + goto noqueues; + + for (i = 0; i < nrings; ++i) { + queues[i] = __ptr_ring_init_queue_alloc(size, gfp); + if (!queues[i]) + goto nomem; + } + + for (i = 0; i < nrings; ++i) { + spin_lock_irqsave(&(rings[i])->producer_lock, flags); + queues[i] = __ptr_ring_swap_queue(rings[i], queues[i], + size, gfp, destroy); + spin_unlock_irqrestore(&(rings[i])->producer_lock, flags); + } + + for (i = 0; i < nrings; ++i) + kfree(queues[i]); + + kfree(queues); + + return 0; + +nomem: + while (--i >= 0) + kfree(queues[i]); + + kfree(queues); + +noqueues: + return -ENOMEM; +} + static inline void ptr_ring_cleanup(struct ptr_ring *r, void (*destroy)(void *)) { void *ptr; diff --git a/tools/virtio/ringtest/ptr_ring.c b/tools/virtio/ringtest/ptr_ring.c index 74abd746ae91..68e4f9f0da3a 100644 --- a/tools/virtio/ringtest/ptr_ring.c +++ b/tools/virtio/ringtest/ptr_ring.c @@ -17,6 +17,11 @@ typedef pthread_spinlock_t spinlock_t; typedef int gfp_t; +static void *kmalloc(unsigned size, gfp_t gfp) +{ + return memalign(64, size); +} + static void *kzalloc(unsigned size, gfp_t gfp) { void *p = memalign(64, size); -- cgit v1.2.3 From bf900b3dbefee49855c17aa09fb4245346a78fb3 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 30 Jun 2016 14:45:34 +0800 Subject: skb_array: add wrappers for resizing Signed-off-by: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- include/linux/skb_array.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include/linux') diff --git a/include/linux/skb_array.h b/include/linux/skb_array.h index 2dd0d1e4ee7e..f4dfade428f0 100644 --- a/include/linux/skb_array.h +++ b/include/linux/skb_array.h @@ -161,6 +161,15 @@ static inline int skb_array_resize(struct skb_array *a, int size, gfp_t gfp) return ptr_ring_resize(&a->ring, size, gfp, __skb_array_destroy_skb); } +static inline int skb_array_resize_multiple(struct skb_array **rings, + int nrings, int size, gfp_t gfp) +{ + BUILD_BUG_ON(offsetof(struct skb_array, ring)); + return ptr_ring_resize_multiple((struct ptr_ring **)rings, + nrings, size, gfp, + __skb_array_destroy_skb); +} + static inline void skb_array_cleanup(struct skb_array *a) { ptr_ring_cleanup(&a->ring, __skb_array_destroy_skb); -- cgit v1.2.3 From 08294a26e15d7baf1e14ee569e9f2bc82a7ae768 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 30 Jun 2016 14:45:35 +0800 Subject: net: introduce NETDEV_CHANGE_TX_QUEUE_LEN This patch introduces a new event - NETDEV_CHANGE_TX_QUEUE_LEN, this will be triggered when tx_queue_len. It could be used by net device who want to do some processing at that time. An example is tun who may want to resize tx array when tx_queue_len is changed. Cc: John Fastabend Signed-off-by: Jason Wang Acked-by: John Fastabend Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + net/core/net-sysfs.c | 15 ++++++++++++++- net/core/rtnetlink.c | 16 ++++++++++++---- 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e84d9d23c2d5..7dc2ec74122a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2237,6 +2237,7 @@ struct netdev_lag_lower_state_info { #define NETDEV_PRECHANGEUPPER 0x001A #define NETDEV_CHANGELOWERSTATE 0x001B #define NETDEV_UDP_TUNNEL_PUSH_INFO 0x001C +#define NETDEV_CHANGE_TX_QUEUE_LEN 0x001E int register_netdevice_notifier(struct notifier_block *nb); int unregister_netdevice_notifier(struct notifier_block *nb); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 7a0b616557ab..6e4f34721080 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -322,7 +322,20 @@ NETDEVICE_SHOW_RW(flags, fmt_hex); static int change_tx_queue_len(struct net_device *dev, unsigned long new_len) { - dev->tx_queue_len = new_len; + int res, orig_len = dev->tx_queue_len; + + if (new_len != orig_len) { + dev->tx_queue_len = new_len; + res = call_netdevice_notifiers(NETDEV_CHANGE_TX_QUEUE_LEN, dev); + res = notifier_to_errno(res); + if (res) { + netdev_err(dev, + "refused to change device tx_queue_len\n"); + dev->tx_queue_len = orig_len; + return -EFAULT; + } + } + return 0; } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index cfed7bc14ee6..a9e3805af739 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1927,11 +1927,19 @@ static int do_setlink(const struct sk_buff *skb, if (tb[IFLA_TXQLEN]) { unsigned long value = nla_get_u32(tb[IFLA_TXQLEN]); - - if (dev->tx_queue_len ^ value) + unsigned long orig_len = dev->tx_queue_len; + + if (dev->tx_queue_len ^ value) { + dev->tx_queue_len = value; + err = call_netdevice_notifiers( + NETDEV_CHANGE_TX_QUEUE_LEN, dev); + err = notifier_to_errno(err); + if (err) { + dev->tx_queue_len = orig_len; + goto errout; + } status |= DO_SETLINK_NOTIFY; - - dev->tx_queue_len = value; + } } if (tb[IFLA_OPERSTATE]) -- cgit v1.2.3 From 1576d98605998fb59d121a39581129e134217182 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 30 Jun 2016 14:45:36 +0800 Subject: tun: switch to use skb array for tx We used to queue tx packets in sk_receive_queue, this is less efficient since it requires spinlocks to synchronize between producer and consumer. This patch tries to address this by: - switch from sk_receive_queue to a skb_array, and resize it when tx_queue_len was changed. - introduce a new proto_ops peek_len which was used for peeking the skb length. - implement a tun version of peek_len for vhost_net to use and convert vhost_net to use peek_len if possible. Pktgen test shows about 15.3% improvement on guest receiving pps for small buffers: Before: ~1300000pps After : ~1500000pps Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++--- drivers/vhost/net.c | 16 +++++- include/linux/net.h | 1 + 3 files changed, 146 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 4884802e0af1..74752159ec34 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -71,6 +71,7 @@ #include #include #include +#include #include @@ -167,6 +168,7 @@ struct tun_file { }; struct list_head next; struct tun_struct *detached; + struct skb_array tx_array; }; struct tun_flow_entry { @@ -515,7 +517,11 @@ static struct tun_struct *tun_enable_queue(struct tun_file *tfile) static void tun_queue_purge(struct tun_file *tfile) { - skb_queue_purge(&tfile->sk.sk_receive_queue); + struct sk_buff *skb; + + while ((skb = skb_array_consume(&tfile->tx_array)) != NULL) + kfree_skb(skb); + skb_queue_purge(&tfile->sk.sk_error_queue); } @@ -560,6 +566,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean) tun->dev->reg_state == NETREG_REGISTERED) unregister_netdevice(tun->dev); } + if (tun) + skb_array_cleanup(&tfile->tx_array); sock_put(&tfile->sk); } } @@ -613,6 +621,7 @@ static void tun_detach_all(struct net_device *dev) static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filter) { struct tun_file *tfile = file->private_data; + struct net_device *dev = tun->dev; int err; err = security_tun_dev_attach(tfile->socket.sk, tun->security); @@ -642,6 +651,13 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte if (!err) goto out; } + + if (!tfile->detached && + skb_array_init(&tfile->tx_array, dev->tx_queue_len, GFP_KERNEL)) { + err = -ENOMEM; + goto out; + } + tfile->queue_index = tun->numqueues; tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN; rcu_assign_pointer(tfile->tun, tun); @@ -891,8 +907,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) nf_reset(skb); - /* Enqueue packet */ - skb_queue_tail(&tfile->socket.sk->sk_receive_queue, skb); + if (skb_array_produce(&tfile->tx_array, skb)) + goto drop; /* Notify and wake up reader process */ if (tfile->flags & TUN_FASYNC) @@ -1107,7 +1123,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait) poll_wait(file, sk_sleep(sk), wait); - if (!skb_queue_empty(&sk->sk_receive_queue)) + if (!skb_array_empty(&tfile->tx_array)) mask |= POLLIN | POLLRDNORM; if (sock_writeable(sk) || @@ -1426,22 +1442,61 @@ done: return total; } +static struct sk_buff *tun_ring_recv(struct tun_file *tfile, int noblock, + int *err) +{ + DECLARE_WAITQUEUE(wait, current); + struct sk_buff *skb = NULL; + + skb = skb_array_consume(&tfile->tx_array); + if (skb) + goto out; + if (noblock) { + *err = -EAGAIN; + goto out; + } + + add_wait_queue(&tfile->wq.wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (1) { + skb = skb_array_consume(&tfile->tx_array); + if (skb) + break; + if (signal_pending(current)) { + *err = -ERESTARTSYS; + break; + } + if (tfile->socket.sk->sk_shutdown & RCV_SHUTDOWN) { + *err = -EFAULT; + break; + } + + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&tfile->wq.wait, &wait); + +out: + return skb; +} + static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, struct iov_iter *to, int noblock) { struct sk_buff *skb; ssize_t ret; - int peeked, err, off = 0; + int err; tun_debug(KERN_INFO, tun, "tun_do_read\n"); if (!iov_iter_count(to)) return 0; - /* Read frames from queue */ - skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0, - &peeked, &off, &err); + /* Read frames from ring */ + skb = tun_ring_recv(tfile, noblock, &err); if (!skb) return err; @@ -1574,8 +1629,25 @@ out: return ret; } +static int tun_peek_len(struct socket *sock) +{ + struct tun_file *tfile = container_of(sock, struct tun_file, socket); + struct tun_struct *tun; + int ret = 0; + + tun = __tun_get(tfile); + if (!tun) + return 0; + + ret = skb_array_peek_len(&tfile->tx_array); + tun_put(tun); + + return ret; +} + /* Ops structure to mimic raw sockets with tun */ static const struct proto_ops tun_socket_ops = { + .peek_len = tun_peek_len, .sendmsg = tun_sendmsg, .recvmsg = tun_recvmsg, }; @@ -2397,6 +2469,53 @@ static const struct ethtool_ops tun_ethtool_ops = { .get_ts_info = ethtool_op_get_ts_info, }; +static int tun_queue_resize(struct tun_struct *tun) +{ + struct net_device *dev = tun->dev; + struct tun_file *tfile; + struct skb_array **arrays; + int n = tun->numqueues + tun->numdisabled; + int ret, i; + + arrays = kmalloc(sizeof *arrays * n, GFP_KERNEL); + if (!arrays) + return -ENOMEM; + + for (i = 0; i < tun->numqueues; i++) { + tfile = rtnl_dereference(tun->tfiles[i]); + arrays[i] = &tfile->tx_array; + } + list_for_each_entry(tfile, &tun->disabled, next) + arrays[i++] = &tfile->tx_array; + + ret = skb_array_resize_multiple(arrays, n, + dev->tx_queue_len, GFP_KERNEL); + + kfree(arrays); + return ret; +} + +static int tun_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct tun_struct *tun = netdev_priv(dev); + + switch (event) { + case NETDEV_CHANGE_TX_QUEUE_LEN: + if (tun_queue_resize(tun)) + return NOTIFY_BAD; + break; + default: + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block tun_notifier_block __read_mostly = { + .notifier_call = tun_device_event, +}; static int __init tun_init(void) { @@ -2416,6 +2535,8 @@ static int __init tun_init(void) pr_err("Can't register misc device %d\n", TUN_MINOR); goto err_misc; } + + register_netdevice_notifier(&tun_notifier_block); return 0; err_misc: rtnl_link_unregister(&tun_link_ops); @@ -2427,6 +2548,7 @@ static void tun_cleanup(void) { misc_deregister(&tun_miscdev); rtnl_link_unregister(&tun_link_ops); + unregister_netdevice_notifier(&tun_notifier_block); } /* Get an underlying socket object from tun file. Returns error unless file is diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 1d3e45f84549..e032ca397371 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -481,10 +481,14 @@ out: static int peek_head_len(struct sock *sk) { + struct socket *sock = sk->sk_socket; struct sk_buff *head; int len = 0; unsigned long flags; + if (sock->ops->peek_len) + return sock->ops->peek_len(sock); + spin_lock_irqsave(&sk->sk_receive_queue.lock, flags); head = skb_peek(&sk->sk_receive_queue); if (likely(head)) { @@ -497,6 +501,16 @@ static int peek_head_len(struct sock *sk) return len; } +static int sk_has_rx_data(struct sock *sk) +{ + struct socket *sock = sk->sk_socket; + + if (sock->ops->peek_len) + return sock->ops->peek_len(sock); + + return skb_queue_empty(&sk->sk_receive_queue); +} + static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) { struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX]; @@ -513,7 +527,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) endtime = busy_clock() + vq->busyloop_timeout; while (vhost_can_busy_poll(&net->dev, endtime) && - skb_queue_empty(&sk->sk_receive_queue) && + !sk_has_rx_data(sk) && vhost_vq_avail_empty(&net->dev, vq)) cpu_relax_lowlatency(); diff --git a/include/linux/net.h b/include/linux/net.h index 25aa03b51c4e..b9f0ff4d489c 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -185,6 +185,7 @@ struct proto_ops { ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); int (*set_peek_off)(struct sock *sk, int val); + int (*peek_len)(struct socket *sock); }; #define DECLARE_SOCKADDR(type, dst, src) \ -- cgit v1.2.3 From 4ae89ad92477219b504a49966ee010fe8dcb85af Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 24 Jun 2016 11:32:26 -0700 Subject: etherdevice.h & bridge: netfilter: Add and use ether_addr_equal_masked There are code duplications of a masked ethernet address comparison here so make it a separate function instead. Miscellanea: o Neaten alignment of FWINV macro uses to make it clearer for the reader Signed-off-by: Joe Perches Acked-by: David S. Miller Signed-off-by: Pablo Neira Ayuso --- include/linux/etherdevice.h | 23 +++++++++++++++++++ net/bridge/netfilter/ebt_arp.c | 17 +++++--------- net/bridge/netfilter/ebt_stp.c | 49 ++++++++++++++++++----------------------- net/bridge/netfilter/ebtables.c | 17 +++++--------- 4 files changed, 57 insertions(+), 49 deletions(-) (limited to 'include/linux') diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 37ff4a6faa9a..6fec9e81bd70 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -373,6 +373,29 @@ static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2) #endif } +/** + * ether_addr_equal_masked - Compare two Ethernet addresses with a mask + * @addr1: Pointer to a six-byte array containing the 1st Ethernet address + * @addr2: Pointer to a six-byte array containing the 2nd Ethernet address + * @mask: Pointer to a six-byte array containing the Ethernet address bitmask + * + * Compare two Ethernet addresses with a mask, returns true if for every bit + * set in the bitmask the equivalent bits in the ethernet addresses are equal. + * Using a mask with all bits set is a slower ether_addr_equal. + */ +static inline bool ether_addr_equal_masked(const u8 *addr1, const u8 *addr2, + const u8 *mask) +{ + int i; + + for (i = 0; i < ETH_ALEN; i++) { + if ((addr1[i] ^ addr2[i]) & mask[i]) + return false; + } + + return true; +} + /** * is_etherdev_addr - Tell if given Ethernet address belongs to the device. * @dev: Pointer to a device structure diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c index cd457b891b27..cca0a899ee15 100644 --- a/net/bridge/netfilter/ebt_arp.c +++ b/net/bridge/netfilter/ebt_arp.c @@ -65,7 +65,6 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { const unsigned char *mp; unsigned char _mac[ETH_ALEN]; - uint8_t verdict, i; if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER)) return false; @@ -74,11 +73,9 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) sizeof(_mac), &_mac); if (mp == NULL) return false; - verdict = 0; - for (i = 0; i < 6; i++) - verdict |= (mp[i] ^ info->smaddr[i]) & - info->smmsk[i]; - if (FWINV(verdict != 0, EBT_ARP_SRC_MAC)) + if (FWINV(!ether_addr_equal_masked(mp, info->smaddr, + info->smmsk), + EBT_ARP_SRC_MAC)) return false; } @@ -88,11 +85,9 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) sizeof(_mac), &_mac); if (mp == NULL) return false; - verdict = 0; - for (i = 0; i < 6; i++) - verdict |= (mp[i] ^ info->dmaddr[i]) & - info->dmmsk[i]; - if (FWINV(verdict != 0, EBT_ARP_DST_MAC)) + if (FWINV(!ether_addr_equal_masked(mp, info->dmaddr, + info->dmmsk), + EBT_ARP_DST_MAC)) return false; } } diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c index e77f90bf8db3..45f73d55422f 100644 --- a/net/bridge/netfilter/ebt_stp.c +++ b/net/bridge/netfilter/ebt_stp.c @@ -46,7 +46,6 @@ static bool ebt_filter_config(const struct ebt_stp_info *info, const struct ebt_stp_config_info *c; u16 v16; u32 v32; - int verdict, i; c = &info->config; if ((info->bitmask & EBT_STP_FLAGS) && @@ -54,66 +53,62 @@ static bool ebt_filter_config(const struct ebt_stp_info *info, return false; if (info->bitmask & EBT_STP_ROOTPRIO) { v16 = NR16(stpc->root); - if (FWINV(v16 < c->root_priol || - v16 > c->root_priou, EBT_STP_ROOTPRIO)) + if (FWINV(v16 < c->root_priol || v16 > c->root_priou, + EBT_STP_ROOTPRIO)) return false; } if (info->bitmask & EBT_STP_ROOTADDR) { - verdict = 0; - for (i = 0; i < 6; i++) - verdict |= (stpc->root[2+i] ^ c->root_addr[i]) & - c->root_addrmsk[i]; - if (FWINV(verdict != 0, EBT_STP_ROOTADDR)) + if (FWINV(!ether_addr_equal_masked(&stpc->root[2], c->root_addr, + c->root_addrmsk), + EBT_STP_ROOTADDR)) return false; } if (info->bitmask & EBT_STP_ROOTCOST) { v32 = NR32(stpc->root_cost); - if (FWINV(v32 < c->root_costl || - v32 > c->root_costu, EBT_STP_ROOTCOST)) + if (FWINV(v32 < c->root_costl || v32 > c->root_costu, + EBT_STP_ROOTCOST)) return false; } if (info->bitmask & EBT_STP_SENDERPRIO) { v16 = NR16(stpc->sender); - if (FWINV(v16 < c->sender_priol || - v16 > c->sender_priou, EBT_STP_SENDERPRIO)) + if (FWINV(v16 < c->sender_priol || v16 > c->sender_priou, + EBT_STP_SENDERPRIO)) return false; } if (info->bitmask & EBT_STP_SENDERADDR) { - verdict = 0; - for (i = 0; i < 6; i++) - verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) & - c->sender_addrmsk[i]; - if (FWINV(verdict != 0, EBT_STP_SENDERADDR)) + if (FWINV(!ether_addr_equal_masked(&stpc->sender[2], + c->sender_addr, + c->sender_addrmsk), + EBT_STP_SENDERADDR)) return false; } if (info->bitmask & EBT_STP_PORT) { v16 = NR16(stpc->port); - if (FWINV(v16 < c->portl || - v16 > c->portu, EBT_STP_PORT)) + if (FWINV(v16 < c->portl || v16 > c->portu, EBT_STP_PORT)) return false; } if (info->bitmask & EBT_STP_MSGAGE) { v16 = NR16(stpc->msg_age); - if (FWINV(v16 < c->msg_agel || - v16 > c->msg_ageu, EBT_STP_MSGAGE)) + if (FWINV(v16 < c->msg_agel || v16 > c->msg_ageu, + EBT_STP_MSGAGE)) return false; } if (info->bitmask & EBT_STP_MAXAGE) { v16 = NR16(stpc->max_age); - if (FWINV(v16 < c->max_agel || - v16 > c->max_ageu, EBT_STP_MAXAGE)) + if (FWINV(v16 < c->max_agel || v16 > c->max_ageu, + EBT_STP_MAXAGE)) return false; } if (info->bitmask & EBT_STP_HELLOTIME) { v16 = NR16(stpc->hello_time); - if (FWINV(v16 < c->hello_timel || - v16 > c->hello_timeu, EBT_STP_HELLOTIME)) + if (FWINV(v16 < c->hello_timel || v16 > c->hello_timeu, + EBT_STP_HELLOTIME)) return false; } if (info->bitmask & EBT_STP_FWDD) { v16 = NR16(stpc->forward_delay); - if (FWINV(v16 < c->forward_delayl || - v16 > c->forward_delayu, EBT_STP_FWDD)) + if (FWINV(v16 < c->forward_delayl || v16 > c->forward_delayu, + EBT_STP_FWDD)) return false; } return true; diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 5a61f35412a0..5721a25be860 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -130,7 +130,6 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, const struct ethhdr *h = eth_hdr(skb); const struct net_bridge_port *p; __be16 ethproto; - int verdict, i; if (skb_vlan_tag_present(skb)) ethproto = htons(ETH_P_8021Q); @@ -157,19 +156,15 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, return 1; if (e->bitmask & EBT_SOURCEMAC) { - verdict = 0; - for (i = 0; i < 6; i++) - verdict |= (h->h_source[i] ^ e->sourcemac[i]) & - e->sourcemsk[i]; - if (FWINV2(verdict != 0, EBT_ISOURCE)) + if (FWINV2(!ether_addr_equal_masked(h->h_source, + e->sourcemac, e->sourcemsk), + EBT_ISOURCE)) return 1; } if (e->bitmask & EBT_DESTMAC) { - verdict = 0; - for (i = 0; i < 6; i++) - verdict |= (h->h_dest[i] ^ e->destmac[i]) & - e->destmsk[i]; - if (FWINV2(verdict != 0, EBT_IDEST)) + if (FWINV2(!ether_addr_equal_masked(h->h_dest, + e->destmac, e->destmsk), + EBT_IDEST)) return 1; } return 0; -- cgit v1.2.3 From 9b45b7bba3d22de52e09df63c50f390a193a3f53 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 29 Jun 2016 19:32:21 +0800 Subject: crypto: rsa - Generate fixed-length output Every implementation of RSA that we have naturally generates output with leading zeroes. The one and only user of RSA, pkcs1pad wants to have those leading zeroes in place, in fact because they are currently absent it has to write those zeroes itself. So we shouldn't be stripping leading zeroes in the first place. In fact this patch makes rsa-generic produce output with fixed length so that pkcs1pad does not need to do any extra work. This patch also changes DH to use the new interface. Signed-off-by: Herbert Xu --- crypto/dh.c | 2 +- crypto/rsa.c | 8 ++++---- include/linux/mpi.h | 2 +- lib/mpi/mpicoder.c | 55 +++++++++++++++++++++++++---------------------------- 4 files changed, 32 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/crypto/dh.c b/crypto/dh.c index 5e960fe28681..9d19360e7189 100644 --- a/crypto/dh.c +++ b/crypto/dh.c @@ -129,7 +129,7 @@ static int dh_compute_value(struct kpp_request *req) if (ret) goto err_free_base; - ret = mpi_write_to_sgl(val, req->dst, &req->dst_len, &sign); + ret = mpi_write_to_sgl(val, req->dst, req->dst_len, &sign); if (ret) goto err_free_base; diff --git a/crypto/rsa.c b/crypto/rsa.c index dc692d43b666..4c280b6a3ea9 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -108,7 +108,7 @@ static int rsa_enc(struct akcipher_request *req) if (ret) goto err_free_m; - ret = mpi_write_to_sgl(c, req->dst, &req->dst_len, &sign); + ret = mpi_write_to_sgl(c, req->dst, req->dst_len, &sign); if (ret) goto err_free_m; @@ -147,7 +147,7 @@ static int rsa_dec(struct akcipher_request *req) if (ret) goto err_free_c; - ret = mpi_write_to_sgl(m, req->dst, &req->dst_len, &sign); + ret = mpi_write_to_sgl(m, req->dst, req->dst_len, &sign); if (ret) goto err_free_c; @@ -185,7 +185,7 @@ static int rsa_sign(struct akcipher_request *req) if (ret) goto err_free_m; - ret = mpi_write_to_sgl(s, req->dst, &req->dst_len, &sign); + ret = mpi_write_to_sgl(s, req->dst, req->dst_len, &sign); if (ret) goto err_free_m; @@ -226,7 +226,7 @@ static int rsa_verify(struct akcipher_request *req) if (ret) goto err_free_s; - ret = mpi_write_to_sgl(m, req->dst, &req->dst_len, &sign); + ret = mpi_write_to_sgl(m, req->dst, req->dst_len, &sign); if (ret) goto err_free_s; diff --git a/include/linux/mpi.h b/include/linux/mpi.h index f219559e5e80..1cc5ffb769af 100644 --- a/include/linux/mpi.h +++ b/include/linux/mpi.h @@ -80,7 +80,7 @@ void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign); int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, int *sign); void *mpi_get_secure_buffer(MPI a, unsigned *nbytes, int *sign); -int mpi_write_to_sgl(MPI a, struct scatterlist *sg, unsigned *nbytes, +int mpi_write_to_sgl(MPI a, struct scatterlist *sg, unsigned nbytes, int *sign); #define log_mpidump g10_log_mpidump diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index 823cf5f5196b..7150e5c23604 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -237,16 +237,13 @@ EXPORT_SYMBOL_GPL(mpi_get_buffer); * @a: a multi precision integer * @sgl: scatterlist to write to. Needs to be at least * mpi_get_size(a) long. - * @nbytes: in/out param - it has the be set to the maximum number of - * bytes that can be written to sgl. This has to be at least - * the size of the integer a. On return it receives the actual - * length of the data written on success or the data that would - * be written if buffer was too small. + * @nbytes: the number of bytes to write. Leading bytes will be + * filled with zero. * @sign: if not NULL, it will be set to the sign of a. * * Return: 0 on success or error code in case of error */ -int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, +int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned nbytes, int *sign) { u8 *p, *p2; @@ -258,43 +255,44 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, #error please implement for this limb size. #endif unsigned int n = mpi_get_size(a); - int i, x, y = 0, lzeros, buf_len; - - if (!nbytes) - return -EINVAL; + int i, x, buf_len; if (sign) *sign = a->sign; - lzeros = count_lzeros(a); - - if (*nbytes < n - lzeros) { - *nbytes = n - lzeros; + if (nbytes < n) return -EOVERFLOW; - } - *nbytes = n - lzeros; buf_len = sgl->length; p2 = sg_virt(sgl); - for (i = a->nlimbs - 1 - lzeros / BYTES_PER_MPI_LIMB, - lzeros %= BYTES_PER_MPI_LIMB; - i >= 0; i--) { + while (nbytes > n) { + if (!buf_len) { + sgl = sg_next(sgl); + if (!sgl) + return -EINVAL; + buf_len = sgl->length; + p2 = sg_virt(sgl); + } + + i = min_t(unsigned, nbytes - n, buf_len); + memset(p2, 0, i); + p2 += i; + buf_len -= i; + nbytes -= i; + } + + for (i = a->nlimbs - 1; i >= 0; i--) { #if BYTES_PER_MPI_LIMB == 4 - alimb = cpu_to_be32(a->d[i]); + alimb = a->d[i] ? cpu_to_be32(a->d[i]) : 0; #elif BYTES_PER_MPI_LIMB == 8 - alimb = cpu_to_be64(a->d[i]); + alimb = a->d[i] ? cpu_to_be64(a->d[i]) : 0; #else #error please implement for this limb size. #endif - if (lzeros) { - y = lzeros; - lzeros = 0; - } - - p = (u8 *)&alimb + y; + p = (u8 *)&alimb; - for (x = 0; x < sizeof(alimb) - y; x++) { + for (x = 0; x < sizeof(alimb); x++) { if (!buf_len) { sgl = sg_next(sgl); if (!sgl) @@ -305,7 +303,6 @@ int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes, *p2++ = *p++; buf_len--; } - y = 0; } return 0; } -- cgit v1.2.3 From 1aacde3d22c42281236155c1ef6d7a5aa32a826b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 30 Jun 2016 17:24:43 +0200 Subject: bpf: generally move prog destruction to RCU deferral Jann Horn reported following analysis that could potentially result in a very hard to trigger (if not impossible) UAF race, to quote his event timeline: - Set up a process with threads T1, T2 and T3 - Let T1 set up a socket filter F1 that invokes another filter F2 through a BPF map [tail call] - Let T1 trigger the socket filter via a unix domain socket write, don't wait for completion - Let T2 call PERF_EVENT_IOC_SET_BPF with F2, don't wait for completion - Now T2 should be behind bpf_prog_get(), but before bpf_prog_put() - Let T3 close the file descriptor for F2, dropping the reference count of F2 to 2 - At this point, T1 should have looked up F2 from the map, but not finished executing it - Let T3 remove F2 from the BPF map, dropping the reference count of F2 to 1 - Now T2 should call bpf_prog_put() (wrong BPF program type), dropping the reference count of F2 to 0 and scheduling bpf_prog_free_deferred() via schedule_work() - At this point, the BPF program could be freed - BPF execution is still running in a freed BPF program While at PERF_EVENT_IOC_SET_BPF time it's only guaranteed that the perf event fd we're doing the syscall on doesn't disappear from underneath us for whole syscall time, it may not be the case for the bpf fd used as an argument only after we did the put. It needs to be a valid fd pointing to a BPF program at the time of the call to make the bpf_prog_get() and while T2 gets preempted, F2 must have dropped reference to 1 on the other CPU. The fput() from the close() in T3 should also add additionally delay to the reference drop via exit_task_work() when bpf_prog_release() gets called as well as scheduling bpf_prog_free_deferred(). That said, it makes nevertheless sense to move the BPF prog destruction generally after RCU grace period to guarantee that such scenario above, but also others as recently fixed in ceb56070359b ("bpf, perf: delay release of BPF prog after grace period") with regards to tail calls won't happen. Integrating bpf_prog_free_deferred() directly into the RCU callback is not allowed since the invocation might happen from either softirq or process context, so we're not permitted to block. Reviewing all bpf_prog_put() invocations from eBPF side (note, cBPF -> eBPF progs don't use this for their destruction) with call_rcu() look good to me. Since we don't know whether at the time of attaching the program, we're already part of a tail call map, we need to use RCU variant. However, due to this, there won't be severely more stress on the RCU callback queue: situations with above bpf_prog_get() and bpf_prog_put() combo in practice normally won't lead to releases, but even if they would, enough effort/ cycles have to be put into loading a BPF program into the kernel already. Reported-by: Jann Horn Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/bpf.h | 5 ----- kernel/bpf/arraymap.c | 4 +--- kernel/bpf/syscall.c | 13 +++---------- kernel/events/core.c | 2 +- 4 files changed, 5 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8411032ac90d..749549888b86 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -220,7 +220,6 @@ void bpf_register_map_type(struct bpf_map_type_list *tl); struct bpf_prog *bpf_prog_get(u32 ufd); struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog); void bpf_prog_put(struct bpf_prog *prog); -void bpf_prog_put_rcu(struct bpf_prog *prog); struct bpf_map *bpf_map_get_with_uref(u32 ufd); struct bpf_map *__bpf_map_get(struct fd f); @@ -281,10 +280,6 @@ static inline struct bpf_prog *bpf_prog_get(u32 ufd) static inline void bpf_prog_put(struct bpf_prog *prog) { } - -static inline void bpf_prog_put_rcu(struct bpf_prog *prog) -{ -} #endif /* CONFIG_BPF_SYSCALL */ /* verifier prototypes for helper functions called from eBPF programs */ diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 5af30732697b..4ec57a649b1f 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -390,9 +390,7 @@ static void *prog_fd_array_get_ptr(struct bpf_map *map, static void prog_fd_array_put_ptr(void *ptr) { - struct bpf_prog *prog = ptr; - - bpf_prog_put_rcu(prog); + bpf_prog_put(ptr); } /* decrement refcnt of all bpf_progs that are stored in this map */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index c23a4e9311b3..f6806a1d7ed9 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -623,7 +623,7 @@ static void bpf_prog_uncharge_memlock(struct bpf_prog *prog) free_uid(user); } -static void __prog_put_common(struct rcu_head *rcu) +static void __bpf_prog_put_rcu(struct rcu_head *rcu) { struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu); @@ -632,17 +632,10 @@ static void __prog_put_common(struct rcu_head *rcu) bpf_prog_free(aux->prog); } -/* version of bpf_prog_put() that is called after a grace period */ -void bpf_prog_put_rcu(struct bpf_prog *prog) -{ - if (atomic_dec_and_test(&prog->aux->refcnt)) - call_rcu(&prog->aux->rcu, __prog_put_common); -} - void bpf_prog_put(struct bpf_prog *prog) { if (atomic_dec_and_test(&prog->aux->refcnt)) - __prog_put_common(&prog->aux->rcu); + call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); } EXPORT_SYMBOL_GPL(bpf_prog_put); @@ -650,7 +643,7 @@ static int bpf_prog_release(struct inode *inode, struct file *filp) { struct bpf_prog *prog = filp->private_data; - bpf_prog_put_rcu(prog); + bpf_prog_put(prog); return 0; } diff --git a/kernel/events/core.c b/kernel/events/core.c index 85cd41878a74..9c51ec3f0f44 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7529,7 +7529,7 @@ static void perf_event_free_bpf_prog(struct perf_event *event) prog = event->tp_event->prog; if (prog) { event->tp_event->prog = NULL; - bpf_prog_put_rcu(prog); + bpf_prog_put(prog); } } -- cgit v1.2.3 From 113214be7f6c98dd6d0435e4765aea8dea91662c Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 30 Jun 2016 17:24:44 +0200 Subject: bpf: refactor bpf_prog_get and type check into helper Since bpf_prog_get() and program type check is used in a couple of places, refactor this into a small helper function that we can make use of. Since the non RO prog->aux part is not used in performance critical paths and a program destruction via RCU is rather very unlikley when doing the put, we shouldn't have an issue just doing the bpf_prog_get() + prog->type != type check, but actually not taking the ref at all (due to being in fdget() / fdput() section of the bpf fd) is even cleaner and makes the diff smaller as well, so just go for that. Callsites are changed to make use of the new helper where possible. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/bpf.h | 7 +++++++ kernel/bpf/syscall.c | 27 +++++++++++++++++++-------- net/core/filter.c | 13 +------------ net/kcm/kcmsock.c | 8 +------- net/packet/af_packet.c | 6 +----- net/sched/act_bpf.c | 7 +------ net/sched/cls_bpf.c | 7 +------ 7 files changed, 31 insertions(+), 44 deletions(-) (limited to 'include/linux') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 749549888b86..b3336b4f5d04 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -218,6 +218,7 @@ void bpf_register_prog_type(struct bpf_prog_type_list *tl); void bpf_register_map_type(struct bpf_map_type_list *tl); struct bpf_prog *bpf_prog_get(u32 ufd); +struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type); struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog); void bpf_prog_put(struct bpf_prog *prog); @@ -277,6 +278,12 @@ static inline struct bpf_prog *bpf_prog_get(u32 ufd) return ERR_PTR(-EOPNOTSUPP); } +static inline struct bpf_prog *bpf_prog_get_type(u32 ufd, + enum bpf_prog_type type) +{ + return ERR_PTR(-EOPNOTSUPP); +} + static inline void bpf_prog_put(struct bpf_prog *prog) { } diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f6806a1d7ed9..22863d9872b1 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -657,7 +657,7 @@ int bpf_prog_new_fd(struct bpf_prog *prog) O_RDWR | O_CLOEXEC); } -static struct bpf_prog *__bpf_prog_get(struct fd f) +static struct bpf_prog *____bpf_prog_get(struct fd f) { if (!f.file) return ERR_PTR(-EBADF); @@ -678,24 +678,35 @@ struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) return prog; } -/* called by sockets/tracing/seccomp before attaching program to an event - * pairs with bpf_prog_put() - */ -struct bpf_prog *bpf_prog_get(u32 ufd) +static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type) { struct fd f = fdget(ufd); struct bpf_prog *prog; - prog = __bpf_prog_get(f); + prog = ____bpf_prog_get(f); if (IS_ERR(prog)) return prog; + if (type && prog->type != *type) { + prog = ERR_PTR(-EINVAL); + goto out; + } prog = bpf_prog_inc(prog); +out: fdput(f); - return prog; } -EXPORT_SYMBOL_GPL(bpf_prog_get); + +struct bpf_prog *bpf_prog_get(u32 ufd) +{ + return __bpf_prog_get(ufd, NULL); +} + +struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type) +{ + return __bpf_prog_get(ufd, &type); +} +EXPORT_SYMBOL_GPL(bpf_prog_get_type); /* last field in 'union bpf_attr' used by this command */ #define BPF_PROG_LOAD_LAST_FIELD kern_version diff --git a/net/core/filter.c b/net/core/filter.c index 76f9a4938be4..76fee35da244 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1301,21 +1301,10 @@ int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk) static struct bpf_prog *__get_bpf(u32 ufd, struct sock *sk) { - struct bpf_prog *prog; - if (sock_flag(sk, SOCK_FILTER_LOCKED)) return ERR_PTR(-EPERM); - prog = bpf_prog_get(ufd); - if (IS_ERR(prog)) - return prog; - - if (prog->type != BPF_PROG_TYPE_SOCKET_FILTER) { - bpf_prog_put(prog); - return ERR_PTR(-EINVAL); - } - - return prog; + return bpf_prog_get_type(ufd, BPF_PROG_TYPE_SOCKET_FILTER); } int sk_attach_bpf(u32 ufd, struct sock *sk) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 0b68ba730a06..cb39e05b166c 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1765,18 +1765,12 @@ static int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info) if (!csock) return -ENOENT; - prog = bpf_prog_get(info->bpf_fd); + prog = bpf_prog_get_type(info->bpf_fd, BPF_PROG_TYPE_SOCKET_FILTER); if (IS_ERR(prog)) { err = PTR_ERR(prog); goto out; } - if (prog->type != BPF_PROG_TYPE_SOCKET_FILTER) { - bpf_prog_put(prog); - err = -EINVAL; - goto out; - } - err = kcm_attach(sock, csock, prog); if (err) { bpf_prog_put(prog); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d1f3b9e977e5..48b58957adf4 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1588,13 +1588,9 @@ static int fanout_set_data_ebpf(struct packet_sock *po, char __user *data, if (copy_from_user(&fd, data, len)) return -EFAULT; - new = bpf_prog_get(fd); + new = bpf_prog_get_type(fd, BPF_PROG_TYPE_SOCKET_FILTER); if (IS_ERR(new)) return PTR_ERR(new); - if (new->type != BPF_PROG_TYPE_SOCKET_FILTER) { - bpf_prog_put(new); - return -EINVAL; - } __fanout_set_data_bpf(po->fanout, new); return 0; diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index f7b6cf49ea6f..ef74bffa6101 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -223,15 +223,10 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg) bpf_fd = nla_get_u32(tb[TCA_ACT_BPF_FD]); - fp = bpf_prog_get(bpf_fd); + fp = bpf_prog_get_type(bpf_fd, BPF_PROG_TYPE_SCHED_ACT); if (IS_ERR(fp)) return PTR_ERR(fp); - if (fp->type != BPF_PROG_TYPE_SCHED_ACT) { - bpf_prog_put(fp); - return -EINVAL; - } - if (tb[TCA_ACT_BPF_NAME]) { name = kmemdup(nla_data(tb[TCA_ACT_BPF_NAME]), nla_len(tb[TCA_ACT_BPF_NAME]), diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 7b342c779da7..c3002c2c68bb 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c @@ -272,15 +272,10 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog, bpf_fd = nla_get_u32(tb[TCA_BPF_FD]); - fp = bpf_prog_get(bpf_fd); + fp = bpf_prog_get_type(bpf_fd, BPF_PROG_TYPE_SCHED_CLS); if (IS_ERR(fp)) return PTR_ERR(fp); - if (fp->type != BPF_PROG_TYPE_SCHED_CLS) { - bpf_prog_put(fp); - return -EINVAL; - } - if (tb[TCA_BPF_NAME]) { name = kmemdup(nla_data(tb[TCA_BPF_NAME]), nla_len(tb[TCA_BPF_NAME]), -- cgit v1.2.3 From 1f3fe7ebf6136c341012db9f554d4caa566fcbaa Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 30 Jun 2016 10:28:42 -0700 Subject: cgroup: Add cgroup_get_from_fd Add a helper function to get a cgroup2 from a fd. It will be stored in a bpf array (BPF_MAP_TYPE_CGROUP_ARRAY) which will be introduced in the later patch. Signed-off-by: Martin KaFai Lau Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Tejun Heo Acked-by: Tejun Heo Signed-off-by: David S. Miller --- include/linux/cgroup.h | 1 + kernel/cgroup.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index a20320c666fd..984f73b719a9 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -87,6 +87,7 @@ struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry, struct cgroup_subsys *ss); struct cgroup *cgroup_get_from_path(const char *path); +struct cgroup *cgroup_get_from_fd(int fd); int cgroup_attach_task_all(struct task_struct *from, struct task_struct *); int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from); diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 75c0ff00aca6..50787cd61da2 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -62,6 +62,7 @@ #include #include #include +#include #include /* @@ -6209,6 +6210,40 @@ struct cgroup *cgroup_get_from_path(const char *path) } EXPORT_SYMBOL_GPL(cgroup_get_from_path); +/** + * cgroup_get_from_fd - get a cgroup pointer from a fd + * @fd: fd obtained by open(cgroup2_dir) + * + * Find the cgroup from a fd which should be obtained + * by opening a cgroup directory. Returns a pointer to the + * cgroup on success. ERR_PTR is returned if the cgroup + * cannot be found. + */ +struct cgroup *cgroup_get_from_fd(int fd) +{ + struct cgroup_subsys_state *css; + struct cgroup *cgrp; + struct file *f; + + f = fget_raw(fd); + if (!f) + return ERR_PTR(-EBADF); + + css = css_tryget_online_from_dir(f->f_path.dentry, NULL); + fput(f); + if (IS_ERR(css)) + return ERR_CAST(css); + + cgrp = css->cgroup; + if (!cgroup_on_dfl(cgrp)) { + cgroup_put(cgrp); + return ERR_PTR(-EBADF); + } + + return cgrp; +} +EXPORT_SYMBOL_GPL(cgroup_get_from_fd); + /* * sock->sk_cgrp_data handling. For more info, see sock_cgroup_data * definition in cgroup-defs.h. -- cgit v1.2.3 From e380538529e83c5d3fd27e8cbfcc1f9799cb6bbb Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Wed, 22 Jun 2016 11:45:52 -0400 Subject: power_supply: fix return value of get_property power_supply_get_property() should ideally return -EAGAIN if it is called while the power_supply is being registered. There was no way previously to determine if use_cnt == 0 meant that the power_supply wasn't fully registered yet, or if it had already been unregistered. Add a new boolean to the power_supply struct to simply show if registration is completed. Lastly, modify the check in power_supply_show_property() to also ignore -EAGAIN when so it doesn't complain about not returning the property. Signed-off-by: Rhyland Klein Signed-off-by: Sebastian Reichel --- drivers/power/power_supply_core.c | 6 +++++- drivers/power/power_supply_sysfs.c | 2 +- include/linux/power_supply.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 456987c88baa..c2ef0c0dfa9d 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -491,8 +491,11 @@ int power_supply_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - if (atomic_read(&psy->use_cnt) <= 0) + if (atomic_read(&psy->use_cnt) <= 0) { + if (!psy->initialized) + return -EAGAIN; return -ENODEV; + } return psy->desc->get_property(psy, psp, val); } @@ -780,6 +783,7 @@ __power_supply_register(struct device *parent, * after calling power_supply_register()). */ atomic_inc(&psy->use_cnt); + psy->initialized = true; queue_delayed_work(system_power_efficient_wq, &psy->deferred_register_work, diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 80fed98832f9..bcde8d13476a 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -83,7 +83,7 @@ static ssize_t power_supply_show_property(struct device *dev, if (ret == -ENODATA) dev_dbg(dev, "driver has no data for `%s' property\n", attr->attr.name); - else if (ret != -ENODEV) + else if (ret != -ENODEV && ret != -EAGAIN) dev_err(dev, "driver failed to report `%s' property: %zd\n", attr->attr.name, ret); return ret; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 751061790626..3965503315ef 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -248,6 +248,7 @@ struct power_supply { struct delayed_work deferred_register_work; spinlock_t changed_lock; bool changed; + bool initialized; atomic_t use_cnt; #ifdef CONFIG_THERMAL struct thermal_zone_device *tzd; -- cgit v1.2.3 From a4b3518d146f150d633f7dc815bb8ee2fbc162e9 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 30 Jun 2016 17:31:13 +0800 Subject: clk: core: support clocks which requires parents enable (part 1) On Freescale i.MX7D platform, all clocks operations, including enable/disable, rate change and re-parent, requires its parent clock enable. Current clock core can not support it well. This patch introduce a new flag CLK_OPS_PARENT_ENABLE to handle this special case in clock core that enable its parent clock firstly for each operation and disable it later after operation complete. The patch part 1 fixes the possible disabling clocks while its parent is off during kernel booting phase in clk_disable_unused_subtree(). Before the completion of kernel booting, clock tree is still not built completely, there may be a case that the child clock is on but its parent is off which could be caused by either HW initial reset state or bootloader initialization. Taking bootloader as an example, we may enable all clocks in HW by default. And during kernel booting time, the parent clock could be disabled in its driver probe due to calling clk_prepare_enable and clk_disable_unprepare. Because it's child clock is only enabled in HW while its SW usecount in clock tree is still 0, so clk_disable of parent clock will gate the parent clock in both HW and SW usecount ultimately. Then there will be a child clock is still on in HW but its parent is already off. Later in clk_disable_unused(), this clock disable accessing while its parent off will cause system hang due to the limitation of HW which must require its parent on. This patch simply enables the parent clock first before disabling if flag CLK_OPS_PARENT_ENABLE is set in clk_disable_unused_subtree(). This is a simple solution and only affects booting time. After kernel booting up the clock tree is already created, there will be no case that child is off but its parent is off. So no need do this checking for normal clk_disable() later. Cc: Michael Turquette Cc: Stephen Boyd Cc: Shawn Guo Signed-off-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 5 +++++ include/linux/clk-provider.h | 2 ++ 2 files changed, 7 insertions(+) (limited to 'include/linux') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index e2e8f0c9f20a..e3bd28c9ef28 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -765,6 +765,9 @@ static void clk_disable_unused_subtree(struct clk_core *core) hlist_for_each_entry(child, &core->children, child_node) clk_disable_unused_subtree(child); + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_prepare_enable(core->parent); + flags = clk_enable_lock(); if (core->enable_count) @@ -789,6 +792,8 @@ static void clk_disable_unused_subtree(struct clk_core *core) unlock_out: clk_enable_unlock(flags); + if (core->flags & CLK_OPS_PARENT_ENABLE) + clk_core_disable_unprepare(core->parent); } static bool clk_ignore_unused; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index eeb2e69ee727..a39c0c530778 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -33,6 +33,8 @@ #define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */ #define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */ #define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ +/* parents need enable during gate/ungate, set rate and re-parent */ +#define CLK_OPS_PARENT_ENABLE BIT(12) struct clk; struct clk_hw; -- cgit v1.2.3 From 1b6cf310103799f371066453f55755088b008be0 Mon Sep 17 00:00:00 2001 From: Venkat Reddy Talla Date: Thu, 30 Jun 2016 17:54:00 +0900 Subject: extcon: adc-jack: add suspend/resume support adding suspend and resume funtionality for extcon-adc-jack driver to configure system wake up for extcon events, also adding support to enable/disable system wakeup through flag wakeup_source based on platform requirement. Signed-off-by: Venkat Reddy Talla Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 34 ++++++++++++++++++++++++++++++++++ include/linux/extcon/extcon-adc-jack.h | 2 ++ 2 files changed, 36 insertions(+) (limited to 'include/linux') diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 7fc0ae1912f8..44e48aa78a84 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -38,6 +38,7 @@ * @chan: iio channel being queried. */ struct adc_jack_data { + struct device *dev; struct extcon_dev *edev; const unsigned int **cable_names; @@ -49,6 +50,7 @@ struct adc_jack_data { struct delayed_work handler; struct iio_channel *chan; + bool wakeup_source; }; static void adc_jack_handler(struct work_struct *work) @@ -105,6 +107,7 @@ static int adc_jack_probe(struct platform_device *pdev) return -EINVAL; } + data->dev = &pdev->dev; data->edev = devm_extcon_dev_allocate(&pdev->dev, pdata->cable_names); if (IS_ERR(data->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); @@ -128,6 +131,7 @@ static int adc_jack_probe(struct platform_device *pdev) return PTR_ERR(data->chan); data->handling_delay = msecs_to_jiffies(pdata->handling_delay_ms); + data->wakeup_source = pdata->wakeup_source; INIT_DEFERRABLE_WORK(&data->handler, adc_jack_handler); @@ -151,6 +155,9 @@ static int adc_jack_probe(struct platform_device *pdev) return err; } + if (data->wakeup_source) + device_init_wakeup(&pdev->dev, 1); + return 0; } @@ -165,11 +172,38 @@ static int adc_jack_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int adc_jack_suspend(struct device *dev) +{ + struct adc_jack_data *data = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&data->handler); + if (device_may_wakeup(data->dev)) + enable_irq_wake(data->irq); + + return 0; +} + +static int adc_jack_resume(struct device *dev) +{ + struct adc_jack_data *data = dev_get_drvdata(dev); + + if (device_may_wakeup(data->dev)) + disable_irq_wake(data->irq); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(adc_jack_pm_ops, + adc_jack_suspend, adc_jack_resume); + static struct platform_driver adc_jack_driver = { .probe = adc_jack_probe, .remove = adc_jack_remove, .driver = { .name = "adc-jack", + .pm = &adc_jack_pm_ops, }, }; diff --git a/include/linux/extcon/extcon-adc-jack.h b/include/linux/extcon/extcon-adc-jack.h index 53c60806bcfb..ac85f2061351 100644 --- a/include/linux/extcon/extcon-adc-jack.h +++ b/include/linux/extcon/extcon-adc-jack.h @@ -53,6 +53,7 @@ struct adc_jack_cond { * milli-seconds after the interrupt occurs. You may * describe such delays with @handling_delay_ms, which * is rounded-off by jiffies. + * @wakeup_source: flag to wake up the system for extcon events. */ struct adc_jack_pdata { const char *name; @@ -65,6 +66,7 @@ struct adc_jack_pdata { unsigned long irq_flags; unsigned long handling_delay_ms; /* in ms */ + bool wakeup_source; }; #endif /* _EXTCON_ADC_JACK_H */ -- cgit v1.2.3 From acbc2004d7129a1ecf02414c1da8808bdc06d5a2 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Fri, 1 Jul 2016 14:50:58 +0300 Subject: net/mlx5: Introduce offloads steering namespace Add a new namespace (MLX5_FLOW_NAMESPACE_OFFLOADS) to be populated with flow steering rules that deal with rules that have have to be executed before the EN NIC steering rules are matched. The namespace is located after the bypass name-space and before the kernel name-space. Therefore, it precedes the HW processing done for rules set for the kernel NIC name-space. Under SRIOV, it would allow us to match on e-switch missed packet and forward them to the relevant VF representor TIR. Signed-off-by: Or Gerlitz Signed-off-by: Amir Vadai Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 11 ++++++++++- include/linux/mlx5/fs.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index e912a3d2505e..b0401104afb9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -83,6 +83,11 @@ #define ANCHOR_NUM_LEVELS 1 #define ANCHOR_NUM_PRIOS 1 #define ANCHOR_MIN_LEVEL (BY_PASS_MIN_LEVEL + 1) + +#define OFFLOADS_MAX_FT 1 +#define OFFLOADS_NUM_PRIOS 1 +#define OFFLOADS_MIN_LEVEL (ANCHOR_MIN_LEVEL + 1) + struct node_caps { size_t arr_sz; long *caps; @@ -98,7 +103,7 @@ static struct init_tree_node { int num_levels; } root_fs = { .type = FS_TYPE_NAMESPACE, - .ar_size = 4, + .ar_size = 5, .children = (struct init_tree_node[]) { ADD_PRIO(0, BY_PASS_MIN_LEVEL, 0, FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en), @@ -107,6 +112,9 @@ static struct init_tree_node { FS_CAP(flow_table_properties_nic_receive.flow_table_modify)), ADD_NS(ADD_MULTIPLE_PRIO(MLX5_BY_PASS_NUM_PRIOS, BY_PASS_PRIO_NUM_LEVELS))), + ADD_PRIO(0, OFFLOADS_MIN_LEVEL, 0, {}, + ADD_NS(ADD_MULTIPLE_PRIO(OFFLOADS_NUM_PRIOS, OFFLOADS_MAX_FT))), + ADD_PRIO(0, KERNEL_MIN_LEVEL, 0, {}, ADD_NS(ADD_MULTIPLE_PRIO(1, 1), ADD_MULTIPLE_PRIO(KERNEL_NIC_NUM_PRIOS, @@ -1369,6 +1377,7 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, switch (type) { case MLX5_FLOW_NAMESPACE_BYPASS: + case MLX5_FLOW_NAMESPACE_OFFLOADS: case MLX5_FLOW_NAMESPACE_KERNEL: case MLX5_FLOW_NAMESPACE_LEFTOVERS: case MLX5_FLOW_NAMESPACE_ANCHOR: diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 4b7a107d9c19..6ad111938709 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -54,6 +54,7 @@ static inline void build_leftovers_ft_param(int *priority, enum mlx5_flow_namespace_type { MLX5_FLOW_NAMESPACE_BYPASS, + MLX5_FLOW_NAMESPACE_OFFLOADS, MLX5_FLOW_NAMESPACE_KERNEL, MLX5_FLOW_NAMESPACE_LEFTOVERS, MLX5_FLOW_NAMESPACE_ANCHOR, -- cgit v1.2.3 From b50d292b4399f4eb11e82d0430aacf62dd5d5365 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Fri, 1 Jul 2016 14:51:04 +0300 Subject: net/mlx5e: Create NIC global resources only once To allow creating more than one netdev over the same PCI function, we change the driver such that global NIC resources are created once and later be shared amongst all the mlx5e netdevs running over that port. Move the CQ UAR, PD (pdn), Transport Domain (tdn), MKey resources from being kept in the mlx5e priv part to a new resources structure (mlx5e_resources) placed under the mlx5_core device. This patch doesn't add any new functionality. Signed-off-by: Hadar Hen Zion Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 6 +- drivers/net/ethernet/mellanox/mlx5/core/en.h | 6 +- .../net/ethernet/mellanox/mlx5/core/en_common.c | 112 +++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 124 +++++++-------------- include/linux/mlx5/driver.h | 13 +++ 5 files changed, 171 insertions(+), 90 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_common.c (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 96f18264a0ef..9b14dadd9309 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -6,8 +6,8 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ fs_counters.o rl.o mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ - en_main.o en_fs.o en_ethtool.o en_tx.o en_rx.o \ - en_rx_am.o en_txrx.o en_clock.o vxlan.o en_tc.o \ - en_arfs.o + en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \ + en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \ + en_tc.o en_arfs.o mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b97511bf4c7b..3226b92a344d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -570,10 +570,6 @@ struct mlx5e_priv { unsigned long state; struct mutex state_lock; /* Protects Interface state */ - struct mlx5_uar cq_uar; - u32 pdn; - u32 tdn; - struct mlx5_core_mkey mkey; struct mlx5_core_mkey umr_mkey; struct mlx5e_rq drop_rq; @@ -788,5 +784,7 @@ int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, #endif u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev); +int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev); +void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev); #endif /* __MLX5_EN_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c new file mode 100644 index 000000000000..33b373216594 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "en.h" + +/* mlx5e global resources should be placed in this file. + * Global resources are common to all the netdevices crated on the same nic. + */ + +static int mlx5e_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, + struct mlx5_core_mkey *mkey) +{ + struct mlx5_create_mkey_mbox_in *in; + int err; + + in = mlx5_vzalloc(sizeof(*in)); + if (!in) + return -ENOMEM; + + in->seg.flags = MLX5_PERM_LOCAL_WRITE | + MLX5_PERM_LOCAL_READ | + MLX5_ACCESS_MODE_PA; + in->seg.flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64); + in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); + + err = mlx5_core_create_mkey(mdev, mkey, in, sizeof(*in), NULL, NULL, + NULL); + + kvfree(in); + + return err; +} + +int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev) +{ + struct mlx5e_resources *res = &mdev->mlx5e_res; + int err; + + err = mlx5_alloc_map_uar(mdev, &res->cq_uar, false); + if (err) { + mlx5_core_err(mdev, "alloc_map uar failed, %d\n", err); + return err; + } + + err = mlx5_core_alloc_pd(mdev, &res->pdn); + if (err) { + mlx5_core_err(mdev, "alloc pd failed, %d\n", err); + goto err_unmap_free_uar; + } + + err = mlx5_core_alloc_transport_domain(mdev, &res->td.tdn); + if (err) { + mlx5_core_err(mdev, "alloc td failed, %d\n", err); + goto err_dealloc_pd; + } + + err = mlx5e_create_mkey(mdev, res->pdn, &res->mkey); + if (err) { + mlx5_core_err(mdev, "create mkey failed, %d\n", err); + goto err_dealloc_transport_domain; + } + + return 0; + +err_dealloc_transport_domain: + mlx5_core_dealloc_transport_domain(mdev, res->td.tdn); +err_dealloc_pd: + mlx5_core_dealloc_pd(mdev, res->pdn); +err_unmap_free_uar: + mlx5_unmap_free_uar(mdev, &res->cq_uar); + + return err; +} + +void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev) +{ + struct mlx5e_resources *res = &mdev->mlx5e_res; + + mlx5_core_destroy_mkey(mdev, &res->mkey); + mlx5_core_dealloc_transport_domain(mdev, res->td.tdn); + mlx5_core_dealloc_pd(mdev, res->pdn); + mlx5_unmap_free_uar(mdev, &res->cq_uar); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index a64ce5df5810..9b2e2b211cee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -858,7 +858,7 @@ static int mlx5e_create_cq(struct mlx5e_channel *c, mcq->comp = mlx5e_completion_event; mcq->event = mlx5e_cq_error_event; mcq->irqn = irqn; - mcq->uar = &priv->cq_uar; + mcq->uar = &mdev->mlx5e_res.cq_uar; for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) { struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(&cq->wq, i); @@ -1136,7 +1136,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, c->cpu = cpu; c->pdev = &priv->mdev->pdev->dev; c->netdev = priv->netdev; - c->mkey_be = cpu_to_be32(priv->mkey.key); + c->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.mkey.key); c->num_tc = priv->params.num_tc; if (priv->params.rx_am_enabled) @@ -1252,7 +1252,7 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv, MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN); MLX5_SET(wq, wq, log_wq_stride, ilog2(sizeof(struct mlx5e_rx_wqe))); MLX5_SET(wq, wq, log_wq_sz, priv->params.log_rq_size); - MLX5_SET(wq, wq, pd, priv->pdn); + MLX5_SET(wq, wq, pd, priv->mdev->mlx5e_res.pdn); MLX5_SET(rqc, rqc, counter_set_id, priv->q_counter); param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev); @@ -1277,7 +1277,7 @@ static void mlx5e_build_sq_param_common(struct mlx5e_priv *priv, void *wq = MLX5_ADDR_OF(sqc, sqc, wq); MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB)); - MLX5_SET(wq, wq, pd, priv->pdn); + MLX5_SET(wq, wq, pd, priv->mdev->mlx5e_res.pdn); param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev); } @@ -1299,7 +1299,7 @@ static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv, { void *cqc = param->cqc; - MLX5_SET(cqc, cqc, uar_page, priv->cq_uar.index); + MLX5_SET(cqc, cqc, uar_page, priv->mdev->mlx5e_res.cq_uar.index); } static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv, @@ -1920,7 +1920,7 @@ static int mlx5e_create_drop_cq(struct mlx5e_priv *priv, mcq->comp = mlx5e_completion_event; mcq->event = mlx5e_cq_error_event; mcq->irqn = irqn; - mcq->uar = &priv->cq_uar; + mcq->uar = &mdev->mlx5e_res.cq_uar; cq->priv = priv; @@ -1986,7 +1986,7 @@ static int mlx5e_create_tis(struct mlx5e_priv *priv, int tc) memset(in, 0, sizeof(in)); MLX5_SET(tisc, tisc, prio, tc << 1); - MLX5_SET(tisc, tisc, transport_domain, priv->tdn); + MLX5_SET(tisc, tisc, transport_domain, mdev->mlx5e_res.td.tdn); return mlx5_core_create_tis(mdev, in, sizeof(in), &priv->tisn[tc]); } @@ -2029,7 +2029,7 @@ static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, { void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); - MLX5_SET(tirc, tirc, transport_domain, priv->tdn); + MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn); #define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ MLX5_HASH_FIELD_SEL_DST_IP) @@ -2136,7 +2136,7 @@ static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, u32 rqtn) { - MLX5_SET(tirc, tirc, transport_domain, priv->tdn); + MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn); mlx5e_build_tir_ctx_lro(tirc, priv); @@ -3082,31 +3082,6 @@ static void mlx5e_build_netdev(struct net_device *netdev) mlx5e_set_netdev_dev_addr(netdev); } -static int mlx5e_create_mkey(struct mlx5e_priv *priv, u32 pdn, - struct mlx5_core_mkey *mkey) -{ - struct mlx5_core_dev *mdev = priv->mdev; - struct mlx5_create_mkey_mbox_in *in; - int err; - - in = mlx5_vzalloc(sizeof(*in)); - if (!in) - return -ENOMEM; - - in->seg.flags = MLX5_PERM_LOCAL_WRITE | - MLX5_PERM_LOCAL_READ | - MLX5_ACCESS_MODE_PA; - in->seg.flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64); - in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); - - err = mlx5_core_create_mkey(mdev, mkey, in, sizeof(*in), NULL, NULL, - NULL); - - kvfree(in); - - return err; -} - static void mlx5e_create_q_counter(struct mlx5e_priv *priv) { struct mlx5_core_dev *mdev = priv->mdev; @@ -3149,7 +3124,7 @@ static int mlx5e_create_umr_mkey(struct mlx5e_priv *priv) MLX5_ACCESS_MODE_MTT; mkc->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); - mkc->flags_pd = cpu_to_be32(priv->pdn); + mkc->flags_pd = cpu_to_be32(mdev->mlx5e_res.pdn); mkc->len = cpu_to_be64(npages << PAGE_SHIFT); mkc->xlt_oct_size = cpu_to_be32(mlx5e_get_mtt_octw(npages)); mkc->log2_page_size = PAGE_SHIFT; @@ -3169,9 +3144,6 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev) int nch = mlx5e_get_max_num_channels(mdev); int err; - if (mlx5e_check_required_hca_cap(mdev)) - return NULL; - netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv), nch * MLX5E_MAX_NUM_TC, nch); @@ -3191,34 +3163,10 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev) if (!priv->wq) goto err_free_netdev; - err = mlx5_alloc_map_uar(mdev, &priv->cq_uar, false); - if (err) { - mlx5_core_err(mdev, "alloc_map uar failed, %d\n", err); - goto err_destroy_wq; - } - - err = mlx5_core_alloc_pd(mdev, &priv->pdn); - if (err) { - mlx5_core_err(mdev, "alloc pd failed, %d\n", err); - goto err_unmap_free_uar; - } - - err = mlx5_core_alloc_transport_domain(mdev, &priv->tdn); - if (err) { - mlx5_core_err(mdev, "alloc td failed, %d\n", err); - goto err_dealloc_pd; - } - - err = mlx5e_create_mkey(priv, priv->pdn, &priv->mkey); - if (err) { - mlx5_core_err(mdev, "create mkey failed, %d\n", err); - goto err_dealloc_transport_domain; - } - err = mlx5e_create_umr_mkey(priv); if (err) { mlx5_core_err(mdev, "create umr mkey failed, %d\n", err); - goto err_destroy_mkey; + goto err_destroy_wq; } err = mlx5e_create_tises(priv); @@ -3304,18 +3252,6 @@ err_destroy_tises: err_destroy_umr_mkey: mlx5_core_destroy_mkey(mdev, &priv->umr_mkey); -err_destroy_mkey: - mlx5_core_destroy_mkey(mdev, &priv->mkey); - -err_dealloc_transport_domain: - mlx5_core_dealloc_transport_domain(mdev, priv->tdn); - -err_dealloc_pd: - mlx5_core_dealloc_pd(mdev, priv->pdn); - -err_unmap_free_uar: - mlx5_unmap_free_uar(mdev, &priv->cq_uar); - err_destroy_wq: destroy_workqueue(priv->wq); @@ -3325,9 +3261,27 @@ err_free_netdev: return NULL; } -static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) +static void *mlx5e_add(struct mlx5_core_dev *mdev) +{ + void *ret; + + if (mlx5e_check_required_hca_cap(mdev)) + return NULL; + + if (mlx5e_create_mdev_resources(mdev)) + return NULL; + + ret = mlx5e_create_netdev(mdev); + if (!ret) { + mlx5e_destroy_mdev_resources(mdev); + return NULL; + } + return ret; +} + +static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, + struct mlx5e_priv *priv) { - struct mlx5e_priv *priv = vpriv; struct net_device *netdev = priv->netdev; set_bit(MLX5E_STATE_DESTROYING, &priv->state); @@ -3351,10 +3305,6 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) mlx5e_close_drop_rq(priv); mlx5e_destroy_tises(priv); mlx5_core_destroy_mkey(priv->mdev, &priv->umr_mkey); - mlx5_core_destroy_mkey(priv->mdev, &priv->mkey); - mlx5_core_dealloc_transport_domain(priv->mdev, priv->tdn); - mlx5_core_dealloc_pd(priv->mdev, priv->pdn); - mlx5_unmap_free_uar(priv->mdev, &priv->cq_uar); cancel_delayed_work_sync(&priv->update_stats_work); destroy_workqueue(priv->wq); @@ -3362,6 +3312,14 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) free_netdev(netdev); } +static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv) +{ + struct mlx5e_priv *priv = vpriv; + + mlx5e_destroy_netdev(mdev, priv); + mlx5e_destroy_mdev_resources(mdev); +} + static void *mlx5e_get_netdev(void *vpriv) { struct mlx5e_priv *priv = vpriv; @@ -3370,8 +3328,8 @@ static void *mlx5e_get_netdev(void *vpriv) } static struct mlx5_interface mlx5e_interface = { - .add = mlx5e_create_netdev, - .remove = mlx5e_destroy_netdev, + .add = mlx5e_add, + .remove = mlx5e_remove, .event = mlx5e_async_event, .protocol = MLX5_INTERFACE_PROTOCOL_ETH, .get_dev = mlx5e_get_netdev, diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 46260fdc5305..e22b3456b2ee 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -578,6 +578,18 @@ enum mlx5_pci_status { MLX5_PCI_STATUS_ENABLED, }; +struct mlx5_td { + struct list_head tirs_list; + u32 tdn; +}; + +struct mlx5e_resources { + struct mlx5_uar cq_uar; + u32 pdn; + struct mlx5_td td; + struct mlx5_core_mkey mkey; +}; + struct mlx5_core_dev { struct pci_dev *pdev; /* sync pci state */ @@ -602,6 +614,7 @@ struct mlx5_core_dev { struct mlx5_profile *profile; atomic_t num_qps; u32 issi; + struct mlx5e_resources mlx5e_res; #ifdef CONFIG_RFS_ACCEL struct cpu_rmap *rmap; #endif -- cgit v1.2.3 From 90efe05562921768d34e44c0292703ea3168ba8d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Jun 2016 15:14:42 +0200 Subject: iio: st_sensors: harden interrupt handling Leonard Crestez observed the following phenomenon: when using hard interrupt triggers (the DRDY line coming out of an ST sensor) sometimes a new value would arrive while reading the previous value, due to latencies in the system. We discovered that the ST hardware as far as can be observed is designed for level interrupts: the DRDY line will be held asserted as long as there are new values coming. The interrupt handler should be re-entered until we're out of values to handle from the sensor. If interrupts were handled as occurring on the edges (usually low-to-high) new values could appear and the line be held asserted after that, and these values would be missed, the interrupt handler would also lock up as new data was available, but as no new edges occurs on the DRDY signal, nothing happens: the edge detector only detects edges. To counter this, do the following: - Accept interrupt lines to be flagged as level interrupts using IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW. If the line is marked like this (in the device tree node or ACPI table or similar) it will be utilized as a level IRQ. We mark the line with IRQF_ONESHOT and mask the IRQ while processing a sample, then the top half will be entered again if new values are available. - If we are flagged as using edge interrupts with IRQF_TRIGGER_RISING or IRQF_TRIGGER_FALLING: remove IRQF_ONESHOT so that the interrupt line is not masked while running the thread part of the interrupt. This way we will never miss an interrupt, then introduce a loop that polls the data ready registers repeatedly until no new samples are available, then exit the interrupt handler. This way we know no new values are available when the interrupt handler exits and new (edge) interrupts will be triggered when data arrives. Take some extra care to update the timestamp in the poll loop if this happens. The timestamp will not be 100% perfect, but it will at least be closer to the actual events. Usually the extra poll loop will handle the new samples, but once in a blue moon, we get a new IRQ while exiting the loop, before returning from the thread IRQ bottom half with IRQ_HANDLED. On these rare occasions, the removal of IRQF_ONESHOT means the interrupt will immediately fire again. - If no interrupt type is indicated from the DT/ACPI, choose IRQF_TRIGGER_RISING as default, as this is necessary for legacy boards. Tested successfully on the LIS331DL and L3G4200D by setting sampling frequency to 400Hz/800Hz and stressing the system: extra reads in the threaded interrupt handler occurs. Cc: Giuseppe Barba Cc: Denis Ciocca Tested-by: Crestez Dan Leonard Reported-by: Crestez Dan Leonard Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_buffer.c | 7 +- drivers/iio/common/st_sensors/st_sensors_trigger.c | 154 +++++++++++++++------ include/linux/iio/common/st_sensors.h | 2 + 3 files changed, 117 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 7c84e90d8ce8..2371fc875d2d 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -58,7 +58,12 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) struct st_sensor_data *sdata = iio_priv(indio_dev); s64 timestamp; - /* If we do timetamping here, do it before reading the values */ + /* + * If we do timetamping here, do it before reading the values, because + * once we've read the values, new interrupts can occur (when using + * the hardware trigger) and the hw_timestamp may get updated. + * By storing it in a local variable first, we are safe. + */ if (sdata->hw_irq_trigger) timestamp = sdata->hw_timestamp; else diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index fab494d71951..e66f12ee8a55 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -17,6 +17,50 @@ #include #include "st_sensors_core.h" +/** + * st_sensors_new_samples_available() - check if more samples came in + * returns: + * 0 - no new samples available + * 1 - new samples available + * negative - error or unknown + */ +static int st_sensors_new_samples_available(struct iio_dev *indio_dev, + struct st_sensor_data *sdata) +{ + u8 status; + int ret; + + /* How would I know if I can't check it? */ + if (!sdata->sensor_settings->drdy_irq.addr_stat_drdy) + return -EINVAL; + + /* No scan mask, no interrupt */ + if (!indio_dev->active_scan_mask) + return 0; + + ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, + sdata->sensor_settings->drdy_irq.addr_stat_drdy, + &status); + if (ret < 0) { + dev_err(sdata->dev, + "error checking samples available\n"); + return ret; + } + /* + * the lower bits of .active_scan_mask[0] is directly mapped + * to the channels on the sensor: either bit 0 for + * one-dimensional sensors, or e.g. x,y,z for accelerometers, + * gyroscopes or magnetometers. No sensor use more than 3 + * channels, so cut the other status bits here. + */ + status &= 0x07; + + if (status & (u8)indio_dev->active_scan_mask[0]) + return 1; + + return 0; +} + /** * st_sensors_irq_handler() - top half of the IRQ-based triggers * @irq: irq number @@ -43,44 +87,43 @@ irqreturn_t st_sensors_irq_thread(int irq, void *p) struct iio_trigger *trig = p; struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct st_sensor_data *sdata = iio_priv(indio_dev); - int ret; /* * If this trigger is backed by a hardware interrupt and we have a - * status register, check if this IRQ came from us + * status register, check if this IRQ came from us. Notice that + * we will process also if st_sensors_new_samples_available() + * returns negative: if we can't check status, then poll + * unconditionally. */ - if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) { - u8 status; - - ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sdata->sensor_settings->drdy_irq.addr_stat_drdy, - &status); - if (ret < 0) { - dev_err(sdata->dev, "could not read channel status\n"); - goto out_poll; - } - /* - * the lower bits of .active_scan_mask[0] is directly mapped - * to the channels on the sensor: either bit 0 for - * one-dimensional sensors, or e.g. x,y,z for accelerometers, - * gyroscopes or magnetometers. No sensor use more than 3 - * channels, so cut the other status bits here. - */ - status &= 0x07; + if (sdata->hw_irq_trigger && + st_sensors_new_samples_available(indio_dev, sdata)) { + iio_trigger_poll_chained(p); + } else { + dev_dbg(sdata->dev, "spurious IRQ\n"); + return IRQ_NONE; + } - /* - * If this was not caused by any channels on this sensor, - * return IRQ_NONE - */ - if (!indio_dev->active_scan_mask) - return IRQ_NONE; - if (!(status & (u8)indio_dev->active_scan_mask[0])) - return IRQ_NONE; + /* + * If we have proper level IRQs the handler will be re-entered if + * the line is still active, so return here and come back in through + * the top half if need be. + */ + if (!sdata->edge_irq) + return IRQ_HANDLED; + + /* + * If we are using egde IRQs, new samples arrived while processing + * the IRQ and those may be missed unless we pick them here, so poll + * again. If the sensor delivery frequency is very high, this thread + * turns into a polled loop handler. + */ + while (sdata->hw_irq_trigger && + st_sensors_new_samples_available(indio_dev, sdata)) { + dev_dbg(sdata->dev, "more samples came in during polling\n"); + sdata->hw_timestamp = iio_get_time_ns(indio_dev); + iio_trigger_poll_chained(p); } -out_poll: - /* It's our IRQ: proceed to handle the register polling */ - iio_trigger_poll_chained(p); return IRQ_HANDLED; } @@ -107,13 +150,18 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, * If the IRQ is triggered on falling edge, we need to mark the * interrupt as active low, if the hardware supports this. */ - if (irq_trig == IRQF_TRIGGER_FALLING) { + switch(irq_trig) { + case IRQF_TRIGGER_FALLING: + case IRQF_TRIGGER_LOW: if (!sdata->sensor_settings->drdy_irq.addr_ihl) { dev_err(&indio_dev->dev, - "falling edge specified for IRQ but hardware " - "only support rising edge, will request " - "rising edge\n"); - irq_trig = IRQF_TRIGGER_RISING; + "falling/low specified for IRQ " + "but hardware only support rising/high: " + "will request rising/high\n"); + if (irq_trig == IRQF_TRIGGER_FALLING) + irq_trig = IRQF_TRIGGER_RISING; + if (irq_trig == IRQF_TRIGGER_LOW) + irq_trig = IRQF_TRIGGER_HIGH; } else { /* Set up INT active low i.e. falling edge */ err = st_sensors_write_data_with_mask(indio_dev, @@ -122,20 +170,39 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, if (err < 0) goto iio_trigger_free; dev_info(&indio_dev->dev, - "interrupts on the falling edge\n"); + "interrupts on the falling edge or " + "active low level\n"); } - } else if (irq_trig == IRQF_TRIGGER_RISING) { + break; + case IRQF_TRIGGER_RISING: dev_info(&indio_dev->dev, "interrupts on the rising edge\n"); - - } else { + break; + case IRQF_TRIGGER_HIGH: + dev_info(&indio_dev->dev, + "interrupts active high level\n"); + break; + default: + /* This is the most preferred mode, if possible */ dev_err(&indio_dev->dev, - "unsupported IRQ trigger specified (%lx), only " - "rising and falling edges supported, enforce " + "unsupported IRQ trigger specified (%lx), enforce " "rising edge\n", irq_trig); irq_trig = IRQF_TRIGGER_RISING; } + /* Tell the interrupt handler that we're dealing with edges */ + if (irq_trig == IRQF_TRIGGER_FALLING || + irq_trig == IRQF_TRIGGER_RISING) + sdata->edge_irq = true; + else + /* + * If we're not using edges (i.e. level interrupts) we + * just mask off the IRQ, handle one interrupt, then + * if the line is still low, we return to the + * interrupt handler top half again and start over. + */ + irq_trig |= IRQF_ONESHOT; + /* * If the interrupt pin is Open Drain, by definition this * means that the interrupt line may be shared with other @@ -148,9 +215,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, sdata->sensor_settings->drdy_irq.addr_stat_drdy) irq_trig |= IRQF_SHARED; - /* Let's create an interrupt thread masking the hard IRQ here */ - irq_trig |= IRQF_ONESHOT; - err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), st_sensors_irq_handler, st_sensors_irq_thread, diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 28052cddaa03..228bd44efa4c 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -223,6 +223,7 @@ struct st_sensor_settings { * @get_irq_data_ready: Function to get the IRQ used for data ready signal. * @tf: Transfer function structure used by I/O operations. * @tb: Transfer buffers and mutex used by I/O operations. + * @edge_irq: the IRQ triggers on edges and need special handling. * @hw_irq_trigger: if we're using the hardware interrupt on the sensor. * @hw_timestamp: Latest timestamp from the interrupt handler, when in use. */ @@ -250,6 +251,7 @@ struct st_sensor_data { const struct st_sensor_transfer_function *tf; struct st_sensor_transfer_buffer tb; + bool edge_irq; bool hw_irq_trigger; s64 hw_timestamp; }; -- cgit v1.2.3 From c37a2dfa67f7920b14ea77dc9f9f9660f7a1f6dd Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 24 Jun 2016 13:25:22 -0700 Subject: netfilter: Convert FWINV<[foo]> macros and uses to NF_INVF netfilter uses multiple FWINV #defines with identical form that hide a specific structure variable and dereference it with a invflags member. $ git grep "#define FWINV" include/linux/netfilter_bridge/ebtables.h:#define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg)) net/bridge/netfilter/ebtables.c:#define FWINV2(bool, invflg) ((bool) ^ !!(e->invflags & invflg)) net/ipv4/netfilter/arp_tables.c:#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) net/ipv4/netfilter/ip_tables.c:#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) net/ipv6/netfilter/ip6_tables.c:#define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg))) net/netfilter/xt_tcpudp.c:#define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg))) Consolidate these macros into a single NF_INVF macro. Miscellanea: o Neaten the alignment around these uses o A few lines are > 80 columns for intelligibility Signed-off-by: Joe Perches Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/x_tables.h | 4 +++ include/linux/netfilter_bridge/ebtables.h | 2 -- net/bridge/netfilter/ebt_802_3.c | 6 ++-- net/bridge/netfilter/ebt_arp.c | 38 +++++++++++----------- net/bridge/netfilter/ebt_ip.c | 28 ++++++++--------- net/bridge/netfilter/ebt_ip6.c | 41 +++++++++++++----------- net/bridge/netfilter/ebt_stp.c | 52 ++++++++++++++++--------------- net/bridge/netfilter/ebtables.c | 27 ++++++++-------- net/ipv4/netfilter/arp_tables.c | 41 ++++++++++++------------ net/ipv4/netfilter/ip_tables.c | 20 ++++++------ net/ipv6/netfilter/ip6_tables.c | 16 +++++----- net/netfilter/xt_tcpudp.c | 7 ++--- 12 files changed, 144 insertions(+), 138 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index dc4f58a3cdcc..e94e81ab2b58 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -6,6 +6,10 @@ #include #include +/* Test a struct->invflags and a boolean for inequality */ +#define NF_INVF(ptr, flag, boolean) \ + ((boolean) ^ !!((ptr)->invflags & (flag))) + /** * struct xt_action_param - parameters for matches/targets * diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index 2ea517c7c6b9..984b2112c77b 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -115,8 +115,6 @@ extern unsigned int ebt_do_table(struct sk_buff *skb, const struct nf_hook_state *state, struct ebt_table *table); -/* Used in the kernel match() functions */ -#define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg)) /* True if the hook mask denotes that the rule is in a base chain, * used in the check() functions */ #define BASE_CHAIN (par->hook_mask & (1 << NF_BR_NUMHOOKS)) diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c index 2a449b7ab8fa..5fc4affd9fdb 100644 --- a/net/bridge/netfilter/ebt_802_3.c +++ b/net/bridge/netfilter/ebt_802_3.c @@ -20,16 +20,16 @@ ebt_802_3_mt(const struct sk_buff *skb, struct xt_action_param *par) __be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; if (info->bitmask & EBT_802_3_SAP) { - if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) + if (NF_INVF(info, EBT_802_3_SAP, info->sap != hdr->llc.ui.ssap)) return false; - if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP)) + if (NF_INVF(info, EBT_802_3_SAP, info->sap != hdr->llc.ui.dsap)) return false; } if (info->bitmask & EBT_802_3_TYPE) { if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE)) return false; - if (FWINV(info->type != type, EBT_802_3_TYPE)) + if (NF_INVF(info, EBT_802_3_TYPE, info->type != type)) return false; } diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c index cca0a899ee15..227142282b45 100644 --- a/net/bridge/netfilter/ebt_arp.c +++ b/net/bridge/netfilter/ebt_arp.c @@ -25,14 +25,14 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); if (ah == NULL) return false; - if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != - ah->ar_op, EBT_ARP_OPCODE)) + if ((info->bitmask & EBT_ARP_OPCODE) && + NF_INVF(info, EBT_ARP_OPCODE, info->opcode != ah->ar_op)) return false; - if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != - ah->ar_hrd, EBT_ARP_HTYPE)) + if ((info->bitmask & EBT_ARP_HTYPE) && + NF_INVF(info, EBT_ARP_HTYPE, info->htype != ah->ar_hrd)) return false; - if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != - ah->ar_pro, EBT_ARP_PTYPE)) + if ((info->bitmask & EBT_ARP_PTYPE) && + NF_INVF(info, EBT_ARP_PTYPE, info->ptype != ah->ar_pro)) return false; if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) { @@ -51,14 +51,16 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) sizeof(daddr), &daddr); if (dap == NULL) return false; - if (info->bitmask & EBT_ARP_SRC_IP && - FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP)) + if ((info->bitmask & EBT_ARP_SRC_IP) && + NF_INVF(info, EBT_ARP_SRC_IP, + info->saddr != (*sap & info->smsk))) return false; - if (info->bitmask & EBT_ARP_DST_IP && - FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP)) + if ((info->bitmask & EBT_ARP_DST_IP) && + NF_INVF(info, EBT_ARP_DST_IP, + info->daddr != (*dap & info->dmsk))) return false; - if (info->bitmask & EBT_ARP_GRAT && - FWINV(*dap != *sap, EBT_ARP_GRAT)) + if ((info->bitmask & EBT_ARP_GRAT) && + NF_INVF(info, EBT_ARP_GRAT, *dap != *sap)) return false; } @@ -73,9 +75,9 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) sizeof(_mac), &_mac); if (mp == NULL) return false; - if (FWINV(!ether_addr_equal_masked(mp, info->smaddr, - info->smmsk), - EBT_ARP_SRC_MAC)) + if (NF_INVF(info, EBT_ARP_SRC_MAC, + !ether_addr_equal_masked(mp, info->smaddr, + info->smmsk))) return false; } @@ -85,9 +87,9 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) sizeof(_mac), &_mac); if (mp == NULL) return false; - if (FWINV(!ether_addr_equal_masked(mp, info->dmaddr, - info->dmmsk), - EBT_ARP_DST_MAC)) + if (NF_INVF(info, EBT_ARP_DST_MAC, + !ether_addr_equal_masked(mp, info->dmaddr, + info->dmmsk))) return false; } } diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c index 23bca62d58d2..d06968bdf5ec 100644 --- a/net/bridge/netfilter/ebt_ip.c +++ b/net/bridge/netfilter/ebt_ip.c @@ -36,19 +36,19 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); if (ih == NULL) return false; - if (info->bitmask & EBT_IP_TOS && - FWINV(info->tos != ih->tos, EBT_IP_TOS)) + if ((info->bitmask & EBT_IP_TOS) && + NF_INVF(info, EBT_IP_TOS, info->tos != ih->tos)) return false; - if (info->bitmask & EBT_IP_SOURCE && - FWINV((ih->saddr & info->smsk) != - info->saddr, EBT_IP_SOURCE)) + if ((info->bitmask & EBT_IP_SOURCE) && + NF_INVF(info, EBT_IP_SOURCE, + (ih->saddr & info->smsk) != info->saddr)) return false; if ((info->bitmask & EBT_IP_DEST) && - FWINV((ih->daddr & info->dmsk) != - info->daddr, EBT_IP_DEST)) + NF_INVF(info, EBT_IP_DEST, + (ih->daddr & info->dmsk) != info->daddr)) return false; if (info->bitmask & EBT_IP_PROTO) { - if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO)) + if (NF_INVF(info, EBT_IP_PROTO, info->protocol != ih->protocol)) return false; if (!(info->bitmask & EBT_IP_DPORT) && !(info->bitmask & EBT_IP_SPORT)) @@ -61,16 +61,16 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) return false; if (info->bitmask & EBT_IP_DPORT) { u32 dst = ntohs(pptr->dst); - if (FWINV(dst < info->dport[0] || - dst > info->dport[1], - EBT_IP_DPORT)) + if (NF_INVF(info, EBT_IP_DPORT, + dst < info->dport[0] || + dst > info->dport[1])) return false; } if (info->bitmask & EBT_IP_SPORT) { u32 src = ntohs(pptr->src); - if (FWINV(src < info->sport[0] || - src > info->sport[1], - EBT_IP_SPORT)) + if (NF_INVF(info, EBT_IP_SPORT, + src < info->sport[0] || + src > info->sport[1])) return false; } } diff --git a/net/bridge/netfilter/ebt_ip6.c b/net/bridge/netfilter/ebt_ip6.c index 98de6e7fd86d..4617491be41e 100644 --- a/net/bridge/netfilter/ebt_ip6.c +++ b/net/bridge/netfilter/ebt_ip6.c @@ -45,15 +45,18 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); if (ih6 == NULL) return false; - if (info->bitmask & EBT_IP6_TCLASS && - FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS)) + if ((info->bitmask & EBT_IP6_TCLASS) && + NF_INVF(info, EBT_IP6_TCLASS, + info->tclass != ipv6_get_dsfield(ih6))) return false; - if ((info->bitmask & EBT_IP6_SOURCE && - FWINV(ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk, - &info->saddr), EBT_IP6_SOURCE)) || - (info->bitmask & EBT_IP6_DEST && - FWINV(ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk, - &info->daddr), EBT_IP6_DEST))) + if (((info->bitmask & EBT_IP6_SOURCE) && + NF_INVF(info, EBT_IP6_SOURCE, + ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk, + &info->saddr))) || + ((info->bitmask & EBT_IP6_DEST) && + NF_INVF(info, EBT_IP6_DEST, + ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk, + &info->daddr)))) return false; if (info->bitmask & EBT_IP6_PROTO) { uint8_t nexthdr = ih6->nexthdr; @@ -63,7 +66,7 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off); if (offset_ph == -1) return false; - if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO)) + if (NF_INVF(info, EBT_IP6_PROTO, info->protocol != nexthdr)) return false; if (!(info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT | EBT_IP6_ICMP6))) @@ -76,22 +79,24 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) return false; if (info->bitmask & EBT_IP6_DPORT) { u16 dst = ntohs(pptr->tcpudphdr.dst); - if (FWINV(dst < info->dport[0] || - dst > info->dport[1], EBT_IP6_DPORT)) + if (NF_INVF(info, EBT_IP6_DPORT, + dst < info->dport[0] || + dst > info->dport[1])) return false; } if (info->bitmask & EBT_IP6_SPORT) { u16 src = ntohs(pptr->tcpudphdr.src); - if (FWINV(src < info->sport[0] || - src > info->sport[1], EBT_IP6_SPORT)) + if (NF_INVF(info, EBT_IP6_SPORT, + src < info->sport[0] || + src > info->sport[1])) return false; } if ((info->bitmask & EBT_IP6_ICMP6) && - FWINV(pptr->icmphdr.type < info->icmpv6_type[0] || - pptr->icmphdr.type > info->icmpv6_type[1] || - pptr->icmphdr.code < info->icmpv6_code[0] || - pptr->icmphdr.code > info->icmpv6_code[1], - EBT_IP6_ICMP6)) + NF_INVF(info, EBT_IP6_ICMP6, + pptr->icmphdr.type < info->icmpv6_type[0] || + pptr->icmphdr.type > info->icmpv6_type[1] || + pptr->icmphdr.code < info->icmpv6_code[0] || + pptr->icmphdr.code > info->icmpv6_code[1])) return false; } return true; diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c index 45f73d55422f..3140eb912d7e 100644 --- a/net/bridge/netfilter/ebt_stp.c +++ b/net/bridge/netfilter/ebt_stp.c @@ -49,66 +49,68 @@ static bool ebt_filter_config(const struct ebt_stp_info *info, c = &info->config; if ((info->bitmask & EBT_STP_FLAGS) && - FWINV(c->flags != stpc->flags, EBT_STP_FLAGS)) + NF_INVF(info, EBT_STP_FLAGS, c->flags != stpc->flags)) return false; if (info->bitmask & EBT_STP_ROOTPRIO) { v16 = NR16(stpc->root); - if (FWINV(v16 < c->root_priol || v16 > c->root_priou, - EBT_STP_ROOTPRIO)) + if (NF_INVF(info, EBT_STP_ROOTPRIO, + v16 < c->root_priol || v16 > c->root_priou)) return false; } if (info->bitmask & EBT_STP_ROOTADDR) { - if (FWINV(!ether_addr_equal_masked(&stpc->root[2], c->root_addr, - c->root_addrmsk), - EBT_STP_ROOTADDR)) + if (NF_INVF(info, EBT_STP_ROOTADDR, + !ether_addr_equal_masked(&stpc->root[2], + c->root_addr, + c->root_addrmsk))) return false; } if (info->bitmask & EBT_STP_ROOTCOST) { v32 = NR32(stpc->root_cost); - if (FWINV(v32 < c->root_costl || v32 > c->root_costu, - EBT_STP_ROOTCOST)) + if (NF_INVF(info, EBT_STP_ROOTCOST, + v32 < c->root_costl || v32 > c->root_costu)) return false; } if (info->bitmask & EBT_STP_SENDERPRIO) { v16 = NR16(stpc->sender); - if (FWINV(v16 < c->sender_priol || v16 > c->sender_priou, - EBT_STP_SENDERPRIO)) + if (NF_INVF(info, EBT_STP_SENDERPRIO, + v16 < c->sender_priol || v16 > c->sender_priou)) return false; } if (info->bitmask & EBT_STP_SENDERADDR) { - if (FWINV(!ether_addr_equal_masked(&stpc->sender[2], - c->sender_addr, - c->sender_addrmsk), - EBT_STP_SENDERADDR)) + if (NF_INVF(info, EBT_STP_SENDERADDR, + !ether_addr_equal_masked(&stpc->sender[2], + c->sender_addr, + c->sender_addrmsk))) return false; } if (info->bitmask & EBT_STP_PORT) { v16 = NR16(stpc->port); - if (FWINV(v16 < c->portl || v16 > c->portu, EBT_STP_PORT)) + if (NF_INVF(info, EBT_STP_PORT, + v16 < c->portl || v16 > c->portu)) return false; } if (info->bitmask & EBT_STP_MSGAGE) { v16 = NR16(stpc->msg_age); - if (FWINV(v16 < c->msg_agel || v16 > c->msg_ageu, - EBT_STP_MSGAGE)) + if (NF_INVF(info, EBT_STP_MSGAGE, + v16 < c->msg_agel || v16 > c->msg_ageu)) return false; } if (info->bitmask & EBT_STP_MAXAGE) { v16 = NR16(stpc->max_age); - if (FWINV(v16 < c->max_agel || v16 > c->max_ageu, - EBT_STP_MAXAGE)) + if (NF_INVF(info, EBT_STP_MAXAGE, + v16 < c->max_agel || v16 > c->max_ageu)) return false; } if (info->bitmask & EBT_STP_HELLOTIME) { v16 = NR16(stpc->hello_time); - if (FWINV(v16 < c->hello_timel || v16 > c->hello_timeu, - EBT_STP_HELLOTIME)) + if (NF_INVF(info, EBT_STP_HELLOTIME, + v16 < c->hello_timel || v16 > c->hello_timeu)) return false; } if (info->bitmask & EBT_STP_FWDD) { v16 = NR16(stpc->forward_delay); - if (FWINV(v16 < c->forward_delayl || v16 > c->forward_delayu, - EBT_STP_FWDD)) + if (NF_INVF(info, EBT_STP_FWDD, + v16 < c->forward_delayl || v16 > c->forward_delayu)) return false; } return true; @@ -130,8 +132,8 @@ ebt_stp_mt(const struct sk_buff *skb, struct xt_action_param *par) if (memcmp(sp, header, sizeof(header))) return false; - if (info->bitmask & EBT_STP_TYPE && - FWINV(info->type != sp->type, EBT_STP_TYPE)) + if ((info->bitmask & EBT_STP_TYPE) && + NF_INVF(info, EBT_STP_TYPE, info->type != sp->type)) return false; if (sp->type == BPDU_TYPE_CONFIG && diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 5721a25be860..cceac5bb658f 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -121,7 +121,6 @@ ebt_dev_check(const char *entry, const struct net_device *device) return devname[i] != entry[i] && entry[i] != 1; } -#define FWINV2(bool, invflg) ((bool) ^ !!(e->invflags & invflg)) /* process standard matches */ static inline int ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, @@ -137,34 +136,36 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, ethproto = h->h_proto; if (e->bitmask & EBT_802_3) { - if (FWINV2(eth_proto_is_802_3(ethproto), EBT_IPROTO)) + if (NF_INVF(e, EBT_IPROTO, eth_proto_is_802_3(ethproto))) return 1; } else if (!(e->bitmask & EBT_NOPROTO) && - FWINV2(e->ethproto != ethproto, EBT_IPROTO)) + NF_INVF(e, EBT_IPROTO, e->ethproto != ethproto)) return 1; - if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN)) + if (NF_INVF(e, EBT_IIN, ebt_dev_check(e->in, in))) return 1; - if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) + if (NF_INVF(e, EBT_IOUT, ebt_dev_check(e->out, out))) return 1; /* rcu_read_lock()ed by nf_hook_slow */ if (in && (p = br_port_get_rcu(in)) != NULL && - FWINV2(ebt_dev_check(e->logical_in, p->br->dev), EBT_ILOGICALIN)) + NF_INVF(e, EBT_ILOGICALIN, + ebt_dev_check(e->logical_in, p->br->dev))) return 1; if (out && (p = br_port_get_rcu(out)) != NULL && - FWINV2(ebt_dev_check(e->logical_out, p->br->dev), EBT_ILOGICALOUT)) + NF_INVF(e, EBT_ILOGICALOUT, + ebt_dev_check(e->logical_out, p->br->dev))) return 1; if (e->bitmask & EBT_SOURCEMAC) { - if (FWINV2(!ether_addr_equal_masked(h->h_source, - e->sourcemac, e->sourcemsk), - EBT_ISOURCE)) + if (NF_INVF(e, EBT_ISOURCE, + !ether_addr_equal_masked(h->h_source, e->sourcemac, + e->sourcemsk))) return 1; } if (e->bitmask & EBT_DESTMAC) { - if (FWINV2(!ether_addr_equal_masked(h->h_dest, - e->destmac, e->destmsk), - EBT_IDEST)) + if (NF_INVF(e, EBT_IDEST, + !ether_addr_equal_masked(h->h_dest, e->destmac, + e->destmsk))) return 1; } return 0; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 2033f929aa66..c8dd9e26b185 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -89,22 +89,20 @@ static inline int arp_packet_match(const struct arphdr *arphdr, __be32 src_ipaddr, tgt_ipaddr; long ret; -#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) - - if (FWINV((arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop, - ARPT_INV_ARPOP)) + if (NF_INVF(arpinfo, ARPT_INV_ARPOP, + (arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop)) return 0; - if (FWINV((arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd, - ARPT_INV_ARPHRD)) + if (NF_INVF(arpinfo, ARPT_INV_ARPHRD, + (arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd)) return 0; - if (FWINV((arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro, - ARPT_INV_ARPPRO)) + if (NF_INVF(arpinfo, ARPT_INV_ARPPRO, + (arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro)) return 0; - if (FWINV((arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln, - ARPT_INV_ARPHLN)) + if (NF_INVF(arpinfo, ARPT_INV_ARPHLN, + (arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln)) return 0; src_devaddr = arpptr; @@ -115,31 +113,32 @@ static inline int arp_packet_match(const struct arphdr *arphdr, arpptr += dev->addr_len; memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); - if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len), - ARPT_INV_SRCDEVADDR) || - FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len), - ARPT_INV_TGTDEVADDR)) + if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR, + arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, + dev->addr_len)) || + NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR, + arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, + dev->addr_len))) return 0; - if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr, - ARPT_INV_SRCIP) || - FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr), - ARPT_INV_TGTIP)) + if (NF_INVF(arpinfo, ARPT_INV_SRCIP, + (src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr) || + NF_INVF(arpinfo, ARPT_INV_TGTIP, + (tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr)) return 0; /* Look for ifname matches. */ ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask); - if (FWINV(ret != 0, ARPT_INV_VIA_IN)) + if (NF_INVF(arpinfo, ARPT_INV_VIA_IN, ret != 0)) return 0; ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask); - if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) + if (NF_INVF(arpinfo, ARPT_INV_VIA_OUT, ret != 0)) return 0; return 1; -#undef FWINV } static inline int arp_checkentry(const struct arpt_arp *arp) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 54906e0e8e0c..f0df66f54ce6 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -58,32 +58,31 @@ ip_packet_match(const struct iphdr *ip, { unsigned long ret; -#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) - - if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, - IPT_INV_SRCIP) || - FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr, - IPT_INV_DSTIP)) + if (NF_INVF(ipinfo, IPT_INV_SRCIP, + (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || + NF_INVF(ipinfo, IPT_INV_DSTIP, + (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr)) return false; ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask); - if (FWINV(ret != 0, IPT_INV_VIA_IN)) + if (NF_INVF(ipinfo, IPT_INV_VIA_IN, ret != 0)) return false; ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask); - if (FWINV(ret != 0, IPT_INV_VIA_OUT)) + if (NF_INVF(ipinfo, IPT_INV_VIA_OUT, ret != 0)) return false; /* Check specific protocol */ if (ipinfo->proto && - FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) + NF_INVF(ipinfo, IPT_INV_PROTO, ip->protocol != ipinfo->proto)) return false; /* If we have a fragment rule but the packet is not a fragment * then we return zero */ - if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) + if (NF_INVF(ipinfo, IPT_INV_FRAG, + (ipinfo->flags & IPT_F_FRAG) && !isfrag)) return false; return true; @@ -122,7 +121,6 @@ static inline bool unconditional(const struct ipt_entry *e) return e->target_offset == sizeof(struct ipt_entry) && memcmp(&e->ip, &uncond, sizeof(uncond)) == 0; -#undef FWINV } /* for const-correctness */ diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 63e06c3dd319..61ed95054efa 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -73,22 +73,22 @@ ip6_packet_match(const struct sk_buff *skb, unsigned long ret; const struct ipv6hdr *ipv6 = ipv6_hdr(skb); -#define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg))) - - if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, - &ip6info->src), IP6T_INV_SRCIP) || - FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, - &ip6info->dst), IP6T_INV_DSTIP)) + if (NF_INVF(ip6info, IP6T_INV_SRCIP, + ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, + &ip6info->src)) || + NF_INVF(ip6info, IP6T_INV_DSTIP, + ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, + &ip6info->dst))) return false; ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask); - if (FWINV(ret != 0, IP6T_INV_VIA_IN)) + if (NF_INVF(ip6info, IP6T_INV_VIA_IN, ret != 0)) return false; ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask); - if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) + if (NF_INVF(ip6info, IP6T_INV_VIA_OUT, ret != 0)) return false; /* ... might want to do something with class and flowlabel here ... */ diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index c14d4645daa3..ade024c90f4f 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c @@ -83,8 +83,6 @@ static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par) return false; } -#define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg))) - th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph); if (th == NULL) { /* We've been asked to examine this packet, and we @@ -102,9 +100,8 @@ static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par) ntohs(th->dest), !!(tcpinfo->invflags & XT_TCP_INV_DSTPT))) return false; - if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask) - == tcpinfo->flg_cmp, - XT_TCP_INV_FLAGS)) + if (!NF_INVF(tcpinfo, XT_TCP_INV_FLAGS, + (((unsigned char *)th)[13] & tcpinfo->flg_mask) == tcpinfo->flg_cmp)) return false; if (tcpinfo->option) { if (th->doff * 4 < sizeof(_tcph)) { -- cgit v1.2.3 From b6140914fd079e43ea75a53429b47128584f033a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:22 +0900 Subject: genirq/msi: Remove unused MSI_FLAG_IDENTITY_MAP No user and we definitely don't want to grow one. Signed-off-by: Thomas Gleixner Reviewed-by: Bart Van Assche Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-2-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner --- include/linux/msi.h | 6 ++---- kernel/irq/msi.c | 8 ++------ 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/include/linux/msi.h b/include/linux/msi.h index 8b425c66305a..c33abfa0f5a7 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -264,12 +264,10 @@ enum { * callbacks. */ MSI_FLAG_USE_DEF_CHIP_OPS = (1 << 1), - /* Build identity map between hwirq and irq */ - MSI_FLAG_IDENTITY_MAP = (1 << 2), /* Support multiple PCI MSI interrupts */ - MSI_FLAG_MULTI_PCI_MSI = (1 << 3), + MSI_FLAG_MULTI_PCI_MSI = (1 << 2), /* Support PCI MSIX interrupts */ - MSI_FLAG_PCI_MSIX = (1 << 4), + MSI_FLAG_PCI_MSIX = (1 << 3), }; int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask, diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 38e89ce7b071..eb5bf2b50b07 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -324,7 +324,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, struct msi_domain_ops *ops = info->ops; msi_alloc_info_t arg; struct msi_desc *desc; - int i, ret, virq = -1; + int i, ret, virq; ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg); if (ret) @@ -332,12 +332,8 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, for_each_msi_entry(desc, dev) { ops->set_desc(&arg, desc); - if (info->flags & MSI_FLAG_IDENTITY_MAP) - virq = (int)ops->get_hwirq(info, &arg); - else - virq = -1; - virq = __irq_domain_alloc_irqs(domain, virq, desc->nvec_used, + virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, dev_to_node(dev), &arg, false); if (virq < 0) { ret = -ENOSPC; -- cgit v1.2.3 From 9c2555835bb3d34dfac52a0be943dcc4bedd650f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:23 +0900 Subject: genirq: Introduce IRQD_AFFINITY_MANAGED flag Interupts marked with this flag are excluded from user space interrupt affinity changes. Contrary to the IRQ_NO_BALANCING flag, the kernel internal affinity mechanism is not blocked. This flag will be used for multi-queue device interrupts. Signed-off-by: Thomas Gleixner Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-3-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner --- include/linux/irq.h | 7 +++++++ kernel/irq/internals.h | 2 ++ kernel/irq/manage.c | 21 ++++++++++++++++++--- kernel/irq/proc.c | 2 +- 4 files changed, 28 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 4d758a7c604a..f6074813688d 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -197,6 +197,7 @@ struct irq_data { * IRQD_IRQ_INPROGRESS - In progress state of the interrupt * IRQD_WAKEUP_ARMED - Wakeup mode armed * IRQD_FORWARDED_TO_VCPU - The interrupt is forwarded to a VCPU + * IRQD_AFFINITY_MANAGED - Affinity is auto-managed by the kernel */ enum { IRQD_TRIGGER_MASK = 0xf, @@ -212,6 +213,7 @@ enum { IRQD_IRQ_INPROGRESS = (1 << 18), IRQD_WAKEUP_ARMED = (1 << 19), IRQD_FORWARDED_TO_VCPU = (1 << 20), + IRQD_AFFINITY_MANAGED = (1 << 21), }; #define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors) @@ -305,6 +307,11 @@ static inline void irqd_clr_forwarded_to_vcpu(struct irq_data *d) __irqd_to_state(d) &= ~IRQD_FORWARDED_TO_VCPU; } +static inline bool irqd_affinity_is_managed(struct irq_data *d) +{ + return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED; +} + #undef __irqd_to_state static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 09be2c903c6d..b15aa3b617a2 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -105,6 +105,8 @@ static inline void unregister_handler_proc(unsigned int irq, struct irqaction *action) { } #endif +extern bool irq_can_set_affinity_usr(unsigned int irq); + extern int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask); extern void irq_set_thread_affinity(struct irq_desc *desc); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ef0bc02c3a70..30658e9827f0 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -115,12 +115,12 @@ EXPORT_SYMBOL(synchronize_irq); #ifdef CONFIG_SMP cpumask_var_t irq_default_affinity; -static int __irq_can_set_affinity(struct irq_desc *desc) +static bool __irq_can_set_affinity(struct irq_desc *desc) { if (!desc || !irqd_can_balance(&desc->irq_data) || !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) - return 0; - return 1; + return false; + return true; } /** @@ -133,6 +133,21 @@ int irq_can_set_affinity(unsigned int irq) return __irq_can_set_affinity(irq_to_desc(irq)); } +/** + * irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space + * @irq: Interrupt to check + * + * Like irq_can_set_affinity() above, but additionally checks for the + * AFFINITY_MANAGED flag. + */ +bool irq_can_set_affinity_usr(unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + + return __irq_can_set_affinity(desc) && + !irqd_affinity_is_managed(&desc->irq_data); +} + /** * irq_set_thread_affinity - Notify irq threads to adjust affinity * @desc: irq descriptor which has affitnity changed diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 4e1b94726818..40bdcdc1f700 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -96,7 +96,7 @@ static ssize_t write_irq_affinity(int type, struct file *file, cpumask_var_t new_value; int err; - if (!irq_can_set_affinity(irq) || no_irq_affinity) + if (!irq_can_set_affinity_usr(irq) || no_irq_affinity) return -EIO; if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) -- cgit v1.2.3 From 06ee6d571f0e350253a8fc3492316b2be007fae2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:24 +0900 Subject: genirq: Add affinity hint to irq allocation Add an extra argument to the irq(domain) allocation functions, so we can hand down affinity hints to the allocator. Thats necessary to implement proper support for multiqueue devices. Signed-off-by: Thomas Gleixner Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-4-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner --- arch/sparc/kernel/irq_64.c | 2 +- arch/x86/kernel/apic/io_apic.c | 5 +++-- include/linux/irq.h | 4 ++-- include/linux/irqdomain.h | 9 ++++++--- kernel/irq/ipi.c | 2 +- kernel/irq/irqdesc.c | 12 ++++++++---- kernel/irq/irqdomain.c | 22 ++++++++++++++-------- kernel/irq/manage.c | 7 ++++--- kernel/irq/msi.c | 3 ++- 9 files changed, 41 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index e22416ce56ea..34a7930b76ef 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -242,7 +242,7 @@ unsigned int irq_alloc(unsigned int dev_handle, unsigned int dev_ino) { int irq; - irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL); + irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL, NULL); if (irq <= 0) goto out; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 446702ed99dc..7c4f90dd4c2a 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -981,7 +981,7 @@ static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi, return __irq_domain_alloc_irqs(domain, irq, 1, ioapic_alloc_attr_node(info), - info, legacy); + info, legacy, NULL); } /* @@ -1014,7 +1014,8 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain, info->ioapic_pin)) return -ENOMEM; } else { - irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true); + irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true, + NULL); if (irq >= 0) { irq_data = irq_domain_get_irq_data(domain, irq); data = irq_data->chip_data; diff --git a/include/linux/irq.h b/include/linux/irq.h index f6074813688d..39ce46ac5c18 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -708,11 +708,11 @@ static inline struct cpumask *irq_data_get_affinity_mask(struct irq_data *d) unsigned int arch_dynirq_lower_bound(unsigned int from); int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, - struct module *owner); + struct module *owner, const struct cpumask *affinity); /* use macros to avoid needing export.h for THIS_MODULE */ #define irq_alloc_descs(irq, from, cnt, node) \ - __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE) + __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE, NULL) #define irq_alloc_desc(node) \ irq_alloc_descs(-1, 0, 1, node) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index f1f36e04d885..1aee0fbe900e 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -39,6 +39,7 @@ struct irq_domain; struct of_device_id; struct irq_chip; struct irq_data; +struct cpumask; /* Number of irqs reserved for a legacy isa controller */ #define NUM_ISA_INTERRUPTS 16 @@ -217,7 +218,8 @@ extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, enum irq_domain_bus_token bus_token); extern void irq_set_default_host(struct irq_domain *host); extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, - irq_hw_number_t hwirq, int node); + irq_hw_number_t hwirq, int node, + const struct cpumask *affinity); static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node) { @@ -389,7 +391,7 @@ static inline struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *par extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, unsigned int nr_irqs, int node, void *arg, - bool realloc); + bool realloc, const struct cpumask *affinity); extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs); extern void irq_domain_activate_irq(struct irq_data *irq_data); extern void irq_domain_deactivate_irq(struct irq_data *irq_data); @@ -397,7 +399,8 @@ extern void irq_domain_deactivate_irq(struct irq_data *irq_data); static inline int irq_domain_alloc_irqs(struct irq_domain *domain, unsigned int nr_irqs, int node, void *arg) { - return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false); + return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false, + NULL); } extern int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c index 89b49f6773f0..4fd23510d5f2 100644 --- a/kernel/irq/ipi.c +++ b/kernel/irq/ipi.c @@ -76,7 +76,7 @@ int irq_reserve_ipi(struct irq_domain *domain, } } - virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE); + virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE, NULL); if (virq <= 0) { pr_warn("Can't reserve IPI, failed to alloc descs\n"); return -ENOMEM; diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 8731e1c5d1e7..b8df4fcdbb5f 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -223,7 +223,7 @@ static void free_desc(unsigned int irq) } static int alloc_descs(unsigned int start, unsigned int cnt, int node, - struct module *owner) + const struct cpumask *affinity, struct module *owner) { struct irq_desc *desc; int i; @@ -333,6 +333,7 @@ static void free_desc(unsigned int irq) } static inline int alloc_descs(unsigned int start, unsigned int cnt, int node, + const struct cpumask *affinity, struct module *owner) { u32 i; @@ -453,12 +454,15 @@ EXPORT_SYMBOL_GPL(irq_free_descs); * @cnt: Number of consecutive irqs to allocate. * @node: Preferred node on which the irq descriptor should be allocated * @owner: Owning module (can be NULL) + * @affinity: Optional pointer to an affinity mask which hints where the + * irq descriptors should be allocated and which default + * affinities to use * * Returns the first irq number or error code */ int __ref __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, - struct module *owner) + struct module *owner, const struct cpumask *affinity) { int start, ret; @@ -494,7 +498,7 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, bitmap_set(allocated_irqs, start, cnt); mutex_unlock(&sparse_irq_lock); - return alloc_descs(start, cnt, node, owner); + return alloc_descs(start, cnt, node, affinity, owner); err: mutex_unlock(&sparse_irq_lock); @@ -512,7 +516,7 @@ EXPORT_SYMBOL_GPL(__irq_alloc_descs); */ unsigned int irq_alloc_hwirqs(int cnt, int node) { - int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL); + int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL, NULL); if (irq < 0) return 0; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8798b6c9e945..79459b732dc9 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -481,7 +481,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain, } /* Allocate a virtual interrupt number */ - virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node)); + virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL); if (virq <= 0) { pr_debug("-> virq allocation failed\n"); return 0; @@ -835,19 +835,23 @@ const struct irq_domain_ops irq_domain_simple_ops = { EXPORT_SYMBOL_GPL(irq_domain_simple_ops); int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq, - int node) + int node, const struct cpumask *affinity) { unsigned int hint; if (virq >= 0) { - virq = irq_alloc_descs(virq, virq, cnt, node); + virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE, + affinity); } else { hint = hwirq % nr_irqs; if (hint == 0) hint++; - virq = irq_alloc_descs_from(hint, cnt, node); - if (virq <= 0 && hint > 1) - virq = irq_alloc_descs_from(1, cnt, node); + virq = __irq_alloc_descs(-1, hint, cnt, node, THIS_MODULE, + affinity); + if (virq <= 0 && hint > 1) { + virq = __irq_alloc_descs(-1, 1, cnt, node, THIS_MODULE, + affinity); + } } return virq; @@ -1160,6 +1164,7 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, * @node: NUMA node id for memory allocation * @arg: domain specific argument * @realloc: IRQ descriptors have already been allocated if true + * @affinity: Optional irq affinity mask for multiqueue devices * * Allocate IRQ numbers and initialized all data structures to support * hierarchy IRQ domains. @@ -1175,7 +1180,7 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, */ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, unsigned int nr_irqs, int node, void *arg, - bool realloc) + bool realloc, const struct cpumask *affinity) { int i, ret, virq; @@ -1193,7 +1198,8 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, if (realloc && irq_base >= 0) { virq = irq_base; } else { - virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node); + virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node, + affinity); if (virq < 0) { pr_debug("cannot allocate IRQ(base %d, count %d)\n", irq_base, nr_irqs); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 30658e9827f0..ad0aac6d1248 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -353,10 +353,11 @@ static int setup_affinity(struct irq_desc *desc, struct cpumask *mask) return 0; /* - * Preserve an userspace affinity setup, but make sure that - * one of the targets is online. + * Preserve the managed affinity setting and an userspace affinity + * setup, but make sure that one of the targets is online. */ - if (irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) { + if (irqd_affinity_is_managed(&desc->irq_data) || + irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) { if (cpumask_intersects(desc->irq_common_data.affinity, cpu_online_mask)) set = desc->irq_common_data.affinity; diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index eb5bf2b50b07..58dbbacc6fbb 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -334,7 +334,8 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, ops->set_desc(&arg, desc); virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, - dev_to_node(dev), &arg, false); + dev_to_node(dev), &arg, false, + NULL); if (virq < 0) { ret = -ENOSPC; if (ops->handle_error) -- cgit v1.2.3 From 0972fa57f53525ffa6ced12d703750fc2791e3ce Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 17:39:26 +0900 Subject: genirq/msi: Make use of affinity aware allocations Allow the MSI code to provide affinity hints per MSI descriptor. Signed-off-by: Thomas Gleixner Cc: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-6-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner --- include/linux/msi.h | 2 ++ kernel/irq/msi.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/msi.h b/include/linux/msi.h index c33abfa0f5a7..4f0bfe5912b2 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -47,6 +47,7 @@ struct fsl_mc_msi_desc { * @nvec_used: The number of vectors used * @dev: Pointer to the device which uses this descriptor * @msg: The last set MSI message cached for reuse + * @affinity: Optional pointer to a cpu affinity mask for this descriptor * * @masked: [PCI MSI/X] Mask bits * @is_msix: [PCI MSI/X] True if MSI-X @@ -67,6 +68,7 @@ struct msi_desc { unsigned int nvec_used; struct device *dev; struct msi_msg msg; + const struct cpumask *affinity; union { /* PCI MSI/X specific data */ diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 58dbbacc6fbb..0e2a736b14a7 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -335,7 +335,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, dev_to_node(dev), &arg, false, - NULL); + desc->affinity); if (virq < 0) { ret = -ENOSPC; if (ops->handle_error) -- cgit v1.2.3 From 5e385a6ef31fbbf2acbda770aecc2bc2ff933d17 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2016 17:39:27 +0900 Subject: genirq: Add a helper to spread an affinity mask for MSI/MSI-X vectors This is lifted from the blk-mq code and adopted to use the affinity mask concept just introduced in the irq handling code. It tries to keep the algorithm the same as the one current used by blk-mq, but improvements like assining vectors on a per-node basis instead of just per sibling are possible with this simple move and refactoring. Signed-off-by: Christoph Hellwig Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-7-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner --- include/linux/interrupt.h | 8 +++++++ kernel/irq/Makefile | 1 + kernel/irq/affinity.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 kernel/irq/affinity.c (limited to 'include/linux') diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 9fcabeb07787..b6683f0ffc9f 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -278,6 +278,8 @@ extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); extern int irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); +struct cpumask *irq_create_affinity_mask(unsigned int *nr_vecs); + #else /* CONFIG_SMP */ static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m) @@ -308,6 +310,12 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) { return 0; } + +static inline struct cpumask *irq_create_affinity_mask(unsigned int *nr_vecs) +{ + *nr_vecs = 1; + return NULL; +} #endif /* CONFIG_SMP */ /* diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 2ee42e95a3ce..1d3ee3169202 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_GENERIC_IRQ_MIGRATION) += cpuhotplug.o obj-$(CONFIG_PM_SLEEP) += pm.o obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o +obj-$(CONFIG_SMP) += affinity.o diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c new file mode 100644 index 000000000000..f68959341c0f --- /dev/null +++ b/kernel/irq/affinity.c @@ -0,0 +1,61 @@ + +#include +#include +#include +#include + +static int get_first_sibling(unsigned int cpu) +{ + unsigned int ret; + + ret = cpumask_first(topology_sibling_cpumask(cpu)); + if (ret < nr_cpu_ids) + return ret; + return cpu; +} + +/* + * Take a map of online CPUs and the number of available interrupt vectors + * and generate an output cpumask suitable for spreading MSI/MSI-X vectors + * so that they are distributed as good as possible around the CPUs. If + * more vectors than CPUs are available we'll map one to each CPU, + * otherwise we map one to the first sibling of each socket. + * + * If there are more vectors than CPUs we will still only have one bit + * set per CPU, but interrupt code will keep on assigning the vectors from + * the start of the bitmap until we run out of vectors. + */ +struct cpumask *irq_create_affinity_mask(unsigned int *nr_vecs) +{ + struct cpumask *affinity_mask; + unsigned int max_vecs = *nr_vecs; + + if (max_vecs == 1) + return NULL; + + affinity_mask = kzalloc(cpumask_size(), GFP_KERNEL); + if (!affinity_mask) { + *nr_vecs = 1; + return NULL; + } + + if (max_vecs >= num_online_cpus()) { + cpumask_copy(affinity_mask, cpu_online_mask); + *nr_vecs = num_online_cpus(); + } else { + unsigned int vecs = 0, cpu; + + for_each_online_cpu(cpu) { + if (cpu == get_first_sibling(cpu)) { + cpumask_set_cpu(cpu, affinity_mask); + vecs++; + } + + if (--max_vecs == 0) + break; + } + *nr_vecs = vecs; + } + + return affinity_mask; +} -- cgit v1.2.3 From 300eb0139cf27044c67f6005ff17b8434c7843f0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 9 May 2016 18:39:59 -0500 Subject: phy: Add set_mode callback The initial use for this is for PHYs that have a mode related to USB OTG. There are several SoCs (e.g. TI OMAP and DA8xx) that have a mode setting in the USB PHY to override OTG VBUS and ID signals. Of course, the enum can be expaned in the future to include modes for other types of PHYs as well. Suggested-by: Kishon Vijay Abraham I Signed-off-by: David Lechner --- drivers/phy/phy-core.c | 15 +++++++++++++++ include/linux/phy/phy.h | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'include/linux') diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index b72e9a3b6429..8eca906b6e70 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -342,6 +342,21 @@ int phy_power_off(struct phy *phy) } EXPORT_SYMBOL_GPL(phy_power_off); +int phy_set_mode(struct phy *phy, enum phy_mode mode) +{ + int ret; + + if (!phy || !phy->ops->set_mode) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->set_mode(phy, mode); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_set_mode); + /** * _of_phy_get() - lookup and obtain a reference to a phy by phandle * @np: device_node for which to get the phy diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index a810f2a18842..f08b67238b58 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -22,12 +22,20 @@ struct phy; +enum phy_mode { + PHY_MODE_INVALID, + PHY_MODE_USB_HOST, + PHY_MODE_USB_DEVICE, + PHY_MODE_USB_OTG, +}; + /** * struct phy_ops - set of function pointers for performing phy operations * @init: operation to be performed for initializing phy * @exit: operation to be performed while exiting * @power_on: powering on the phy * @power_off: powering off the phy + * @set_mode: set the mode of the phy * @owner: the module owner containing the ops */ struct phy_ops { @@ -35,6 +43,7 @@ struct phy_ops { int (*exit)(struct phy *phy); int (*power_on)(struct phy *phy); int (*power_off)(struct phy *phy); + int (*set_mode)(struct phy *phy, enum phy_mode mode); struct module *owner; }; @@ -126,6 +135,7 @@ int phy_init(struct phy *phy); int phy_exit(struct phy *phy); int phy_power_on(struct phy *phy); int phy_power_off(struct phy *phy); +int phy_set_mode(struct phy *phy, enum phy_mode mode); static inline int phy_get_bus_width(struct phy *phy) { return phy->attrs.bus_width; @@ -233,6 +243,13 @@ static inline int phy_power_off(struct phy *phy) return -ENOSYS; } +static inline int phy_set_mode(struct phy *phy, enum phy_mode mode) +{ + if (!phy) + return 0; + return -ENOSYS; +} + static inline int phy_get_bus_width(struct phy *phy) { return -ENOSYS; -- cgit v1.2.3 From 8b10cab64c134ffbffac96edd1899d303d3afcac Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 2 Jul 2016 06:43:14 -0400 Subject: net: simplify and make pkt_type_ok() available for other users Suggested-by: Daniel Borkmann Signed-off-by: Jamal Hadi Salim Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/skbuff.h | 10 ++++++++++ net/netfilter/nft_meta.c | 9 +-------- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index dc0fca747c5e..638b0e004310 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -37,6 +37,7 @@ #include #include #include +#include #include /* The interface for checksum offload between the stack and networking drivers @@ -881,6 +882,15 @@ static inline struct rtable *skb_rtable(const struct sk_buff *skb) return (struct rtable *)skb_dst(skb); } +/* For mangling skb->pkt_type from user space side from applications + * such as nft, tc, etc, we only allow a conservative subset of + * possible pkt_types to be set. +*/ +static inline bool skb_pkt_type_ok(u32 ptype) +{ + return ptype <= PACKET_OTHERHOST; +} + void kfree_skb(struct sk_buff *skb); void kfree_skb_list(struct sk_buff *segs); void skb_tx_error(struct sk_buff *skb); diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 16c50b0dd426..03e5e33b5c39 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c @@ -199,13 +199,6 @@ err: } EXPORT_SYMBOL_GPL(nft_meta_get_eval); -/* don't change or set _LOOPBACK, _USER, etc. */ -static bool pkt_type_ok(u32 p) -{ - return p == PACKET_HOST || p == PACKET_BROADCAST || - p == PACKET_MULTICAST || p == PACKET_OTHERHOST; -} - void nft_meta_set_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) @@ -223,7 +216,7 @@ void nft_meta_set_eval(const struct nft_expr *expr, break; case NFT_META_PKTTYPE: if (skb->pkt_type != value && - pkt_type_ok(value) && pkt_type_ok(skb->pkt_type)) + skb_pkt_type_ok(value) && skb_pkt_type_ok(skb->pkt_type)) skb->pkt_type = value; break; case NFT_META_NFTRACE: -- cgit v1.2.3 From 7ce856aaaf13a5dc969ac5f998e5daaf1abe4cd2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 4 Jul 2016 08:23:12 +0200 Subject: mlxsw: spectrum: Add couple of lower device helper functions Add functions that iterate over lower devices and find port device. As a dependency add netdev_for_each_all_lower_dev and netdev_for_each_all_lower_dev_rcu macro with netdev_all_lower_get_next and netdev_all_lower_get_next_rcu shelpers. Also, add functions to return mlxsw struct according to lower device found and mlxsw_port struct with a reference to lower device. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 65 ++++++++++++++++++++++++-- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 3 ++ include/linux/netdevice.h | 18 +++++++ net/core/dev.c | 46 ++++++++++++++++++ 4 files changed, 127 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index f0799898817d..f54fd6ab6ec9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2567,6 +2567,66 @@ static struct mlxsw_driver mlxsw_sp_driver = { .profile = &mlxsw_sp_config_profile, }; +static bool mlxsw_sp_port_dev_check(const struct net_device *dev) +{ + return dev->netdev_ops == &mlxsw_sp_port_netdev_ops; +} + +static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev) +{ + struct net_device *lower_dev; + struct list_head *iter; + + if (mlxsw_sp_port_dev_check(dev)) + return netdev_priv(dev); + + netdev_for_each_all_lower_dev(dev, lower_dev, iter) { + if (mlxsw_sp_port_dev_check(lower_dev)) + return netdev_priv(lower_dev); + } + return NULL; +} + +static struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev) +{ + struct mlxsw_sp_port *mlxsw_sp_port; + + mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev); + return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL; +} + +static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev) +{ + struct net_device *lower_dev; + struct list_head *iter; + + if (mlxsw_sp_port_dev_check(dev)) + return netdev_priv(dev); + + netdev_for_each_all_lower_dev_rcu(dev, lower_dev, iter) { + if (mlxsw_sp_port_dev_check(lower_dev)) + return netdev_priv(lower_dev); + } + return NULL; +} + +struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev) +{ + struct mlxsw_sp_port *mlxsw_sp_port; + + rcu_read_lock(); + mlxsw_sp_port = mlxsw_sp_port_dev_lower_find_rcu(dev); + if (mlxsw_sp_port) + dev_hold(mlxsw_sp_port->dev); + rcu_read_unlock(); + return mlxsw_sp_port; +} + +void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port) +{ + dev_put(mlxsw_sp_port->dev); +} + static bool mlxsw_sp_lag_port_fid_member(struct mlxsw_sp_port *lag_port, u16 fid) { @@ -2647,11 +2707,6 @@ int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid) return mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_port, fid); } -static bool mlxsw_sp_port_dev_check(const struct net_device *dev) -{ - return dev->netdev_ops == &mlxsw_sp_port_netdev_ops; -} - static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp, struct net_device *br_dev) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 877a8793fd97..fefff255b30d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -292,6 +292,9 @@ struct mlxsw_sp_port { struct list_head vports_list; }; +struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); +void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); + static inline bool mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port) { diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7dc2ec74122a..0c6ee2c5099f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3804,12 +3804,30 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev, void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter); + #define netdev_for_each_lower_dev(dev, ldev, iter) \ for (iter = (dev)->adj_list.lower.next, \ ldev = netdev_lower_get_next(dev, &(iter)); \ ldev; \ ldev = netdev_lower_get_next(dev, &(iter))) +struct net_device *netdev_all_lower_get_next(struct net_device *dev, + struct list_head **iter); +struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev, + struct list_head **iter); + +#define netdev_for_each_all_lower_dev(dev, ldev, iter) \ + for (iter = (dev)->all_adj_list.lower.next, \ + ldev = netdev_all_lower_get_next(dev, &(iter)); \ + ldev; \ + ldev = netdev_all_lower_get_next(dev, &(iter))) + +#define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \ + for (iter = (dev)->all_adj_list.lower.next, \ + ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \ + ldev; \ + ldev = netdev_all_lower_get_next_rcu(dev, &(iter))) + void *netdev_adjacent_get_private(struct list_head *adj_list); void *netdev_lower_get_first_private_rcu(struct net_device *dev); struct net_device *netdev_master_upper_dev_get(struct net_device *dev); diff --git a/net/core/dev.c b/net/core/dev.c index aba10d2a8bc3..a4f3b0a9aeaf 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5444,6 +5444,52 @@ void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter) } EXPORT_SYMBOL(netdev_lower_get_next); +/** + * netdev_all_lower_get_next - Get the next device from all lower neighbour list + * @dev: device + * @iter: list_head ** of the current position + * + * Gets the next netdev_adjacent from the dev's all lower neighbour + * list, starting from iter position. The caller must hold RTNL lock or + * its own locking that guarantees that the neighbour all lower + * list will remain unchanged. + */ +struct net_device *netdev_all_lower_get_next(struct net_device *dev, struct list_head **iter) +{ + struct netdev_adjacent *lower; + + lower = list_entry(*iter, struct netdev_adjacent, list); + + if (&lower->list == &dev->all_adj_list.lower) + return NULL; + + *iter = lower->list.next; + + return lower->dev; +} +EXPORT_SYMBOL(netdev_all_lower_get_next); + +/** + * netdev_all_lower_get_next_rcu - Get the next device from all + * lower neighbour list, RCU variant + * @dev: device + * @iter: list_head ** of the current position + * + * Gets the next netdev_adjacent from the dev's all lower neighbour + * list, starting from iter position. The caller must hold RCU read lock. + */ +struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev, + struct list_head **iter) +{ + struct netdev_adjacent *lower; + + lower = list_first_or_null_rcu(&dev->all_adj_list.lower, + struct netdev_adjacent, list); + + return lower ? lower->dev : NULL; +} +EXPORT_SYMBOL(netdev_all_lower_get_next_rcu); + /** * netdev_lower_get_first_private_rcu - Get the first ->private from the * lower neighbour list, RCU -- cgit v1.2.3 From c5bb17302e734967822be559cf661704b707b4ed Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Mon, 4 Jul 2016 17:23:05 +0300 Subject: net/mlx5: Refactor mlx5_add_flow_rule Reduce the set of arguments passed to mlx5_add_flow_rule by introducing flow_spec structure. Signed-off-by: Maor Gottlieb Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/main.c | 21 ++--- drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 68 ++++++-------- drivers/net/ethernet/mellanox/mlx5/core/en_fs.c | 96 ++++++++------------ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 31 +++---- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 100 ++++++++------------- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 55 ++++++------ drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 22 ++--- include/linux/mlx5/fs.h | 10 ++- 8 files changed, 171 insertions(+), 232 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index b48ad85315dc..dad63f038bb8 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1528,21 +1528,18 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev, { struct mlx5_flow_table *ft = ft_prio->flow_table; struct mlx5_ib_flow_handler *handler; + struct mlx5_flow_spec *spec; void *ib_flow = flow_attr + 1; - u8 match_criteria_enable = 0; unsigned int spec_index; - u32 *match_c; - u32 *match_v; u32 action; int err = 0; if (!is_valid_attr(flow_attr)) return ERR_PTR(-EINVAL); - match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); + spec = mlx5_vzalloc(sizeof(*spec)); handler = kzalloc(sizeof(*handler), GFP_KERNEL); - if (!handler || !match_c || !match_v) { + if (!handler || !spec) { err = -ENOMEM; goto free; } @@ -1550,7 +1547,8 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev, INIT_LIST_HEAD(&handler->list); for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) { - err = parse_flow_attr(match_c, match_v, ib_flow); + err = parse_flow_attr(spec->match_criteria, + spec->match_value, ib_flow); if (err < 0) goto free; @@ -1558,11 +1556,11 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev, } /* Outer header support only */ - match_criteria_enable = (!outer_header_zero(match_c)) << 0; + spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria)) + << 0; action = dst ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST : MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO; - handler->rule = mlx5_add_flow_rule(ft, match_criteria_enable, - match_c, match_v, + handler->rule = mlx5_add_flow_rule(ft, spec, action, MLX5_FS_DEFAULT_FLOW_TAG, dst); @@ -1578,8 +1576,7 @@ static struct mlx5_ib_flow_handler *create_flow_rule(struct mlx5_ib_dev *dev, free: if (err) kfree(handler); - kfree(match_c); - kfree(match_v); + kvfree(spec); return err ? ERR_PTR(err) : handler; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index 10f18d46b8ab..a8cb38789774 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -175,15 +175,12 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv, { struct arfs_table *arfs_t = &priv->fs.arfs.arfs_tables[type]; struct mlx5_flow_destination dest; - u8 match_criteria_enable = 0; struct mlx5e_tir *tir = priv->indir_tir; - u32 *match_criteria; - u32 *match_value; + struct mlx5_flow_spec *spec; int err = 0; - match_value = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - if (!match_value || !match_criteria) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { netdev_err(priv->netdev, "%s: alloc failed\n", __func__); err = -ENOMEM; goto out; @@ -208,8 +205,7 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv, goto out; } - arfs_t->default_rule = mlx5_add_flow_rule(arfs_t->ft.t, match_criteria_enable, - match_criteria, match_value, + arfs_t->default_rule = mlx5_add_flow_rule(arfs_t->ft.t, spec, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, MLX5_FS_DEFAULT_FLOW_TAG, &dest); @@ -220,8 +216,7 @@ static int arfs_add_default_rule(struct mlx5e_priv *priv, __func__, type); } out: - kvfree(match_criteria); - kvfree(match_value); + kvfree(spec); return err; } @@ -475,23 +470,20 @@ static struct mlx5_flow_rule *arfs_add_rule(struct mlx5e_priv *priv, struct mlx5_flow_rule *rule = NULL; struct mlx5_flow_destination dest; struct arfs_table *arfs_table; - u8 match_criteria_enable = 0; + struct mlx5_flow_spec *spec; struct mlx5_flow_table *ft; - u32 *match_criteria; - u32 *match_value; int err = 0; - match_value = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - if (!match_value || !match_criteria) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { netdev_err(priv->netdev, "%s: alloc failed\n", __func__); err = -ENOMEM; goto out; } - match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - MLX5_SET_TO_ONES(fte_match_param, match_criteria, + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype); - MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ntohs(tuple->etype)); arfs_table = arfs_get_table(arfs, tuple->ip_proto, tuple->etype); if (!arfs_table) { @@ -501,59 +493,58 @@ static struct mlx5_flow_rule *arfs_add_rule(struct mlx5e_priv *priv, ft = arfs_table->ft.t; if (tuple->ip_proto == IPPROTO_TCP) { - MLX5_SET_TO_ONES(fte_match_param, match_criteria, + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.tcp_dport); - MLX5_SET_TO_ONES(fte_match_param, match_criteria, + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.tcp_sport); - MLX5_SET(fte_match_param, match_value, outer_headers.tcp_dport, + MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_dport, ntohs(tuple->dst_port)); - MLX5_SET(fte_match_param, match_value, outer_headers.tcp_sport, + MLX5_SET(fte_match_param, spec->match_value, outer_headers.tcp_sport, ntohs(tuple->src_port)); } else { - MLX5_SET_TO_ONES(fte_match_param, match_criteria, + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.udp_dport); - MLX5_SET_TO_ONES(fte_match_param, match_criteria, + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.udp_sport); - MLX5_SET(fte_match_param, match_value, outer_headers.udp_dport, + MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_dport, ntohs(tuple->dst_port)); - MLX5_SET(fte_match_param, match_value, outer_headers.udp_sport, + MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_sport, ntohs(tuple->src_port)); } if (tuple->etype == htons(ETH_P_IP)) { - memcpy(MLX5_ADDR_OF(fte_match_param, match_value, + memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4), &tuple->src_ipv4, 4); - memcpy(MLX5_ADDR_OF(fte_match_param, match_value, + memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4), &tuple->dst_ipv4, 4); - MLX5_SET_TO_ONES(fte_match_param, match_criteria, + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4); - MLX5_SET_TO_ONES(fte_match_param, match_criteria, + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4); } else { - memcpy(MLX5_ADDR_OF(fte_match_param, match_value, + memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), &tuple->src_ipv6, 16); - memcpy(MLX5_ADDR_OF(fte_match_param, match_value, + memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), &tuple->dst_ipv6, 16); - memset(MLX5_ADDR_OF(fte_match_param, match_criteria, + memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6), 0xff, 16); - memset(MLX5_ADDR_OF(fte_match_param, match_criteria, + memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6), 0xff, 16); } dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; dest.tir_num = priv->direct_tir[arfs_rule->rxq].tirn; - rule = mlx5_add_flow_rule(ft, match_criteria_enable, match_criteria, - match_value, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, + rule = mlx5_add_flow_rule(ft, spec, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, MLX5_FS_DEFAULT_FLOW_TAG, &dest); if (IS_ERR(rule)) { @@ -563,8 +554,7 @@ static struct mlx5_flow_rule *arfs_add_rule(struct mlx5e_priv *priv, } out: - kvfree(match_criteria); - kvfree(match_value); + kvfree(spec); return err ? ERR_PTR(err) : rule; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c index 606e69b4babc..2e1e86316fe7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c @@ -156,19 +156,18 @@ enum mlx5e_vlan_rule_type { static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, enum mlx5e_vlan_rule_type rule_type, - u16 vid, u32 *mc, u32 *mv) + u16 vid, struct mlx5_flow_spec *spec) { struct mlx5_flow_table *ft = priv->fs.vlan.ft.t; struct mlx5_flow_destination dest; - u8 match_criteria_enable = 0; struct mlx5_flow_rule **rule_p; int err = 0; dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; dest.ft = priv->fs.l2.ft.t; - match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.vlan_tag); + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.vlan_tag); switch (rule_type) { case MLX5E_VLAN_RULE_TYPE_UNTAGGED: @@ -176,17 +175,19 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, break; case MLX5E_VLAN_RULE_TYPE_ANY_VID: rule_p = &priv->fs.vlan.any_vlan_rule; - MLX5_SET(fte_match_param, mv, outer_headers.vlan_tag, 1); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.vlan_tag, 1); break; default: /* MLX5E_VLAN_RULE_TYPE_MATCH_VID */ rule_p = &priv->fs.vlan.active_vlans_rule[vid]; - MLX5_SET(fte_match_param, mv, outer_headers.vlan_tag, 1); - MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.first_vid); - MLX5_SET(fte_match_param, mv, outer_headers.first_vid, vid); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.vlan_tag, 1); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, + outer_headers.first_vid); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, + vid); break; } - *rule_p = mlx5_add_flow_rule(ft, match_criteria_enable, mc, mv, + *rule_p = mlx5_add_flow_rule(ft, spec, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, MLX5_FS_DEFAULT_FLOW_TAG, &dest); @@ -203,27 +204,21 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_priv *priv, static int mlx5e_add_vlan_rule(struct mlx5e_priv *priv, enum mlx5e_vlan_rule_type rule_type, u16 vid) { - u32 *match_criteria; - u32 *match_value; + struct mlx5_flow_spec *spec; int err = 0; - match_value = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - if (!match_value || !match_criteria) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { netdev_err(priv->netdev, "%s: alloc failed\n", __func__); - err = -ENOMEM; - goto add_vlan_rule_out; + return -ENOMEM; } if (rule_type == MLX5E_VLAN_RULE_TYPE_MATCH_VID) mlx5e_vport_context_update_vlans(priv); - err = __mlx5e_add_vlan_rule(priv, rule_type, vid, match_criteria, - match_value); + err = __mlx5e_add_vlan_rule(priv, rule_type, vid, spec); -add_vlan_rule_out: - kvfree(match_criteria); - kvfree(match_value); + kvfree(spec); return err; } @@ -598,32 +593,27 @@ static struct mlx5_flow_rule *mlx5e_generate_ttc_rule(struct mlx5e_priv *priv, u8 proto) { struct mlx5_flow_rule *rule; - u8 match_criteria_enable = 0; - u32 *match_criteria; - u32 *match_value; + struct mlx5_flow_spec *spec; int err = 0; - match_value = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - if (!match_value || !match_criteria) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { netdev_err(priv->netdev, "%s: alloc failed\n", __func__); - err = -ENOMEM; - goto out; + return ERR_PTR(-ENOMEM); } if (proto) { - match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.ip_protocol); - MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, proto); + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, proto); } if (etype) { - match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.ethertype); - MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, etype); + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, etype); } - rule = mlx5_add_flow_rule(ft, match_criteria_enable, - match_criteria, match_value, + rule = mlx5_add_flow_rule(ft, spec, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, MLX5_FS_DEFAULT_FLOW_TAG, dest); @@ -631,9 +621,8 @@ static struct mlx5_flow_rule *mlx5e_generate_ttc_rule(struct mlx5e_priv *priv, err = PTR_ERR(rule); netdev_err(priv->netdev, "%s: add rule failed\n", __func__); } -out: - kvfree(match_criteria); - kvfree(match_value); + + kvfree(spec); return err ? ERR_PTR(err) : rule; } @@ -792,24 +781,20 @@ static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, { struct mlx5_flow_table *ft = priv->fs.l2.ft.t; struct mlx5_flow_destination dest; - u8 match_criteria_enable = 0; - u32 *match_criteria; - u32 *match_value; + struct mlx5_flow_spec *spec; int err = 0; u8 *mc_dmac; u8 *mv_dmac; - match_value = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param)); - if (!match_value || !match_criteria) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { netdev_err(priv->netdev, "%s: alloc failed\n", __func__); - err = -ENOMEM; - goto add_l2_rule_out; + return -ENOMEM; } - mc_dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, + mc_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers.dmac_47_16); - mv_dmac = MLX5_ADDR_OF(fte_match_param, match_value, + mv_dmac = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.dmac_47_16); dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; @@ -817,13 +802,13 @@ static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, switch (type) { case MLX5E_FULLMATCH: - match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; eth_broadcast_addr(mc_dmac); ether_addr_copy(mv_dmac, ai->addr); break; case MLX5E_ALLMULTI: - match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; mc_dmac[0] = 0x01; mv_dmac[0] = 0x01; break; @@ -832,8 +817,7 @@ static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, break; } - ai->rule = mlx5_add_flow_rule(ft, match_criteria_enable, match_criteria, - match_value, + ai->rule = mlx5_add_flow_rule(ft, spec, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, MLX5_FS_DEFAULT_FLOW_TAG, &dest); if (IS_ERR(ai->rule)) { @@ -843,9 +827,7 @@ static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv, ai->rule = NULL; } -add_l2_rule_out: - kvfree(match_criteria); - kvfree(match_value); + kvfree(spec); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 704c3d30493e..3261e8b1286e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -50,7 +50,7 @@ struct mlx5e_tc_flow { #define MLX5E_TC_TABLE_NUM_GROUPS 4 static struct mlx5_flow_rule *mlx5e_tc_add_flow(struct mlx5e_priv *priv, - u32 *match_c, u32 *match_v, + struct mlx5_flow_spec *spec, u32 action, u32 flow_tag) { struct mlx5_core_dev *dev = priv->mdev; @@ -88,8 +88,8 @@ static struct mlx5_flow_rule *mlx5e_tc_add_flow(struct mlx5e_priv *priv, table_created = true; } - rule = mlx5_add_flow_rule(priv->fs.tc.t, MLX5_MATCH_OUTER_HEADERS, - match_c, match_v, + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + rule = mlx5_add_flow_rule(priv->fs.tc.t, spec, action, flow_tag, &dest); @@ -126,12 +126,13 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, } } -static int parse_cls_flower(struct mlx5e_priv *priv, - u32 *match_c, u32 *match_v, +static int parse_cls_flower(struct mlx5e_priv *priv, struct mlx5_flow_spec *spec, struct tc_cls_flower_offload *f) { - void *headers_c = MLX5_ADDR_OF(fte_match_param, match_c, outer_headers); - void *headers_v = MLX5_ADDR_OF(fte_match_param, match_v, outer_headers); + void *headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, + outer_headers); + void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, + outer_headers); u16 addr_type = 0; u8 ip_proto = 0; @@ -342,12 +343,11 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, struct tc_cls_flower_offload *f) { struct mlx5e_tc_table *tc = &priv->fs.tc; - u32 *match_c; - u32 *match_v; int err = 0; u32 flow_tag; u32 action; struct mlx5e_tc_flow *flow; + struct mlx5_flow_spec *spec; struct mlx5_flow_rule *old = NULL; flow = rhashtable_lookup_fast(&tc->ht, &f->cookie, @@ -357,16 +357,15 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, else flow = kzalloc(sizeof(*flow), GFP_KERNEL); - match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - if (!match_c || !match_v || !flow) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec || !flow) { err = -ENOMEM; goto err_free; } flow->cookie = f->cookie; - err = parse_cls_flower(priv, match_c, match_v, f); + err = parse_cls_flower(priv, spec, f); if (err < 0) goto err_free; @@ -379,8 +378,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, if (err) goto err_free; - flow->rule = mlx5e_tc_add_flow(priv, match_c, match_v, action, - flow_tag); + flow->rule = mlx5e_tc_add_flow(priv, spec, action, flow_tag); if (IS_ERR(flow->rule)) { err = PTR_ERR(flow->rule); goto err_hash_del; @@ -398,8 +396,7 @@ err_free: if (!old) kfree(flow); out: - kfree(match_c); - kfree(match_v); + kvfree(spec); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index f0a973557f7b..f6d667797ee1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -329,25 +329,23 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule, MLX5_MATCH_OUTER_HEADERS); struct mlx5_flow_rule *flow_rule = NULL; struct mlx5_flow_destination dest; + struct mlx5_flow_spec *spec; void *mv_misc = NULL; void *mc_misc = NULL; u8 *dmac_v = NULL; u8 *dmac_c = NULL; - u32 *match_v; - u32 *match_c; if (rx_rule) match_header |= MLX5_MATCH_MISC_PARAMETERS; - match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - if (!match_v || !match_c) { + + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { pr_warn("FDB: Failed to alloc match parameters\n"); - goto out; + return NULL; } - - dmac_v = MLX5_ADDR_OF(fte_match_param, match_v, + dmac_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.dmac_47_16); - dmac_c = MLX5_ADDR_OF(fte_match_param, match_c, + dmac_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers.dmac_47_16); if (match_header & MLX5_MATCH_OUTER_HEADERS) { @@ -356,8 +354,10 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule, } if (match_header & MLX5_MATCH_MISC_PARAMETERS) { - mv_misc = MLX5_ADDR_OF(fte_match_param, match_v, misc_parameters); - mc_misc = MLX5_ADDR_OF(fte_match_param, match_c, misc_parameters); + mv_misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, + misc_parameters); + mc_misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, + misc_parameters); MLX5_SET(fte_match_set_misc, mv_misc, source_port, UPLINK_VPORT); MLX5_SET_TO_ONES(fte_match_set_misc, mc_misc, source_port); } @@ -368,11 +368,9 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule, esw_debug(esw->dev, "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n", dmac_v, dmac_c, vport); + spec->match_criteria_enable = match_header; flow_rule = - mlx5_add_flow_rule(esw->fdb_table.fdb, - match_header, - match_c, - match_v, + mlx5_add_flow_rule(esw->fdb_table.fdb, spec, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, 0, &dest); if (IS_ERR(flow_rule)) { @@ -381,9 +379,8 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule, dmac_v, dmac_c, vport, PTR_ERR(flow_rule)); flow_rule = NULL; } -out: - kfree(match_v); - kfree(match_c); + + kvfree(spec); return flow_rule; } @@ -1293,9 +1290,8 @@ static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, static int esw_vport_ingress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { + struct mlx5_flow_spec *spec; u8 smac[ETH_ALEN]; - u32 *match_v; - u32 *match_c; int err = 0; u8 *smac_v; @@ -1329,9 +1325,8 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n", vport->vport, vport->vlan, vport->qos); - match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - if (!match_v || !match_c) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { err = -ENOMEM; esw_warn(esw->dev, "vport[%d] configure ingress rules failed, err(%d)\n", vport->vport, err); @@ -1339,22 +1334,20 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, } if (vport->vlan || vport->qos) - MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.vlan_tag); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.vlan_tag); if (vport->spoofchk) { - MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.smac_47_16); - MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.smac_15_0); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_47_16); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_15_0); smac_v = MLX5_ADDR_OF(fte_match_param, - match_v, + spec->match_value, outer_headers.smac_47_16); ether_addr_copy(smac_v, smac); } + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; vport->ingress.allow_rule = - mlx5_add_flow_rule(vport->ingress.acl, - MLX5_MATCH_OUTER_HEADERS, - match_c, - match_v, + mlx5_add_flow_rule(vport->ingress.acl, spec, MLX5_FLOW_CONTEXT_ACTION_ALLOW, 0, NULL); if (IS_ERR(vport->ingress.allow_rule)) { @@ -1365,13 +1358,9 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, goto out; } - memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param)); - memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param)); + memset(spec, 0, sizeof(*spec)); vport->ingress.drop_rule = - mlx5_add_flow_rule(vport->ingress.acl, - 0, - match_c, - match_v, + mlx5_add_flow_rule(vport->ingress.acl, spec, MLX5_FLOW_CONTEXT_ACTION_DROP, 0, NULL); if (IS_ERR(vport->ingress.drop_rule)) { @@ -1385,17 +1374,14 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, out: if (err) esw_vport_cleanup_ingress_rules(esw, vport); - - kfree(match_v); - kfree(match_c); + kvfree(spec); return err; } static int esw_vport_egress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - u32 *match_v; - u32 *match_c; + struct mlx5_flow_spec *spec; int err = 0; esw_vport_cleanup_egress_rules(esw, vport); @@ -1411,9 +1397,8 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", vport->vport, vport->vlan, vport->qos); - match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - if (!match_v || !match_c) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { err = -ENOMEM; esw_warn(esw->dev, "vport[%d] configure egress rules failed, err(%d)\n", vport->vport, err); @@ -1421,16 +1406,14 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, } /* Allowed vlan rule */ - MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.vlan_tag); - MLX5_SET_TO_ONES(fte_match_param, match_v, outer_headers.vlan_tag); - MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.first_vid); - MLX5_SET(fte_match_param, match_v, outer_headers.first_vid, vport->vlan); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.vlan_tag); + MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.vlan_tag); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vport->vlan); + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; vport->egress.allowed_vlan = - mlx5_add_flow_rule(vport->egress.acl, - MLX5_MATCH_OUTER_HEADERS, - match_c, - match_v, + mlx5_add_flow_rule(vport->egress.acl, spec, MLX5_FLOW_CONTEXT_ACTION_ALLOW, 0, NULL); if (IS_ERR(vport->egress.allowed_vlan)) { @@ -1442,13 +1425,9 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, } /* Drop others rule (star rule) */ - memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param)); - memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param)); + memset(spec, 0, sizeof(*spec)); vport->egress.drop_rule = - mlx5_add_flow_rule(vport->egress.acl, - 0, - match_c, - match_v, + mlx5_add_flow_rule(vport->egress.acl, spec, MLX5_FLOW_CONTEXT_ACTION_DROP, 0, NULL); if (IS_ERR(vport->egress.drop_rule)) { @@ -1458,8 +1437,7 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, vport->egress.drop_rule = NULL; } out: - kfree(match_v); - kfree(match_c); + kvfree(spec); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index ed8ad988f07a..1842dfb4636b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -43,37 +43,35 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn { struct mlx5_flow_destination dest; struct mlx5_flow_rule *flow_rule; - int match_header = MLX5_MATCH_MISC_PARAMETERS; - u32 *match_v, *match_c; + struct mlx5_flow_spec *spec; void *misc; - match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - if (!match_v || !match_c) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { esw_warn(esw->dev, "FDB: Failed to alloc match parameters\n"); flow_rule = ERR_PTR(-ENOMEM); goto out; } - misc = MLX5_ADDR_OF(fte_match_param, match_v, misc_parameters); + misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn); MLX5_SET(fte_match_set_misc, misc, source_port, 0x0); /* source vport is 0 */ - misc = MLX5_ADDR_OF(fte_match_param, match_c, misc_parameters); + misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn); MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); + spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS; dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT; dest.vport_num = vport; - flow_rule = mlx5_add_flow_rule(esw->fdb_table.fdb, match_header, match_c, - match_v, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, + flow_rule = mlx5_add_flow_rule(esw->fdb_table.fdb, spec, + MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, 0, &dest); if (IS_ERR(flow_rule)) esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule)); out: - kfree(match_v); - kfree(match_c); + kvfree(spec); return flow_rule; } @@ -138,12 +136,11 @@ static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw) { struct mlx5_flow_destination dest; struct mlx5_flow_rule *flow_rule = NULL; - u32 *match_v, *match_c; + struct mlx5_flow_spec *spec; int err = 0; - match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - if (!match_v || !match_c) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { esw_warn(esw->dev, "FDB: Failed to alloc match parameters\n"); err = -ENOMEM; goto out; @@ -152,8 +149,9 @@ static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw) dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT; dest.vport_num = 0; - flow_rule = mlx5_add_flow_rule(esw->fdb_table.fdb, 0, match_c, match_v, - MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, 0, &dest); + flow_rule = mlx5_add_flow_rule(esw->fdb_table.fdb, spec, + MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, + 0, &dest); if (IS_ERR(flow_rule)) { err = PTR_ERR(flow_rule); esw_warn(esw->dev, "FDB: Failed to add miss flow rule err %d\n", err); @@ -162,8 +160,7 @@ static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw) esw->fdb_table.offloads.miss_rule = flow_rule; out: - kfree(match_v); - kfree(match_c); + kvfree(spec); return err; } @@ -351,29 +348,28 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn) { struct mlx5_flow_destination dest; struct mlx5_flow_rule *flow_rule; - int match_header = MLX5_MATCH_MISC_PARAMETERS; - u32 *match_v, *match_c; + struct mlx5_flow_spec *spec; void *misc; - match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - if (!match_v || !match_c) { + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) { esw_warn(esw->dev, "Failed to alloc match parameters\n"); flow_rule = ERR_PTR(-ENOMEM); goto out; } - misc = MLX5_ADDR_OF(fte_match_param, match_v, misc_parameters); + misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); MLX5_SET(fte_match_set_misc, misc, source_port, vport); - misc = MLX5_ADDR_OF(fte_match_param, match_c, misc_parameters); + misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); + spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS; dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR; dest.tir_num = tirn; - flow_rule = mlx5_add_flow_rule(esw->offloads.ft_offloads, match_header, match_c, - match_v, MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, + flow_rule = mlx5_add_flow_rule(esw->offloads.ft_offloads, spec, + MLX5_FLOW_CONTEXT_ACTION_FWD_DEST, 0, &dest); if (IS_ERR(flow_rule)) { esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule)); @@ -381,8 +377,7 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn) } out: - kfree(match_v); - kfree(match_c); + kvfree(spec); return flow_rule; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index b0401104afb9..7fcdae1cf053 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1160,9 +1160,7 @@ static bool dest_is_valid(struct mlx5_flow_destination *dest, static struct mlx5_flow_rule * _mlx5_add_flow_rule(struct mlx5_flow_table *ft, - u8 match_criteria_enable, - u32 *match_criteria, - u32 *match_value, + struct mlx5_flow_spec *spec, u32 action, u32 flow_tag, struct mlx5_flow_destination *dest) @@ -1176,22 +1174,23 @@ _mlx5_add_flow_rule(struct mlx5_flow_table *ft, nested_lock_ref_node(&ft->node, FS_MUTEX_GRANDPARENT); fs_for_each_fg(g, ft) if (compare_match_criteria(g->mask.match_criteria_enable, - match_criteria_enable, + spec->match_criteria_enable, g->mask.match_criteria, - match_criteria)) { - rule = add_rule_fg(g, match_value, + spec->match_criteria)) { + rule = add_rule_fg(g, spec->match_value, action, flow_tag, dest); if (!IS_ERR(rule) || PTR_ERR(rule) != -ENOSPC) goto unlock; } - g = create_autogroup(ft, match_criteria_enable, match_criteria); + g = create_autogroup(ft, spec->match_criteria_enable, + spec->match_criteria); if (IS_ERR(g)) { rule = (void *)g; goto unlock; } - rule = add_rule_fg(g, match_value, + rule = add_rule_fg(g, spec->match_value, action, flow_tag, dest); if (IS_ERR(rule)) { /* Remove assumes refcount > 0 and autogroup creates a group @@ -1215,9 +1214,7 @@ static bool fwd_next_prio_supported(struct mlx5_flow_table *ft) struct mlx5_flow_rule * mlx5_add_flow_rule(struct mlx5_flow_table *ft, - u8 match_criteria_enable, - u32 *match_criteria, - u32 *match_value, + struct mlx5_flow_spec *spec, u32 action, u32 flow_tag, struct mlx5_flow_destination *dest) @@ -1248,8 +1245,7 @@ mlx5_add_flow_rule(struct mlx5_flow_table *ft, } } - rule = _mlx5_add_flow_rule(ft, match_criteria_enable, match_criteria, - match_value, action, flow_tag, dest); + rule = _mlx5_add_flow_rule(ft, spec, action, flow_tag, dest); if (sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) { if (!IS_ERR_OR_NULL(rule) && diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 6ad111938709..d22fe7e5a39a 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -68,6 +68,12 @@ struct mlx5_flow_group; struct mlx5_flow_rule; struct mlx5_flow_namespace; +struct mlx5_flow_spec { + u8 match_criteria_enable; + u32 match_criteria[MLX5_ST_SZ_DW(fte_match_param)]; + u32 match_value[MLX5_ST_SZ_DW(fte_match_param)]; +}; + struct mlx5_flow_destination { enum mlx5_flow_destination_type type; union { @@ -116,9 +122,7 @@ void mlx5_destroy_flow_group(struct mlx5_flow_group *fg); */ struct mlx5_flow_rule * mlx5_add_flow_rule(struct mlx5_flow_table *ft, - u8 match_criteria_enable, - u32 *match_criteria, - u32 *match_value, + struct mlx5_flow_spec *spec, u32 action, u32 flow_tag, struct mlx5_flow_destination *dest); -- cgit v1.2.3 From fba53f7b571925b8a0d59d460ad6de1fda928a3e Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Mon, 4 Jul 2016 17:23:06 +0300 Subject: net/mlx5: Introduce mlx5_flow_steering structure Instead of having all steering private name spaces and steering module fields flat in mlx5_core_priv, we wrap them in mlx5_flow_steering for better modularity and API exposure. Signed-off-by: Maor Gottlieb Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 134 ++++++++++++---------- drivers/net/ethernet/mellanox/mlx5/core/fs_core.h | 8 ++ include/linux/mlx5/driver.h | 6 +- 3 files changed, 84 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 7fcdae1cf053..0f969cb2291a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1363,12 +1363,13 @@ void mlx5_destroy_flow_group(struct mlx5_flow_group *fg) struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, enum mlx5_flow_namespace_type type) { - struct mlx5_flow_root_namespace *root_ns = dev->priv.root_ns; + struct mlx5_flow_steering *steering = dev->priv.steering; + struct mlx5_flow_root_namespace *root_ns; int prio; struct fs_prio *fs_prio; struct mlx5_flow_namespace *ns; - if (!root_ns) + if (!steering) return NULL; switch (type) { @@ -1380,24 +1381,28 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, prio = type; break; case MLX5_FLOW_NAMESPACE_FDB: - if (dev->priv.fdb_root_ns) - return &dev->priv.fdb_root_ns->ns; + if (steering->fdb_root_ns) + return &steering->fdb_root_ns->ns; else return NULL; case MLX5_FLOW_NAMESPACE_ESW_EGRESS: - if (dev->priv.esw_egress_root_ns) - return &dev->priv.esw_egress_root_ns->ns; + if (steering->esw_egress_root_ns) + return &steering->esw_egress_root_ns->ns; else return NULL; case MLX5_FLOW_NAMESPACE_ESW_INGRESS: - if (dev->priv.esw_ingress_root_ns) - return &dev->priv.esw_ingress_root_ns->ns; + if (steering->esw_ingress_root_ns) + return &steering->esw_ingress_root_ns->ns; else return NULL; default: return NULL; } + root_ns = steering->root_ns; + if (!root_ns) + return NULL; + fs_prio = find_prio(&root_ns->ns, prio); if (!fs_prio) return NULL; @@ -1483,13 +1488,13 @@ static bool has_required_caps(struct mlx5_core_dev *dev, struct node_caps *caps) return true; } -static int init_root_tree_recursive(struct mlx5_core_dev *dev, +static int init_root_tree_recursive(struct mlx5_flow_steering *steering, struct init_tree_node *init_node, struct fs_node *fs_parent_node, struct init_tree_node *init_parent_node, int prio) { - int max_ft_level = MLX5_CAP_FLOWTABLE(dev, + int max_ft_level = MLX5_CAP_FLOWTABLE(steering->dev, flow_table_properties_nic_receive. max_ft_level); struct mlx5_flow_namespace *fs_ns; @@ -1500,7 +1505,7 @@ static int init_root_tree_recursive(struct mlx5_core_dev *dev, if (init_node->type == FS_TYPE_PRIO) { if ((init_node->min_ft_level > max_ft_level) || - !has_required_caps(dev, &init_node->caps)) + !has_required_caps(steering->dev, &init_node->caps)) return 0; fs_get_obj(fs_ns, fs_parent_node); @@ -1521,7 +1526,7 @@ static int init_root_tree_recursive(struct mlx5_core_dev *dev, } prio = 0; for (i = 0; i < init_node->ar_size; i++) { - err = init_root_tree_recursive(dev, &init_node->children[i], + err = init_root_tree_recursive(steering, &init_node->children[i], base, init_node, prio); if (err) return err; @@ -1534,7 +1539,7 @@ static int init_root_tree_recursive(struct mlx5_core_dev *dev, return 0; } -static int init_root_tree(struct mlx5_core_dev *dev, +static int init_root_tree(struct mlx5_flow_steering *steering, struct init_tree_node *init_node, struct fs_node *fs_parent_node) { @@ -1544,7 +1549,7 @@ static int init_root_tree(struct mlx5_core_dev *dev, fs_get_obj(fs_ns, fs_parent_node); for (i = 0; i < init_node->ar_size; i++) { - err = init_root_tree_recursive(dev, &init_node->children[i], + err = init_root_tree_recursive(steering, &init_node->children[i], &fs_ns->node, init_node, i); if (err) @@ -1553,7 +1558,7 @@ static int init_root_tree(struct mlx5_core_dev *dev, return 0; } -static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_core_dev *dev, +static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_flow_steering *steering, enum fs_flow_table_type table_type) { @@ -1565,7 +1570,7 @@ static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_core_dev *dev if (!root_ns) return NULL; - root_ns->dev = dev; + root_ns->dev = steering->dev; root_ns->table_type = table_type; ns = &root_ns->ns; @@ -1620,46 +1625,45 @@ static void set_prio_attrs(struct mlx5_flow_root_namespace *root_ns) #define ANCHOR_PRIO 0 #define ANCHOR_SIZE 1 #define ANCHOR_LEVEL 0 -static int create_anchor_flow_table(struct mlx5_core_dev - *dev) +static int create_anchor_flow_table(struct mlx5_flow_steering *steering) { struct mlx5_flow_namespace *ns = NULL; struct mlx5_flow_table *ft; - ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ANCHOR); + ns = mlx5_get_flow_namespace(steering->dev, MLX5_FLOW_NAMESPACE_ANCHOR); if (!ns) return -EINVAL; ft = mlx5_create_flow_table(ns, ANCHOR_PRIO, ANCHOR_SIZE, ANCHOR_LEVEL); if (IS_ERR(ft)) { - mlx5_core_err(dev, "Failed to create last anchor flow table"); + mlx5_core_err(steering->dev, "Failed to create last anchor flow table"); return PTR_ERR(ft); } return 0; } -static int init_root_ns(struct mlx5_core_dev *dev) +static int init_root_ns(struct mlx5_flow_steering *steering) { - dev->priv.root_ns = create_root_ns(dev, FS_FT_NIC_RX); - if (IS_ERR_OR_NULL(dev->priv.root_ns)) + steering->root_ns = create_root_ns(steering, FS_FT_NIC_RX); + if (IS_ERR_OR_NULL(steering->root_ns)) goto cleanup; - if (init_root_tree(dev, &root_fs, &dev->priv.root_ns->ns.node)) + if (init_root_tree(steering, &root_fs, &steering->root_ns->ns.node)) goto cleanup; - set_prio_attrs(dev->priv.root_ns); + set_prio_attrs(steering->root_ns); - if (create_anchor_flow_table(dev)) + if (create_anchor_flow_table(steering)) goto cleanup; return 0; cleanup: - mlx5_cleanup_fs(dev); + mlx5_cleanup_fs(steering->dev); return -ENOMEM; } -static void cleanup_single_prio_root_ns(struct mlx5_core_dev *dev, +static void cleanup_single_prio_root_ns(struct mlx5_flow_steering *steering, struct mlx5_flow_root_namespace *root_ns) { struct fs_node *prio; @@ -1672,11 +1676,11 @@ static void cleanup_single_prio_root_ns(struct mlx5_core_dev *dev, struct fs_node, list); if (tree_remove_node(prio)) - mlx5_core_warn(dev, + mlx5_core_warn(steering->dev, "Flow steering priority wasn't destroyed, refcount > 1\n"); } if (tree_remove_node(&root_ns->ns.node)) - mlx5_core_warn(dev, + mlx5_core_warn(steering->dev, "Flow steering namespace wasn't destroyed, refcount > 1\n"); root_ns = NULL; } @@ -1690,12 +1694,12 @@ static void destroy_flow_tables(struct fs_prio *prio) mlx5_destroy_flow_table(iter); } -static void cleanup_root_ns(struct mlx5_core_dev *dev) +static void cleanup_root_ns(struct mlx5_flow_steering *steering) { - struct mlx5_flow_root_namespace *root_ns = dev->priv.root_ns; + struct mlx5_flow_root_namespace *root_ns = steering->root_ns; struct fs_prio *iter_prio; - if (!MLX5_CAP_GEN(dev, nic_flow_table)) + if (!MLX5_CAP_GEN(steering->dev, nic_flow_table)) return; if (!root_ns) @@ -1720,7 +1724,7 @@ static void cleanup_root_ns(struct mlx5_core_dev *dev) fs_get_obj(obj_iter_prio2, iter_prio2); destroy_flow_tables(obj_iter_prio2); if (tree_remove_node(iter_prio2)) { - mlx5_core_warn(dev, + mlx5_core_warn(steering->dev, "Priority %d wasn't destroyed, refcount > 1\n", obj_iter_prio2->prio); return; @@ -1737,7 +1741,7 @@ static void cleanup_root_ns(struct mlx5_core_dev *dev) struct fs_node, list); if (tree_remove_node(iter_ns)) { - mlx5_core_warn(dev, + mlx5_core_warn(steering->dev, "Namespace wasn't destroyed, refcount > 1\n"); return; } @@ -1754,7 +1758,7 @@ static void cleanup_root_ns(struct mlx5_core_dev *dev) fs_get_obj(obj_prio_node, prio_node); if (tree_remove_node(prio_node)) { - mlx5_core_warn(dev, + mlx5_core_warn(steering->dev, "Priority %d wasn't destroyed, refcount > 1\n", obj_prio_node->prio); return; @@ -1762,70 +1766,75 @@ static void cleanup_root_ns(struct mlx5_core_dev *dev) } if (tree_remove_node(&root_ns->ns.node)) { - mlx5_core_warn(dev, + mlx5_core_warn(steering->dev, "root namespace wasn't destroyed, refcount > 1\n"); return; } - dev->priv.root_ns = NULL; + steering->root_ns = NULL; } void mlx5_cleanup_fs(struct mlx5_core_dev *dev) { + struct mlx5_flow_steering *steering = dev->priv.steering; + if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) return; - cleanup_root_ns(dev); - cleanup_single_prio_root_ns(dev, dev->priv.fdb_root_ns); - cleanup_single_prio_root_ns(dev, dev->priv.esw_egress_root_ns); - cleanup_single_prio_root_ns(dev, dev->priv.esw_ingress_root_ns); + cleanup_root_ns(steering); + cleanup_single_prio_root_ns(steering, steering->esw_egress_root_ns); + cleanup_single_prio_root_ns(steering, steering->esw_ingress_root_ns); + cleanup_single_prio_root_ns(steering, steering->fdb_root_ns); mlx5_cleanup_fc_stats(dev); + kfree(steering); } -static int init_fdb_root_ns(struct mlx5_core_dev *dev) +static int init_fdb_root_ns(struct mlx5_flow_steering *steering) { struct fs_prio *prio; - dev->priv.fdb_root_ns = create_root_ns(dev, FS_FT_FDB); - if (!dev->priv.fdb_root_ns) + steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB); + if (!steering->fdb_root_ns) return -ENOMEM; /* Create single prio */ - prio = fs_create_prio(&dev->priv.fdb_root_ns->ns, 0, 1); + prio = fs_create_prio(&steering->fdb_root_ns->ns, 0, 1); if (IS_ERR(prio)) { - cleanup_single_prio_root_ns(dev, dev->priv.fdb_root_ns); + cleanup_single_prio_root_ns(steering, steering->fdb_root_ns); return PTR_ERR(prio); } else { return 0; } } -static int init_egress_acl_root_ns(struct mlx5_core_dev *dev) +static int init_ingress_acl_root_ns(struct mlx5_flow_steering *steering) { struct fs_prio *prio; - dev->priv.esw_egress_root_ns = create_root_ns(dev, FS_FT_ESW_EGRESS_ACL); - if (!dev->priv.esw_egress_root_ns) + steering->esw_egress_root_ns = create_root_ns(steering, FS_FT_ESW_EGRESS_ACL); + if (!steering->esw_egress_root_ns) return -ENOMEM; /* create 1 prio*/ - prio = fs_create_prio(&dev->priv.esw_egress_root_ns->ns, 0, MLX5_TOTAL_VPORTS(dev)); + prio = fs_create_prio(&steering->esw_egress_root_ns->ns, 0, + MLX5_TOTAL_VPORTS(steering->dev)); if (IS_ERR(prio)) return PTR_ERR(prio); else return 0; } -static int init_ingress_acl_root_ns(struct mlx5_core_dev *dev) +static int init_egress_acl_root_ns(struct mlx5_flow_steering *steering) { struct fs_prio *prio; - dev->priv.esw_ingress_root_ns = create_root_ns(dev, FS_FT_ESW_INGRESS_ACL); - if (!dev->priv.esw_ingress_root_ns) + steering->esw_ingress_root_ns = create_root_ns(steering, FS_FT_ESW_INGRESS_ACL); + if (!steering->esw_ingress_root_ns) return -ENOMEM; /* create 1 prio*/ - prio = fs_create_prio(&dev->priv.esw_ingress_root_ns->ns, 0, MLX5_TOTAL_VPORTS(dev)); + prio = fs_create_prio(&steering->esw_ingress_root_ns->ns, 0, + MLX5_TOTAL_VPORTS(steering->dev)); if (IS_ERR(prio)) return PTR_ERR(prio); else @@ -1834,6 +1843,7 @@ static int init_ingress_acl_root_ns(struct mlx5_core_dev *dev) int mlx5_init_fs(struct mlx5_core_dev *dev) { + struct mlx5_flow_steering *steering; int err = 0; if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) @@ -1843,26 +1853,32 @@ int mlx5_init_fs(struct mlx5_core_dev *dev) if (err) return err; + steering = kzalloc(sizeof(*steering), GFP_KERNEL); + if (!steering) + return -ENOMEM; + steering->dev = dev; + dev->priv.steering = steering; + if (MLX5_CAP_GEN(dev, nic_flow_table) && MLX5_CAP_FLOWTABLE_NIC_RX(dev, ft_support)) { - err = init_root_ns(dev); + err = init_root_ns(steering); if (err) goto err; } if (MLX5_CAP_GEN(dev, eswitch_flow_table)) { if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, ft_support)) { - err = init_fdb_root_ns(dev); + err = init_fdb_root_ns(steering); if (err) goto err; } if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) { - err = init_egress_acl_root_ns(dev); + err = init_egress_acl_root_ns(steering); if (err) goto err; } if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) { - err = init_ingress_acl_root_ns(dev); + err = init_ingress_acl_root_ns(steering); if (err) goto err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index aa41a7314691..d7ba91a1eea2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -55,6 +55,14 @@ enum fs_fte_status { FS_FTE_STATUS_EXISTING = 1UL << 0, }; +struct mlx5_flow_steering { + struct mlx5_core_dev *dev; + struct mlx5_flow_root_namespace *root_ns; + struct mlx5_flow_root_namespace *fdb_root_ns; + struct mlx5_flow_root_namespace *esw_egress_root_ns; + struct mlx5_flow_root_namespace *esw_ingress_root_ns; +}; + struct fs_node { struct list_head list; struct list_head children; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index e22b3456b2ee..f21c45941887 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -550,14 +550,10 @@ struct mlx5_priv { struct list_head ctx_list; spinlock_t ctx_lock; + struct mlx5_flow_steering *steering; struct mlx5_eswitch *eswitch; struct mlx5_core_sriov sriov; unsigned long pci_dev_data; - struct mlx5_flow_root_namespace *root_ns; - struct mlx5_flow_root_namespace *fdb_root_ns; - struct mlx5_flow_root_namespace *esw_egress_root_ns; - struct mlx5_flow_root_namespace *esw_ingress_root_ns; - struct mlx5_fc_stats fc_stats; struct mlx5_rl_table rl_table; }; -- cgit v1.2.3 From 6dc6071cfcde6cf687f8d288c9cef9ee6ee24dc7 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Mon, 4 Jul 2016 17:23:08 +0300 Subject: net/mlx5e: Add ethtool flow steering support Implement etrhtool set_rxnfc callback to support ethtool flow spec direct steering. This patch adds only the support of ether flow type spec. L3/L4 flow specs support will be added in downstream patches. Signed-off-by: Maor Gottlieb Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en.h | 20 ++ .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 21 ++ drivers/net/ethernet/mellanox/mlx5/core/en_fs.c | 3 + .../ethernet/mellanox/mlx5/core/en_fs_ethtool.c | 393 +++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 28 +- include/linux/mlx5/fs.h | 1 + 7 files changed, 456 insertions(+), 12 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index a574deabdda8..05cc1effc13c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -8,6 +8,6 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \ mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \ en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \ en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \ - en_tc.o en_arfs.o en_rep.o + en_tc.o en_arfs.o en_rep.o en_fs_ethtool.o mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 00643a116492..357320e79de2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -544,8 +544,22 @@ enum { MLX5E_ARFS_FT_LEVEL }; +struct mlx5e_ethtool_table { + struct mlx5_flow_table *ft; + int num_rules; +}; + +#define ETHTOOL_NUM_L2_FTS 4 + +struct mlx5e_ethtool_steering { + struct mlx5e_ethtool_table l2_ft[ETHTOOL_NUM_L2_FTS]; + struct list_head rules; + int tot_num_rules; +}; + struct mlx5e_flow_steering { struct mlx5_flow_namespace *ns; + struct mlx5e_ethtool_steering ethtool; struct mlx5e_tc_table tc; struct mlx5e_vlan_table vlan; struct mlx5e_l2_table l2; @@ -701,6 +715,12 @@ int mlx5e_create_flow_steering(struct mlx5e_priv *priv); void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv); void mlx5e_init_l2_addr(struct mlx5e_priv *priv); void mlx5e_destroy_flow_table(struct mlx5e_flow_table *ft); +int mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv, + struct ethtool_rx_flow_spec *fs); +int mlx5e_ethtool_flow_remove(struct mlx5e_priv *priv, + int location); +void mlx5e_ethtool_init_steering(struct mlx5e_priv *priv); +void mlx5e_ethtool_cleanup_steering(struct mlx5e_priv *priv); void mlx5e_set_rx_mode_work(struct work_struct *work); void mlx5e_fill_hwstamp(struct mlx5e_tstamp *clock, u64 timestamp, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 7e61ffa96732..edbb665f4d22 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -1368,6 +1368,26 @@ static u32 mlx5e_get_priv_flags(struct net_device *netdev) return priv->pflags; } +static int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) +{ + int err = 0; + struct mlx5e_priv *priv = netdev_priv(dev); + + switch (cmd->cmd) { + case ETHTOOL_SRXCLSRLINS: + err = mlx5e_ethtool_flow_replace(priv, &cmd->fs); + break; + case ETHTOOL_SRXCLSRLDEL: + err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + const struct ethtool_ops mlx5e_ethtool_ops = { .get_drvinfo = mlx5e_get_drvinfo, .get_link = ethtool_op_get_link, @@ -1387,6 +1407,7 @@ const struct ethtool_ops mlx5e_ethtool_ops = { .get_rxfh = mlx5e_get_rxfh, .set_rxfh = mlx5e_set_rxfh, .get_rxnfc = mlx5e_get_rxnfc, + .set_rxnfc = mlx5e_set_rxnfc, .get_tunable = mlx5e_get_tunable, .set_tunable = mlx5e_set_tunable, .get_pauseparam = mlx5e_get_pauseparam, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c index 2e1e86316fe7..1587a9fd5724 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c @@ -1084,6 +1084,8 @@ int mlx5e_create_flow_steering(struct mlx5e_priv *priv) goto err_destroy_l2_table; } + mlx5e_ethtool_init_steering(priv); + return 0; err_destroy_l2_table: @@ -1103,4 +1105,5 @@ void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv) mlx5e_destroy_l2_table(priv); mlx5e_destroy_ttc_table(priv); mlx5e_arfs_destroy_tables(priv); + mlx5e_ethtool_cleanup_steering(priv); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c new file mode 100644 index 000000000000..ee28a9fc0b9d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2016, Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "en.h" + +struct mlx5e_ethtool_rule { + struct list_head list; + struct ethtool_rx_flow_spec flow_spec; + struct mlx5_flow_rule *rule; + struct mlx5e_ethtool_table *eth_ft; +}; + +static void put_flow_table(struct mlx5e_ethtool_table *eth_ft) +{ + if (!--eth_ft->num_rules) { + mlx5_destroy_flow_table(eth_ft->ft); + eth_ft->ft = NULL; + } +} + +#define MLX5E_ETHTOOL_L2_PRIO 0 +#define MLX5E_ETHTOOL_NUM_ENTRIES 64000 +#define MLX5E_ETHTOOL_NUM_GROUPS 10 +static struct mlx5e_ethtool_table *get_flow_table(struct mlx5e_priv *priv, + struct ethtool_rx_flow_spec *fs, + int num_tuples) +{ + struct mlx5e_ethtool_table *eth_ft; + struct mlx5_flow_namespace *ns; + struct mlx5_flow_table *ft; + int max_tuples; + int table_size; + int prio; + + switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { + case ETHER_FLOW: + max_tuples = ETHTOOL_NUM_L2_FTS; + prio = max_tuples - num_tuples; + eth_ft = &priv->fs.ethtool.l2_ft[prio]; + prio += MLX5E_ETHTOOL_L2_PRIO; + break; + default: + return ERR_PTR(-EINVAL); + } + + eth_ft->num_rules++; + if (eth_ft->ft) + return eth_ft; + + ns = mlx5_get_flow_namespace(priv->mdev, + MLX5_FLOW_NAMESPACE_ETHTOOL); + if (!ns) + return ERR_PTR(-ENOTSUPP); + + table_size = min_t(u32, BIT(MLX5_CAP_FLOWTABLE(priv->mdev, + flow_table_properties_nic_receive.log_max_ft_size)), + MLX5E_ETHTOOL_NUM_ENTRIES); + ft = mlx5_create_auto_grouped_flow_table(ns, prio, + table_size, + MLX5E_ETHTOOL_NUM_GROUPS, 0); + if (IS_ERR(ft)) + return (void *)ft; + + eth_ft->ft = ft; + return eth_ft; +} + +static void mask_spec(u8 *mask, u8 *val, size_t size) +{ + unsigned int i; + + for (i = 0; i < size; i++, mask++, val++) + *((u8 *)val) = *((u8 *)mask) & *((u8 *)val); +} + +static int set_flow_attrs(u32 *match_c, u32 *match_v, + struct ethtool_rx_flow_spec *fs) +{ + void *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_c, + outer_headers); + void *outer_headers_v = MLX5_ADDR_OF(fte_match_param, match_v, + outer_headers); + u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT); + struct ethhdr *eth_val; + struct ethhdr *eth_mask; + + switch (flow_type) { + case ETHER_FLOW: + eth_mask = &fs->m_u.ether_spec; + eth_val = &fs->h_u.ether_spec; + + mask_spec((u8 *)eth_mask, (u8 *)eth_val, sizeof(*eth_mask)); + ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, + outer_headers_c, smac_47_16), + eth_mask->h_source); + ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, + outer_headers_v, smac_47_16), + eth_val->h_source); + ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, + outer_headers_c, dmac_47_16), + eth_mask->h_dest); + ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, + outer_headers_v, dmac_47_16), + eth_val->h_dest); + MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, ethertype, + ntohs(eth_mask->h_proto)); + MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, ethertype, + ntohs(eth_val->h_proto)); + break; + default: + return -EINVAL; + } + + if ((fs->flow_type & FLOW_EXT) && + (fs->m_ext.vlan_tci & cpu_to_be16(VLAN_VID_MASK))) { + MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + vlan_tag, 1); + MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + vlan_tag, 1); + MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + first_vid, 0xfff); + MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + first_vid, ntohs(fs->h_ext.vlan_tci)); + } + + return 0; +} + +static void add_rule_to_list(struct mlx5e_priv *priv, + struct mlx5e_ethtool_rule *rule) +{ + struct mlx5e_ethtool_rule *iter; + struct list_head *head = &priv->fs.ethtool.rules; + + list_for_each_entry(iter, &priv->fs.ethtool.rules, list) { + if (iter->flow_spec.location > rule->flow_spec.location) + break; + head = &iter->list; + } + priv->fs.ethtool.tot_num_rules++; + list_add(&rule->list, head); +} + +static bool outer_header_zero(u32 *match_criteria) +{ + int size = MLX5_ST_SZ_BYTES(fte_match_param); + char *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_criteria, + outer_headers); + + return outer_headers_c[0] == 0 && !memcmp(outer_headers_c, + outer_headers_c + 1, + size - 1); +} + +static struct mlx5_flow_rule *add_ethtool_flow_rule(struct mlx5e_priv *priv, + struct mlx5_flow_table *ft, + struct ethtool_rx_flow_spec *fs) +{ + struct mlx5_flow_destination *dst = NULL; + struct mlx5_flow_spec *spec; + struct mlx5_flow_rule *rule; + int err = 0; + u32 action; + + spec = mlx5_vzalloc(sizeof(*spec)); + if (!spec) + return ERR_PTR(-ENOMEM); + err = set_flow_attrs(spec->match_criteria, spec->match_value, + fs); + if (err) + goto free; + + if (fs->ring_cookie == RX_CLS_FLOW_DISC) { + action = MLX5_FLOW_CONTEXT_ACTION_DROP; + } else { + dst = kzalloc(sizeof(*dst), GFP_KERNEL); + if (!dst) { + err = -ENOMEM; + goto free; + } + + dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR; + dst->tir_num = priv->direct_tir[fs->ring_cookie].tirn; + action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; + } + + spec->match_criteria_enable = (!outer_header_zero(spec->match_criteria)); + rule = mlx5_add_flow_rule(ft, spec, action, + MLX5_FS_DEFAULT_FLOW_TAG, dst); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + netdev_err(priv->netdev, "%s: failed to add ethtool steering rule: %d\n", + __func__, err); + goto free; + } +free: + kvfree(spec); + kfree(dst); + return err ? ERR_PTR(err) : rule; +} + +static void del_ethtool_rule(struct mlx5e_priv *priv, + struct mlx5e_ethtool_rule *eth_rule) +{ + if (eth_rule->rule) + mlx5_del_flow_rule(eth_rule->rule); + list_del(ð_rule->list); + priv->fs.ethtool.tot_num_rules--; + put_flow_table(eth_rule->eth_ft); + kfree(eth_rule); +} + +static struct mlx5e_ethtool_rule *find_ethtool_rule(struct mlx5e_priv *priv, + int location) +{ + struct mlx5e_ethtool_rule *iter; + + list_for_each_entry(iter, &priv->fs.ethtool.rules, list) { + if (iter->flow_spec.location == location) + return iter; + } + return NULL; +} + +static struct mlx5e_ethtool_rule *get_ethtool_rule(struct mlx5e_priv *priv, + int location) +{ + struct mlx5e_ethtool_rule *eth_rule; + + eth_rule = find_ethtool_rule(priv, location); + if (eth_rule) + del_ethtool_rule(priv, eth_rule); + + eth_rule = kzalloc(sizeof(*eth_rule), GFP_KERNEL); + if (!eth_rule) + return ERR_PTR(-ENOMEM); + + add_rule_to_list(priv, eth_rule); + return eth_rule; +} + +#define MAX_NUM_OF_ETHTOOL_RULES BIT(10) +static int validate_flow(struct mlx5e_priv *priv, + struct ethtool_rx_flow_spec *fs) +{ + struct ethhdr *eth_mask; + int num_tuples = 0; + + if (fs->location >= MAX_NUM_OF_ETHTOOL_RULES) + return -EINVAL; + + if (fs->ring_cookie >= priv->params.num_channels && + fs->ring_cookie != RX_CLS_FLOW_DISC) + return -EINVAL; + + switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { + case ETHER_FLOW: + eth_mask = &fs->m_u.ether_spec; + if (!is_zero_ether_addr(eth_mask->h_dest)) + num_tuples++; + if (!is_zero_ether_addr(eth_mask->h_source)) + num_tuples++; + if (eth_mask->h_proto) + num_tuples++; + break; + default: + return -EINVAL; + } + if ((fs->flow_type & FLOW_EXT)) { + if (fs->m_ext.vlan_etype || + (fs->m_ext.vlan_tci != cpu_to_be16(VLAN_VID_MASK))) + return -EINVAL; + + if (fs->m_ext.vlan_tci) { + if (be16_to_cpu(fs->h_ext.vlan_tci) >= VLAN_N_VID) + return -EINVAL; + } + num_tuples++; + } + + return num_tuples; +} + +int mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv, + struct ethtool_rx_flow_spec *fs) +{ + struct mlx5e_ethtool_table *eth_ft; + struct mlx5e_ethtool_rule *eth_rule; + struct mlx5_flow_rule *rule; + int num_tuples; + int err; + + num_tuples = validate_flow(priv, fs); + if (num_tuples <= 0) { + netdev_warn(priv->netdev, "%s: flow is not valid\n", __func__); + return -EINVAL; + } + + eth_ft = get_flow_table(priv, fs, num_tuples); + if (IS_ERR(eth_ft)) + return PTR_ERR(eth_ft); + + eth_rule = get_ethtool_rule(priv, fs->location); + if (IS_ERR(eth_rule)) { + put_flow_table(eth_ft); + return PTR_ERR(eth_rule); + } + + eth_rule->flow_spec = *fs; + eth_rule->eth_ft = eth_ft; + if (!eth_ft->ft) { + err = -EINVAL; + goto del_ethtool_rule; + } + rule = add_ethtool_flow_rule(priv, eth_ft->ft, fs); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + goto del_ethtool_rule; + } + + eth_rule->rule = rule; + + return 0; + +del_ethtool_rule: + del_ethtool_rule(priv, eth_rule); + + return err; +} + +int mlx5e_ethtool_flow_remove(struct mlx5e_priv *priv, + int location) +{ + struct mlx5e_ethtool_rule *eth_rule; + int err = 0; + + if (location >= MAX_NUM_OF_ETHTOOL_RULES) + return -ENOSPC; + + eth_rule = find_ethtool_rule(priv, location); + if (!eth_rule) { + err = -ENOENT; + goto out; + } + + del_ethtool_rule(priv, eth_rule); +out: + return err; +} + +void mlx5e_ethtool_cleanup_steering(struct mlx5e_priv *priv) +{ + struct mlx5e_ethtool_rule *iter; + struct mlx5e_ethtool_rule *temp; + + list_for_each_entry_safe(iter, temp, &priv->fs.ethtool.rules, list) + del_ethtool_rule(priv, iter); +} + +void mlx5e_ethtool_init_steering(struct mlx5e_priv *priv) +{ + INIT_LIST_HEAD(&priv->fs.ethtool.rules); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 3e9577537b52..83fa98fde795 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -67,13 +67,21 @@ #define FS_REQUIRED_CAPS(...) {.arr_sz = INIT_CAPS_ARRAY_SIZE(__VA_ARGS__), \ .caps = (long[]) {__VA_ARGS__} } +#define FS_CHAINING_CAPS FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en), \ + FS_CAP(flow_table_properties_nic_receive.modify_root), \ + FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode), \ + FS_CAP(flow_table_properties_nic_receive.flow_table_modify)) + #define LEFTOVERS_NUM_LEVELS 1 #define LEFTOVERS_NUM_PRIOS 1 #define BY_PASS_PRIO_NUM_LEVELS 1 -#define BY_PASS_MIN_LEVEL (KERNEL_MIN_LEVEL + MLX5_BY_PASS_NUM_PRIOS +\ +#define BY_PASS_MIN_LEVEL (ETHTOOL_MIN_LEVEL + MLX5_BY_PASS_NUM_PRIOS +\ LEFTOVERS_NUM_PRIOS) +#define ETHTOOL_PRIO_NUM_LEVELS 1 +#define ETHTOOL_NUM_PRIOS 4 +#define ETHTOOL_MIN_LEVEL (KERNEL_MIN_LEVEL + ETHTOOL_NUM_PRIOS) /* Vlan, mac, ttc, aRFS */ #define KERNEL_NIC_PRIO_NUM_LEVELS 4 #define KERNEL_NIC_NUM_PRIOS 1 @@ -103,27 +111,24 @@ static struct init_tree_node { int num_levels; } root_fs = { .type = FS_TYPE_NAMESPACE, - .ar_size = 5, + .ar_size = 6, .children = (struct init_tree_node[]) { ADD_PRIO(0, BY_PASS_MIN_LEVEL, 0, - FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en), - FS_CAP(flow_table_properties_nic_receive.modify_root), - FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode), - FS_CAP(flow_table_properties_nic_receive.flow_table_modify)), + FS_CHAINING_CAPS, ADD_NS(ADD_MULTIPLE_PRIO(MLX5_BY_PASS_NUM_PRIOS, BY_PASS_PRIO_NUM_LEVELS))), ADD_PRIO(0, OFFLOADS_MIN_LEVEL, 0, {}, ADD_NS(ADD_MULTIPLE_PRIO(OFFLOADS_NUM_PRIOS, OFFLOADS_MAX_FT))), - + ADD_PRIO(0, ETHTOOL_MIN_LEVEL, 0, + FS_CHAINING_CAPS, + ADD_NS(ADD_MULTIPLE_PRIO(ETHTOOL_NUM_PRIOS, + ETHTOOL_PRIO_NUM_LEVELS))), ADD_PRIO(0, KERNEL_MIN_LEVEL, 0, {}, ADD_NS(ADD_MULTIPLE_PRIO(1, 1), ADD_MULTIPLE_PRIO(KERNEL_NIC_NUM_PRIOS, KERNEL_NIC_PRIO_NUM_LEVELS))), ADD_PRIO(0, BY_PASS_MIN_LEVEL, 0, - FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en), - FS_CAP(flow_table_properties_nic_receive.modify_root), - FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode), - FS_CAP(flow_table_properties_nic_receive.flow_table_modify)), + FS_CHAINING_CAPS, ADD_NS(ADD_MULTIPLE_PRIO(LEFTOVERS_NUM_PRIOS, LEFTOVERS_NUM_LEVELS))), ADD_PRIO(0, ANCHOR_MIN_LEVEL, 0, {}, ADD_NS(ADD_MULTIPLE_PRIO(ANCHOR_NUM_PRIOS, ANCHOR_NUM_LEVELS))), @@ -1375,6 +1380,7 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev, switch (type) { case MLX5_FLOW_NAMESPACE_BYPASS: case MLX5_FLOW_NAMESPACE_OFFLOADS: + case MLX5_FLOW_NAMESPACE_ETHTOOL: case MLX5_FLOW_NAMESPACE_KERNEL: case MLX5_FLOW_NAMESPACE_LEFTOVERS: case MLX5_FLOW_NAMESPACE_ANCHOR: diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index d22fe7e5a39a..e036d6030867 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -55,6 +55,7 @@ static inline void build_leftovers_ft_param(int *priority, enum mlx5_flow_namespace_type { MLX5_FLOW_NAMESPACE_BYPASS, MLX5_FLOW_NAMESPACE_OFFLOADS, + MLX5_FLOW_NAMESPACE_ETHTOOL, MLX5_FLOW_NAMESPACE_KERNEL, MLX5_FLOW_NAMESPACE_LEFTOVERS, MLX5_FLOW_NAMESPACE_ANCHOR, -- cgit v1.2.3 From 503eebc265dcf5c512454fd5a6b6673ea4f1d7f2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 5 Jul 2016 11:27:37 +0200 Subject: net: add dev arg to ndo_neigh_construct/destroy As the following patch will allow upper devices to follow the call down lower devices, we need to add dev here and not rely on n->dev. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker_main.c | 3 ++- include/linux/netdevice.h | 6 ++++-- net/atm/clip.c | 2 +- net/core/neighbour.c | 4 ++-- net/ieee802154/6lowpan/core.c | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 28b775e5a9ad..f0b09b05ed3f 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1996,7 +1996,8 @@ static int rocker_port_change_proto_down(struct net_device *dev, return 0; } -static void rocker_port_neigh_destroy(struct neighbour *n) +static void rocker_port_neigh_destroy(struct net_device *dev, + struct neighbour *n) { struct rocker_port *rocker_port = netdev_priv(n->dev); int err; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0c6ee2c5099f..91af73c9dd51 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1209,8 +1209,10 @@ struct net_device_ops { netdev_features_t features); int (*ndo_set_features)(struct net_device *dev, netdev_features_t features); - int (*ndo_neigh_construct)(struct neighbour *n); - void (*ndo_neigh_destroy)(struct neighbour *n); + int (*ndo_neigh_construct)(struct net_device *dev, + struct neighbour *n); + void (*ndo_neigh_destroy)(struct net_device *dev, + struct neighbour *n); int (*ndo_fdb_add)(struct ndmsg *ndm, struct nlattr *tb[], diff --git a/net/atm/clip.c b/net/atm/clip.c index e07f551a863c..53b4ac09e7b7 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -286,7 +286,7 @@ static const struct neigh_ops clip_neigh_ops = { .connected_output = neigh_direct_output, }; -static int clip_constructor(struct neighbour *neigh) +static int clip_constructor(struct net_device *dev, struct neighbour *neigh) { struct atmarp_entry *entry = neighbour_priv(neigh); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 510cd62fcb99..952aabb5aa56 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -473,7 +473,7 @@ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, } if (dev->netdev_ops->ndo_neigh_construct) { - error = dev->netdev_ops->ndo_neigh_construct(n); + error = dev->netdev_ops->ndo_neigh_construct(dev, n); if (error < 0) { rc = ERR_PTR(error); goto out_neigh_release; @@ -701,7 +701,7 @@ void neigh_destroy(struct neighbour *neigh) neigh->arp_queue_len_bytes = 0; if (dev->netdev_ops->ndo_neigh_destroy) - dev->netdev_ops->ndo_neigh_destroy(neigh); + dev->netdev_ops->ndo_neigh_destroy(dev, neigh); dev_put(dev); neigh_parms_put(neigh->parms); diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index 8c004a0c8d64..935ab932e841 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -81,7 +81,7 @@ static int lowpan_stop(struct net_device *dev) return 0; } -static int lowpan_neigh_construct(struct neighbour *n) +static int lowpan_neigh_construct(struct net_device *dev, struct neighbour *n) { struct lowpan_802154_neigh *neigh = lowpan_802154_neigh(neighbour_priv(n)); -- cgit v1.2.3 From 18bfb924f0005a728caadd90ba755b2a660bf441 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 5 Jul 2016 11:27:38 +0200 Subject: net: introduce default neigh_construct/destroy ndo calls for L2 upper devices L2 upper device needs to propagate neigh_construct/destroy calls down to lower devices. Do this by defining default ndo functions and use them in team, bond, bridge and vlan. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 ++ drivers/net/team/team.c | 2 ++ include/linux/netdevice.h | 4 ++++ net/8021q/vlan_dev.c | 2 ++ net/bridge/br_device.c | 2 ++ net/core/dev.c | 44 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 56 insertions(+) (limited to 'include/linux') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 90157e20357e..480d73ac7d1b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4137,6 +4137,8 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, .ndo_fix_features = bond_fix_features, + .ndo_neigh_construct = netdev_default_l2upper_neigh_construct, + .ndo_neigh_destroy = netdev_default_l2upper_neigh_destroy, .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_getlink = switchdev_port_bridge_getlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index f9eebea83516..a380649bf6b5 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2002,6 +2002,8 @@ static const struct net_device_ops team_netdev_ops = { .ndo_add_slave = team_add_slave, .ndo_del_slave = team_del_slave, .ndo_fix_features = team_fix_features, + .ndo_neigh_construct = netdev_default_l2upper_neigh_construct, + .ndo_neigh_destroy = netdev_default_l2upper_neigh_destroy, .ndo_change_carrier = team_change_carrier, .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_getlink = switchdev_port_bridge_getlink, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 91af73c9dd51..49736a31acaa 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3845,6 +3845,10 @@ void *netdev_lower_dev_get_private(struct net_device *dev, struct net_device *lower_dev); void netdev_lower_state_changed(struct net_device *lower_dev, void *lower_state_info); +int netdev_default_l2upper_neigh_construct(struct net_device *dev, + struct neighbour *n); +void netdev_default_l2upper_neigh_destroy(struct net_device *dev, + struct neighbour *n); /* RSS keys are 40 or 52 bytes long */ #define NETDEV_RSS_KEY_LEN 52 diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 86ae75b77390..c8f422c90856 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -790,6 +790,8 @@ static const struct net_device_ops vlan_netdev_ops = { .ndo_netpoll_cleanup = vlan_dev_netpoll_cleanup, #endif .ndo_fix_features = vlan_dev_fix_features, + .ndo_neigh_construct = netdev_default_l2upper_neigh_construct, + .ndo_neigh_destroy = netdev_default_l2upper_neigh_destroy, .ndo_fdb_add = switchdev_port_fdb_add, .ndo_fdb_del = switchdev_port_fdb_del, .ndo_fdb_dump = switchdev_port_fdb_dump, diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 0c39e0f6da09..8eecd0ec22f2 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -349,6 +349,8 @@ static const struct net_device_ops br_netdev_ops = { .ndo_add_slave = br_add_slave, .ndo_del_slave = br_del_slave, .ndo_fix_features = br_fix_features, + .ndo_neigh_construct = netdev_default_l2upper_neigh_construct, + .ndo_neigh_destroy = netdev_default_l2upper_neigh_destroy, .ndo_fdb_add = br_fdb_add, .ndo_fdb_del = br_fdb_delete, .ndo_fdb_dump = br_fdb_dump, diff --git a/net/core/dev.c b/net/core/dev.c index a4f3b0a9aeaf..b92d63bfde7a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6087,6 +6087,50 @@ void netdev_lower_state_changed(struct net_device *lower_dev, } EXPORT_SYMBOL(netdev_lower_state_changed); +int netdev_default_l2upper_neigh_construct(struct net_device *dev, + struct neighbour *n) +{ + struct net_device *lower_dev, *stop_dev; + struct list_head *iter; + int err; + + netdev_for_each_lower_dev(dev, lower_dev, iter) { + if (!lower_dev->netdev_ops->ndo_neigh_construct) + continue; + err = lower_dev->netdev_ops->ndo_neigh_construct(lower_dev, n); + if (err) { + stop_dev = lower_dev; + goto rollback; + } + } + return 0; + +rollback: + netdev_for_each_lower_dev(dev, lower_dev, iter) { + if (lower_dev == stop_dev) + break; + if (!lower_dev->netdev_ops->ndo_neigh_destroy) + continue; + lower_dev->netdev_ops->ndo_neigh_destroy(lower_dev, n); + } + return err; +} +EXPORT_SYMBOL_GPL(netdev_default_l2upper_neigh_construct); + +void netdev_default_l2upper_neigh_destroy(struct net_device *dev, + struct neighbour *n) +{ + struct net_device *lower_dev; + struct list_head *iter; + + netdev_for_each_lower_dev(dev, lower_dev, iter) { + if (!lower_dev->netdev_ops->ndo_neigh_destroy) + continue; + lower_dev->netdev_ops->ndo_neigh_destroy(lower_dev, n); + } +} +EXPORT_SYMBOL_GPL(netdev_default_l2upper_neigh_destroy); + static void dev_change_rx_flags(struct net_device *dev, int flags) { const struct net_device_ops *ops = dev->netdev_ops; -- cgit v1.2.3 From 1f5bd336b9150560458b03460cbcfcfbcf8995b1 Mon Sep 17 00:00:00 2001 From: Ming Lin Date: Mon, 13 Jun 2016 16:45:21 +0200 Subject: blk-mq: add blk_mq_alloc_request_hctx For some protocols like NVMe over Fabrics we need to be able to send initialization commands to a specific queue. Based on an earlier patch from Christoph Hellwig . Signed-off-by: Ming Lin [hch: disallow sleeping allocation, req_op fixes] Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- block/blk-mq.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/blk-mq.h | 2 ++ 2 files changed, 41 insertions(+) (limited to 'include/linux') diff --git a/block/blk-mq.c b/block/blk-mq.c index 13f460368759..7aa60c4f56fd 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -267,6 +267,45 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw, } EXPORT_SYMBOL(blk_mq_alloc_request); +struct request *blk_mq_alloc_request_hctx(struct request_queue *q, int rw, + unsigned int flags, unsigned int hctx_idx) +{ + struct blk_mq_hw_ctx *hctx; + struct blk_mq_ctx *ctx; + struct request *rq; + struct blk_mq_alloc_data alloc_data; + int ret; + + /* + * If the tag allocator sleeps we could get an allocation for a + * different hardware context. No need to complicate the low level + * allocator for this for the rare use case of a command tied to + * a specific queue. + */ + if (WARN_ON_ONCE(!(flags & BLK_MQ_REQ_NOWAIT))) + return ERR_PTR(-EINVAL); + + if (hctx_idx >= q->nr_hw_queues) + return ERR_PTR(-EIO); + + ret = blk_queue_enter(q, true); + if (ret) + return ERR_PTR(ret); + + hctx = q->queue_hw_ctx[hctx_idx]; + ctx = __blk_mq_get_ctx(q, cpumask_first(hctx->cpumask)); + + blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx); + rq = __blk_mq_alloc_request(&alloc_data, rw, 0); + if (!rq) { + blk_queue_exit(q); + return ERR_PTR(-EWOULDBLOCK); + } + + return rq; +} +EXPORT_SYMBOL_GPL(blk_mq_alloc_request_hctx); + static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx, struct request *rq) { diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 2498fdf3a503..cbfd8ca5f13e 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -196,6 +196,8 @@ enum { struct request *blk_mq_alloc_request(struct request_queue *q, int rw, unsigned int flags); +struct request *blk_mq_alloc_request_hctx(struct request_queue *q, int op, + unsigned int flags, unsigned int hctx_idx); struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag); struct cpumask *blk_mq_tags_cpumask(struct blk_mq_tags *tags); -- cgit v1.2.3 From eb793e2c9286cca415423edff4942e4ba28e3cd4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Jun 2016 16:45:25 +0200 Subject: nvme.h: add NVMe over Fabrics definitions The NVMe over Fabrics specification defines a protocol interface and related extensions to NVMe that enable operation over network protocols. The NVMe over Fabrics specification has an NVMe Transport binding for each NVMe Transport. This patch adds the fabrics related definitions: - fabric specific command set and error codes - transport addressing and binding definitions - fabrics sgl extensions - controller identification fabrics enhancements - discovery log page definition Signed-off-by: Armen Baloyan Signed-off-by: James Smart Signed-off-by: Jay Freyensee Signed-off-by: Ming Lin Signed-off-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- drivers/nvme/host/core.c | 4 +- drivers/nvme/host/pci.c | 4 +- include/linux/nvme.h | 337 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 322 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f5676c69842a..3a1e82e5c7f6 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -524,7 +524,7 @@ int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid, memset(&c, 0, sizeof(c)); c.features.opcode = nvme_admin_get_features; c.features.nsid = cpu_to_le32(nsid); - c.features.prp1 = cpu_to_le64(dma_addr); + c.features.dptr.prp1 = cpu_to_le64(dma_addr); c.features.fid = cpu_to_le32(fid); ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &cqe, NULL, 0, 0, @@ -543,7 +543,7 @@ int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11, memset(&c, 0, sizeof(c)); c.features.opcode = nvme_admin_set_features; - c.features.prp1 = cpu_to_le64(dma_addr); + c.features.dptr.prp1 = cpu_to_le64(dma_addr); c.features.fid = cpu_to_le32(fid); c.features.dword11 = cpu_to_le32(dword11); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index de222ed030ab..79a4f56c06cd 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -520,8 +520,8 @@ static int nvme_map_data(struct nvme_dev *dev, struct request *req, goto out_unmap; } - cmnd->rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); - cmnd->rw.prp2 = cpu_to_le64(iod->first_dma); + cmnd->rw.dptr.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); + cmnd->rw.dptr.prp2 = cpu_to_le64(iod->first_dma); if (blk_integrity_rq(req)) cmnd->rw.metadata = cpu_to_le64(sg_dma_address(&iod->meta_sg)); return BLK_MQ_RQ_QUEUE_OK; diff --git a/include/linux/nvme.h b/include/linux/nvme.h index dc815cc6718d..75250303bcb3 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -16,6 +16,78 @@ #define _LINUX_NVME_H #include +#include + +/* NQN names in commands fields specified one size */ +#define NVMF_NQN_FIELD_LEN 256 + +/* However the max length of a qualified name is another size */ +#define NVMF_NQN_SIZE 223 + +#define NVMF_TRSVCID_SIZE 32 +#define NVMF_TRADDR_SIZE 256 +#define NVMF_TSAS_SIZE 256 + +#define NVME_DISC_SUBSYS_NAME "nqn.2014-08.org.nvmexpress.discovery" + +#define NVME_RDMA_IP_PORT 4420 + +enum nvme_subsys_type { + NVME_NQN_DISC = 1, /* Discovery type target subsystem */ + NVME_NQN_NVME = 2, /* NVME type target subsystem */ +}; + +/* Address Family codes for Discovery Log Page entry ADRFAM field */ +enum { + NVMF_ADDR_FAMILY_PCI = 0, /* PCIe */ + NVMF_ADDR_FAMILY_IP4 = 1, /* IP4 */ + NVMF_ADDR_FAMILY_IP6 = 2, /* IP6 */ + NVMF_ADDR_FAMILY_IB = 3, /* InfiniBand */ + NVMF_ADDR_FAMILY_FC = 4, /* Fibre Channel */ +}; + +/* Transport Type codes for Discovery Log Page entry TRTYPE field */ +enum { + NVMF_TRTYPE_RDMA = 1, /* RDMA */ + NVMF_TRTYPE_FC = 2, /* Fibre Channel */ + NVMF_TRTYPE_LOOP = 254, /* Reserved for host usage */ + NVMF_TRTYPE_MAX, +}; + +/* Transport Requirements codes for Discovery Log Page entry TREQ field */ +enum { + NVMF_TREQ_NOT_SPECIFIED = 0, /* Not specified */ + NVMF_TREQ_REQUIRED = 1, /* Required */ + NVMF_TREQ_NOT_REQUIRED = 2, /* Not Required */ +}; + +/* RDMA QP Service Type codes for Discovery Log Page entry TSAS + * RDMA_QPTYPE field + */ +enum { + NVMF_RDMA_QPTYPE_CONNECTED = 0, /* Reliable Connected */ + NVMF_RDMA_QPTYPE_DATAGRAM = 1, /* Reliable Datagram */ +}; + +/* RDMA QP Service Type codes for Discovery Log Page entry TSAS + * RDMA_QPTYPE field + */ +enum { + NVMF_RDMA_PRTYPE_NOT_SPECIFIED = 0, /* No Provider Specified */ + NVMF_RDMA_PRTYPE_IB = 1, /* InfiniBand */ + NVMF_RDMA_PRTYPE_ROCE = 2, /* InfiniBand RoCE */ + NVMF_RDMA_PRTYPE_ROCEV2 = 3, /* InfiniBand RoCEV2 */ + NVMF_RDMA_PRTYPE_IWARP = 4, /* IWARP */ +}; + +/* RDMA Connection Management Service Type codes for Discovery Log Page + * entry TSAS RDMA_CMS field + */ +enum { + NVMF_RDMA_CMS_RDMA_CM = 0, /* Sockets based enpoint addressing */ +}; + +#define NVMF_AQ_DEPTH 32 enum { NVME_REG_CAP = 0x0000, /* Controller Capabilities */ @@ -117,7 +189,8 @@ struct nvme_id_ctrl { __le32 rtd3r; __le32 rtd3e; __le32 oaes; - __u8 rsvd96[160]; + __le32 ctratt; + __u8 rsvd100[156]; __le16 oacs; __u8 acl; __u8 aerl; @@ -132,7 +205,7 @@ struct nvme_id_ctrl { __u8 rsvd270[242]; __u8 sqes; __u8 cqes; - __u8 rsvd514[2]; + __le16 maxcmd; __le32 nn; __le16 oncs; __le16 fuses; @@ -145,7 +218,15 @@ struct nvme_id_ctrl { __le16 acwu; __u8 rsvd534[2]; __le32 sgls; - __u8 rsvd540[1508]; + __u8 rsvd540[228]; + char subnqn[256]; + __u8 rsvd1024[768]; + __le32 ioccsz; + __le32 iorcsz; + __le16 icdoff; + __u8 ctrattr; + __u8 msdbd; + __u8 rsvd1804[244]; struct nvme_id_power_state psd[32]; __u8 vs[1024]; }; @@ -306,6 +387,61 @@ enum nvme_opcode { nvme_cmd_resv_release = 0x15, }; +/* + * Descriptor subtype - lower 4 bits of nvme_(keyed_)sgl_desc identifier + * + * @NVME_SGL_FMT_ADDRESS: absolute address of the data block + * @NVME_SGL_FMT_OFFSET: relative offset of the in-capsule data block + * @NVME_SGL_FMT_INVALIDATE: RDMA transport specific remote invalidation + * request subtype + */ +enum { + NVME_SGL_FMT_ADDRESS = 0x00, + NVME_SGL_FMT_OFFSET = 0x01, + NVME_SGL_FMT_INVALIDATE = 0x0f, +}; + +/* + * Descriptor type - upper 4 bits of nvme_(keyed_)sgl_desc identifier + * + * For struct nvme_sgl_desc: + * @NVME_SGL_FMT_DATA_DESC: data block descriptor + * @NVME_SGL_FMT_SEG_DESC: sgl segment descriptor + * @NVME_SGL_FMT_LAST_SEG_DESC: last sgl segment descriptor + * + * For struct nvme_keyed_sgl_desc: + * @NVME_KEY_SGL_FMT_DATA_DESC: keyed data block descriptor + */ +enum { + NVME_SGL_FMT_DATA_DESC = 0x00, + NVME_SGL_FMT_SEG_DESC = 0x02, + NVME_SGL_FMT_LAST_SEG_DESC = 0x03, + NVME_KEY_SGL_FMT_DATA_DESC = 0x04, +}; + +struct nvme_sgl_desc { + __le64 addr; + __le32 length; + __u8 rsvd[3]; + __u8 type; +}; + +struct nvme_keyed_sgl_desc { + __le64 addr; + __u8 length[3]; + __u8 key[4]; + __u8 type; +}; + +union nvme_data_ptr { + struct { + __le64 prp1; + __le64 prp2; + }; + struct nvme_sgl_desc sgl; + struct nvme_keyed_sgl_desc ksgl; +}; + /* * Lowest two bits of our flags field (FUSE field in the spec): * @@ -336,8 +472,7 @@ struct nvme_common_command { __le32 nsid; __le32 cdw2[2]; __le64 metadata; - __le64 prp1; - __le64 prp2; + union nvme_data_ptr dptr; __le32 cdw10[6]; }; @@ -348,8 +483,7 @@ struct nvme_rw_command { __le32 nsid; __u64 rsvd2; __le64 metadata; - __le64 prp1; - __le64 prp2; + union nvme_data_ptr dptr; __le64 slba; __le16 length; __le16 control; @@ -389,8 +523,7 @@ struct nvme_dsm_cmd { __u16 command_id; __le32 nsid; __u64 rsvd2[2]; - __le64 prp1; - __le64 prp2; + union nvme_data_ptr dptr; __le32 nr; __le32 attributes; __u32 rsvd12[4]; @@ -454,6 +587,7 @@ enum { NVME_LOG_ERROR = 0x01, NVME_LOG_SMART = 0x02, NVME_LOG_FW_SLOT = 0x03, + NVME_LOG_DISC = 0x70, NVME_LOG_RESERVATION = 0x80, NVME_FWACT_REPL = (0 << 3), NVME_FWACT_REPL_ACTV = (1 << 3), @@ -466,8 +600,7 @@ struct nvme_identify { __u16 command_id; __le32 nsid; __u64 rsvd2[2]; - __le64 prp1; - __le64 prp2; + union nvme_data_ptr dptr; __le32 cns; __u32 rsvd11[5]; }; @@ -478,8 +611,7 @@ struct nvme_features { __u16 command_id; __le32 nsid; __u64 rsvd2[2]; - __le64 prp1; - __le64 prp2; + union nvme_data_ptr dptr; __le32 fid; __le32 dword11; __u32 rsvd12[4]; @@ -538,8 +670,7 @@ struct nvme_download_firmware { __u8 flags; __u16 command_id; __u32 rsvd1[5]; - __le64 prp1; - __le64 prp2; + union nvme_data_ptr dptr; __le32 numd; __le32 offset; __u32 rsvd12[4]; @@ -561,8 +692,7 @@ struct nvme_get_log_page_command { __u16 command_id; __le32 nsid; __u64 rsvd2[2]; - __le64 prp1; - __le64 prp2; + union nvme_data_ptr dptr; __u8 lid; __u8 rsvd10; __le16 numdl; @@ -573,6 +703,126 @@ struct nvme_get_log_page_command { __u32 rsvd14[2]; }; +/* + * Fabrics subcommands. + */ +enum nvmf_fabrics_opcode { + nvme_fabrics_command = 0x7f, +}; + +enum nvmf_capsule_command { + nvme_fabrics_type_property_set = 0x00, + nvme_fabrics_type_connect = 0x01, + nvme_fabrics_type_property_get = 0x04, +}; + +struct nvmf_common_command { + __u8 opcode; + __u8 resv1; + __u16 command_id; + __u8 fctype; + __u8 resv2[35]; + __u8 ts[24]; +}; + +/* + * The legal cntlid range a NVMe Target will provide. + * Note that cntlid of value 0 is considered illegal in the fabrics world. + * Devices based on earlier specs did not have the subsystem concept; + * therefore, those devices had their cntlid value set to 0 as a result. + */ +#define NVME_CNTLID_MIN 1 +#define NVME_CNTLID_MAX 0xffef +#define NVME_CNTLID_DYNAMIC 0xffff + +#define MAX_DISC_LOGS 255 + +/* Discovery log page entry */ +struct nvmf_disc_rsp_page_entry { + __u8 trtype; + __u8 adrfam; + __u8 nqntype; + __u8 treq; + __le16 portid; + __le16 cntlid; + __le16 asqsz; + __u8 resv8[22]; + char trsvcid[NVMF_TRSVCID_SIZE]; + __u8 resv64[192]; + char subnqn[NVMF_NQN_FIELD_LEN]; + char traddr[NVMF_TRADDR_SIZE]; + union tsas { + char common[NVMF_TSAS_SIZE]; + struct rdma { + __u8 qptype; + __u8 prtype; + __u8 cms; + __u8 resv3[5]; + __u16 pkey; + __u8 resv10[246]; + } rdma; + } tsas; +}; + +/* Discovery log page header */ +struct nvmf_disc_rsp_page_hdr { + __le64 genctr; + __le64 numrec; + __le16 recfmt; + __u8 resv14[1006]; + struct nvmf_disc_rsp_page_entry entries[0]; +}; + +struct nvmf_connect_command { + __u8 opcode; + __u8 resv1; + __u16 command_id; + __u8 fctype; + __u8 resv2[19]; + union nvme_data_ptr dptr; + __le16 recfmt; + __le16 qid; + __le16 sqsize; + __u8 cattr; + __u8 resv3; + __le32 kato; + __u8 resv4[12]; +}; + +struct nvmf_connect_data { + uuid_le hostid; + __le16 cntlid; + char resv4[238]; + char subsysnqn[NVMF_NQN_FIELD_LEN]; + char hostnqn[NVMF_NQN_FIELD_LEN]; + char resv5[256]; +}; + +struct nvmf_property_set_command { + __u8 opcode; + __u8 resv1; + __u16 command_id; + __u8 fctype; + __u8 resv2[35]; + __u8 attrib; + __u8 resv3[3]; + __le32 offset; + __le64 value; + __u8 resv4[8]; +}; + +struct nvmf_property_get_command { + __u8 opcode; + __u8 resv1; + __u16 command_id; + __u8 fctype; + __u8 resv2[35]; + __u8 attrib; + __u8 resv3[3]; + __le32 offset; + __u8 resv4[16]; +}; + struct nvme_command { union { struct nvme_common_command common; @@ -587,15 +837,29 @@ struct nvme_command { struct nvme_dsm_cmd dsm; struct nvme_abort_cmd abort; struct nvme_get_log_page_command get_log_page; + struct nvmf_common_command fabrics; + struct nvmf_connect_command connect; + struct nvmf_property_set_command prop_set; + struct nvmf_property_get_command prop_get; }; }; static inline bool nvme_is_write(struct nvme_command *cmd) { + /* + * What a mess... + * + * Why can't we simply have a Fabrics In and Fabrics out command? + */ + if (unlikely(cmd->common.opcode == nvme_fabrics_command)) + return cmd->fabrics.opcode & 1; return cmd->common.opcode & 1; } enum { + /* + * Generic Command Status: + */ NVME_SC_SUCCESS = 0x0, NVME_SC_INVALID_OPCODE = 0x1, NVME_SC_INVALID_FIELD = 0x2, @@ -614,10 +878,18 @@ enum { NVME_SC_SGL_INVALID_DATA = 0xf, NVME_SC_SGL_INVALID_METADATA = 0x10, NVME_SC_SGL_INVALID_TYPE = 0x11, + + NVME_SC_SGL_INVALID_OFFSET = 0x16, + NVME_SC_SGL_INVALID_SUBTYPE = 0x17, + NVME_SC_LBA_RANGE = 0x80, NVME_SC_CAP_EXCEEDED = 0x81, NVME_SC_NS_NOT_READY = 0x82, NVME_SC_RESERVATION_CONFLICT = 0x83, + + /* + * Command Specific Status: + */ NVME_SC_CQ_INVALID = 0x100, NVME_SC_QID_INVALID = 0x101, NVME_SC_QUEUE_SIZE = 0x102, @@ -635,9 +907,29 @@ enum { NVME_SC_FEATURE_NOT_CHANGEABLE = 0x10e, NVME_SC_FEATURE_NOT_PER_NS = 0x10f, NVME_SC_FW_NEEDS_RESET_SUBSYS = 0x110, + + /* + * I/O Command Set Specific - NVM commands: + */ NVME_SC_BAD_ATTRIBUTES = 0x180, NVME_SC_INVALID_PI = 0x181, NVME_SC_READ_ONLY = 0x182, + + /* + * I/O Command Set Specific - Fabrics commands: + */ + NVME_SC_CONNECT_FORMAT = 0x180, + NVME_SC_CONNECT_CTRL_BUSY = 0x181, + NVME_SC_CONNECT_INVALID_PARAM = 0x182, + NVME_SC_CONNECT_RESTART_DISC = 0x183, + NVME_SC_CONNECT_INVALID_HOST = 0x184, + + NVME_SC_DISCOVERY_RESTART = 0x190, + NVME_SC_AUTH_REQUIRED = 0x191, + + /* + * Media and Data Integrity Errors: + */ NVME_SC_WRITE_FAULT = 0x280, NVME_SC_READ_ERROR = 0x281, NVME_SC_GUARD_CHECK = 0x282, @@ -645,12 +937,19 @@ enum { NVME_SC_REFTAG_CHECK = 0x284, NVME_SC_COMPARE_FAILED = 0x285, NVME_SC_ACCESS_DENIED = 0x286, + NVME_SC_DNR = 0x4000, }; struct nvme_completion { - __le32 result; /* Used by admin commands to return data */ - __u32 rsvd; + /* + * Used by Admin and Fabrics commands to return data: + */ + union { + __le16 result16; + __le32 result; + __le64 result64; + }; __le16 sq_head; /* how much of this queue may be reclaimed */ __le16 sq_id; /* submission queue that generated this entry */ __u16 command_id; /* of the command which completed */ -- cgit v1.2.3 From 7b89eae29eec4dd9259acd82ed57bec8d9e430ca Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 13 Jun 2016 16:45:27 +0200 Subject: nvme.h: Add keep-alive opcode and identify controller attribute KAS: keep-alive support and granularity of kato in units of 100 ms nvme_admin_keep_alive opcode: 0x18 Signed-off-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- include/linux/nvme.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 75250303bcb3..d8b37bab2887 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -202,7 +202,9 @@ struct nvme_id_ctrl { __u8 apsta; __le16 wctemp; __le16 cctemp; - __u8 rsvd270[242]; + __u8 rsvd270[50]; + __le16 kas; + __u8 rsvd322[190]; __u8 sqes; __u8 cqes; __le16 maxcmd; @@ -556,6 +558,7 @@ enum nvme_admin_opcode { nvme_admin_async_event = 0x0c, nvme_admin_activate_fw = 0x10, nvme_admin_download_fw = 0x11, + nvme_admin_keep_alive = 0x18, nvme_admin_format_nvm = 0x80, nvme_admin_security_send = 0x81, nvme_admin_security_recv = 0x82, @@ -580,6 +583,7 @@ enum { NVME_FEAT_WRITE_ATOMIC = 0x0a, NVME_FEAT_ASYNC_EVENT = 0x0b, NVME_FEAT_AUTO_PST = 0x0c, + NVME_FEAT_KATO = 0x0f, NVME_FEAT_SW_PROGRESS = 0x80, NVME_FEAT_HOST_ID = 0x81, NVME_FEAT_RESV_MASK = 0x82, -- cgit v1.2.3 From 0bd23d09b874e53bd1a2fe2296030aa2720d7b08 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 29 Jun 2016 14:54:46 -0500 Subject: vfs: Don't modify inodes with a uid or gid unknown to the vfs When a filesystem outside of init_user_ns is mounted it could have uids and gids stored in it that do not map to init_user_ns. The plan is to allow those filesystems to set i_uid to INVALID_UID and i_gid to INVALID_GID for unmapped uids and gids and then to handle that strange case in the vfs to ensure there is consistent robust handling of the weirdness. Upon a careful review of the vfs and filesystems about the only case where there is any possibility of confusion or trouble is when the inode is written back to disk. In that case filesystems typically read the inode->i_uid and inode->i_gid and write them to disk even when just an inode timestamp is being updated. Which leads to a rule that is very simple to implement and understand inodes whose i_uid or i_gid is not valid may not be written. In dealing with access times this means treat those inodes as if the inode flag S_NOATIME was set. Reads of the inodes appear safe and useful, but any write or modification is disallowed. The only inode write that is allowed is a chown that sets the uid and gid on the inode to valid values. After such a chown the inode is normal and may be treated as such. Denying all writes to inodes with uids or gids unknown to the vfs also prevents several oddball cases where corruption would have occurred because the vfs does not have complete information. One problem case that is prevented is attempting to use the gid of a directory for new inodes where the directories sgid bit is set but the directories gid is not mapped. Another problem case avoided is attempting to update the evm hash after setxattr, removexattr, and setattr. As the evm hash includeds the inode->i_uid or inode->i_gid not knowning the uid or gid prevents a correct evm hash from being computed. evm hash verification also fails when i_uid or i_gid is unknown but that is essentially harmless as it does not cause filesystem corruption. Acked-by: Seth Forshee Signed-off-by: "Eric W. Biederman" --- fs/attr.c | 8 ++++++++ fs/inode.c | 7 +++++++ fs/namei.c | 26 +++++++++++++++++++++----- fs/xattr.c | 7 +++++++ include/linux/fs.h | 5 +++++ 5 files changed, 48 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/fs/attr.c b/fs/attr.c index dd723578ddce..42bb42bb3c72 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -266,6 +266,14 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de !kgid_has_mapping(inode->i_sb->s_user_ns, attr->ia_gid)) return -EOVERFLOW; + /* Don't allow modifications of files with invalid uids or + * gids unless those uids & gids are being made valid. + */ + if (!(ia_valid & ATTR_UID) && !uid_valid(inode->i_uid)) + return -EOVERFLOW; + if (!(ia_valid & ATTR_GID) && !gid_valid(inode->i_gid)) + return -EOVERFLOW; + error = security_inode_setattr(dentry, attr); if (error) return error; diff --git a/fs/inode.c b/fs/inode.c index 4ccbc21b30ce..c0ebb97fb085 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1617,6 +1617,13 @@ bool atime_needs_update(const struct path *path, struct inode *inode) if (inode->i_flags & S_NOATIME) return false; + + /* Atime updates will likely cause i_uid and i_gid to be written + * back improprely if their true value is unknown to the vfs. + */ + if (HAS_UNMAPPED_ID(inode)) + return false; + if (IS_NOATIME(inode)) return false; if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) diff --git a/fs/namei.c b/fs/namei.c index 8701bd9a5270..840201c4c290 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -410,6 +410,14 @@ int __inode_permission(struct inode *inode, int mask) */ if (IS_IMMUTABLE(inode)) return -EACCES; + + /* + * Updating mtime will likely cause i_uid and i_gid to be + * written back improperly if their true value is unknown + * to the vfs. + */ + if (HAS_UNMAPPED_ID(inode)) + return -EACCES; } retval = do_inode_permission(inode, mask); @@ -2759,10 +2767,11 @@ EXPORT_SYMBOL(__check_sticky); * c. have CAP_FOWNER capability * 6. If the victim is append-only or immutable we can't do antyhing with * links pointing to it. - * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. - * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. - * 9. We can't remove a root or mountpoint. - * 10. We don't allow removal of NFS sillyrenamed files; it's handled by + * 7. If the victim has an unknown uid or gid we can't change the inode. + * 8. If we were asked to remove a directory and victim isn't one - ENOTDIR. + * 9. If we were asked to remove a non-directory and victim isn't one - EISDIR. + * 10. We can't remove a root or mountpoint. + * 11. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). */ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) @@ -2784,7 +2793,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) return -EPERM; if (check_sticky(dir, inode) || IS_APPEND(inode) || - IS_IMMUTABLE(inode) || IS_SWAPFILE(inode)) + IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode)) return -EPERM; if (isdir) { if (!d_is_dir(victim)) @@ -4190,6 +4199,13 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de */ if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return -EPERM; + /* + * Updating the link count will likely cause i_uid and i_gid to + * be writen back improperly if their true value is unknown to + * the vfs. + */ + if (HAS_UNMAPPED_ID(inode)) + return -EPERM; if (!dir->i_op->link) return -EPERM; if (S_ISDIR(inode->i_mode)) diff --git a/fs/xattr.c b/fs/xattr.c index 4beafc43daa5..c243905835ab 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -38,6 +38,13 @@ xattr_permission(struct inode *inode, const char *name, int mask) if (mask & MAY_WRITE) { if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; + /* + * Updating an xattr will likely cause i_uid and i_gid + * to be writen back improperly if their true value is + * unknown to the vfs. + */ + if (HAS_UNMAPPED_ID(inode)) + return -EPERM; } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 375e37f42cdf..cb25ceb6d1ef 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1874,6 +1874,11 @@ struct super_operations { #define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \ (inode)->i_rdev == WHITEOUT_DEV) +static inline bool HAS_UNMAPPED_ID(struct inode *inode) +{ + return !uid_valid(inode->i_uid) || !gid_valid(inode->i_gid); +} + /* * Inode state bits. Protected by inode->i_lock * -- cgit v1.2.3 From d49d37624a1931c2f3b5d0cbe95bd5181cbdc279 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 30 Jun 2016 16:31:01 -0500 Subject: quota: Ensure qids map to the filesystem Introduce the helper qid_has_mapping and use it to ensure that the quota system only considers qids that map to the filesystems s_user_ns. In practice for quota supporting filesystems today this is the exact same check as qid_valid. As only 0xffffffff aka (qid_t)-1 does not map into init_user_ns. Replace the qid_valid calls with qid_has_mapping as values come in from userspace. This is harmless today and it prepares the quota system to work on filesystems with quotas but mounted by unprivileged users. Call qid_has_mapping from dqget. This ensures the passed in qid has a prepresentation on the underlying filesystem. Previously this was unnecessary as filesystesm never had qids that could not map. With the introduction of filesystems outside of s_user_ns this will not remain true. All of this ensures the quota code never has to deal with qids that don't map to the underlying filesystem. Cc: Jan Kara Acked-by: Seth Forshee Signed-off-by: "Eric W. Biederman" --- fs/quota/dquot.c | 3 +++ fs/quota/quota.c | 12 ++++++------ include/linux/quota.h | 10 ++++++++++ 3 files changed, 19 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index ff21980d0119..74706b6aa747 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -841,6 +841,9 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) unsigned int hashent = hashfn(sb, qid); struct dquot *dquot, *empty = NULL; + if (!qid_has_mapping(sb->s_user_ns, qid)) + return ERR_PTR(-EINVAL); + if (!sb_has_quota_active(sb, qid.type)) return ERR_PTR(-ESRCH); we_slept: diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 0f10ee9892ce..73f6f4cf0a21 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -211,7 +211,7 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id, if (!sb->s_qcop->get_dqblk) return -ENOSYS; qid = make_kqid(current_user_ns(), type, id); - if (!qid_valid(qid)) + if (!qid_has_mapping(sb->s_user_ns, qid)) return -EINVAL; ret = sb->s_qcop->get_dqblk(sb, qid, &fdq); if (ret) @@ -237,7 +237,7 @@ static int quota_getnextquota(struct super_block *sb, int type, qid_t id, if (!sb->s_qcop->get_nextdqblk) return -ENOSYS; qid = make_kqid(current_user_ns(), type, id); - if (!qid_valid(qid)) + if (!qid_has_mapping(sb->s_user_ns, qid)) return -EINVAL; ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq); if (ret) @@ -288,7 +288,7 @@ static int quota_setquota(struct super_block *sb, int type, qid_t id, if (!sb->s_qcop->set_dqblk) return -ENOSYS; qid = make_kqid(current_user_ns(), type, id); - if (!qid_valid(qid)) + if (!qid_has_mapping(sb->s_user_ns, qid)) return -EINVAL; copy_from_if_dqblk(&fdq, &idq); return sb->s_qcop->set_dqblk(sb, qid, &fdq); @@ -581,7 +581,7 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id, if (!sb->s_qcop->set_dqblk) return -ENOSYS; qid = make_kqid(current_user_ns(), type, id); - if (!qid_valid(qid)) + if (!qid_has_mapping(sb->s_user_ns, qid)) return -EINVAL; /* Are we actually setting timer / warning limits for all users? */ if (from_kqid(&init_user_ns, qid) == 0 && @@ -642,7 +642,7 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id, if (!sb->s_qcop->get_dqblk) return -ENOSYS; qid = make_kqid(current_user_ns(), type, id); - if (!qid_valid(qid)) + if (!qid_has_mapping(sb->s_user_ns, qid)) return -EINVAL; ret = sb->s_qcop->get_dqblk(sb, qid, &qdq); if (ret) @@ -669,7 +669,7 @@ static int quota_getnextxquota(struct super_block *sb, int type, qid_t id, if (!sb->s_qcop->get_nextdqblk) return -ENOSYS; qid = make_kqid(current_user_ns(), type, id); - if (!qid_valid(qid)) + if (!qid_has_mapping(sb->s_user_ns, qid)) return -EINVAL; ret = sb->s_qcop->get_nextdqblk(sb, &qid, &qdq); if (ret) diff --git a/include/linux/quota.h b/include/linux/quota.h index 9dfb6bce8c9e..1db16ee39b31 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -179,6 +179,16 @@ static inline struct kqid make_kqid_projid(kprojid_t projid) return kqid; } +/** + * qid_has_mapping - Report if a qid maps into a user namespace. + * @ns: The user namespace to see if a value maps into. + * @qid: The kernel internal quota identifier to test. + */ +static inline bool qid_has_mapping(struct user_namespace *ns, struct kqid qid) +{ + return from_kqid(ns, qid) != (qid_t) -1; +} + extern spinlock_t dq_data_lock; -- cgit v1.2.3 From 81754357770ebd900801231e7bc8d151ddc00498 Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Thu, 11 Dec 2014 10:15:45 -0600 Subject: fs: Update i_[ug]id_(read|write) to translate relative to s_user_ns For filesystems mounted from a user namespace on-disk ids should be translated relative to s_users_ns rather than init_user_ns. When an id in the filesystem doesn't exist in s_user_ns the associated id in the inode will be set to INVALID_[UG]ID, which turns these into de facto "nobody" ids. This actually maps pretty well into the way most code already works, and those places where it didn't were fixed in previous patches. Moving forward vfs code needs to be careful to handle instances where ids in inodes may be invalid. Signed-off-by: Seth Forshee Signed-off-by: Eric W. Biederman --- include/linux/fs.h | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fs.h b/include/linux/fs.h index cb25ceb6d1ef..8aa9b72e0bc5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -831,31 +831,6 @@ static inline void i_size_write(struct inode *inode, loff_t i_size) #endif } -/* Helper functions so that in most cases filesystems will - * not need to deal directly with kuid_t and kgid_t and can - * instead deal with the raw numeric values that are stored - * in the filesystem. - */ -static inline uid_t i_uid_read(const struct inode *inode) -{ - return from_kuid(&init_user_ns, inode->i_uid); -} - -static inline gid_t i_gid_read(const struct inode *inode) -{ - return from_kgid(&init_user_ns, inode->i_gid); -} - -static inline void i_uid_write(struct inode *inode, uid_t uid) -{ - inode->i_uid = make_kuid(&init_user_ns, uid); -} - -static inline void i_gid_write(struct inode *inode, gid_t gid) -{ - inode->i_gid = make_kgid(&init_user_ns, gid); -} - static inline unsigned iminor(const struct inode *inode) { return MINOR(inode->i_rdev); @@ -1461,6 +1436,31 @@ struct super_block { struct list_head s_inodes; /* all inodes */ }; +/* Helper functions so that in most cases filesystems will + * not need to deal directly with kuid_t and kgid_t and can + * instead deal with the raw numeric values that are stored + * in the filesystem. + */ +static inline uid_t i_uid_read(const struct inode *inode) +{ + return from_kuid(inode->i_sb->s_user_ns, inode->i_uid); +} + +static inline gid_t i_gid_read(const struct inode *inode) +{ + return from_kgid(inode->i_sb->s_user_ns, inode->i_gid); +} + +static inline void i_uid_write(struct inode *inode, uid_t uid) +{ + inode->i_uid = make_kuid(inode->i_sb->s_user_ns, uid); +} + +static inline void i_gid_write(struct inode *inode, gid_t gid) +{ + inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid); +} + extern struct timespec current_fs_time(struct super_block *sb); /* -- cgit v1.2.3 From a4a551b8f1d4c4ebffd0f49dfef44df3128546f8 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 29 Jun 2016 19:56:48 +0900 Subject: ftrace: Reduce size of function graph entries Currently ftrace_graph_ent{,_entry} and ftrace_graph_ret{,_entry} struct can have padding bytes at the end due to alignment in 64-bit data type. As these data are recorded so frequently, those paddings waste non-negligible space. As the ring buffer maintains alignment properly for each architecture, just to remove the extra padding using 'packed' attribute. ftrace_graph_ent_entry: 24 -> 20 ftrace_graph_ret_entry: 48 -> 44 Also I moved the 'overrun' field in struct ftrace_graph_ret to minimize the padding in the middle. Tested on x86_64 only. Link: http://lkml.kernel.org/r/1467197808-13578-1-git-send-email-namhyung@kernel.org Cc: Ingo Molnar Cc: linux-arch@vger.kernel.org Signed-off-by: Namhyung Kim Signed-off-by: Steven Rostedt --- include/linux/ftrace.h | 12 ++++++++---- kernel/trace/trace.h | 11 +++++++++++ kernel/trace/trace_entries.h | 4 ++-- 3 files changed, 21 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 66a36a815f0a..7d565afe35d2 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -754,23 +754,27 @@ static inline void ftrace_init(void) { } /* * Structure that defines an entry function trace. + * It's already packed but the attribute "packed" is needed + * to remove extra padding at the end. */ struct ftrace_graph_ent { unsigned long func; /* Current function */ int depth; -}; +} __packed; /* * Structure that defines a return function trace. + * It's already packed but the attribute "packed" is needed + * to remove extra padding at the end. */ struct ftrace_graph_ret { unsigned long func; /* Current function */ - unsigned long long calltime; - unsigned long long rettime; /* Number of functions that overran the depth limit for current task */ unsigned long overrun; + unsigned long long calltime; + unsigned long long rettime; int depth; -}; +} __packed; /* Type of the callback handlers for tracing function graph*/ typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); /* return */ diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index c1de3f493cd3..f783df416726 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -80,6 +80,12 @@ enum trace_type { FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \ filter) +#undef FTRACE_ENTRY_PACKED +#define FTRACE_ENTRY_PACKED(name, struct_name, id, tstruct, print, \ + filter) \ + FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \ + filter) __packed + #include "trace_entries.h" /* @@ -1625,6 +1631,11 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled); #define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print, filter) \ FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \ filter) +#undef FTRACE_ENTRY_PACKED +#define FTRACE_ENTRY_PACKED(call, struct_name, id, tstruct, print, filter) \ + FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \ + filter) + #include "trace_entries.h" #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_FUNCTION_TRACER) diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index ee7b94a4810a..5c30efcda5e6 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h @@ -72,7 +72,7 @@ FTRACE_ENTRY_REG(function, ftrace_entry, ); /* Function call entry */ -FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry, +FTRACE_ENTRY_PACKED(funcgraph_entry, ftrace_graph_ent_entry, TRACE_GRAPH_ENT, @@ -88,7 +88,7 @@ FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry, ); /* Function return entry */ -FTRACE_ENTRY(funcgraph_exit, ftrace_graph_ret_entry, +FTRACE_ENTRY_PACKED(funcgraph_exit, ftrace_graph_ret_entry, TRACE_GRAPH_RET, -- cgit v1.2.3 From a5864c999de6703f7ce908f72337568520c6cad3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 3 Jun 2016 17:07:19 -0400 Subject: NFS: Do not serialise O_DIRECT reads and writes Allow dio requests to be scheduled in parallel, but ensuring that they do not conflict with buffered I/O. Signed-off-by: Trond Myklebust --- fs/nfs/Makefile | 2 +- fs/nfs/direct.c | 41 +++----------- fs/nfs/file.c | 12 ++-- fs/nfs/internal.h | 8 +++ fs/nfs/io.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/nfs_fs.h | 1 + 6 files changed, 174 insertions(+), 37 deletions(-) create mode 100644 fs/nfs/io.c (limited to 'include/linux') diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 8664417955a2..6abdda209642 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o CFLAGS_nfstrace.o += -I$(src) nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ - direct.o pagelist.o read.o symlink.o unlink.o \ + io.o direct.o pagelist.o read.o symlink.o unlink.o \ write.o namespace.o mount_clnt.o nfstrace.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_SYSCTL) += sysctl.o diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 0169eca8eb42..6d0e88096440 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -578,17 +578,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) if (!count) goto out; - inode_lock(inode); - result = nfs_sync_mapping(mapping); - if (result) - goto out_unlock; - task_io_account_read(count); result = -ENOMEM; dreq = nfs_direct_req_alloc(); if (dreq == NULL) - goto out_unlock; + goto out; dreq->inode = inode; dreq->bytes_left = dreq->max_count = count; @@ -603,10 +598,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; + nfs_start_io_direct(inode); + NFS_I(inode)->read_io += count; result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos); - inode_unlock(inode); + nfs_end_io_direct(inode); if (!result) { result = nfs_direct_wait(dreq); @@ -614,13 +611,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter) iocb->ki_pos += result; } - nfs_direct_req_release(dreq); - return result; - out_release: nfs_direct_req_release(dreq); -out_unlock: - inode_unlock(inode); out: return result; } @@ -1008,25 +1000,12 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) pos = iocb->ki_pos; end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT; - inode_lock(inode); - - result = nfs_sync_mapping(mapping); - if (result) - goto out_unlock; - - if (mapping->nrpages) { - result = invalidate_inode_pages2_range(mapping, - pos >> PAGE_SHIFT, end); - if (result) - goto out_unlock; - } - task_io_account_write(count); result = -ENOMEM; dreq = nfs_direct_req_alloc(); if (!dreq) - goto out_unlock; + goto out; dreq->inode = inode; dreq->bytes_left = dreq->max_count = count; @@ -1041,6 +1020,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) if (!is_sync_kiocb(iocb)) dreq->iocb = iocb; + nfs_start_io_direct(inode); + result = nfs_direct_write_schedule_iovec(dreq, iter, pos); if (mapping->nrpages) { @@ -1048,7 +1029,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) pos >> PAGE_SHIFT, end); } - inode_unlock(inode); + nfs_end_io_direct(inode); if (!result) { result = nfs_direct_wait(dreq); @@ -1058,13 +1039,9 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) generic_write_sync(iocb, result); } } - nfs_direct_req_release(dreq); - return result; - out_release: nfs_direct_req_release(dreq); -out_unlock: - inode_unlock(inode); +out: return result; } diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 46cf0afe3c0f..9f8da9e1b23f 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -170,12 +170,14 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) iocb->ki_filp, iov_iter_count(to), (unsigned long) iocb->ki_pos); - result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping); + nfs_start_io_read(inode); + result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); if (!result) { result = generic_file_read_iter(iocb, to); if (result > 0) nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); } + nfs_end_io_read(inode); return result; } EXPORT_SYMBOL_GPL(nfs_file_read); @@ -191,12 +193,14 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n", filp, (unsigned long) count, (unsigned long long) *ppos); - res = nfs_revalidate_mapping_protected(inode, filp->f_mapping); + nfs_start_io_read(inode); + res = nfs_revalidate_mapping(inode, filp->f_mapping); if (!res) { res = generic_file_splice_read(filp, ppos, pipe, count, flags); if (res > 0) nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res); } + nfs_end_io_read(inode); return res; } EXPORT_SYMBOL_GPL(nfs_file_splice_read); @@ -645,14 +649,14 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) goto out; } - inode_lock(inode); + nfs_start_io_write(inode); result = generic_write_checks(iocb, from); if (result > 0) { current->backing_dev_info = inode_to_bdi(inode); result = generic_perform_write(file, from, iocb->ki_pos); current->backing_dev_info = NULL; } - inode_unlock(inode); + nfs_end_io_write(inode); if (result <= 0) goto out; diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 0eb5c924886d..159b64ede82a 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -411,6 +411,14 @@ extern void __exit unregister_nfs_fs(void); extern bool nfs_sb_active(struct super_block *sb); extern void nfs_sb_deactive(struct super_block *sb); +/* io.c */ +extern void nfs_start_io_read(struct inode *inode); +extern void nfs_end_io_read(struct inode *inode); +extern void nfs_start_io_write(struct inode *inode); +extern void nfs_end_io_write(struct inode *inode); +extern void nfs_start_io_direct(struct inode *inode); +extern void nfs_end_io_direct(struct inode *inode); + /* namespace.c */ #define NFS_PATH_CANONICAL 1 extern char *nfs_path(char **p, struct dentry *dentry, diff --git a/fs/nfs/io.c b/fs/nfs/io.c new file mode 100644 index 000000000000..1fc5d1ce327e --- /dev/null +++ b/fs/nfs/io.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Trond Myklebust + * + * I/O and data path helper functionality. + */ + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +/* Call with exclusively locked inode->i_rwsem */ +static void nfs_block_o_direct(struct nfs_inode *nfsi, struct inode *inode) +{ + if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) { + clear_bit(NFS_INO_ODIRECT, &nfsi->flags); + inode_dio_wait(inode); + } +} + +/** + * nfs_start_io_read - declare the file is being used for buffered reads + * @inode - file inode + * + * Declare that a buffered read operation is about to start, and ensure + * that we block all direct I/O. + * On exit, the function ensures that the NFS_INO_ODIRECT flag is unset, + * and holds a shared lock on inode->i_rwsem to ensure that the flag + * cannot be changed. + * In practice, this means that buffered read operations are allowed to + * execute in parallel, thanks to the shared lock, whereas direct I/O + * operations need to wait to grab an exclusive lock in order to set + * NFS_INO_ODIRECT. + * Note that buffered writes and truncates both take a write lock on + * inode->i_rwsem, meaning that those are serialised w.r.t. the reads. + */ +void +nfs_start_io_read(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + /* Be an optimist! */ + down_read(&inode->i_rwsem); + if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0) + return; + up_read(&inode->i_rwsem); + /* Slow path.... */ + down_write(&inode->i_rwsem); + nfs_block_o_direct(nfsi, inode); + downgrade_write(&inode->i_rwsem); +} + +/** + * nfs_end_io_read - declare that the buffered read operation is done + * @inode - file inode + * + * Declare that a buffered read operation is done, and release the shared + * lock on inode->i_rwsem. + */ +void +nfs_end_io_read(struct inode *inode) +{ + up_read(&inode->i_rwsem); +} + +/** + * nfs_start_io_write - declare the file is being used for buffered writes + * @inode - file inode + * + * Declare that a buffered read operation is about to start, and ensure + * that we block all direct I/O. + */ +void +nfs_start_io_write(struct inode *inode) +{ + down_write(&inode->i_rwsem); + nfs_block_o_direct(NFS_I(inode), inode); +} + +/** + * nfs_end_io_write - declare that the buffered write operation is done + * @inode - file inode + * + * Declare that a buffered write operation is done, and release the + * lock on inode->i_rwsem. + */ +void +nfs_end_io_write(struct inode *inode) +{ + up_write(&inode->i_rwsem); +} + +/* Call with exclusively locked inode->i_rwsem */ +static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode) +{ + if (!test_bit(NFS_INO_ODIRECT, &nfsi->flags)) { + set_bit(NFS_INO_ODIRECT, &nfsi->flags); + nfs_wb_all(inode); + } +} + +/** + * nfs_end_io_direct - declare the file is being used for direct i/o + * @inode - file inode + * + * Declare that a direct I/O operation is about to start, and ensure + * that we block all buffered I/O. + * On exit, the function ensures that the NFS_INO_ODIRECT flag is set, + * and holds a shared lock on inode->i_rwsem to ensure that the flag + * cannot be changed. + * In practice, this means that direct I/O operations are allowed to + * execute in parallel, thanks to the shared lock, whereas buffered I/O + * operations need to wait to grab an exclusive lock in order to clear + * NFS_INO_ODIRECT. + * Note that buffered writes and truncates both take a write lock on + * inode->i_rwsem, meaning that those are serialised w.r.t. O_DIRECT. + */ +void +nfs_start_io_direct(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + /* Be an optimist! */ + down_read(&inode->i_rwsem); + if (test_bit(NFS_INO_ODIRECT, &nfsi->flags) != 0) + return; + up_read(&inode->i_rwsem); + /* Slow path.... */ + down_write(&inode->i_rwsem); + nfs_block_buffered(nfsi, inode); + downgrade_write(&inode->i_rwsem); +} + +/** + * nfs_end_io_direct - declare that the direct i/o operation is done + * @inode - file inode + * + * Declare that a direct I/O operation is done, and release the shared + * lock on inode->i_rwsem. + */ +void +nfs_end_io_direct(struct inode *inode) +{ + up_read(&inode->i_rwsem); +} diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 120dd04b553c..225d17d35277 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -210,6 +210,7 @@ struct nfs_inode { #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ +#define NFS_INO_ODIRECT (12) /* I/O setting is O_DIRECT */ static inline struct nfs_inode *NFS_I(const struct inode *inode) { -- cgit v1.2.3 From be527494e02b89e03485955b30de6c1e976a07eb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 22 Jun 2016 08:19:36 -0400 Subject: NFS: Remove unused function nfs_revalidate_mapping_protected() Clean up... Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 38 ++++---------------------------------- include/linux/nfs_fs.h | 1 - 2 files changed, 4 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6c0618eb5d57..0e0500f2bb6b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1131,14 +1131,12 @@ out: } /** - * __nfs_revalidate_mapping - Revalidate the pagecache + * nfs_revalidate_mapping - Revalidate the pagecache * @inode - pointer to host inode * @mapping - pointer to mapping - * @may_lock - take inode->i_mutex? */ -static int __nfs_revalidate_mapping(struct inode *inode, - struct address_space *mapping, - bool may_lock) +int nfs_revalidate_mapping(struct inode *inode, + struct address_space *mapping) { struct nfs_inode *nfsi = NFS_I(inode); unsigned long *bitlock = &nfsi->flags; @@ -1187,12 +1185,7 @@ static int __nfs_revalidate_mapping(struct inode *inode, nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; spin_unlock(&inode->i_lock); trace_nfs_invalidate_mapping_enter(inode); - if (may_lock) { - inode_lock(inode); - ret = nfs_invalidate_mapping(inode, mapping); - inode_unlock(inode); - } else - ret = nfs_invalidate_mapping(inode, mapping); + ret = nfs_invalidate_mapping(inode, mapping); trace_nfs_invalidate_mapping_exit(inode, ret); clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); @@ -1202,29 +1195,6 @@ out: return ret; } -/** - * nfs_revalidate_mapping - Revalidate the pagecache - * @inode - pointer to host inode - * @mapping - pointer to mapping - */ -int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) -{ - return __nfs_revalidate_mapping(inode, mapping, false); -} - -/** - * nfs_revalidate_mapping_protected - Revalidate the pagecache - * @inode - pointer to host inode - * @mapping - pointer to mapping - * - * Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex - * while invalidating the mapping. - */ -int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping) -{ - return __nfs_revalidate_mapping(inode, mapping, true); -} - static bool nfs_file_has_writers(struct nfs_inode *nfsi) { struct inode *inode = &nfsi->vfs_inode; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 225d17d35277..810124b33327 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -351,7 +351,6 @@ extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *ino extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); extern int nfs_revalidate_mapping_rcu(struct inode *inode); -extern int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping); extern int nfs_setattr(struct dentry *, struct iattr *); extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *); extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, -- cgit v1.2.3 From 9c6098685a1d5df72da61ff7838ebb1524796869 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Thu, 7 Apr 2016 20:03:33 +0800 Subject: FDT: Add a helper to get the subnode by given name Sometimes it needs to check if there is a subnode of given node in FDT by given name. Introduce this helper to get the subnode if it exists. CC: Rob Herring Signed-off-by: Shannon Zhao Acked-by: Stefano Stabellini Acked-by: Rob Herring Tested-by: Julien Grall --- drivers/of/fdt.c | 13 +++++++++++++ include/linux/of_fdt.h | 2 ++ 2 files changed, 15 insertions(+) (limited to 'include/linux') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 33daffc4392c..0e02947a8a7a 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -743,6 +743,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, return rc; } +/** + * of_get_flat_dt_subnode_by_name - get the subnode by given name + * + * @node: the parent node + * @uname: the name of subnode + * @return offset of the subnode, or -FDT_ERR_NOTFOUND if there is none + */ + +int of_get_flat_dt_subnode_by_name(unsigned long node, const char *uname) +{ + return fdt_subnode_offset(initial_boot_params, node, uname); +} + /** * of_get_flat_dt_root - find the root node in the flat blob */ diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index 901ec01c9fba..26c3302ae58f 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -53,6 +53,8 @@ extern char __dtb_end[]; extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, int depth, void *data), void *data); +extern int of_get_flat_dt_subnode_by_name(unsigned long node, + const char *uname); extern const void *of_get_flat_dt_prop(unsigned long node, const char *name, int *size); extern int of_flat_dt_is_compatible(unsigned long node, const char *name); -- cgit v1.2.3 From ecb23dc6f2eff0ce64dd60351a81f376f13b12cc Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 20 May 2016 09:26:48 +0200 Subject: xen: add steal_clock support on x86 The pv_time_ops structure contains a function pointer for the "steal_clock" functionality used only by KVM and Xen on ARM. Xen on x86 uses its own mechanism to account for the "stolen" time a thread wasn't able to run due to hypervisor scheduling. Add support in Xen arch independent time handling for this feature by moving it out of the arm arch into drivers/xen and remove the x86 Xen hack. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Reviewed-by: Stefano Stabellini Signed-off-by: David Vrabel --- arch/arm/xen/enlighten.c | 18 ++---------------- arch/x86/xen/time.c | 44 ++------------------------------------------ drivers/xen/time.c | 20 ++++++++++++++++++++ include/linux/kernel_stat.h | 1 - include/xen/xen-ops.h | 1 + kernel/sched/cputime.c | 10 ---------- 6 files changed, 25 insertions(+), 69 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index d4f36eba3499..47acb3613f40 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -86,19 +85,6 @@ int xen_unmap_domain_gfn_range(struct vm_area_struct *vma, } EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range); -static unsigned long long xen_stolen_accounting(int cpu) -{ - struct vcpu_runstate_info state; - - BUG_ON(cpu != smp_processor_id()); - - xen_get_runstate_snapshot(&state); - - WARN_ON(state.state != RUNSTATE_running); - - return state.time[RUNSTATE_runnable] + state.time[RUNSTATE_offline]; -} - static void xen_read_wallclock(struct timespec64 *ts) { u32 version; @@ -432,8 +418,8 @@ static int __init xen_guest_init(void) register_cpu_notifier(&xen_cpu_notifier); - pv_time_ops.steal_clock = xen_stolen_accounting; - static_key_slow_inc(¶virt_steal_enabled); + xen_time_setup_guest(); + if (xen_initial_domain()) pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 6deba5bc7e34..c31006f0f37f 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include #include @@ -31,44 +29,6 @@ /* Xen may fire a timer up to this many ns early */ #define TIMER_SLOP 100000 -#define NS_PER_TICK (1000000000LL / HZ) - -/* snapshots of runstate info */ -static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot); - -/* unused ns of stolen time */ -static DEFINE_PER_CPU(u64, xen_residual_stolen); - -static void do_stolen_accounting(void) -{ - struct vcpu_runstate_info state; - struct vcpu_runstate_info *snap; - s64 runnable, offline, stolen; - cputime_t ticks; - - xen_get_runstate_snapshot(&state); - - WARN_ON(state.state != RUNSTATE_running); - - snap = this_cpu_ptr(&xen_runstate_snapshot); - - /* work out how much time the VCPU has not been runn*ing* */ - runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable]; - offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline]; - - *snap = state; - - /* Add the appropriate number of ticks of stolen time, - including any left-overs from last time. */ - stolen = runnable + offline + __this_cpu_read(xen_residual_stolen); - - if (stolen < 0) - stolen = 0; - - ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen); - __this_cpu_write(xen_residual_stolen, stolen); - account_steal_ticks(ticks); -} /* Get the TSC speed from Xen */ static unsigned long xen_tsc_khz(void) @@ -335,8 +295,6 @@ static irqreturn_t xen_timer_interrupt(int irq, void *dev_id) ret = IRQ_HANDLED; } - do_stolen_accounting(); - return ret; } @@ -431,6 +389,8 @@ static void __init xen_time_init(void) xen_setup_timer(cpu); xen_setup_cpu_clockevents(); + xen_time_setup_guest(); + if (xen_initial_domain()) pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); } diff --git a/drivers/xen/time.c b/drivers/xen/time.c index 71078425c9ea..2257b6663766 100644 --- a/drivers/xen/time.c +++ b/drivers/xen/time.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -75,6 +76,15 @@ bool xen_vcpu_stolen(int vcpu) return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable; } +static u64 xen_steal_clock(int cpu) +{ + struct vcpu_runstate_info state; + + BUG_ON(cpu != smp_processor_id()); + xen_get_runstate_snapshot(&state); + return state.time[RUNSTATE_runnable] + state.time[RUNSTATE_offline]; +} + void xen_setup_runstate_info(int cpu) { struct vcpu_register_runstate_memory_area area; @@ -86,3 +96,13 @@ void xen_setup_runstate_info(int cpu) BUG(); } +void __init xen_time_setup_guest(void) +{ + pv_time_ops.steal_clock = xen_steal_clock; + + static_key_slow_inc(¶virt_steal_enabled); + /* + * We can't set paravirt_steal_rq_enabled as this would require the + * capability to read another cpu's runstate info. + */ +} diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 25a822f6f000..44fda64ad434 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -92,7 +92,6 @@ static inline void account_process_tick(struct task_struct *tsk, int user) extern void account_process_tick(struct task_struct *, int user); #endif -extern void account_steal_ticks(unsigned long ticks); extern void account_idle_ticks(unsigned long ticks); #endif /* _LINUX_KERNEL_STAT_H */ diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 3491582bf50a..355275bad2cf 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -21,6 +21,7 @@ void xen_resume_notifier_unregister(struct notifier_block *nb); bool xen_vcpu_stolen(int vcpu); void xen_setup_runstate_info(int cpu); +void xen_time_setup_guest(void); void xen_get_runstate_snapshot(struct vcpu_runstate_info *res); int xen_setup_shutdown_event(void); diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 75f98c5498d5..8c4c6dcc052c 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -489,16 +489,6 @@ void account_process_tick(struct task_struct *p, int user_tick) account_idle_time(cputime_one_jiffy); } -/* - * Account multiple ticks of steal time. - * @p: the process from which the cpu time has been stolen - * @ticks: number of stolen ticks - */ -void account_steal_ticks(unsigned long ticks) -{ - account_steal_time(jiffies_to_cputime(ticks)); -} - /* * Account multiple ticks of idle time. * @ticks: number of stolen ticks -- cgit v1.2.3 From c1adf20052d80f776849fa2c1acb472cdeb7786c Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 1 Jul 2016 07:53:51 +0100 Subject: Introduce rb_replace_node_rcu() Implement an RCU-safe variant of rb_replace_node() and rearrange rb_replace_node() to do things in the same order. Signed-off-by: David Howells Acked-by: Peter Zijlstra (Intel) --- include/linux/rbtree.h | 2 ++ include/linux/rbtree_augmented.h | 13 +++++++++++++ lib/rbtree.c | 26 ++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index b6900099ea81..e585018498d5 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h @@ -76,6 +76,8 @@ extern struct rb_node *rb_next_postorder(const struct rb_node *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */ extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); +extern void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); static inline void rb_link_node(struct rb_node *node, struct rb_node *parent, struct rb_node **rb_link) diff --git a/include/linux/rbtree_augmented.h b/include/linux/rbtree_augmented.h index 14d7b831b63a..d076183e49be 100644 --- a/include/linux/rbtree_augmented.h +++ b/include/linux/rbtree_augmented.h @@ -130,6 +130,19 @@ __rb_change_child(struct rb_node *old, struct rb_node *new, WRITE_ONCE(root->rb_node, new); } +static inline void +__rb_change_child_rcu(struct rb_node *old, struct rb_node *new, + struct rb_node *parent, struct rb_root *root) +{ + if (parent) { + if (parent->rb_left == old) + rcu_assign_pointer(parent->rb_left, new); + else + rcu_assign_pointer(parent->rb_right, new); + } else + rcu_assign_pointer(root->rb_node, new); +} + extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); diff --git a/lib/rbtree.c b/lib/rbtree.c index 1356454e36de..eb8a19fee110 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c @@ -539,17 +539,39 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new, { struct rb_node *parent = rb_parent(victim); + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; + /* Set the surrounding nodes to point to the replacement */ - __rb_change_child(victim, new, parent, root); if (victim->rb_left) rb_set_parent(victim->rb_left, new); if (victim->rb_right) rb_set_parent(victim->rb_right, new); + __rb_change_child(victim, new, parent, root); +} +EXPORT_SYMBOL(rb_replace_node); + +void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = rb_parent(victim); /* Copy the pointers/colour from the victim to the replacement */ *new = *victim; + + /* Set the surrounding nodes to point to the replacement */ + if (victim->rb_left) + rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + rb_set_parent(victim->rb_right, new); + + /* Set the parent's pointer to the new node last after an RCU barrier + * so that the pointers onwards are seen to be set correctly when doing + * an RCU walk over the tree. + */ + __rb_change_child_rcu(victim, new, parent, root); } -EXPORT_SYMBOL(rb_replace_node); +EXPORT_SYMBOL(rb_replace_node_rcu); static struct rb_node *rb_left_deepest_node(const struct rb_node *node) { -- cgit v1.2.3 From 995f1405610bd8446c5be37d2ffc031a7729e406 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 1 Jul 2016 13:44:53 -0700 Subject: rcu: Suppress sparse warnings for rcu_dereference_raw() Data structures that are used both with and without RCU protection are difficult to write in a sparse-clean manner. If you mark the relevant pointers with __rcu, sparse will complain about all non-RCU uses, but if you don't mark those pointers, sparse will complain about all RCU uses. This commit therefore suppresses sparse warnings for rcu_dereference_raw(), allowing mixed-protection data structures to avoid these warnings. Reported-by: David Howells Signed-off-by: Paul E. McKenney Signed-off-by: David Howells --- include/linux/rcupdate.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 5f1533e3d032..85830e6c797b 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -611,6 +611,12 @@ static inline void rcu_preempt_sleep_check(void) rcu_dereference_sparse(p, space); \ ((typeof(*p) __force __kernel *)(p)); \ }) +#define rcu_dereference_raw(p) \ +({ \ + /* Dependency order vs. p above. */ \ + typeof(p) ________p1 = lockless_dereference(p); \ + ((typeof(*p) __force __kernel *)(________p1)); \ +}) /** * RCU_INITIALIZER() - statically initialize an RCU-protected global variable @@ -729,8 +735,6 @@ static inline void rcu_preempt_sleep_check(void) __rcu_dereference_check((p), (c) || rcu_read_lock_sched_held(), \ __rcu) -#define rcu_dereference_raw(p) rcu_dereference_check(p, 1) /*@@@ needed? @@@*/ - /* * The tracing infrastructure traces RCU (we want that), but unfortunately * some of the RCU checks causes tracing to lock up the system. -- cgit v1.2.3 From da0c6dc00c69d0adaae99c3b3d2ea0c869a3fb35 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 27 Jun 2016 16:04:07 +0530 Subject: cpufreq: Handle sorted frequency tables more efficiently cpufreq drivers aren't required to provide a sorted frequency table today, and even the ones which provide a sorted table aren't handled efficiently by cpufreq core. This patch adds infrastructure to verify if the freq-table provided by the drivers is sorted or not, and use efficient helpers if they are sorted. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/freq_table.c | 73 ++++++++++++-- include/linux/cpufreq.h | 234 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 296 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index eac8bcbdaad1..3bbbf9e6960c 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -113,9 +113,9 @@ int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy) } EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify); -int cpufreq_frequency_table_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) { struct cpufreq_frequency_table optimal = { .driver_data = ~0, @@ -205,7 +205,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, table[index].frequency); return index; } -EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); +EXPORT_SYMBOL_GPL(cpufreq_table_index_unsorted); int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, unsigned int freq) @@ -297,15 +297,72 @@ struct freq_attr *cpufreq_generic_attr[] = { }; EXPORT_SYMBOL_GPL(cpufreq_generic_attr); +static int set_freq_table_sorted(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *pos, *table = policy->freq_table; + struct cpufreq_frequency_table *prev = NULL; + int ascending = 0; + + policy->freq_table_sorted = CPUFREQ_TABLE_UNSORTED; + + cpufreq_for_each_valid_entry(pos, table) { + if (!prev) { + prev = pos; + continue; + } + + if (pos->frequency == prev->frequency) { + pr_warn("Duplicate freq-table entries: %u\n", + pos->frequency); + return -EINVAL; + } + + /* Frequency increased from prev to pos */ + if (pos->frequency > prev->frequency) { + /* But frequency was decreasing earlier */ + if (ascending < 0) { + pr_debug("Freq table is unsorted\n"); + return 0; + } + + ascending++; + } else { + /* Frequency decreased from prev to pos */ + + /* But frequency was increasing earlier */ + if (ascending > 0) { + pr_debug("Freq table is unsorted\n"); + return 0; + } + + ascending--; + } + + prev = pos; + } + + if (ascending > 0) + policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_ASCENDING; + else + policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_DESCENDING; + + pr_debug("Freq table is sorted in %s order\n", + ascending > 0 ? "ascending" : "descending"); + + return 0; +} + int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { - int ret = cpufreq_frequency_table_cpuinfo(policy, table); + int ret; - if (!ret) - policy->freq_table = table; + ret = cpufreq_frequency_table_cpuinfo(policy, table); + if (ret) + return ret; - return ret; + policy->freq_table = table; + return set_freq_table_sorted(policy); } EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index c378776628b4..c6410b1b2490 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -36,6 +36,12 @@ struct cpufreq_governor; +enum cpufreq_table_sorting { + CPUFREQ_TABLE_UNSORTED, + CPUFREQ_TABLE_SORTED_ASCENDING, + CPUFREQ_TABLE_SORTED_DESCENDING +}; + struct cpufreq_freqs { unsigned int cpu; /* cpu nr */ unsigned int old; @@ -87,6 +93,7 @@ struct cpufreq_policy { struct cpufreq_user_policy user_policy; struct cpufreq_frequency_table *freq_table; + enum cpufreq_table_sorting freq_table_sorted; struct list_head policy_list; struct kobject kobj; @@ -597,9 +604,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table); int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy); -int cpufreq_frequency_table_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation); +int cpufreq_table_index_unsorted(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, unsigned int freq); @@ -610,6 +617,227 @@ int cpufreq_boost_trigger_state(int state); int cpufreq_boost_enabled(void); int cpufreq_enable_boost_support(void); bool policy_has_boost_freq(struct cpufreq_policy *policy); + +/* Find lowest freq at or above target in a table in ascending order */ +static inline int cpufreq_table_find_index_al(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + struct cpufreq_frequency_table *table = policy->freq_table; + unsigned int freq; + int i, best = -1; + + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + freq = table[i].frequency; + + if (freq >= target_freq) + return i; + + best = i; + } + + return best; +} + +/* Find lowest freq at or above target in a table in descending order */ +static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + struct cpufreq_frequency_table *table = policy->freq_table; + unsigned int freq; + int i, best = -1; + + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + freq = table[i].frequency; + + if (freq == target_freq) + return i; + + if (freq > target_freq) { + best = i; + continue; + } + + /* No freq found above target_freq */ + if (best == -1) + return i; + + return best; + } + + return best; +} + +/* Works only on sorted freq-tables */ +static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + target_freq = clamp_val(target_freq, policy->min, policy->max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_al(policy, target_freq); + else + return cpufreq_table_find_index_dl(policy, target_freq); +} + +/* Find highest freq at or below target in a table in ascending order */ +static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + struct cpufreq_frequency_table *table = policy->freq_table; + unsigned int freq; + int i, best = -1; + + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + freq = table[i].frequency; + + if (freq == target_freq) + return i; + + if (freq < target_freq) { + best = i; + continue; + } + + /* No freq found below target_freq */ + if (best == -1) + return i; + + return best; + } + + return best; +} + +/* Find highest freq at or below target in a table in descending order */ +static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + struct cpufreq_frequency_table *table = policy->freq_table; + unsigned int freq; + int i, best = -1; + + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + freq = table[i].frequency; + + if (freq <= target_freq) + return i; + + best = i; + } + + return best; +} + +/* Works only on sorted freq-tables */ +static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + target_freq = clamp_val(target_freq, policy->min, policy->max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_ah(policy, target_freq); + else + return cpufreq_table_find_index_dh(policy, target_freq); +} + +/* Find closest freq to target in a table in ascending order */ +static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + struct cpufreq_frequency_table *table = policy->freq_table; + unsigned int freq; + int i, best = -1; + + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + freq = table[i].frequency; + + if (freq == target_freq) + return i; + + if (freq < target_freq) { + best = i; + continue; + } + + /* No freq found below target_freq */ + if (best == -1) + return i; + + /* Choose the closest freq */ + if (target_freq - table[best].frequency > freq - target_freq) + return i; + + return best; + } + + return best; +} + +/* Find closest freq to target in a table in descending order */ +static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + struct cpufreq_frequency_table *table = policy->freq_table; + unsigned int freq; + int i, best = -1; + + for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { + freq = table[i].frequency; + + if (freq == target_freq) + return i; + + if (freq > target_freq) { + best = i; + continue; + } + + /* No freq found above target_freq */ + if (best == -1) + return i; + + /* Choose the closest freq */ + if (table[best].frequency - target_freq > target_freq - freq) + return i; + + return best; + } + + return best; +} + +/* Works only on sorted freq-tables */ +static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + target_freq = clamp_val(target_freq, policy->min, policy->max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + return cpufreq_table_find_index_ac(policy, target_freq); + else + return cpufreq_table_find_index_dc(policy, target_freq); +} + +static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED)) + return cpufreq_table_index_unsorted(policy, target_freq, + relation); + + switch (relation) { + case CPUFREQ_RELATION_L: + return cpufreq_table_find_index_l(policy, target_freq); + case CPUFREQ_RELATION_H: + return cpufreq_table_find_index_h(policy, target_freq); + case CPUFREQ_RELATION_C: + return cpufreq_table_find_index_c(policy, target_freq); + default: + pr_err("%s: Invalid relation: %d\n", __func__, relation); + return -EINVAL; + } +} #else static inline int cpufreq_boost_trigger_state(int state) { -- cgit v1.2.3 From f06628638cf6e75f179742b6c1b35076965b9fdd Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Tue, 28 Jun 2016 14:56:51 -0700 Subject: locking/atomic: Introduce inc/dec variants for the atomic_fetch_$op() API With the inclusion of atomic FETCH-OP variants, many places in the kernel can make use of atomic_fetch_$op() to avoid the callers that need to compute the value/state _before_ the operation. Peter Zijlstra laid out the machinery but we are still missing the simpler dec,inc() calls (which future patches will make use of). This patch only deals with the generic code, as at least right now no arch actually implement them -- which is similar to what the OP-RETURN primitives currently do. Signed-off-by: Davidlohr Bueso Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: James.Bottomley@HansenPartnership.com Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: awalls@md.metrocast.net Cc: bp@alien8.de Cc: cw00.choi@samsung.com Cc: davem@davemloft.net Cc: dledford@redhat.com Cc: dougthompson@xmission.com Cc: gregkh@linuxfoundation.org Cc: hans.verkuil@cisco.com Cc: heiko.carstens@de.ibm.com Cc: jikos@kernel.org Cc: kys@microsoft.com Cc: mchehab@osg.samsung.com Cc: pfg@sgi.com Cc: schwidefsky@de.ibm.com Cc: sean.hefty@intel.com Cc: sumit.semwal@linaro.org Link: http://lkml.kernel.org/r/20160628215651.GA20048@linux-80c1.suse Signed-off-by: Ingo Molnar --- include/asm-generic/atomic-long.h | 22 +++++++ include/linux/atomic.h | 128 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) (limited to 'include/linux') diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h index 2d0d3cf791ab..288cc9e96395 100644 --- a/include/asm-generic/atomic-long.h +++ b/include/asm-generic/atomic-long.h @@ -146,6 +146,28 @@ ATOMIC_LONG_FETCH_OP(xor, _relaxed) ATOMIC_LONG_FETCH_OP(xor, _acquire) ATOMIC_LONG_FETCH_OP(xor, _release) +#undef ATOMIC_LONG_FETCH_OP + +#define ATOMIC_LONG_FETCH_INC_DEC_OP(op, mo) \ +static inline long \ +atomic_long_fetch_##op##mo(atomic_long_t *l) \ +{ \ + ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ + \ + return (long)ATOMIC_LONG_PFX(_fetch_##op##mo)(v); \ +} + +ATOMIC_LONG_FETCH_INC_DEC_OP(inc,) +ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _relaxed) +ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _acquire) +ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _release) +ATOMIC_LONG_FETCH_INC_DEC_OP(dec,) +ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _relaxed) +ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _acquire) +ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _release) + +#undef ATOMIC_LONG_FETCH_INC_DEC_OP + #define ATOMIC_LONG_OP(op) \ static __always_inline void \ atomic_long_##op(long i, atomic_long_t *l) \ diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 12d910d61b83..e71835bf60a9 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -188,6 +188,38 @@ #endif #endif /* atomic_fetch_add_relaxed */ +/* atomic_fetch_inc_relaxed */ +#ifndef atomic_fetch_inc_relaxed + +#ifndef atomic_fetch_inc +#define atomic_fetch_inc(v) atomic_fetch_add(1, (v)) +#define atomic_fetch_inc_relaxed(v) atomic_fetch_add_relaxed(1, (v)) +#define atomic_fetch_inc_acquire(v) atomic_fetch_add_acquire(1, (v)) +#define atomic_fetch_inc_release(v) atomic_fetch_add_release(1, (v)) +#else /* atomic_fetch_inc */ +#define atomic_fetch_inc_relaxed atomic_fetch_inc +#define atomic_fetch_inc_acquire atomic_fetch_inc +#define atomic_fetch_inc_release atomic_fetch_inc +#endif /* atomic_fetch_inc */ + +#else /* atomic_fetch_inc_relaxed */ + +#ifndef atomic_fetch_inc_acquire +#define atomic_fetch_inc_acquire(...) \ + __atomic_op_acquire(atomic_fetch_inc, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_inc_release +#define atomic_fetch_inc_release(...) \ + __atomic_op_release(atomic_fetch_inc, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_inc +#define atomic_fetch_inc(...) \ + __atomic_op_fence(atomic_fetch_inc, __VA_ARGS__) +#endif +#endif /* atomic_fetch_inc_relaxed */ + /* atomic_fetch_sub_relaxed */ #ifndef atomic_fetch_sub_relaxed #define atomic_fetch_sub_relaxed atomic_fetch_sub @@ -212,6 +244,38 @@ #endif #endif /* atomic_fetch_sub_relaxed */ +/* atomic_fetch_dec_relaxed */ +#ifndef atomic_fetch_dec_relaxed + +#ifndef atomic_fetch_dec +#define atomic_fetch_dec(v) atomic_fetch_sub(1, (v)) +#define atomic_fetch_dec_relaxed(v) atomic_fetch_sub_relaxed(1, (v)) +#define atomic_fetch_dec_acquire(v) atomic_fetch_sub_acquire(1, (v)) +#define atomic_fetch_dec_release(v) atomic_fetch_sub_release(1, (v)) +#else /* atomic_fetch_dec */ +#define atomic_fetch_dec_relaxed atomic_fetch_dec +#define atomic_fetch_dec_acquire atomic_fetch_dec +#define atomic_fetch_dec_release atomic_fetch_dec +#endif /* atomic_fetch_dec */ + +#else /* atomic_fetch_dec_relaxed */ + +#ifndef atomic_fetch_dec_acquire +#define atomic_fetch_dec_acquire(...) \ + __atomic_op_acquire(atomic_fetch_dec, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_dec_release +#define atomic_fetch_dec_release(...) \ + __atomic_op_release(atomic_fetch_dec, __VA_ARGS__) +#endif + +#ifndef atomic_fetch_dec +#define atomic_fetch_dec(...) \ + __atomic_op_fence(atomic_fetch_dec, __VA_ARGS__) +#endif +#endif /* atomic_fetch_dec_relaxed */ + /* atomic_fetch_or_relaxed */ #ifndef atomic_fetch_or_relaxed #define atomic_fetch_or_relaxed atomic_fetch_or @@ -697,6 +761,38 @@ static inline int atomic_dec_if_positive(atomic_t *v) #endif #endif /* atomic64_fetch_add_relaxed */ +/* atomic64_fetch_inc_relaxed */ +#ifndef atomic64_fetch_inc_relaxed + +#ifndef atomic64_fetch_inc +#define atomic64_fetch_inc(v) atomic64_fetch_add(1, (v)) +#define atomic64_fetch_inc_relaxed(v) atomic64_fetch_add_relaxed(1, (v)) +#define atomic64_fetch_inc_acquire(v) atomic64_fetch_add_acquire(1, (v)) +#define atomic64_fetch_inc_release(v) atomic64_fetch_add_release(1, (v)) +#else /* atomic64_fetch_inc */ +#define atomic64_fetch_inc_relaxed atomic64_fetch_inc +#define atomic64_fetch_inc_acquire atomic64_fetch_inc +#define atomic64_fetch_inc_release atomic64_fetch_inc +#endif /* atomic64_fetch_inc */ + +#else /* atomic64_fetch_inc_relaxed */ + +#ifndef atomic64_fetch_inc_acquire +#define atomic64_fetch_inc_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_inc, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_inc_release +#define atomic64_fetch_inc_release(...) \ + __atomic_op_release(atomic64_fetch_inc, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_inc +#define atomic64_fetch_inc(...) \ + __atomic_op_fence(atomic64_fetch_inc, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_inc_relaxed */ + /* atomic64_fetch_sub_relaxed */ #ifndef atomic64_fetch_sub_relaxed #define atomic64_fetch_sub_relaxed atomic64_fetch_sub @@ -721,6 +817,38 @@ static inline int atomic_dec_if_positive(atomic_t *v) #endif #endif /* atomic64_fetch_sub_relaxed */ +/* atomic64_fetch_dec_relaxed */ +#ifndef atomic64_fetch_dec_relaxed + +#ifndef atomic64_fetch_dec +#define atomic64_fetch_dec(v) atomic64_fetch_sub(1, (v)) +#define atomic64_fetch_dec_relaxed(v) atomic64_fetch_sub_relaxed(1, (v)) +#define atomic64_fetch_dec_acquire(v) atomic64_fetch_sub_acquire(1, (v)) +#define atomic64_fetch_dec_release(v) atomic64_fetch_sub_release(1, (v)) +#else /* atomic64_fetch_dec */ +#define atomic64_fetch_dec_relaxed atomic64_fetch_dec +#define atomic64_fetch_dec_acquire atomic64_fetch_dec +#define atomic64_fetch_dec_release atomic64_fetch_dec +#endif /* atomic64_fetch_dec */ + +#else /* atomic64_fetch_dec_relaxed */ + +#ifndef atomic64_fetch_dec_acquire +#define atomic64_fetch_dec_acquire(...) \ + __atomic_op_acquire(atomic64_fetch_dec, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_dec_release +#define atomic64_fetch_dec_release(...) \ + __atomic_op_release(atomic64_fetch_dec, __VA_ARGS__) +#endif + +#ifndef atomic64_fetch_dec +#define atomic64_fetch_dec(...) \ + __atomic_op_fence(atomic64_fetch_dec, __VA_ARGS__) +#endif +#endif /* atomic64_fetch_dec_relaxed */ + /* atomic64_fetch_or_relaxed */ #ifndef atomic64_fetch_or_relaxed #define atomic64_fetch_or_relaxed atomic64_fetch_or -- cgit v1.2.3 From e675447bda51c1ea72d1ac9132ce3bed974f1da3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:15 +0000 Subject: timers: Make 'pinned' a timer property We want to move the timer migration logic from a 'push' to a 'pull' model. Under the current 'push' model pinned timers are handled via a runtime API variant: mod_timer_pinned(). The 'pull' model requires us to store the pinned attribute of a timer in the timer_list structure itself, as a new TIMER_PINNED bit in timer->flags. This flag must be set at initialization time and the timer APIs recognize the flag. This patch: - Implements the new flag and associated new-style initialization methods - makes mod_timer() recognize new-style pinned timers, - and adds some migration helper facility to allow step by step conversion of old-style to new-style pinned timers. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.049338558@linutronix.de Signed-off-by: Ingo Molnar --- include/linux/timer.h | 25 ++++++++++++++++++++++--- kernel/time/timer.c | 10 +++++----- 2 files changed, 27 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timer.h b/include/linux/timer.h index 20ac746f3eb3..046d6cf26498 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -62,7 +62,8 @@ struct timer_list { #define TIMER_MIGRATING 0x00080000 #define TIMER_BASEMASK (TIMER_CPUMASK | TIMER_MIGRATING) #define TIMER_DEFERRABLE 0x00100000 -#define TIMER_IRQSAFE 0x00200000 +#define TIMER_PINNED 0x00200000 +#define TIMER_IRQSAFE 0x00400000 #define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ .entry = { .next = TIMER_ENTRY_STATIC }, \ @@ -78,9 +79,15 @@ struct timer_list { #define TIMER_INITIALIZER(_function, _expires, _data) \ __TIMER_INITIALIZER((_function), (_expires), (_data), 0) +#define TIMER_PINNED_INITIALIZER(_function, _expires, _data) \ + __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_PINNED) + #define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data) \ __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE) +#define TIMER_PINNED_DEFERRED_INITIALIZER(_function, _expires, _data) \ + __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE | TIMER_PINNED) + #define DEFINE_TIMER(_name, _function, _expires, _data) \ struct timer_list _name = \ TIMER_INITIALIZER(_function, _expires, _data) @@ -124,8 +131,12 @@ static inline void init_timer_on_stack_key(struct timer_list *timer, #define init_timer(timer) \ __init_timer((timer), 0) +#define init_timer_pinned(timer) \ + __init_timer((timer), TIMER_PINNED) #define init_timer_deferrable(timer) \ __init_timer((timer), TIMER_DEFERRABLE) +#define init_timer_pinned_deferrable(timer) \ + __init_timer((timer), TIMER_DEFERRABLE | TIMER_PINNED) #define init_timer_on_stack(timer) \ __init_timer_on_stack((timer), 0) @@ -145,12 +156,20 @@ static inline void init_timer_on_stack_key(struct timer_list *timer, #define setup_timer(timer, fn, data) \ __setup_timer((timer), (fn), (data), 0) +#define setup_pinned_timer(timer, fn, data) \ + __setup_timer((timer), (fn), (data), TIMER_PINNED) #define setup_deferrable_timer(timer, fn, data) \ __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE) +#define setup_pinned_deferrable_timer(timer, fn, data) \ + __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE | TIMER_PINNED) #define setup_timer_on_stack(timer, fn, data) \ __setup_timer_on_stack((timer), (fn), (data), 0) +#define setup_pinned_timer_on_stack(timer, fn, data) \ + __setup_timer_on_stack((timer), (fn), (data), TIMER_PINNED) #define setup_deferrable_timer_on_stack(timer, fn, data) \ __setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE) +#define setup_pinned_deferrable_timer_on_stack(timer, fn, data) \ + __setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE | TIMER_PINNED) /** * timer_pending - is a timer pending? @@ -175,8 +194,8 @@ extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); extern void set_timer_slack(struct timer_list *time, int slack_hz); -#define TIMER_NOT_PINNED 0 -#define TIMER_PINNED 1 +#define MOD_TIMER_NOT_PINNED 0 +#define MOD_TIMER_PINNED 1 /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 3a95f9728778..693f6d14058e 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -782,7 +782,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, debug_activate(timer, expires); - new_base = get_target_base(base, pinned); + new_base = get_target_base(base, pinned || timer->flags & TIMER_PINNED); if (base != new_base) { /* @@ -825,7 +825,7 @@ out_unlock: */ int mod_timer_pending(struct timer_list *timer, unsigned long expires) { - return __mod_timer(timer, expires, true, TIMER_NOT_PINNED); + return __mod_timer(timer, expires, true, MOD_TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer_pending); @@ -900,7 +900,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires) if (timer_pending(timer) && timer->expires == expires) return 1; - return __mod_timer(timer, expires, false, TIMER_NOT_PINNED); + return __mod_timer(timer, expires, false, MOD_TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer); @@ -928,7 +928,7 @@ int mod_timer_pinned(struct timer_list *timer, unsigned long expires) if (timer->expires == expires && timer_pending(timer)) return 1; - return __mod_timer(timer, expires, false, TIMER_PINNED); + return __mod_timer(timer, expires, false, MOD_TIMER_PINNED); } EXPORT_SYMBOL(mod_timer_pinned); @@ -1512,7 +1512,7 @@ signed long __sched schedule_timeout(signed long timeout) expire = timeout + jiffies; setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); - __mod_timer(&timer, expire, false, TIMER_NOT_PINNED); + __mod_timer(&timer, expire, false, MOD_TIMER_NOT_PINNED); schedule(); del_singleshot_timer_sync(&timer); -- cgit v1.2.3 From 177ec0a0a531695210b277d734b2f92ee5796303 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:24 +0000 Subject: timers: Remove the deprecated mod_timer_pinned() API We switched all users to initialize the timers as pinned and call mod_timer(). Remove the now unused timer API function. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.706205231@linutronix.de Signed-off-by: Ingo Molnar --- include/linux/timer.h | 3 --- kernel/time/timer.c | 39 +++++---------------------------------- 2 files changed, 5 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timer.h b/include/linux/timer.h index 046d6cf26498..a8f6c70eb414 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -190,12 +190,9 @@ extern void add_timer_on(struct timer_list *timer, int cpu); extern int del_timer(struct timer_list * timer); extern int mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); -extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); extern void set_timer_slack(struct timer_list *time, int slack_hz); -#define MOD_TIMER_NOT_PINNED 0 -#define MOD_TIMER_PINNED 1 /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 693f6d14058e..ba49c1cf80f5 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -764,8 +764,7 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer, } static inline int -__mod_timer(struct timer_list *timer, unsigned long expires, - bool pending_only, int pinned) +__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) { struct tvec_base *base, *new_base; unsigned long flags; @@ -782,7 +781,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, debug_activate(timer, expires); - new_base = get_target_base(base, pinned || timer->flags & TIMER_PINNED); + new_base = get_target_base(base, timer->flags & TIMER_PINNED); if (base != new_base) { /* @@ -825,7 +824,7 @@ out_unlock: */ int mod_timer_pending(struct timer_list *timer, unsigned long expires) { - return __mod_timer(timer, expires, true, MOD_TIMER_NOT_PINNED); + return __mod_timer(timer, expires, true); } EXPORT_SYMBOL(mod_timer_pending); @@ -900,38 +899,10 @@ int mod_timer(struct timer_list *timer, unsigned long expires) if (timer_pending(timer) && timer->expires == expires) return 1; - return __mod_timer(timer, expires, false, MOD_TIMER_NOT_PINNED); + return __mod_timer(timer, expires, false); } EXPORT_SYMBOL(mod_timer); -/** - * mod_timer_pinned - modify a timer's timeout - * @timer: the timer to be modified - * @expires: new timeout in jiffies - * - * mod_timer_pinned() is a way to update the expire field of an - * active timer (if the timer is inactive it will be activated) - * and to ensure that the timer is scheduled on the current CPU. - * - * Note that this does not prevent the timer from being migrated - * when the current CPU goes offline. If this is a problem for - * you, use CPU-hotplug notifiers to handle it correctly, for - * example, cancelling the timer when the corresponding CPU goes - * offline. - * - * mod_timer_pinned(timer, expires) is equivalent to: - * - * del_timer(timer); timer->expires = expires; add_timer(timer); - */ -int mod_timer_pinned(struct timer_list *timer, unsigned long expires) -{ - if (timer->expires == expires && timer_pending(timer)) - return 1; - - return __mod_timer(timer, expires, false, MOD_TIMER_PINNED); -} -EXPORT_SYMBOL(mod_timer_pinned); - /** * add_timer - start a timer * @timer: the timer to be added @@ -1512,7 +1483,7 @@ signed long __sched schedule_timeout(signed long timeout) expire = timeout + jiffies; setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); - __mod_timer(&timer, expire, false, MOD_TIMER_NOT_PINNED); + __mod_timer(&timer, expire, false); schedule(); del_singleshot_timer_sync(&timer); -- cgit v1.2.3 From 15dba1e37b5cfd7fab9bc84e0f05f35c918f4eef Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:27 +0000 Subject: hlist: Add hlist_is_singular_node() helper Required to figure out whether the entry is the only one in the hlist. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094341.867631372@linutronix.de Signed-off-by: Ingo Molnar --- include/linux/list.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/linux') diff --git a/include/linux/list.h b/include/linux/list.h index 5356f4d661a7..5183138aa932 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -678,6 +678,16 @@ static inline bool hlist_fake(struct hlist_node *h) return h->pprev == &h->next; } +/* + * Check whether the node is the only node of the head without + * accessing head: + */ +static inline bool +hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h) +{ + return !n->next && n->pprev == &h->first; +} + /* * Move a list from one list head to another. Fixup the pprev * reference of the first entry if it exists. -- cgit v1.2.3 From b0d6e2dcb284f1f4dcb4b92760f49eeaf5fc0bc7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:29 +0000 Subject: timers: Reduce the CPU index space to 256k We want to store the array index in the flags space. 256k CPUs should be enough for a while. Signed-off-by: Thomas Gleixner Reviewed-by: Frederic Weisbecker Cc: Arjan van de Ven Cc: Chris Mason Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.030144293@linutronix.de Signed-off-by: Ingo Molnar --- include/linux/timer.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timer.h b/include/linux/timer.h index a8f6c70eb414..989f33d16ebf 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -58,12 +58,12 @@ struct timer_list { * workqueue locking issues. It's not meant for executing random crap * with interrupts disabled. Abuse is monitored! */ -#define TIMER_CPUMASK 0x0007FFFF -#define TIMER_MIGRATING 0x00080000 +#define TIMER_CPUMASK 0x0003FFFF +#define TIMER_MIGRATING 0x00040000 #define TIMER_BASEMASK (TIMER_CPUMASK | TIMER_MIGRATING) -#define TIMER_DEFERRABLE 0x00100000 -#define TIMER_PINNED 0x00200000 -#define TIMER_IRQSAFE 0x00400000 +#define TIMER_DEFERRABLE 0x00080000 +#define TIMER_PINNED 0x00100000 +#define TIMER_IRQSAFE 0x00200000 #define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ .entry = { .next = TIMER_ENTRY_STATIC }, \ -- cgit v1.2.3 From 500462a9de657f86edaa102f8ab6bff7f7e43fc2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:30 +0000 Subject: timers: Switch to a non-cascading wheel The current timer wheel has some drawbacks: 1) Cascading: Cascading can be an unbound operation and is completely pointless in most cases because the vast majority of the timer wheel timers are canceled or rearmed before expiration. (They are used as timeout safeguards, not as real timers to measure time.) 2) No fast lookup of the next expiring timer: In NOHZ scenarios the first timer soft interrupt after a long NOHZ period must fast forward the base time to the current value of jiffies. As we have no way to find the next expiring timer fast, the code loops linearly and increments the base time one by one and checks for expired timers in each step. This causes unbound overhead spikes exactly in the moment when we should wake up as fast as possible. After a thorough analysis of real world data gathered on laptops, workstations, webservers and other machines (thanks Chris!) I came to the conclusion that the current 'classic' timer wheel implementation can be modified to address the above issues. The vast majority of timer wheel timers is canceled or rearmed before expiry. Most of them are timeouts for networking and other I/O tasks. The nature of timeouts is to catch the exception from normal operation (TCP ack timed out, disk does not respond, etc.). For these kinds of timeouts the accuracy of the timeout is not really a concern. Timeouts are very often approximate worst-case values and in case the timeout fires, we already waited for a long time and performance is down the drain already. The few timers which actually expire can be split into two categories: 1) Short expiry times which expect halfways accurate expiry 2) Long term expiry times are inaccurate today already due to the batching which is done for NOHZ automatically and also via the set_timer_slack() API. So for long term expiry timers we can avoid the cascading property and just leave them in the less granular outer wheels until expiry or cancelation. Timers which are armed with a timeout larger than the wheel capacity are no longer cascaded. We expire them with the longest possible timeout (6+ days). We have not observed such timeouts in our data collection, but at least we handle them, applying the rule of the least surprise. To avoid extending the wheel levels for HZ=1000 so we can accomodate the longest observed timeouts (5 days in the network conntrack code) we reduce the first level granularity on HZ=1000 to 4ms, which effectively is the same as the HZ=250 behaviour. From our data analysis there is nothing which relies on that 1ms granularity and as a side effect we get better batching and timer locality for the networking code as well. Contrary to the classic wheel the granularity of the next wheel is not the capacity of the first wheel. The granularities of the wheels are in the currently chosen setting 8 times the granularity of the previous wheel. So for HZ=250 we end up with the following granularity levels: Level Offset Granularity Range 0 0 4 ms 0 ms - 252 ms 1 64 32 ms 256 ms - 2044 ms (256ms - ~2s) 2 128 256 ms 2048 ms - 16380 ms (~2s - ~16s) 3 192 2048 ms (~2s) 16384 ms - 131068 ms (~16s - ~2m) 4 256 16384 ms (~16s) 131072 ms - 1048572 ms (~2m - ~17m) 5 320 131072 ms (~2m) 1048576 ms - 8388604 ms (~17m - ~2h) 6 384 1048576 ms (~17m) 8388608 ms - 67108863 ms (~2h - ~18h) 7 448 8388608 ms (~2h) 67108864 ms - 536870911 ms (~18h - ~6d) That's a worst case inaccuracy of 12.5% for the timers which are queued at the beginning of a level. So the new wheel concept addresses the old issues: 1) Cascading is avoided completely 2) By keeping the timers in the bucket until expiry/cancelation we can track the buckets which have timers enqueued in a bucket bitmap and therefore can look up the next expiring timer very fast and O(1). A further benefit of the concept is that the slack calculation which is done on every timer start is no longer necessary because the granularity levels provide natural batching already. Our extensive testing with various loads did not show any performance degradation vs. the current wheel implementation. This patch does not address the 'fast lookup' issue as we wanted to make sure that there is no regression introduced by the wheel redesign. The optimizations are in follow up patches. This patch contains fixes from Anna-Maria Gleixner and Richard Cochran. Signed-off-by: Thomas Gleixner Cc: Arjan van de Ven Cc: Chris Mason Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.108621834@linutronix.de Signed-off-by: Ingo Molnar --- include/linux/timer.h | 2 + kernel/time/timer.c | 829 ++++++++++++++++++++++++++++---------------------- 2 files changed, 469 insertions(+), 362 deletions(-) (limited to 'include/linux') diff --git a/include/linux/timer.h b/include/linux/timer.h index 989f33d16ebf..5869ab9848fe 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -64,6 +64,8 @@ struct timer_list { #define TIMER_DEFERRABLE 0x00080000 #define TIMER_PINNED 0x00100000 #define TIMER_IRQSAFE 0x00200000 +#define TIMER_ARRAYSHIFT 22 +#define TIMER_ARRAYMASK 0xFFC00000 #define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ .entry = { .next = TIMER_ENTRY_STATIC }, \ diff --git a/kernel/time/timer.c b/kernel/time/timer.c index f259a3ef4577..86e95b72665d 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -59,43 +59,151 @@ __visible u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; EXPORT_SYMBOL(jiffies_64); /* - * per-CPU timer vector definitions: + * The timer wheel has LVL_DEPTH array levels. Each level provides an array of + * LVL_SIZE buckets. Each level is driven by its own clock and therefor each + * level has a different granularity. + * + * The level granularity is: LVL_CLK_DIV ^ lvl + * The level clock frequency is: HZ / (LVL_CLK_DIV ^ level) + * + * The array level of a newly armed timer depends on the relative expiry + * time. The farther the expiry time is away the higher the array level and + * therefor the granularity becomes. + * + * Contrary to the original timer wheel implementation, which aims for 'exact' + * expiry of the timers, this implementation removes the need for recascading + * the timers into the lower array levels. The previous 'classic' timer wheel + * implementation of the kernel already violated the 'exact' expiry by adding + * slack to the expiry time to provide batched expiration. The granularity + * levels provide implicit batching. + * + * This is an optimization of the original timer wheel implementation for the + * majority of the timer wheel use cases: timeouts. The vast majority of + * timeout timers (networking, disk I/O ...) are canceled before expiry. If + * the timeout expires it indicates that normal operation is disturbed, so it + * does not matter much whether the timeout comes with a slight delay. + * + * The only exception to this are networking timers with a small expiry + * time. They rely on the granularity. Those fit into the first wheel level, + * which has HZ granularity. + * + * We don't have cascading anymore. timers with a expiry time above the + * capacity of the last wheel level are force expired at the maximum timeout + * value of the last wheel level. From data sampling we know that the maximum + * value observed is 5 days (network connection tracking), so this should not + * be an issue. + * + * The currently chosen array constants values are a good compromise between + * array size and granularity. + * + * This results in the following granularity and range levels: + * + * HZ 1000 steps + * Level Offset Granularity Range + * 0 0 1 ms 0 ms - 63 ms + * 1 64 8 ms 64 ms - 511 ms + * 2 128 64 ms 512 ms - 4095 ms (512ms - ~4s) + * 3 192 512 ms 4096 ms - 32767 ms (~4s - ~32s) + * 4 256 4096 ms (~4s) 32768 ms - 262143 ms (~32s - ~4m) + * 5 320 32768 ms (~32s) 262144 ms - 2097151 ms (~4m - ~34m) + * 6 384 262144 ms (~4m) 2097152 ms - 16777215 ms (~34m - ~4h) + * 7 448 2097152 ms (~34m) 16777216 ms - 134217727 ms (~4h - ~1d) + * 8 512 16777216 ms (~4h) 134217728 ms - 1073741822 ms (~1d - ~12d) + * + * HZ 300 + * Level Offset Granularity Range + * 0 0 3 ms 0 ms - 210 ms + * 1 64 26 ms 213 ms - 1703 ms (213ms - ~1s) + * 2 128 213 ms 1706 ms - 13650 ms (~1s - ~13s) + * 3 192 1706 ms (~1s) 13653 ms - 109223 ms (~13s - ~1m) + * 4 256 13653 ms (~13s) 109226 ms - 873810 ms (~1m - ~14m) + * 5 320 109226 ms (~1m) 873813 ms - 6990503 ms (~14m - ~1h) + * 6 384 873813 ms (~14m) 6990506 ms - 55924050 ms (~1h - ~15h) + * 7 448 6990506 ms (~1h) 55924053 ms - 447392423 ms (~15h - ~5d) + * 8 512 55924053 ms (~15h) 447392426 ms - 3579139406 ms (~5d - ~41d) + * + * HZ 250 + * Level Offset Granularity Range + * 0 0 4 ms 0 ms - 255 ms + * 1 64 32 ms 256 ms - 2047 ms (256ms - ~2s) + * 2 128 256 ms 2048 ms - 16383 ms (~2s - ~16s) + * 3 192 2048 ms (~2s) 16384 ms - 131071 ms (~16s - ~2m) + * 4 256 16384 ms (~16s) 131072 ms - 1048575 ms (~2m - ~17m) + * 5 320 131072 ms (~2m) 1048576 ms - 8388607 ms (~17m - ~2h) + * 6 384 1048576 ms (~17m) 8388608 ms - 67108863 ms (~2h - ~18h) + * 7 448 8388608 ms (~2h) 67108864 ms - 536870911 ms (~18h - ~6d) + * 8 512 67108864 ms (~18h) 536870912 ms - 4294967288 ms (~6d - ~49d) + * + * HZ 100 + * Level Offset Granularity Range + * 0 0 10 ms 0 ms - 630 ms + * 1 64 80 ms 640 ms - 5110 ms (640ms - ~5s) + * 2 128 640 ms 5120 ms - 40950 ms (~5s - ~40s) + * 3 192 5120 ms (~5s) 40960 ms - 327670 ms (~40s - ~5m) + * 4 256 40960 ms (~40s) 327680 ms - 2621430 ms (~5m - ~43m) + * 5 320 327680 ms (~5m) 2621440 ms - 20971510 ms (~43m - ~5h) + * 6 384 2621440 ms (~43m) 20971520 ms - 167772150 ms (~5h - ~1d) + * 7 448 20971520 ms (~5h) 167772160 ms - 1342177270 ms (~1d - ~15d) */ -#define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6) -#define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8) -#define TVN_SIZE (1 << TVN_BITS) -#define TVR_SIZE (1 << TVR_BITS) -#define TVN_MASK (TVN_SIZE - 1) -#define TVR_MASK (TVR_SIZE - 1) -#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1)) - -struct tvec { - struct hlist_head vec[TVN_SIZE]; -}; -struct tvec_root { - struct hlist_head vec[TVR_SIZE]; -}; +/* Clock divisor for the next level */ +#define LVL_CLK_SHIFT 3 +#define LVL_CLK_DIV (1UL << LVL_CLK_SHIFT) +#define LVL_CLK_MASK (LVL_CLK_DIV - 1) +#define LVL_SHIFT(n) ((n) * LVL_CLK_SHIFT) +#define LVL_GRAN(n) (1UL << LVL_SHIFT(n)) + +/* + * The time start value for each level to select the bucket at enqueue + * time. + */ +#define LVL_START(n) ((LVL_SIZE - 1) << (((n) - 1) * LVL_CLK_SHIFT)) + +/* Size of each clock level */ +#define LVL_BITS 6 +#define LVL_SIZE (1UL << LVL_BITS) +#define LVL_MASK (LVL_SIZE - 1) +#define LVL_OFFS(n) ((n) * LVL_SIZE) + +/* Level depth */ +#if HZ > 100 +# define LVL_DEPTH 9 +# else +# define LVL_DEPTH 8 +#endif + +/* The cutoff (max. capacity of the wheel) */ +#define WHEEL_TIMEOUT_CUTOFF (LVL_START(LVL_DEPTH)) +#define WHEEL_TIMEOUT_MAX (WHEEL_TIMEOUT_CUTOFF - LVL_GRAN(LVL_DEPTH - 1)) + +/* + * The resulting wheel size. If NOHZ is configured we allocate two + * wheels so we have a separate storage for the deferrable timers. + */ +#define WHEEL_SIZE (LVL_SIZE * LVL_DEPTH) + +#ifdef CONFIG_NO_HZ_COMMON +# define NR_BASES 2 +# define BASE_STD 0 +# define BASE_DEF 1 +#else +# define NR_BASES 1 +# define BASE_STD 0 +# define BASE_DEF 0 +#endif struct timer_base { - spinlock_t lock; - struct timer_list *running_timer; - unsigned long clk; - unsigned long next_timer; - unsigned long active_timers; - unsigned long all_timers; - int cpu; - bool migration_enabled; - bool nohz_active; - struct tvec_root tv1; - struct tvec tv2; - struct tvec tv3; - struct tvec tv4; - struct tvec tv5; + spinlock_t lock; + struct timer_list *running_timer; + unsigned long clk; + unsigned int cpu; + bool migration_enabled; + bool nohz_active; + DECLARE_BITMAP(pending_map, WHEEL_SIZE); + struct hlist_head vectors[WHEEL_SIZE]; } ____cacheline_aligned; - -static DEFINE_PER_CPU(struct timer_base, timer_bases); +static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]); #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) unsigned int sysctl_timer_migration = 1; @@ -106,15 +214,17 @@ void timers_update_migration(bool update_nohz) unsigned int cpu; /* Avoid the loop, if nothing to update */ - if (this_cpu_read(timer_bases.migration_enabled) == on) + if (this_cpu_read(timer_bases[BASE_STD].migration_enabled) == on) return; for_each_possible_cpu(cpu) { - per_cpu(timer_bases.migration_enabled, cpu) = on; + per_cpu(timer_bases[BASE_STD].migration_enabled, cpu) = on; + per_cpu(timer_bases[BASE_DEF].migration_enabled, cpu) = on; per_cpu(hrtimer_bases.migration_enabled, cpu) = on; if (!update_nohz) continue; - per_cpu(timer_bases.nohz_active, cpu) = true; + per_cpu(timer_bases[BASE_STD].nohz_active, cpu) = true; + per_cpu(timer_bases[BASE_DEF].nohz_active, cpu) = true; per_cpu(hrtimer_bases.nohz_active, cpu) = true; } } @@ -133,20 +243,6 @@ int timer_migration_handler(struct ctl_table *table, int write, mutex_unlock(&mutex); return ret; } - -static inline struct timer_base *get_target_base(struct timer_base *base, - int pinned) -{ - if (pinned || !base->migration_enabled) - return this_cpu_ptr(&timer_bases); - return per_cpu_ptr(&timer_bases, get_nohz_timer_target()); -} -#else -static inline struct timer_base *get_target_base(struct timer_base *base, - int pinned) -{ - return this_cpu_ptr(&timer_bases); -} #endif static unsigned long round_jiffies_common(unsigned long j, int cpu, @@ -370,78 +466,91 @@ void set_timer_slack(struct timer_list *timer, int slack_hz) } EXPORT_SYMBOL_GPL(set_timer_slack); +static inline unsigned int timer_get_idx(struct timer_list *timer) +{ + return (timer->flags & TIMER_ARRAYMASK) >> TIMER_ARRAYSHIFT; +} + +static inline void timer_set_idx(struct timer_list *timer, unsigned int idx) +{ + timer->flags = (timer->flags & ~TIMER_ARRAYMASK) | + idx << TIMER_ARRAYSHIFT; +} + +/* + * Helper function to calculate the array index for a given expiry + * time. + */ +static inline unsigned calc_index(unsigned expires, unsigned lvl) +{ + expires = (expires + LVL_GRAN(lvl)) >> LVL_SHIFT(lvl); + return LVL_OFFS(lvl) + (expires & LVL_MASK); +} + static void __internal_add_timer(struct timer_base *base, struct timer_list *timer) { unsigned long expires = timer->expires; - unsigned long idx = expires - base->clk; + unsigned long delta = expires - base->clk; struct hlist_head *vec; - - if (idx < TVR_SIZE) { - int i = expires & TVR_MASK; - vec = base->tv1.vec + i; - } else if (idx < 1 << (TVR_BITS + TVN_BITS)) { - int i = (expires >> TVR_BITS) & TVN_MASK; - vec = base->tv2.vec + i; - } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) { - int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK; - vec = base->tv3.vec + i; - } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) { - int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK; - vec = base->tv4.vec + i; - } else if ((signed long) idx < 0) { - /* - * Can happen if you add a timer with expires == jiffies, - * or you set a timer to go off in the past - */ - vec = base->tv1.vec + (base->clk & TVR_MASK); + unsigned int idx; + + if (delta < LVL_START(1)) { + idx = calc_index(expires, 0); + } else if (delta < LVL_START(2)) { + idx = calc_index(expires, 1); + } else if (delta < LVL_START(3)) { + idx = calc_index(expires, 2); + } else if (delta < LVL_START(4)) { + idx = calc_index(expires, 3); + } else if (delta < LVL_START(5)) { + idx = calc_index(expires, 4); + } else if (delta < LVL_START(6)) { + idx = calc_index(expires, 5); + } else if (delta < LVL_START(7)) { + idx = calc_index(expires, 6); + } else if (LVL_DEPTH > 8 && delta < LVL_START(8)) { + idx = calc_index(expires, 7); + } else if ((long) delta < 0) { + idx = base->clk & LVL_MASK; } else { - int i; - /* If the timeout is larger than MAX_TVAL (on 64-bit - * architectures or with CONFIG_BASE_SMALL=1) then we - * use the maximum timeout. + /* + * Force expire obscene large timeouts to expire at the + * capacity limit of the wheel. */ - if (idx > MAX_TVAL) { - idx = MAX_TVAL; - expires = idx + base->clk; - } - i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; - vec = base->tv5.vec + i; - } + if (expires >= WHEEL_TIMEOUT_CUTOFF) + expires = WHEEL_TIMEOUT_MAX; + idx = calc_index(expires, LVL_DEPTH - 1); + } + /* + * Enqueue the timer into the array bucket, mark it pending in + * the bitmap and store the index in the timer flags. + */ + vec = base->vectors + idx; hlist_add_head(&timer->entry, vec); + __set_bit(idx, base->pending_map); + timer_set_idx(timer, idx); } static void internal_add_timer(struct timer_base *base, struct timer_list *timer) { - /* Advance base->jiffies, if the base is empty */ - if (!base->all_timers++) - base->clk = jiffies; - __internal_add_timer(base, timer); - /* - * Update base->active_timers and base->next_timer - */ - if (!(timer->flags & TIMER_DEFERRABLE)) { - if (!base->active_timers++ || - time_before(timer->expires, base->next_timer)) - base->next_timer = timer->expires; - } /* * Check whether the other CPU is in dynticks mode and needs - * to be triggered to reevaluate the timer wheel. - * We are protected against the other CPU fiddling - * with the timer by holding the timer base lock. This also - * makes sure that a CPU on the way to stop its tick can not - * evaluate the timer wheel. + * to be triggered to reevaluate the timer wheel. We are + * protected against the other CPU fiddling with the timer by + * holding the timer base lock. This also makes sure that a + * CPU on the way to stop its tick can not evaluate the timer + * wheel. * * Spare the IPI for deferrable timers on idle targets though. * The next busy ticks will take care of it. Except full dynticks * require special care against races with idle_cpu(), lets deal * with that later. */ - if (base->nohz_active) { + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) { if (!(timer->flags & TIMER_DEFERRABLE) || tick_nohz_full_cpu(base->cpu)) wake_up_nohz_cpu(base->cpu); @@ -706,54 +815,87 @@ static inline void detach_timer(struct timer_list *timer, bool clear_pending) entry->next = LIST_POISON2; } -static inline void -detach_expired_timer(struct timer_list *timer, struct timer_base *base) -{ - detach_timer(timer, true); - if (!(timer->flags & TIMER_DEFERRABLE)) - base->active_timers--; - base->all_timers--; -} - static int detach_if_pending(struct timer_list *timer, struct timer_base *base, bool clear_pending) { + unsigned idx = timer_get_idx(timer); + if (!timer_pending(timer)) return 0; + if (hlist_is_singular_node(&timer->entry, base->vectors + idx)) + __clear_bit(idx, base->pending_map); + detach_timer(timer, clear_pending); - if (!(timer->flags & TIMER_DEFERRABLE)) { - base->active_timers--; - if (timer->expires == base->next_timer) - base->next_timer = base->clk; - } - /* If this was the last timer, advance base->jiffies */ - if (!--base->all_timers) - base->clk = jiffies; return 1; } +static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu) +{ + struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu); + + /* + * If the timer is deferrable and nohz is active then we need to use + * the deferrable base. + */ + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && + (tflags & TIMER_DEFERRABLE)) + base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu); + return base; +} + +static inline struct timer_base *get_timer_this_cpu_base(u32 tflags) +{ + struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); + + /* + * If the timer is deferrable and nohz is active then we need to use + * the deferrable base. + */ + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && + (tflags & TIMER_DEFERRABLE)) + base = this_cpu_ptr(&timer_bases[BASE_DEF]); + return base; +} + +static inline struct timer_base *get_timer_base(u32 tflags) +{ + return get_timer_cpu_base(tflags, tflags & TIMER_CPUMASK); +} + +static inline struct timer_base *get_target_base(struct timer_base *base, + unsigned tflags) +{ +#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) + if ((tflags & TIMER_PINNED) || !base->migration_enabled) + return get_timer_this_cpu_base(tflags); + return get_timer_cpu_base(tflags, get_nohz_timer_target()); +#else + return get_timer_this_cpu_base(tflags); +#endif +} + /* - * We are using hashed locking: holding per_cpu(timer_bases).lock - * means that all timers which are tied to this base via timer->base are - * locked, and the base itself is locked too. + * We are using hashed locking: Holding per_cpu(timer_bases[x]).lock means + * that all timers which are tied to this base are locked, and the base itself + * is locked too. * * So __run_timers/migrate_timers can safely modify all timers which could - * be found on ->tvX lists. + * be found in the base->vectors array. * - * When the timer's base is locked and removed from the list, the - * TIMER_MIGRATING flag is set, FIXME + * When a timer is migrating then the TIMER_MIGRATING flag is set and we need + * to wait until the migration is done. */ static struct timer_base *lock_timer_base(struct timer_list *timer, - unsigned long *flags) + unsigned long *flags) __acquires(timer->base->lock) { for (;;) { - u32 tf = timer->flags; struct timer_base *base; + u32 tf = timer->flags; if (!(tf & TIMER_MIGRATING)) { - base = per_cpu_ptr(&timer_bases, tf & TIMER_CPUMASK); + base = get_timer_base(tf); spin_lock_irqsave(&base->lock, *flags); if (timer->flags == tf) return base; @@ -770,6 +912,27 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) unsigned long flags; int ret = 0; + /* + * TODO: Calculate the array bucket of the timer right here w/o + * holding the base lock. This allows to check not only + * timer->expires == expires below, but also whether the timer + * ends up in the same bucket. If we really need to requeue + * the timer then we check whether base->clk have + * advanced between here and locking the timer base. If + * jiffies advanced we have to recalc the array bucket with the + * lock held. + */ + + /* + * This is a common optimization triggered by the + * networking code - if the timer is re-modified + * to be the same thing then just return: + */ + if (timer_pending(timer)) { + if (timer->expires == expires) + return 1; + } + timer_stats_timer_set_start_info(timer); BUG_ON(!timer->function); @@ -781,15 +944,15 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) debug_activate(timer, expires); - new_base = get_target_base(base, timer->flags & TIMER_PINNED); + new_base = get_target_base(base, timer->flags); if (base != new_base) { /* - * We are trying to schedule the timer on the local CPU. + * We are trying to schedule the timer on the new base. * However we can't change timer's base while it is running, * otherwise del_timer_sync() can't detect that the timer's - * handler yet has not finished. This also guarantees that - * the timer is serialized wrt itself. + * handler yet has not finished. This also guarantees that the + * timer is serialized wrt itself. */ if (likely(base->running_timer != timer)) { /* See the comment in lock_timer_base() */ @@ -828,45 +991,6 @@ int mod_timer_pending(struct timer_list *timer, unsigned long expires) } EXPORT_SYMBOL(mod_timer_pending); -/* - * Decide where to put the timer while taking the slack into account - * - * Algorithm: - * 1) calculate the maximum (absolute) time - * 2) calculate the highest bit where the expires and new max are different - * 3) use this bit to make a mask - * 4) use the bitmask to round down the maximum time, so that all last - * bits are zeros - */ -static inline -unsigned long apply_slack(struct timer_list *timer, unsigned long expires) -{ - unsigned long expires_limit, mask; - int bit; - - if (timer->slack >= 0) { - expires_limit = expires + timer->slack; - } else { - long delta = expires - jiffies; - - if (delta < 256) - return expires; - - expires_limit = expires + delta / 256; - } - mask = expires ^ expires_limit; - if (mask == 0) - return expires; - - bit = __fls(mask); - - mask = (1UL << bit) - 1; - - expires_limit = expires_limit & ~(mask); - - return expires_limit; -} - /** * mod_timer - modify a timer's timeout * @timer: the timer to be modified @@ -889,16 +1013,6 @@ unsigned long apply_slack(struct timer_list *timer, unsigned long expires) */ int mod_timer(struct timer_list *timer, unsigned long expires) { - expires = apply_slack(timer, expires); - - /* - * This is a common optimization triggered by the - * networking code - if the timer is re-modified - * to be the same thing then just return: - */ - if (timer_pending(timer) && timer->expires == expires) - return 1; - return __mod_timer(timer, expires, false); } EXPORT_SYMBOL(mod_timer); @@ -933,13 +1047,14 @@ EXPORT_SYMBOL(add_timer); */ void add_timer_on(struct timer_list *timer, int cpu) { - struct timer_base *new_base = per_cpu_ptr(&timer_bases, cpu); - struct timer_base *base; + struct timer_base *new_base, *base; unsigned long flags; timer_stats_timer_set_start_info(timer); BUG_ON(timer_pending(timer) || !timer->function); + new_base = get_timer_cpu_base(timer->flags, cpu); + /* * If @timer was on a different CPU, it should be migrated with the * old base locked to prevent other operations proceeding with the @@ -1085,27 +1200,6 @@ int del_timer_sync(struct timer_list *timer) EXPORT_SYMBOL(del_timer_sync); #endif -static int cascade(struct timer_base *base, struct tvec *tv, int index) -{ - /* cascade all the timers from tv up one level */ - struct timer_list *timer; - struct hlist_node *tmp; - struct hlist_head tv_list; - - hlist_move_list(tv->vec + index, &tv_list); - - /* - * We are removing _all_ timers from the list, so we - * don't have to detach them individually. - */ - hlist_for_each_entry_safe(timer, tmp, &tv_list, entry) { - /* No accounting, while moving them */ - __internal_add_timer(base, timer); - } - - return index; -} - static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long), unsigned long data) { @@ -1149,68 +1243,80 @@ static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long), } } -#define INDEX(N) ((base->clk >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK) +static void expire_timers(struct timer_base *base, struct hlist_head *head) +{ + while (!hlist_empty(head)) { + struct timer_list *timer; + void (*fn)(unsigned long); + unsigned long data; + + timer = hlist_entry(head->first, struct timer_list, entry); + timer_stats_account_timer(timer); + + base->running_timer = timer; + detach_timer(timer, true); + + fn = timer->function; + data = timer->data; + + if (timer->flags & TIMER_IRQSAFE) { + spin_unlock(&base->lock); + call_timer_fn(timer, fn, data); + spin_lock(&base->lock); + } else { + spin_unlock_irq(&base->lock); + call_timer_fn(timer, fn, data); + spin_lock_irq(&base->lock); + } + } +} + +static int collect_expired_timers(struct timer_base *base, + struct hlist_head *heads) +{ + unsigned long clk = base->clk; + struct hlist_head *vec; + int i, levels = 0; + unsigned int idx; + + for (i = 0; i < LVL_DEPTH; i++) { + idx = (clk & LVL_MASK) + i * LVL_SIZE; + + if (__test_and_clear_bit(idx, base->pending_map)) { + vec = base->vectors + idx; + hlist_move_list(vec, heads++); + levels++; + } + /* Is it time to look at the next level? */ + if (clk & LVL_CLK_MASK) + break; + /* Shift clock for the next level granularity */ + clk >>= LVL_CLK_SHIFT; + } + return levels; +} /** * __run_timers - run all expired timers (if any) on this CPU. * @base: the timer vector to be processed. - * - * This function cascades all vectors and executes all expired timer - * vectors. */ static inline void __run_timers(struct timer_base *base) { - struct timer_list *timer; + struct hlist_head heads[LVL_DEPTH]; + int levels; + + if (!time_after_eq(jiffies, base->clk)) + return; spin_lock_irq(&base->lock); while (time_after_eq(jiffies, base->clk)) { - struct hlist_head work_list; - struct hlist_head *head = &work_list; - int index; - if (!base->all_timers) { - base->clk = jiffies; - break; - } - - index = base->clk & TVR_MASK; + levels = collect_expired_timers(base, heads); + base->clk++; - /* - * Cascade timers: - */ - if (!index && - (!cascade(base, &base->tv2, INDEX(0))) && - (!cascade(base, &base->tv3, INDEX(1))) && - !cascade(base, &base->tv4, INDEX(2))) - cascade(base, &base->tv5, INDEX(3)); - ++base->clk; - hlist_move_list(base->tv1.vec + index, head); - while (!hlist_empty(head)) { - void (*fn)(unsigned long); - unsigned long data; - bool irqsafe; - - timer = hlist_entry(head->first, struct timer_list, entry); - fn = timer->function; - data = timer->data; - irqsafe = timer->flags & TIMER_IRQSAFE; - - timer_stats_account_timer(timer); - - base->running_timer = timer; - detach_expired_timer(timer, base); - - if (irqsafe) { - spin_unlock(&base->lock); - call_timer_fn(timer, fn, data); - spin_lock(&base->lock); - } else { - spin_unlock_irq(&base->lock); - call_timer_fn(timer, fn, data); - spin_lock_irq(&base->lock); - } - } + while (levels--) + expire_timers(base, heads + levels); } base->running_timer = NULL; spin_unlock_irq(&base->lock); @@ -1218,78 +1324,87 @@ static inline void __run_timers(struct timer_base *base) #ifdef CONFIG_NO_HZ_COMMON /* - * Find out when the next timer event is due to happen. This - * is used on S/390 to stop all activity when a CPU is idle. - * This function needs to be called with interrupts disabled. + * Find the next pending bucket of a level. Search from @offset + @clk upwards + * and if nothing there, search from start of the level (@offset) up to + * @offset + clk. + */ +static int next_pending_bucket(struct timer_base *base, unsigned offset, + unsigned clk) +{ + unsigned pos, start = offset + clk; + unsigned end = offset + LVL_SIZE; + + pos = find_next_bit(base->pending_map, end, start); + if (pos < end) + return pos - start; + + pos = find_next_bit(base->pending_map, start, offset); + return pos < start ? pos + LVL_SIZE - start : -1; +} + +/* + * Search the first expiring timer in the various clock levels. */ static unsigned long __next_timer_interrupt(struct timer_base *base) { - unsigned long clk = base->clk; - unsigned long expires = clk + NEXT_TIMER_MAX_DELTA; - int index, slot, array, found = 0; - struct timer_list *nte; - struct tvec *varray[4]; - - /* Look for timer events in tv1. */ - index = slot = clk & TVR_MASK; - do { - hlist_for_each_entry(nte, base->tv1.vec + slot, entry) { - if (nte->flags & TIMER_DEFERRABLE) - continue; - - found = 1; - expires = nte->expires; - /* Look at the cascade bucket(s)? */ - if (!index || slot < index) - goto cascade; - return expires; + unsigned long clk, next, adj; + unsigned lvl, offset = 0; + + spin_lock(&base->lock); + next = base->clk + NEXT_TIMER_MAX_DELTA; + clk = base->clk; + for (lvl = 0; lvl < LVL_DEPTH; lvl++, offset += LVL_SIZE) { + int pos = next_pending_bucket(base, offset, clk & LVL_MASK); + + if (pos >= 0) { + unsigned long tmp = clk + (unsigned long) pos; + + tmp <<= LVL_SHIFT(lvl); + if (time_before(tmp, next)) + next = tmp; } - slot = (slot + 1) & TVR_MASK; - } while (slot != index); - -cascade: - /* Calculate the next cascade event */ - if (index) - clk += TVR_SIZE - index; - clk >>= TVR_BITS; - - /* Check tv2-tv5. */ - varray[0] = &base->tv2; - varray[1] = &base->tv3; - varray[2] = &base->tv4; - varray[3] = &base->tv5; - - for (array = 0; array < 4; array++) { - struct tvec *varp = varray[array]; - - index = slot = clk & TVN_MASK; - do { - hlist_for_each_entry(nte, varp->vec + slot, entry) { - if (nte->flags & TIMER_DEFERRABLE) - continue; - - found = 1; - if (time_before(nte->expires, expires)) - expires = nte->expires; - } - /* - * Do we still search for the first timer or are - * we looking up the cascade buckets ? - */ - if (found) { - /* Look at the cascade bucket(s)? */ - if (!index || slot < index) - break; - return expires; - } - slot = (slot + 1) & TVN_MASK; - } while (slot != index); - - if (index) - clk += TVN_SIZE - index; - clk >>= TVN_BITS; + /* + * Clock for the next level. If the current level clock lower + * bits are zero, we look at the next level as is. If not we + * need to advance it by one because that's going to be the + * next expiring bucket in that level. base->clk is the next + * expiring jiffie. So in case of: + * + * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 + * 0 0 0 0 0 0 + * + * we have to look at all levels @index 0. With + * + * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 + * 0 0 0 0 0 2 + * + * LVL0 has the next expiring bucket @index 2. The upper + * levels have the next expiring bucket @index 1. + * + * In case that the propagation wraps the next level the same + * rules apply: + * + * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 + * 0 0 0 0 F 2 + * + * So after looking at LVL0 we get: + * + * LVL5 LVL4 LVL3 LVL2 LVL1 + * 0 0 0 1 0 + * + * So no propagation from LVL1 to LVL2 because that happened + * with the add already, but then we need to propagate further + * from LVL2 to LVL3. + * + * So the simple check whether the lower bits of the current + * level are 0 or not is sufficient for all cases. + */ + adj = clk & LVL_CLK_MASK ? 1 : 0; + clk >>= LVL_CLK_SHIFT; + clk += adj; } - return expires; + spin_unlock(&base->lock); + return next; } /* @@ -1335,7 +1450,7 @@ static u64 cmp_next_hrtimer_event(u64 basem, u64 expires) */ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) { - struct timer_base *base = this_cpu_ptr(&timer_bases); + struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); u64 expires = KTIME_MAX; unsigned long nextevt; @@ -1346,17 +1461,11 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem) if (cpu_is_offline(smp_processor_id())) return expires; - spin_lock(&base->lock); - if (base->active_timers) { - if (time_before_eq(base->next_timer, base->clk)) - base->next_timer = __next_timer_interrupt(base); - nextevt = base->next_timer; - if (time_before_eq(nextevt, basej)) - expires = basem; - else - expires = basem + (nextevt - basej) * TICK_NSEC; - } - spin_unlock(&base->lock); + nextevt = __next_timer_interrupt(base); + if (time_before_eq(nextevt, basej)) + expires = basem; + else + expires = basem + (nextevt - basej) * TICK_NSEC; return cmp_next_hrtimer_event(basem, expires); } @@ -1387,10 +1496,11 @@ void update_process_times(int user_tick) */ static void run_timer_softirq(struct softirq_action *h) { - struct timer_base *base = this_cpu_ptr(&timer_bases); + struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - if (time_after_eq(jiffies, base->clk)) - __run_timers(base); + __run_timers(base); + if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) + __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); } /* @@ -1541,7 +1651,6 @@ static void migrate_timer_list(struct timer_base *new_base, struct hlist_head *h while (!hlist_empty(head)) { timer = hlist_entry(head->first, struct timer_list, entry); - /* We ignore the accounting on the dying cpu */ detach_timer(timer, false); timer->flags = (timer->flags & ~TIMER_BASEMASK) | cpu; internal_add_timer(new_base, timer); @@ -1552,35 +1661,29 @@ static void migrate_timers(int cpu) { struct timer_base *old_base; struct timer_base *new_base; - int i; + int b, i; BUG_ON(cpu_online(cpu)); - old_base = per_cpu_ptr(&timer_bases, cpu); - new_base = get_cpu_ptr(&timer_bases); - /* - * The caller is globally serialized and nobody else - * takes two locks at once, deadlock is not possible. - */ - spin_lock_irq(&new_base->lock); - spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); - - BUG_ON(old_base->running_timer); - - for (i = 0; i < TVR_SIZE; i++) - migrate_timer_list(new_base, old_base->tv1.vec + i); - for (i = 0; i < TVN_SIZE; i++) { - migrate_timer_list(new_base, old_base->tv2.vec + i); - migrate_timer_list(new_base, old_base->tv3.vec + i); - migrate_timer_list(new_base, old_base->tv4.vec + i); - migrate_timer_list(new_base, old_base->tv5.vec + i); - } - old_base->active_timers = 0; - old_base->all_timers = 0; + for (b = 0; b < NR_BASES; b++) { + old_base = per_cpu_ptr(&timer_bases[b], cpu); + new_base = get_cpu_ptr(&timer_bases[b]); + /* + * The caller is globally serialized and nobody else + * takes two locks at once, deadlock is not possible. + */ + spin_lock_irq(&new_base->lock); + spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); + + BUG_ON(old_base->running_timer); + + for (i = 0; i < WHEEL_SIZE; i++) + migrate_timer_list(new_base, old_base->vectors + i); - spin_unlock(&old_base->lock); - spin_unlock_irq(&new_base->lock); - put_cpu_ptr(&timer_bases); + spin_unlock(&old_base->lock); + spin_unlock_irq(&new_base->lock); + put_cpu_ptr(&timer_bases); + } } static int timer_cpu_notify(struct notifier_block *self, @@ -1608,13 +1711,15 @@ static inline void timer_register_cpu_notifier(void) { } static void __init init_timer_cpu(int cpu) { - struct timer_base *base = per_cpu_ptr(&timer_bases, cpu); - - base->cpu = cpu; - spin_lock_init(&base->lock); + struct timer_base *base; + int i; - base->clk = jiffies; - base->next_timer = base->clk; + for (i = 0; i < NR_BASES; i++) { + base = per_cpu_ptr(&timer_bases[i], cpu); + base->cpu = cpu; + spin_lock_init(&base->lock); + base->clk = jiffies; + } } static void __init init_timer_cpus(void) -- cgit v1.2.3 From 53bf837b78d155b8e1110b3c25b4d0d6391b8ff3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Jul 2016 09:50:31 +0000 Subject: timers: Remove set_timer_slack() leftovers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now have implicit batching in the timer wheel. The slack API is no longer used, so remove it. Signed-off-by: Thomas Gleixner Cc: Alan Stern Cc: Andrew F. Davis Cc: Arjan van de Ven Cc: Chris Mason Cc: David S. Miller Cc: David Woodhouse Cc: Dmitry Eremin-Solenikov Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: George Spelvin Cc: Greg Kroah-Hartman Cc: Jaehoon Chung Cc: Jens Axboe Cc: John Stultz Cc: Josh Triplett Cc: Len Brown Cc: Linus Torvalds Cc: Mathias Nyman Cc: Pali Rohár Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rik van Riel Cc: Sebastian Reichel Cc: Ulf Hansson Cc: linux-block@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mmc@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: linux-usb@vger.kernel.org Cc: netdev@vger.kernel.org Cc: rt@linutronix.de Link: http://lkml.kernel.org/r/20160704094342.189813118@linutronix.de Signed-off-by: Ingo Molnar --- block/genhd.c | 5 ----- drivers/mmc/host/jz4740_mmc.c | 2 -- drivers/power/bq27xxx_battery.c | 5 +---- drivers/usb/host/ohci-hcd.c | 1 - drivers/usb/host/xhci.c | 2 -- include/linux/timer.h | 4 ---- kernel/time/timer.c | 19 ------------------- lib/random32.c | 1 - 8 files changed, 1 insertion(+), 38 deletions(-) (limited to 'include/linux') diff --git a/block/genhd.c b/block/genhd.c index 9f42526b4d62..f06d7f3b075b 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1523,12 +1523,7 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now) if (--ev->block) goto out_unlock; - /* - * Not exactly a latency critical operation, set poll timer - * slack to 25% and kick event check. - */ intv = disk_events_poll_jiffies(disk); - set_timer_slack(&ev->dwork.timer, intv / 4); if (check_now) queue_delayed_work(system_freezable_power_efficient_wq, &ev->dwork, 0); diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 03ddf0ecf402..684087db170b 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1068,8 +1068,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev) jz4740_mmc_clock_disable(host); setup_timer(&host->timeout_timer, jz4740_mmc_timeout, (unsigned long)host); - /* It is not important when it times out, it just needs to timeout. */ - set_timer_slack(&host->timeout_timer, HZ); host->use_dma = true; if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0) diff --git a/drivers/power/bq27xxx_battery.c b/drivers/power/bq27xxx_battery.c index 45f6ebf88df6..e90b3f307e0f 100644 --- a/drivers/power/bq27xxx_battery.c +++ b/drivers/power/bq27xxx_battery.c @@ -735,11 +735,8 @@ static void bq27xxx_battery_poll(struct work_struct *work) bq27xxx_battery_update(di); - if (poll_interval > 0) { - /* The timer does not have to be accurate. */ - set_timer_slack(&di->work.timer, poll_interval * HZ / 4); + if (poll_interval > 0) schedule_delayed_work(&di->work, poll_interval * HZ); - } } /* diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0449235d4f22..1700908b84ef 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -500,7 +500,6 @@ static int ohci_init (struct ohci_hcd *ohci) setup_timer(&ohci->io_watchdog, io_watchdog_func, (unsigned long) ohci); - set_timer_slack(&ohci->io_watchdog, msecs_to_jiffies(20)); ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f2f9518c53ab..a986fe763d87 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -490,8 +490,6 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) xhci->comp_mode_recovery_timer.expires = jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS); - set_timer_slack(&xhci->comp_mode_recovery_timer, - msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); add_timer(&xhci->comp_mode_recovery_timer); xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, "Compliance mode recovery timer initialized"); diff --git a/include/linux/timer.h b/include/linux/timer.h index 5869ab9848fe..4419506b564e 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -19,7 +19,6 @@ struct timer_list { void (*function)(unsigned long); unsigned long data; u32 flags; - int slack; #ifdef CONFIG_TIMER_STATS int start_pid; @@ -73,7 +72,6 @@ struct timer_list { .expires = (_expires), \ .data = (_data), \ .flags = (_flags), \ - .slack = -1, \ __TIMER_LOCKDEP_MAP_INITIALIZER( \ __FILE__ ":" __stringify(__LINE__)) \ } @@ -193,8 +191,6 @@ extern int del_timer(struct timer_list * timer); extern int mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); -extern void set_timer_slack(struct timer_list *time, int slack_hz); - /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 86e95b72665d..a83e23d0bc25 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -447,24 +447,6 @@ unsigned long round_jiffies_up_relative(unsigned long j) } EXPORT_SYMBOL_GPL(round_jiffies_up_relative); -/** - * set_timer_slack - set the allowed slack for a timer - * @timer: the timer to be modified - * @slack_hz: the amount of time (in jiffies) allowed for rounding - * - * Set the amount of time, in jiffies, that a certain timer has - * in terms of slack. By setting this value, the timer subsystem - * will schedule the actual timer somewhere between - * the time mod_timer() asks for, and that time plus the slack. - * - * By setting the slack to -1, a percentage of the delay is used - * instead. - */ -void set_timer_slack(struct timer_list *timer, int slack_hz) -{ - timer->slack = slack_hz; -} -EXPORT_SYMBOL_GPL(set_timer_slack); static inline unsigned int timer_get_idx(struct timer_list *timer) { @@ -775,7 +757,6 @@ static void do_init_timer(struct timer_list *timer, unsigned int flags, { timer->entry.pprev = NULL; timer->flags = flags | raw_smp_processor_id(); - timer->slack = -1; #ifdef CONFIG_TIMER_STATS timer->start_site = NULL; timer->start_pid = -1; diff --git a/lib/random32.c b/lib/random32.c index 510d1ce7d4d2..69ed593aab07 100644 --- a/lib/random32.c +++ b/lib/random32.c @@ -233,7 +233,6 @@ static void __prandom_timer(unsigned long dontcare) static void __init __prandom_start_seed_timer(void) { - set_timer_slack(&seed_timer, HZ); seed_timer.expires = jiffies + msecs_to_jiffies(40 * MSEC_PER_SEC); add_timer(&seed_timer); } -- cgit v1.2.3 From 529435e8188674fa1071235f50e6fbbbe020c93f Mon Sep 17 00:00:00 2001 From: Javier González Date: Thu, 7 Jul 2016 09:54:08 +0200 Subject: lightnvm: add media manager mark_blk helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose media manager mark_blk() to targets, as done for the rest of the media manager callback functions. Signed-off-by: Javier González Updated description Signed-off-by: Matias Bjørling Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/core.c | 6 ++++++ include/linux/lightnvm.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'include/linux') diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 160c1a6838e1..13993c905601 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -210,6 +210,12 @@ void nvm_put_blk(struct nvm_dev *dev, struct nvm_block *blk) } EXPORT_SYMBOL(nvm_put_blk); +void nvm_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type) +{ + return dev->mt->mark_blk(dev, ppa, type); +} +EXPORT_SYMBOL(nvm_mark_blk); + int nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) { return dev->mt->submit_io(dev, rqd); diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index ef2c7d2e76c4..9c56148d6f63 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -532,6 +532,8 @@ extern int nvm_register(struct request_queue *, char *, struct nvm_dev_ops *); extern void nvm_unregister(char *); +void nvm_mark_blk(struct nvm_dev *dev, struct ppa_addr ppa, int type); + extern int nvm_submit_io(struct nvm_dev *, struct nvm_rq *); extern void nvm_generic_to_addr_mode(struct nvm_dev *, struct nvm_rq *); extern void nvm_addr_to_generic_mode(struct nvm_dev *, struct nvm_rq *); -- cgit v1.2.3 From 5389a1dfb39786df08d4f6a482bd2734b1b50e33 Mon Sep 17 00:00:00 2001 From: Javier González Date: Thu, 7 Jul 2016 09:54:09 +0200 Subject: lightnvm: initialize ppa_addr in dev_to_generic_addr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ->reserved bit is not initialized when allocated on stack. This may lead targets to misinterpret the PPA as cached. Signed-off-by: Javier González Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- include/linux/lightnvm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 9c56148d6f63..cee4c8de34d5 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -385,6 +385,7 @@ static inline struct ppa_addr dev_to_generic_addr(struct nvm_dev *dev, { struct ppa_addr l; + l.ppa = 0; /* * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc. */ -- cgit v1.2.3 From 077d2389994197277f4f7662b13d11b2f67646a7 Mon Sep 17 00:00:00 2001 From: Matias Bjørling Date: Thu, 7 Jul 2016 09:54:14 +0200 Subject: lightnvm: remove open/close statistics for gennvm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The responsibility of the media manager is not to keep track of open/closed blocks. This is better maintained within a target, that already manages this information on writes. Remove the statistics and merge the states NVM_BLK_ST_OPEN and NVM_BLK_ST_CLOSED. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/gennvm.c | 31 ++++++------------------------- drivers/lightnvm/rrpc.c | 5 ----- include/linux/lightnvm.h | 13 ++----------- 3 files changed, 8 insertions(+), 41 deletions(-) (limited to 'include/linux') diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index ec9fb6876e38..1a3e1649346b 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -122,9 +122,6 @@ static int gennvm_luns_init(struct nvm_dev *dev, struct gen_nvm *gn) lun->vlun.lun_id = i % dev->luns_per_chnl; lun->vlun.chnl_id = i / dev->luns_per_chnl; lun->vlun.nr_free_blocks = dev->blks_per_lun; - lun->vlun.nr_open_blocks = 0; - lun->vlun.nr_closed_blocks = 0; - lun->vlun.nr_bad_blocks = 0; } return 0; } @@ -149,7 +146,6 @@ static int gennvm_block_bb(struct gen_nvm *gn, struct ppa_addr ppa, blk = &lun->vlun.blocks[i]; list_move_tail(&blk->list, &lun->bb_list); - lun->vlun.nr_bad_blocks++; lun->vlun.nr_free_blocks--; } @@ -200,9 +196,8 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private) * block state. The block is assumed to be open. */ list_move_tail(&blk->list, &lun->used_list); - blk->state = NVM_BLK_ST_OPEN; + blk->state = NVM_BLK_ST_TGT; lun->vlun.nr_free_blocks--; - lun->vlun.nr_open_blocks++; } } @@ -346,11 +341,10 @@ static struct nvm_block *gennvm_get_blk_unlocked(struct nvm_dev *dev, goto out; blk = list_first_entry(&lun->free_list, struct nvm_block, list); - list_move_tail(&blk->list, &lun->used_list); - blk->state = NVM_BLK_ST_OPEN; + list_move_tail(&blk->list, &lun->used_list); + blk->state = NVM_BLK_ST_TGT; lun->vlun.nr_free_blocks--; - lun->vlun.nr_open_blocks++; out: return blk; @@ -374,27 +368,18 @@ static void gennvm_put_blk_unlocked(struct nvm_dev *dev, struct nvm_block *blk) assert_spin_locked(&vlun->lock); - if (blk->state & NVM_BLK_ST_OPEN) { - list_move_tail(&blk->list, &lun->free_list); - lun->vlun.nr_open_blocks--; - lun->vlun.nr_free_blocks++; - blk->state = NVM_BLK_ST_FREE; - } else if (blk->state & NVM_BLK_ST_CLOSED) { + if (blk->state & NVM_BLK_ST_TGT) { list_move_tail(&blk->list, &lun->free_list); - lun->vlun.nr_closed_blocks--; lun->vlun.nr_free_blocks++; blk->state = NVM_BLK_ST_FREE; } else if (blk->state & NVM_BLK_ST_BAD) { list_move_tail(&blk->list, &lun->bb_list); - lun->vlun.nr_bad_blocks++; blk->state = NVM_BLK_ST_BAD; } else { WARN_ON_ONCE(1); pr_err("gennvm: erroneous block type (%lu -> %u)\n", blk->id, blk->state); list_move_tail(&blk->list, &lun->bb_list); - lun->vlun.nr_bad_blocks++; - blk->state = NVM_BLK_ST_BAD; } } @@ -516,12 +501,8 @@ static void gennvm_lun_info_print(struct nvm_dev *dev) gennvm_for_each_lun(gn, lun, i) { spin_lock(&lun->vlun.lock); - pr_info("%s: lun%8u\t%u\t%u\t%u\t%u\n", - dev->name, i, - lun->vlun.nr_free_blocks, - lun->vlun.nr_open_blocks, - lun->vlun.nr_closed_blocks, - lun->vlun.nr_bad_blocks); + pr_info("%s: lun%8u\t%u\n", dev->name, i, + lun->vlun.nr_free_blocks); spin_unlock(&lun->vlun.lock); } diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 90c7cb4e9c43..c3a6f34d3b7c 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -512,17 +512,12 @@ static void rrpc_gc_queue(struct work_struct *work) struct rrpc_block *rblk = gcb->rblk; struct rrpc_lun *rlun = rblk->rlun; struct nvm_lun *lun = rblk->parent->lun; - struct nvm_block *blk = rblk->parent; spin_lock(&rlun->lock); list_add_tail(&rblk->prio, &rlun->prio_list); spin_unlock(&rlun->lock); spin_lock(&lun->lock); - lun->nr_open_blocks--; - lun->nr_closed_blocks++; - blk->state &= ~NVM_BLK_ST_OPEN; - blk->state |= NVM_BLK_ST_CLOSED; list_move_tail(&rblk->list, &rlun->closed_list); spin_unlock(&lun->lock); diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index cee4c8de34d5..8b51d5767331 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -269,24 +269,15 @@ struct nvm_lun { int lun_id; int chnl_id; - /* It is up to the target to mark blocks as closed. If the target does - * not do it, all blocks are marked as open, and nr_open_blocks - * represents the number of blocks in use - */ - unsigned int nr_open_blocks; /* Number of used, writable blocks */ - unsigned int nr_closed_blocks; /* Number of used, read-only blocks */ - unsigned int nr_free_blocks; /* Number of unused blocks */ - unsigned int nr_bad_blocks; /* Number of bad blocks */ - spinlock_t lock; + unsigned int nr_free_blocks; /* Number of unused blocks */ struct nvm_block *blocks; }; enum { NVM_BLK_ST_FREE = 0x1, /* Free block */ - NVM_BLK_ST_OPEN = 0x2, /* Open block - read-write */ - NVM_BLK_ST_CLOSED = 0x4, /* Closed block - read-only */ + NVM_BLK_ST_TGT = 0x2, /* Block in use by target */ NVM_BLK_ST_BAD = 0x8, /* Bad block */ }; -- cgit v1.2.3 From b76eb20bb0c6f4f9c2e1ad493f73c52817b8aaff Mon Sep 17 00:00:00 2001 From: Matias Bjørling Date: Thu, 7 Jul 2016 09:54:16 +0200 Subject: lightnvm: move target mgmt into media mgr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To enable persistent block management to easily control creation and removal of targets, we move target management into the media manager. The LightNVM core continues to maintain which target types are registered, while the media manager now keeps track of its initialized targets. Two new callbacks for the media manager are introduced. create_tgt and remove_tgt. Note that remove_tgt returns 0 on successfully removing a target, and returns 1 if the target was not found. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/core.c | 198 +++++++++------------------------------------- drivers/lightnvm/gennvm.c | 154 ++++++++++++++++++++++++++++++++++++ drivers/lightnvm/gennvm.h | 3 + include/linux/lightnvm.h | 10 +++ 4 files changed, 206 insertions(+), 159 deletions(-) (limited to 'include/linux') diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 0da196f6891b..8afb04cc4d5a 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -18,8 +18,6 @@ * */ -#include -#include #include #include #include @@ -28,42 +26,37 @@ #include #include #include -#include static LIST_HEAD(nvm_tgt_types); static LIST_HEAD(nvm_mgrs); static LIST_HEAD(nvm_devices); -static LIST_HEAD(nvm_targets); static DECLARE_RWSEM(nvm_lock); -static struct nvm_target *nvm_find_target(const char *name) +struct nvm_tgt_type *nvm_find_target_type(const char *name, int lock) { - struct nvm_target *tgt; + struct nvm_tgt_type *tmp, *tt = NULL; - list_for_each_entry(tgt, &nvm_targets, list) - if (!strcmp(name, tgt->disk->disk_name)) - return tgt; + if (lock) + down_write(&nvm_lock); - return NULL; -} - -static struct nvm_tgt_type *nvm_find_target_type(const char *name) -{ - struct nvm_tgt_type *tt; - - list_for_each_entry(tt, &nvm_tgt_types, list) - if (!strcmp(name, tt->name)) - return tt; + list_for_each_entry(tmp, &nvm_tgt_types, list) + if (!strcmp(name, tmp->name)) { + tt = tmp; + break; + } - return NULL; + if (lock) + up_write(&nvm_lock); + return tt; } +EXPORT_SYMBOL(nvm_find_target_type); int nvm_register_tgt_type(struct nvm_tgt_type *tt) { int ret = 0; down_write(&nvm_lock); - if (nvm_find_target_type(tt->name)) + if (nvm_find_target_type(tt->name, 0)) ret = -EEXIST; else list_add(&tt->list, &nvm_tgt_types); @@ -605,42 +598,11 @@ err_fmtype: return ret; } -static void nvm_remove_target(struct nvm_target *t) -{ - struct nvm_tgt_type *tt = t->type; - struct gendisk *tdisk = t->disk; - struct request_queue *q = tdisk->queue; - - lockdep_assert_held(&nvm_lock); - - del_gendisk(tdisk); - blk_cleanup_queue(q); - - if (tt->exit) - tt->exit(tdisk->private_data); - - put_disk(tdisk); - - list_del(&t->list); - kfree(t); -} - static void nvm_free_mgr(struct nvm_dev *dev) { - struct nvm_target *tgt, *tmp; - if (!dev->mt) return; - down_write(&nvm_lock); - list_for_each_entry_safe(tgt, tmp, &nvm_targets, list) { - if (tgt->dev != dev) - continue; - - nvm_remove_target(tgt); - } - up_write(&nvm_lock); - dev->mt->unregister_mgr(dev); dev->mt = NULL; } @@ -787,91 +749,6 @@ void nvm_unregister(char *disk_name) } EXPORT_SYMBOL(nvm_unregister); -static const struct block_device_operations nvm_fops = { - .owner = THIS_MODULE, -}; - -static int nvm_create_target(struct nvm_dev *dev, - struct nvm_ioctl_create *create) -{ - struct nvm_ioctl_create_simple *s = &create->conf.s; - struct request_queue *tqueue; - struct gendisk *tdisk; - struct nvm_tgt_type *tt; - struct nvm_target *t; - void *targetdata; - - if (!dev->mt) { - pr_info("nvm: device has no media manager registered.\n"); - return -ENODEV; - } - - down_write(&nvm_lock); - tt = nvm_find_target_type(create->tgttype); - if (!tt) { - pr_err("nvm: target type %s not found\n", create->tgttype); - up_write(&nvm_lock); - return -EINVAL; - } - - t = nvm_find_target(create->tgtname); - if (t) { - pr_err("nvm: target name already exists.\n"); - up_write(&nvm_lock); - return -EINVAL; - } - up_write(&nvm_lock); - - t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL); - if (!t) - return -ENOMEM; - - tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node); - if (!tqueue) - goto err_t; - blk_queue_make_request(tqueue, tt->make_rq); - - tdisk = alloc_disk(0); - if (!tdisk) - goto err_queue; - - sprintf(tdisk->disk_name, "%s", create->tgtname); - tdisk->flags = GENHD_FL_EXT_DEVT; - tdisk->major = 0; - tdisk->first_minor = 0; - tdisk->fops = &nvm_fops; - tdisk->queue = tqueue; - - targetdata = tt->init(dev, tdisk, s->lun_begin, s->lun_end); - if (IS_ERR(targetdata)) - goto err_init; - - tdisk->private_data = targetdata; - tqueue->queuedata = targetdata; - - blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect); - - set_capacity(tdisk, tt->capacity(targetdata)); - add_disk(tdisk); - - t->type = tt; - t->disk = tdisk; - t->dev = dev; - - down_write(&nvm_lock); - list_add_tail(&t->list, &nvm_targets); - up_write(&nvm_lock); - - return 0; -err_init: - put_disk(tdisk); -err_queue: - blk_cleanup_queue(tqueue); -err_t: - kfree(t); - return -ENOMEM; -} - static int __nvm_configure_create(struct nvm_ioctl_create *create) { struct nvm_dev *dev; @@ -880,11 +757,17 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create) down_write(&nvm_lock); dev = nvm_find_nvm_dev(create->dev); up_write(&nvm_lock); + if (!dev) { pr_err("nvm: device not found\n"); return -EINVAL; } + if (!dev->mt) { + pr_info("nvm: device has no media manager registered.\n"); + return -ENODEV; + } + if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE) { pr_err("nvm: config type not valid\n"); return -EINVAL; @@ -897,25 +780,7 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create) return -EINVAL; } - return nvm_create_target(dev, create); -} - -static int __nvm_configure_remove(struct nvm_ioctl_remove *remove) -{ - struct nvm_target *t; - - down_write(&nvm_lock); - t = nvm_find_target(remove->tgtname); - if (!t) { - pr_err("nvm: target \"%s\" doesn't exist.\n", remove->tgtname); - up_write(&nvm_lock); - return -EINVAL; - } - - nvm_remove_target(t); - up_write(&nvm_lock); - - return 0; + return dev->mt->create_tgt(dev, create); } #ifdef CONFIG_NVM_DEBUG @@ -950,8 +815,9 @@ static int nvm_configure_show(const char *val) static int nvm_configure_remove(const char *val) { struct nvm_ioctl_remove remove; + struct nvm_dev *dev; char opcode; - int ret; + int ret = 0; ret = sscanf(val, "%c %256s", &opcode, remove.tgtname); if (ret != 2) { @@ -961,7 +827,13 @@ static int nvm_configure_remove(const char *val) remove.flags = 0; - return __nvm_configure_remove(&remove); + list_for_each_entry(dev, &nvm_devices, devices) { + ret = dev->mt->remove_tgt(dev, &remove); + if (!ret) + break; + } + + return ret; } static int nvm_configure_create(const char *val) @@ -1158,6 +1030,8 @@ static long nvm_ioctl_dev_create(struct file *file, void __user *arg) static long nvm_ioctl_dev_remove(struct file *file, void __user *arg) { struct nvm_ioctl_remove remove; + struct nvm_dev *dev; + int ret = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1172,7 +1046,13 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg) return -EINVAL; } - return __nvm_configure_remove(&remove); + list_for_each_entry(dev, &nvm_devices, devices) { + ret = dev->mt->remove_tgt(dev, &remove); + if (!ret) + break; + } + + return ret; } static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info) diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index 3d2762f2a6fe..41760b24bea7 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -20,6 +20,144 @@ #include "gennvm.h" +static struct nvm_target *gen_find_target(struct gen_dev *gn, const char *name) +{ + struct nvm_target *tgt; + + list_for_each_entry(tgt, &gn->targets, list) + if (!strcmp(name, tgt->disk->disk_name)) + return tgt; + + return NULL; +} + +static const struct block_device_operations gen_fops = { + .owner = THIS_MODULE, +}; + +static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) +{ + struct gen_dev *gn = dev->mp; + struct nvm_ioctl_create_simple *s = &create->conf.s; + struct request_queue *tqueue; + struct gendisk *tdisk; + struct nvm_tgt_type *tt; + struct nvm_target *t; + void *targetdata; + + tt = nvm_find_target_type(create->tgttype, 1); + if (!tt) { + pr_err("nvm: target type %s not found\n", create->tgttype); + return -EINVAL; + } + + mutex_lock(&gn->lock); + t = gen_find_target(gn, create->tgtname); + if (t) { + pr_err("nvm: target name already exists.\n"); + mutex_unlock(&gn->lock); + return -EINVAL; + } + mutex_unlock(&gn->lock); + + t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL); + if (!t) + return -ENOMEM; + + tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node); + if (!tqueue) + goto err_t; + blk_queue_make_request(tqueue, tt->make_rq); + + tdisk = alloc_disk(0); + if (!tdisk) + goto err_queue; + + sprintf(tdisk->disk_name, "%s", create->tgtname); + tdisk->flags = GENHD_FL_EXT_DEVT; + tdisk->major = 0; + tdisk->first_minor = 0; + tdisk->fops = &gen_fops; + tdisk->queue = tqueue; + + targetdata = tt->init(dev, tdisk, s->lun_begin, s->lun_end); + if (IS_ERR(targetdata)) + goto err_init; + + tdisk->private_data = targetdata; + tqueue->queuedata = targetdata; + + blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect); + + set_capacity(tdisk, tt->capacity(targetdata)); + add_disk(tdisk); + + t->type = tt; + t->disk = tdisk; + t->dev = dev; + + mutex_lock(&gn->lock); + list_add_tail(&t->list, &gn->targets); + mutex_unlock(&gn->lock); + + return 0; +err_init: + put_disk(tdisk); +err_queue: + blk_cleanup_queue(tqueue); +err_t: + kfree(t); + return -ENOMEM; +} + +static void __gen_remove_target(struct nvm_target *t) +{ + struct nvm_tgt_type *tt = t->type; + struct gendisk *tdisk = t->disk; + struct request_queue *q = tdisk->queue; + + del_gendisk(tdisk); + blk_cleanup_queue(q); + + if (tt->exit) + tt->exit(tdisk->private_data); + + put_disk(tdisk); + + list_del(&t->list); + kfree(t); +} + +/** + * gen_remove_tgt - Removes a target from the media manager + * @dev: device + * @remove: ioctl structure with target name to remove. + * + * Returns: + * 0: on success + * 1: on not found + * <0: on error + */ +static int gen_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove) +{ + struct gen_dev *gn = dev->mp; + struct nvm_target *t; + + if (!gn) + return 1; + + mutex_lock(&gn->lock); + t = gen_find_target(gn, remove->tgtname); + if (!t) { + mutex_unlock(&gn->lock); + return 1; + } + __gen_remove_target(t); + mutex_unlock(&gn->lock); + + return 0; +} + static int gen_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len) { struct gen_dev *gn = dev->mp; @@ -295,6 +433,8 @@ static int gen_register(struct nvm_dev *dev) gn->dev = dev; gn->nr_luns = dev->nr_luns; INIT_LIST_HEAD(&gn->area_list); + mutex_init(&gn->lock); + INIT_LIST_HEAD(&gn->targets); dev->mp = gn; ret = gen_luns_init(dev, gn); @@ -318,6 +458,17 @@ err: static void gen_unregister(struct nvm_dev *dev) { + struct gen_dev *gn = dev->mp; + struct nvm_target *t, *tmp; + + mutex_lock(&gn->lock); + list_for_each_entry_safe(t, tmp, &gn->targets, list) { + if (t->dev != dev) + continue; + __gen_remove_target(t); + } + mutex_unlock(&gn->lock); + gen_free(dev); module_put(THIS_MODULE); } @@ -515,6 +666,9 @@ static struct nvmm_type gen = { .register_mgr = gen_register, .unregister_mgr = gen_unregister, + .create_tgt = gen_create_tgt, + .remove_tgt = gen_remove_tgt, + .get_blk_unlocked = gen_get_blk_unlocked, .put_blk_unlocked = gen_put_blk_unlocked, diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h index bf0621963c7c..8ecfa817d21d 100644 --- a/drivers/lightnvm/gennvm.h +++ b/drivers/lightnvm/gennvm.h @@ -40,6 +40,9 @@ struct gen_dev { int nr_luns; struct gen_lun *luns; struct list_head area_list; + + struct mutex lock; + struct list_head targets; }; struct gen_area { diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index 8b51d5767331..d619f6dde7df 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -1,7 +1,9 @@ #ifndef NVM_H #define NVM_H +#include #include +#include enum { NVM_IO_OK = 0, @@ -447,6 +449,8 @@ struct nvm_tgt_type { struct list_head list; }; +extern struct nvm_tgt_type *nvm_find_target_type(const char *, int); + extern int nvm_register_tgt_type(struct nvm_tgt_type *); extern void nvm_unregister_tgt_type(struct nvm_tgt_type *); @@ -455,6 +459,9 @@ extern void nvm_dev_dma_free(struct nvm_dev *, void *, dma_addr_t); typedef int (nvmm_register_fn)(struct nvm_dev *); typedef void (nvmm_unregister_fn)(struct nvm_dev *); + +typedef int (nvmm_create_tgt_fn)(struct nvm_dev *, struct nvm_ioctl_create *); +typedef int (nvmm_remove_tgt_fn)(struct nvm_dev *, struct nvm_ioctl_remove *); typedef struct nvm_block *(nvmm_get_blk_fn)(struct nvm_dev *, struct nvm_lun *, unsigned long); typedef void (nvmm_put_blk_fn)(struct nvm_dev *, struct nvm_block *); @@ -480,6 +487,9 @@ struct nvmm_type { nvmm_register_fn *register_mgr; nvmm_unregister_fn *unregister_mgr; + nvmm_create_tgt_fn *create_tgt; + nvmm_remove_tgt_fn *remove_tgt; + /* Block administration callbacks */ nvmm_get_blk_fn *get_blk_unlocked; nvmm_put_blk_fn *put_blk_unlocked; -- cgit v1.2.3 From 41285fad511a2c3746bee7ccb3b2f21b70305c14 Mon Sep 17 00:00:00 2001 From: Matias Bjørling Date: Thu, 7 Jul 2016 09:54:19 +0200 Subject: lightnvm: remove _unlocked variant of [get/put]_blk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The [get/put]_blk API enables targets to get ownership of blocks at runtime. This information is currently not recorded on disk, and the information is therefore lost on power failure. To restore the metadata, the [get/put]_blk must persist its metadata. In that case, we need to control the outer lock, so that we can disable them while updating the on-disk metadata. Fortunately, the _unlocked versions can be removed, which allows us to move the lock into the [get/put]_blk functions. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/core.c | 14 -------------- drivers/lightnvm/gennvm.c | 32 ++++---------------------------- drivers/lightnvm/rrpc.c | 14 ++------------ include/linux/lightnvm.h | 6 ------ 4 files changed, 6 insertions(+), 60 deletions(-) (limited to 'include/linux') diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 04469e0c84ce..ddc809803084 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -176,20 +176,6 @@ static struct nvm_dev *nvm_find_nvm_dev(const char *name) return NULL; } -struct nvm_block *nvm_get_blk_unlocked(struct nvm_dev *dev, struct nvm_lun *lun, - unsigned long flags) -{ - return dev->mt->get_blk_unlocked(dev, lun, flags); -} -EXPORT_SYMBOL(nvm_get_blk_unlocked); - -/* Assumes that all valid pages have already been moved on release to bm */ -void nvm_put_blk_unlocked(struct nvm_dev *dev, struct nvm_block *blk) -{ - return dev->mt->put_blk_unlocked(dev, blk); -} -EXPORT_SYMBOL(nvm_put_blk_unlocked); - struct nvm_block *nvm_get_blk(struct nvm_dev *dev, struct nvm_lun *lun, unsigned long flags) { diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index 41760b24bea7..c65fb675e374 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c @@ -473,15 +473,14 @@ static void gen_unregister(struct nvm_dev *dev) module_put(THIS_MODULE); } -static struct nvm_block *gen_get_blk_unlocked(struct nvm_dev *dev, +static struct nvm_block *gen_get_blk(struct nvm_dev *dev, struct nvm_lun *vlun, unsigned long flags) { struct gen_lun *lun = container_of(vlun, struct gen_lun, vlun); struct nvm_block *blk = NULL; int is_gc = flags & NVM_IOTYPE_GC; - assert_spin_locked(&vlun->lock); - + spin_lock(&vlun->lock); if (list_empty(&lun->free_list)) { pr_err_ratelimited("gen: lun %u have no free pages available", lun->vlun.id); @@ -496,29 +495,17 @@ static struct nvm_block *gen_get_blk_unlocked(struct nvm_dev *dev, list_move_tail(&blk->list, &lun->used_list); blk->state = NVM_BLK_ST_TGT; lun->vlun.nr_free_blocks--; - out: - return blk; -} - -static struct nvm_block *gen_get_blk(struct nvm_dev *dev, - struct nvm_lun *vlun, unsigned long flags) -{ - struct nvm_block *blk; - - spin_lock(&vlun->lock); - blk = gen_get_blk_unlocked(dev, vlun, flags); spin_unlock(&vlun->lock); return blk; } -static void gen_put_blk_unlocked(struct nvm_dev *dev, struct nvm_block *blk) +static void gen_put_blk(struct nvm_dev *dev, struct nvm_block *blk) { struct nvm_lun *vlun = blk->lun; struct gen_lun *lun = container_of(vlun, struct gen_lun, vlun); - assert_spin_locked(&vlun->lock); - + spin_lock(&vlun->lock); if (blk->state & NVM_BLK_ST_TGT) { list_move_tail(&blk->list, &lun->free_list); lun->vlun.nr_free_blocks++; @@ -532,14 +519,6 @@ static void gen_put_blk_unlocked(struct nvm_dev *dev, struct nvm_block *blk) blk->id, blk->state); list_move_tail(&blk->list, &lun->bb_list); } -} - -static void gen_put_blk(struct nvm_dev *dev, struct nvm_block *blk) -{ - struct nvm_lun *vlun = blk->lun; - - spin_lock(&vlun->lock); - gen_put_blk_unlocked(dev, blk); spin_unlock(&vlun->lock); } @@ -669,9 +648,6 @@ static struct nvmm_type gen = { .create_tgt = gen_create_tgt, .remove_tgt = gen_remove_tgt, - .get_blk_unlocked = gen_get_blk_unlocked, - .put_blk_unlocked = gen_put_blk_unlocked, - .get_blk = gen_get_blk, .put_blk = gen_put_blk, diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 10ed22b9875d..fa8d5be2987c 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -192,21 +192,16 @@ static void rrpc_set_lun_cur(struct rrpc_lun *rlun, struct rrpc_block *rblk) static struct rrpc_block *rrpc_get_blk(struct rrpc *rrpc, struct rrpc_lun *rlun, unsigned long flags) { - struct nvm_lun *lun = rlun->parent; struct nvm_block *blk; struct rrpc_block *rblk; - spin_lock(&lun->lock); - blk = nvm_get_blk_unlocked(rrpc->dev, rlun->parent, flags); + blk = nvm_get_blk(rrpc->dev, rlun->parent, flags); if (!blk) { pr_err("nvm: rrpc: cannot get new block from media manager\n"); - spin_unlock(&lun->lock); return NULL; } rblk = rrpc_get_rblk(rlun, blk->id); - spin_unlock(&lun->lock); - blk->priv = rblk; bitmap_zero(rblk->invalid_pages, rrpc->dev->sec_per_blk); rblk->next_page = 0; @@ -218,12 +213,7 @@ static struct rrpc_block *rrpc_get_blk(struct rrpc *rrpc, struct rrpc_lun *rlun, static void rrpc_put_blk(struct rrpc *rrpc, struct rrpc_block *rblk) { - struct rrpc_lun *rlun = rblk->rlun; - struct nvm_lun *lun = rlun->parent; - - spin_lock(&lun->lock); - nvm_put_blk_unlocked(rrpc->dev, rblk->parent); - spin_unlock(&lun->lock); + nvm_put_blk(rrpc->dev, rblk->parent); } static void rrpc_put_blks(struct rrpc *rrpc) diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index d619f6dde7df..e9836cfb6fde 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -491,8 +491,6 @@ struct nvmm_type { nvmm_remove_tgt_fn *remove_tgt; /* Block administration callbacks */ - nvmm_get_blk_fn *get_blk_unlocked; - nvmm_put_blk_fn *put_blk_unlocked; nvmm_get_blk_fn *get_blk; nvmm_put_blk_fn *put_blk; nvmm_open_blk_fn *open_blk; @@ -522,10 +520,6 @@ struct nvmm_type { extern int nvm_register_mgr(struct nvmm_type *); extern void nvm_unregister_mgr(struct nvmm_type *); -extern struct nvm_block *nvm_get_blk_unlocked(struct nvm_dev *, - struct nvm_lun *, unsigned long); -extern void nvm_put_blk_unlocked(struct nvm_dev *, struct nvm_block *); - extern struct nvm_block *nvm_get_blk(struct nvm_dev *, struct nvm_lun *, unsigned long); extern void nvm_put_blk(struct nvm_dev *, struct nvm_block *); -- cgit v1.2.3 From 8680f165eaa56cc9812d7d9b4903f449df0f6a45 Mon Sep 17 00:00:00 2001 From: Matias Bjørling Date: Thu, 7 Jul 2016 09:54:22 +0200 Subject: lightnvm: make ppa_list const in nvm_set_rqd_list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The passed by reference ppa list in nvm_set_rqd_list() is updated when multiple planes are available. In that case, each PPA plane is incremented when the device side PPA list is created. This prevents the caller to rely on the PPA list to be unmodified after a call. Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe --- drivers/lightnvm/core.c | 8 +++++--- include/linux/lightnvm.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index ddc809803084..00b64f78887d 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -237,9 +237,10 @@ void nvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd) EXPORT_SYMBOL(nvm_generic_to_addr_mode); int nvm_set_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd, - struct ppa_addr *ppas, int nr_ppas, int vblk) + const struct ppa_addr *ppas, int nr_ppas, int vblk) { int i, plane_cnt, pl_idx; + struct ppa_addr ppa; if ((!vblk || dev->plane_mode == NVM_PLANE_SINGLE) && nr_ppas == 1) { rqd->nr_ppas = nr_ppas; @@ -264,8 +265,9 @@ int nvm_set_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd, for (i = 0; i < nr_ppas; i++) { for (pl_idx = 0; pl_idx < plane_cnt; pl_idx++) { - ppas[i].g.pl = pl_idx; - rqd->ppa_list[(pl_idx * nr_ppas) + i] = ppas[i]; + ppa = ppas[i]; + ppa.g.pl = pl_idx; + rqd->ppa_list[(pl_idx * nr_ppas) + i] = ppa; } } } diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index e9836cfb6fde..ba78b8306674 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -534,7 +534,7 @@ extern int nvm_submit_io(struct nvm_dev *, struct nvm_rq *); extern void nvm_generic_to_addr_mode(struct nvm_dev *, struct nvm_rq *); extern void nvm_addr_to_generic_mode(struct nvm_dev *, struct nvm_rq *); extern int nvm_set_rqd_ppalist(struct nvm_dev *, struct nvm_rq *, - struct ppa_addr *, int, int); + const struct ppa_addr *, int, int); extern void nvm_free_rqd_ppalist(struct nvm_dev *, struct nvm_rq *); extern int nvm_erase_ppa(struct nvm_dev *, struct ppa_addr *, int); extern int nvm_erase_blk(struct nvm_dev *, struct nvm_block *); -- cgit v1.2.3 From 29b9aa0aa3837c93ecd804dd3ada39b8cc75607d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Jun 2016 17:42:38 -0700 Subject: libnvdimm: introduce devm_nvdimm_memremap(), convert nfit_spa_map() users In preparation for generically mapping flush hint addresses for both the BLK and PMEM use case, provide a generic / reference counted mapping api. Given the fact that a dimm may belong to multiple regions (PMEM and BLK), the flush hint addresses need to be held valid as long as any region associated with the dimm is active. This is similar to the existing BLK-region case where multiple BLK-regions may share an aperture mapping. Up-level this shared / reference-counted mapping capability from the nfit driver to a core nvdimm capability. This eliminates the need for the nd_blk_region.disable() callback. Note that the removal of nfit_spa_map() and related infrastructure is deferred to a later patch. Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 14 +++--- drivers/nvdimm/Kconfig | 2 +- drivers/nvdimm/core.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/nvdimm/nd-core.h | 1 + include/linux/libnvdimm.h | 9 ++++ 5 files changed, 141 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index f8c1a850effc..b047dbe13bed 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -1616,7 +1616,8 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, * when all region devices referencing the same mapping are disabled / * unbound. */ -static void __iomem *nfit_spa_map(struct acpi_nfit_desc *acpi_desc, +static __maybe_unused void __iomem *nfit_spa_map( + struct acpi_nfit_desc *acpi_desc, struct acpi_nfit_system_address *spa, enum spa_map_type type) { void __iomem *iomem; @@ -1669,7 +1670,6 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, struct device *dev) { struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); - struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct nd_blk_region *ndbr = to_nd_blk_region(dev); struct nfit_flush *nfit_flush; struct nfit_blk_mmio *mmio; @@ -1697,8 +1697,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, /* map block aperture memory */ nfit_blk->bdw_offset = nfit_mem->bdw->offset; mmio = &nfit_blk->mmio[BDW]; - mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw, - SPA_MAP_APERTURE); + mmio->addr.base = devm_nvdimm_memremap(dev, nfit_mem->spa_bdw->address, + nfit_mem->spa_bdw->length, ARCH_MEMREMAP_PMEM); if (!mmio->addr.base) { dev_dbg(dev, "%s: %s failed to map bdw\n", __func__, nvdimm_name(nvdimm)); @@ -1720,8 +1720,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, nfit_blk->cmd_offset = nfit_mem->dcr->command_offset; nfit_blk->stat_offset = nfit_mem->dcr->status_offset; mmio = &nfit_blk->mmio[DCR]; - mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr, - SPA_MAP_CONTROL); + mmio->addr.base = devm_nvdimm_ioremap(dev, nfit_mem->spa_dcr->address, + nfit_mem->spa_dcr->length); if (!mmio->addr.base) { dev_dbg(dev, "%s: %s failed to map dcr\n", __func__, nvdimm_name(nvdimm)); @@ -1748,7 +1748,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, nfit_flush = nfit_mem->nfit_flush; if (nfit_flush && nfit_flush->flush->hint_count != 0) { - nfit_blk->nvdimm_flush = devm_ioremap_nocache(dev, + nfit_blk->nvdimm_flush = devm_nvdimm_ioremap(dev, nfit_flush->flush->hint_address[0], 8); if (!nfit_blk->nvdimm_flush) return -ENOMEM; diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 7c8a3bf07884..124c2432ac9c 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -1,6 +1,7 @@ menuconfig LIBNVDIMM tristate "NVDIMM (Non-Volatile Memory Device) Support" depends on PHYS_ADDR_T_64BIT + depends on HAS_IOMEM depends on BLK_DEV help Generic support for non-volatile memory devices including @@ -19,7 +20,6 @@ if LIBNVDIMM config BLK_DEV_PMEM tristate "PMEM: Persistent memory block device support" default LIBNVDIMM - depends on HAS_IOMEM select ND_BTT if BTT select ND_PFN if NVDIMM_PFN help diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index 32e4fe2f6274..757e0cf028bf 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "nd-core.h" #include "nd.h" @@ -57,6 +58,127 @@ bool is_nvdimm_bus_locked(struct device *dev) } EXPORT_SYMBOL(is_nvdimm_bus_locked); +struct nvdimm_map { + struct nvdimm_bus *nvdimm_bus; + struct list_head list; + resource_size_t offset; + unsigned long flags; + size_t size; + union { + void *mem; + void __iomem *iomem; + }; + struct kref kref; +}; + +static struct nvdimm_map *find_nvdimm_map(struct device *dev, + resource_size_t offset) +{ + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct nvdimm_map *nvdimm_map; + + list_for_each_entry(nvdimm_map, &nvdimm_bus->mapping_list, list) + if (nvdimm_map->offset == offset) + return nvdimm_map; + return NULL; +} + +static struct nvdimm_map *alloc_nvdimm_map(struct device *dev, + resource_size_t offset, size_t size, unsigned long flags) +{ + struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); + struct nvdimm_map *nvdimm_map; + + nvdimm_map = kzalloc(sizeof(*nvdimm_map), GFP_KERNEL); + if (!nvdimm_map) + return NULL; + + INIT_LIST_HEAD(&nvdimm_map->list); + nvdimm_map->nvdimm_bus = nvdimm_bus; + nvdimm_map->offset = offset; + nvdimm_map->flags = flags; + nvdimm_map->size = size; + kref_init(&nvdimm_map->kref); + + if (!request_mem_region(offset, size, dev_name(&nvdimm_bus->dev))) + goto err_request_region; + + if (flags) + nvdimm_map->mem = memremap(offset, size, flags); + else + nvdimm_map->iomem = ioremap(offset, size); + + if (!nvdimm_map->mem) + goto err_map; + + dev_WARN_ONCE(dev, !is_nvdimm_bus_locked(dev), "%s: bus unlocked!", + __func__); + list_add(&nvdimm_map->list, &nvdimm_bus->mapping_list); + + return nvdimm_map; + + err_map: + release_mem_region(offset, size); + err_request_region: + kfree(nvdimm_map); + return NULL; +} + +static void nvdimm_map_release(struct kref *kref) +{ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_map *nvdimm_map; + + nvdimm_map = container_of(kref, struct nvdimm_map, kref); + nvdimm_bus = nvdimm_map->nvdimm_bus; + + dev_dbg(&nvdimm_bus->dev, "%s: %pa\n", __func__, &nvdimm_map->offset); + list_del(&nvdimm_map->list); + if (nvdimm_map->flags) + memunmap(nvdimm_map->mem); + else + iounmap(nvdimm_map->iomem); + release_mem_region(nvdimm_map->offset, nvdimm_map->size); + kfree(nvdimm_map); +} + +static void nvdimm_map_put(void *data) +{ + struct nvdimm_map *nvdimm_map = data; + struct nvdimm_bus *nvdimm_bus = nvdimm_map->nvdimm_bus; + + nvdimm_bus_lock(&nvdimm_bus->dev); + kref_put(&nvdimm_map->kref, nvdimm_map_release); + nvdimm_bus_unlock(&nvdimm_bus->dev); +} + +/** + * devm_nvdimm_memremap - map a resource that is shared across regions + * @dev: device that will own a reference to the shared mapping + * @offset: physical base address of the mapping + * @size: mapping size + * @flags: memremap flags, or, if zero, perform an ioremap instead + */ +void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset, + size_t size, unsigned long flags) +{ + struct nvdimm_map *nvdimm_map; + + nvdimm_bus_lock(dev); + nvdimm_map = find_nvdimm_map(dev, offset); + if (!nvdimm_map) + nvdimm_map = alloc_nvdimm_map(dev, offset, size, flags); + else + kref_get(&nvdimm_map->kref); + nvdimm_bus_unlock(dev); + + if (devm_add_action_or_reset(dev, nvdimm_map_put, nvdimm_map)) + return NULL; + + return nvdimm_map->mem; +} +EXPORT_SYMBOL_GPL(devm_nvdimm_memremap); + u64 nd_fletcher64(void *addr, size_t len, bool le) { u32 *buf = addr; @@ -335,6 +457,7 @@ struct nvdimm_bus *__nvdimm_bus_register(struct device *parent, if (!nvdimm_bus) return NULL; INIT_LIST_HEAD(&nvdimm_bus->list); + INIT_LIST_HEAD(&nvdimm_bus->mapping_list); INIT_LIST_HEAD(&nvdimm_bus->poison_list); init_waitqueue_head(&nvdimm_bus->probe_wait); nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL); diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 284cdaa268cf..790b62cc81ed 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -31,6 +31,7 @@ struct nvdimm_bus { struct device dev; int id, probe_active; struct list_head poison_list; + struct list_head mapping_list; struct mutex reconfig_mutex; }; diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 0c3c30cbbea5..18c3cc48a970 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -99,6 +99,15 @@ struct nd_region_desc { unsigned long flags; }; +struct device; +void *devm_nvdimm_memremap(struct device *dev, resource_size_t offset, + size_t size, unsigned long flags); +static inline void __iomem *devm_nvdimm_ioremap(struct device *dev, + resource_size_t offset, size_t size) +{ + return (void __iomem *) devm_nvdimm_memremap(dev, offset, size, 0); +} + struct nvdimm_bus; struct module; struct device; -- cgit v1.2.3 From 069f0cd00df0abfb9252e0dbdc355e40e6ab75fc Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 5 Jul 2016 00:31:26 +0200 Subject: printk: Make the printk*once() variants return a value Have printk*once() return a bool which denotes whether the string was printed or not so that calling code can react accordingly. Signed-off-by: Borislav Petkov Cc: Andrew Morton Cc: Andy Lutomirski Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Frederic Weisbecker Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1467671487-10344-3-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar --- include/linux/printk.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/printk.h b/include/linux/printk.h index f4da695fd615..f136b22c7772 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -108,11 +108,14 @@ struct va_format { * Dummy printk for disabled debugging statements to use whilst maintaining * gcc's format checking. */ -#define no_printk(fmt, ...) \ -do { \ - if (0) \ - printk(fmt, ##__VA_ARGS__); \ -} while (0) +#define no_printk(fmt, ...) \ +({ \ + do { \ + if (0) \ + printk(fmt, ##__VA_ARGS__); \ + } while (0); \ + 0; \ +}) #ifdef CONFIG_EARLY_PRINTK extern asmlinkage __printf(1, 2) @@ -309,20 +312,24 @@ extern asmlinkage void dump_stack(void) __cold; #define printk_once(fmt, ...) \ ({ \ static bool __print_once __read_mostly; \ + bool __ret_print_once = !__print_once; \ \ if (!__print_once) { \ __print_once = true; \ printk(fmt, ##__VA_ARGS__); \ } \ + unlikely(__ret_print_once); \ }) #define printk_deferred_once(fmt, ...) \ ({ \ static bool __print_once __read_mostly; \ + bool __ret_print_once = !__print_once; \ \ if (!__print_once) { \ __print_once = true; \ printk_deferred(fmt, ##__VA_ARGS__); \ } \ + unlikely(__ret_print_once); \ }) #else #define printk_once(fmt, ...) \ -- cgit v1.2.3 From 9cc577dd25b9762df7f353658426bb2e048c480a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 6 Jul 2016 23:32:24 +0200 Subject: ieee802154: add ieee802154_skb_dst_pan helper This patch adds ieee802154_skb_dst_pan function to get the pointer address of the destination pan id at skb mac pointer. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/linux/ieee802154.h | 16 ++++++++++++++++ include/net/mac802154.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) (limited to 'include/linux') diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h index acedbb68a5a3..91f4665fea63 100644 --- a/include/linux/ieee802154.h +++ b/include/linux/ieee802154.h @@ -31,6 +31,8 @@ #define IEEE802154_MIN_PSDU_LEN 9 #define IEEE802154_FCS_LEN 2 #define IEEE802154_MAX_AUTH_TAG_LEN 16 +#define IEEE802154_FC_LEN 2 +#define IEEE802154_SEQ_LEN 1 /* General MAC frame format: * 2 bytes: Frame Control @@ -221,9 +223,14 @@ enum { #define IEEE802154_FCTL_ACKREQ 0x0020 #define IEEE802154_FCTL_SECEN 0x0004 #define IEEE802154_FCTL_INTRA_PAN 0x0040 +#define IEEE802154_FCTL_DADDR 0x0c00 #define IEEE802154_FTYPE_DATA 0x0001 +#define IEEE802154_FCTL_ADDR_NONE 0x0000 +#define IEEE802154_FCTL_DADDR_SHORT 0x0800 +#define IEEE802154_FCTL_DADDR_EXTENDED 0x0c00 + /* * ieee802154_is_data - check if type is IEEE802154_FTYPE_DATA * @fc: frame control bytes in little-endian byteorder @@ -261,6 +268,15 @@ static inline bool ieee802154_is_intra_pan(__le16 fc) return fc & cpu_to_le16(IEEE802154_FCTL_INTRA_PAN); } +/* + * ieee802154_daddr_mode - get daddr mode from fc + * @fc: frame control bytes in little-endian byteorder + */ +static inline __le16 ieee802154_daddr_mode(__le16 fc) +{ + return fc & cpu_to_le16(IEEE802154_FCTL_DADDR); +} + /** * ieee802154_is_valid_psdu_len - check if psdu len is valid * available lengths: diff --git a/include/net/mac802154.h b/include/net/mac802154.h index e465c8551ac3..b3f7cd868fe9 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -257,6 +257,35 @@ static inline __le16 ieee802154_get_fc_from_skb(const struct sk_buff *skb) return get_unaligned_le16(skb_mac_header(skb)); } +/** + * ieee802154_skb_dst_pan - get the pointer to destination pan field + * @fc: mac header frame control field + * @skb: skb where the destination pan pointer will be get from + */ +static inline unsigned char *ieee802154_skb_dst_pan(__le16 fc, + const struct sk_buff *skb) +{ + unsigned char *dst_pan; + + switch (ieee802154_daddr_mode(fc)) { + case cpu_to_le16(IEEE802154_FCTL_ADDR_NONE): + dst_pan = NULL; + break; + case cpu_to_le16(IEEE802154_FCTL_DADDR_SHORT): + case cpu_to_le16(IEEE802154_FCTL_DADDR_EXTENDED): + dst_pan = skb_mac_header(skb) + + IEEE802154_FC_LEN + + IEEE802154_SEQ_LEN; + break; + default: + WARN_ONCE(1, "invalid addr mode detected"); + dst_pan = NULL; + break; + } + + return dst_pan; +} + /** * ieee802154_be64_to_le64 - copies and convert be64 to le64 * @le64_dst: le64 destination pointer -- cgit v1.2.3 From 19580cc1ed299c736b56b45c7576b477f185f8f5 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 6 Jul 2016 23:32:25 +0200 Subject: ieee802154: add ieee802154_skb_src_pan helper This patch adds ieee802154_skb_src_pan function to get the pointer address of the source pan id at skb mac pointer. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/linux/ieee802154.h | 13 ++++++++++ include/net/mac802154.h | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) (limited to 'include/linux') diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h index 91f4665fea63..ddb890174a0e 100644 --- a/include/linux/ieee802154.h +++ b/include/linux/ieee802154.h @@ -50,6 +50,7 @@ #define IEEE802154_EXTENDED_ADDR_LEN 8 #define IEEE802154_SHORT_ADDR_LEN 2 +#define IEEE802154_PAN_ID_LEN 2 #define IEEE802154_LIFS_PERIOD 40 #define IEEE802154_SIFS_PERIOD 12 @@ -224,12 +225,15 @@ enum { #define IEEE802154_FCTL_SECEN 0x0004 #define IEEE802154_FCTL_INTRA_PAN 0x0040 #define IEEE802154_FCTL_DADDR 0x0c00 +#define IEEE802154_FCTL_SADDR 0xc000 #define IEEE802154_FTYPE_DATA 0x0001 #define IEEE802154_FCTL_ADDR_NONE 0x0000 #define IEEE802154_FCTL_DADDR_SHORT 0x0800 #define IEEE802154_FCTL_DADDR_EXTENDED 0x0c00 +#define IEEE802154_FCTL_SADDR_SHORT 0x8000 +#define IEEE802154_FCTL_SADDR_EXTENDED 0xc000 /* * ieee802154_is_data - check if type is IEEE802154_FTYPE_DATA @@ -277,6 +281,15 @@ static inline __le16 ieee802154_daddr_mode(__le16 fc) return fc & cpu_to_le16(IEEE802154_FCTL_DADDR); } +/* + * ieee802154_saddr_mode - get saddr mode from fc + * @fc: frame control bytes in little-endian byteorder + */ +static inline __le16 ieee802154_saddr_mode(__le16 fc) +{ + return fc & cpu_to_le16(IEEE802154_FCTL_SADDR); +} + /** * ieee802154_is_valid_psdu_len - check if psdu len is valid * available lengths: diff --git a/include/net/mac802154.h b/include/net/mac802154.h index b3f7cd868fe9..ec01b35bc969 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -286,6 +286,65 @@ static inline unsigned char *ieee802154_skb_dst_pan(__le16 fc, return dst_pan; } +/** + * ieee802154_skb_src_pan - get the pointer to source pan field + * @fc: mac header frame control field + * @skb: skb where the source pan pointer will be get from + */ +static inline unsigned char *ieee802154_skb_src_pan(__le16 fc, + const struct sk_buff *skb) +{ + unsigned char *src_pan; + + switch (ieee802154_saddr_mode(fc)) { + case cpu_to_le16(IEEE802154_FCTL_ADDR_NONE): + src_pan = NULL; + break; + case cpu_to_le16(IEEE802154_FCTL_SADDR_SHORT): + case cpu_to_le16(IEEE802154_FCTL_SADDR_EXTENDED): + /* if intra-pan and source addr mode is non none, + * then source pan id is equal destination pan id. + */ + if (ieee802154_is_intra_pan(fc)) { + src_pan = ieee802154_skb_dst_pan(fc, skb); + break; + } + + switch (ieee802154_daddr_mode(fc)) { + case cpu_to_le16(IEEE802154_FCTL_ADDR_NONE): + src_pan = skb_mac_header(skb) + + IEEE802154_FC_LEN + + IEEE802154_SEQ_LEN; + break; + case cpu_to_le16(IEEE802154_FCTL_DADDR_SHORT): + src_pan = skb_mac_header(skb) + + IEEE802154_FC_LEN + + IEEE802154_SEQ_LEN + + IEEE802154_PAN_ID_LEN + + IEEE802154_SHORT_ADDR_LEN; + break; + case cpu_to_le16(IEEE802154_FCTL_DADDR_EXTENDED): + src_pan = skb_mac_header(skb) + + IEEE802154_FC_LEN + + IEEE802154_SEQ_LEN + + IEEE802154_PAN_ID_LEN + + IEEE802154_EXTENDED_ADDR_LEN; + break; + default: + WARN_ONCE(1, "invalid addr mode detected"); + src_pan = NULL; + break; + } + break; + default: + WARN_ONCE(1, "invalid addr mode detected"); + src_pan = NULL; + break; + } + + return src_pan; +} + /** * ieee802154_be64_to_le64 - copies and convert be64 to le64 * @le64_dst: le64 destination pointer -- cgit v1.2.3 From b059a453b1cf1c8453c2b2ed373d3147d6264ebd Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Tue, 28 Jun 2016 14:35:38 +0300 Subject: x86/vdso: Add mremap hook to vm_special_mapping Add possibility for 32-bit user-space applications to move the vDSO mapping. Previously, when a user-space app called mremap() for the vDSO address, in the syscall return path it would land on the previous address of the vDSOpage, resulting in segmentation violation. Now it lands fine and returns to userspace with a remapped vDSO. This will also fix the context.vdso pointer for 64-bit, which does not affect the user of vDSO after mremap() currently, but this may change in the future. As suggested by Andy, return -EINVAL for mremap() that would split the vDSO image: that operation cannot possibly result in a working system so reject it. Renamed and moved the text_mapping structure declaration inside map_vdso(), as it used only there and now it complements the vvar_mapping variable. There is still a problem for remapping the vDSO in glibc applications: the linker relocates addresses for syscalls on the vDSO page, so you need to relink with the new addresses. Without that the next syscall through glibc may fail: Program received signal SIGSEGV, Segmentation fault. #0 0xf7fd9b80 in __kernel_vsyscall () #1 0xf7ec8238 in _exit () from /usr/lib32/libc.so.6 Signed-off-by: Dmitry Safonov Acked-by: Andy Lutomirski Cc: 0x7f454c46@gmail.com Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20160628113539.13606-2-dsafonov@virtuozzo.com Signed-off-by: Ingo Molnar --- arch/x86/entry/vdso/vma.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- include/linux/mm_types.h | 3 +++ mm/mmap.c | 10 ++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index ab220ac9b3b9..3329844e3c43 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -97,10 +98,40 @@ static int vdso_fault(const struct vm_special_mapping *sm, return 0; } -static const struct vm_special_mapping text_mapping = { - .name = "[vdso]", - .fault = vdso_fault, -}; +static void vdso_fix_landing(const struct vdso_image *image, + struct vm_area_struct *new_vma) +{ +#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION + if (in_ia32_syscall() && image == &vdso_image_32) { + struct pt_regs *regs = current_pt_regs(); + unsigned long vdso_land = image->sym_int80_landing_pad; + unsigned long old_land_addr = vdso_land + + (unsigned long)current->mm->context.vdso; + + /* Fixing userspace landing - look at do_fast_syscall_32 */ + if (regs->ip == old_land_addr) + regs->ip = new_vma->vm_start + vdso_land; + } +#endif +} + +static int vdso_mremap(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma) +{ + unsigned long new_size = new_vma->vm_end - new_vma->vm_start; + const struct vdso_image *image = current->mm->context.vdso_image; + + if (image->size != new_size) + return -EINVAL; + + if (WARN_ON_ONCE(current->mm != new_vma->vm_mm)) + return -EFAULT; + + vdso_fix_landing(image, new_vma); + current->mm->context.vdso = (void __user *)new_vma->vm_start; + + return 0; +} static int vvar_fault(const struct vm_special_mapping *sm, struct vm_area_struct *vma, struct vm_fault *vmf) @@ -151,6 +182,12 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr) struct vm_area_struct *vma; unsigned long addr, text_start; int ret = 0; + + static const struct vm_special_mapping vdso_mapping = { + .name = "[vdso]", + .fault = vdso_fault, + .mremap = vdso_mremap, + }; static const struct vm_special_mapping vvar_mapping = { .name = "[vvar]", .fault = vvar_fault, @@ -185,7 +222,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr) image->size, VM_READ|VM_EXEC| VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, - &text_mapping); + &vdso_mapping); if (IS_ERR(vma)) { ret = PTR_ERR(vma); diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index ca3e517980a0..917f2b6a0cde 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -594,6 +594,9 @@ struct vm_special_mapping { int (*fault)(const struct vm_special_mapping *sm, struct vm_area_struct *vma, struct vm_fault *vmf); + + int (*mremap)(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma); }; enum tlb_flush_reason { diff --git a/mm/mmap.c b/mm/mmap.c index de2c1769cc68..234edffec1d0 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2943,9 +2943,19 @@ static const char *special_mapping_name(struct vm_area_struct *vma) return ((struct vm_special_mapping *)vma->vm_private_data)->name; } +static int special_mapping_mremap(struct vm_area_struct *new_vma) +{ + struct vm_special_mapping *sm = new_vma->vm_private_data; + + if (sm->mremap) + return sm->mremap(sm, new_vma); + return 0; +} + static const struct vm_operations_struct special_mapping_vmops = { .close = special_mapping_close, .fault = special_mapping_fault, + .mremap = special_mapping_mremap, .name = special_mapping_name, }; -- cgit v1.2.3 From 7fb2b43c3252c9177825a0a49138cd16144b6b5e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 27 Jun 2016 12:49:20 +0200 Subject: efi: Reorganize the GUID table to make it easier to read Re-organize the GUID table so that every GUID takes a single line. This makes each line super long, but if you have a large enough terminal (or zoom out of a small terminal) then you can see the structure at a glance - which is more readable than it was the case with the multi-line layout. Acked-by: Matt Fleming Cc: Ard Biesheuvel Cc: Joe Perches Cc: Linus Torvalds Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/20160627104920.GA9099@gmail.com Signed-off-by: Ingo Molnar --- include/linux/efi.h | 145 +++++++++++++--------------------------------------- 1 file changed, 36 insertions(+), 109 deletions(-) (limited to 'include/linux') diff --git a/include/linux/efi.h b/include/linux/efi.h index 0174f28ce9b3..7f80a75ee9e3 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -538,9 +538,11 @@ void efi_native_runtime_setup(void); /* * EFI Configuration Table and GUID definitions * - * These should be formatted roughly like the ones in the UEFI SPEC has - * them. It makes them easier to grep for, and they look the same when - * you're staring at them. Here's the guide: + * These are all defined in a single line to make them easier to + * grep for and to see them at a glance - while still having a + * similar structure to the definitions in the spec. + * + * Here's how they are structured: * * GUID: 12345678-1234-1234-1234-123456789012 * Spec: @@ -548,119 +550,44 @@ void efi_native_runtime_setup(void); * {0x12345678,0x1234,0x1234,\ * {0x12,0x34,0x12,0x34,0x56,0x78,0x90,0x12}} * Here: - * #define SOME_PROTOCOL_GUID \ - * EFI_GUID(0x12345678, 0x1234, 0x1234, \ - * 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12) - * ^ tab ^tab ^ space + * #define SOME_PROTOCOL_GUID EFI_GUID(0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12) + * ^ tabs ^extra space + * + * Note that the 'extra space' separates the values at the same place + * where the UEFI SPEC breaks the line. */ -#define NULL_GUID \ - EFI_GUID(0x00000000, 0x0000, 0x0000, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) - -#define MPS_TABLE_GUID \ - EFI_GUID(0xeb9d2d2f, 0x2d88, 0x11d3, \ - 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -#define ACPI_TABLE_GUID \ - EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, \ - 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -#define ACPI_20_TABLE_GUID \ - EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, \ - 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81) - -#define SMBIOS_TABLE_GUID \ - EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \ - 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -#define SMBIOS3_TABLE_GUID \ - EFI_GUID(0xf2fd1544, 0x9794, 0x4a2c, \ - 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94) - -#define SAL_SYSTEM_TABLE_GUID \ - EFI_GUID(0xeb9d2d32, 0x2d88, 0x11d3, \ - 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -#define HCDP_TABLE_GUID \ - EFI_GUID(0xf951938d, 0x620b, 0x42ef, \ - 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98) - -#define UGA_IO_PROTOCOL_GUID \ - EFI_GUID(0x61a4d49e, 0x6f68, 0x4f1b, \ - 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0x0b, 0x07, 0xa2) - -#define EFI_GLOBAL_VARIABLE_GUID \ - EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, \ - 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) - -#define UV_SYSTEM_TABLE_GUID \ - EFI_GUID(0x3b13a7d4, 0x633e, 0x11dd, \ - 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93) - -#define LINUX_EFI_CRASH_GUID \ - EFI_GUID(0xcfc8fc79, 0xbe2e, 0x4ddc, \ - 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0) - -#define LOADED_IMAGE_PROTOCOL_GUID \ - EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \ - 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) - -#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ - EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ - 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) - -#define EFI_UGA_PROTOCOL_GUID \ - EFI_GUID(0x982c298b, 0xf4fa, 0x41cb, \ - 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39) - -#define EFI_PCI_IO_PROTOCOL_GUID \ - EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5, \ - 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a) - -#define EFI_FILE_INFO_ID \ - EFI_GUID(0x9576e92, 0x6d3f, 0x11d2, \ - 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) - -#define EFI_SYSTEM_RESOURCE_TABLE_GUID \ - EFI_GUID(0xb122a263, 0x3661, 0x4f68, \ - 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80) - -#define EFI_FILE_SYSTEM_GUID \ - EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \ - 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) - -#define DEVICE_TREE_GUID \ - EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \ - 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) - -#define EFI_PROPERTIES_TABLE_GUID \ - EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, \ - 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5) - -#define EFI_RNG_PROTOCOL_GUID \ - EFI_GUID(0x3152bca5, 0xeade, 0x433d, \ - 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) - -#define EFI_MEMORY_ATTRIBUTES_TABLE_GUID \ - EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, \ - 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) - -#define EFI_CONSOLE_OUT_DEVICE_GUID \ - EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, \ - 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define NULL_GUID EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) +#define MPS_TABLE_GUID EFI_GUID(0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define ACPI_TABLE_GUID EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define ACPI_20_TABLE_GUID EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SMBIOS_TABLE_GUID EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define SMBIOS3_TABLE_GUID EFI_GUID(0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94) +#define SAL_SYSTEM_TABLE_GUID EFI_GUID(0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define HCDP_TABLE_GUID EFI_GUID(0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98) +#define UGA_IO_PROTOCOL_GUID EFI_GUID(0x61a4d49e, 0x6f68, 0x4f1b, 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0x0b, 0x07, 0xa2) +#define EFI_GLOBAL_VARIABLE_GUID EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) +#define UV_SYSTEM_TABLE_GUID EFI_GUID(0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93) +#define LINUX_EFI_CRASH_GUID EFI_GUID(0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0) +#define LOADED_IMAGE_PROTOCOL_GUID EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) +#define EFI_UGA_PROTOCOL_GUID EFI_GUID(0x982c298b, 0xf4fa, 0x41cb, 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39) +#define EFI_PCI_IO_PROTOCOL_GUID EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5, 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a) +#define EFI_FILE_INFO_ID EFI_GUID(0x09576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define EFI_SYSTEM_RESOURCE_TABLE_GUID EFI_GUID(0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80) +#define EFI_FILE_SYSTEM_GUID EFI_GUID(0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define DEVICE_TREE_GUID EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) +#define EFI_PROPERTIES_TABLE_GUID EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5) +#define EFI_RNG_PROTOCOL_GUID EFI_GUID(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) +#define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) +#define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) /* * This GUID is used to pass to the kernel proper the struct screen_info * structure that was populated by the stub based on the GOP protocol instance * associated with ConOut */ -#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID \ - EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, \ - 0xb9, 0xe, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) - -#define LINUX_EFI_LOADER_ENTRY_GUID \ - EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, \ - 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) +#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) +#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) typedef struct { efi_guid_t guid; -- cgit v1.2.3 From 3467f0d433016c45d1851f3587d32816b7b2ffb0 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Thu, 23 Jun 2016 16:57:09 +0200 Subject: ath9k: Allow configuration of LED polarity in platform data. Some devices running OpenWrt need this and it makes sense to add this to ath9k_platform_data as the next patches will add a devicetree (boolean) property for it as well. Suggested-by: Vittorio Gambaletta Signed-off-by: Martin Blumenstingl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 3 +++ include/linux/ath9k_platform.h | 1 + 2 files changed, 4 insertions(+) (limited to 'include/linux') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 2ee8624755f7..384929d71696 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -527,6 +527,9 @@ static int ath9k_init_soc_platform(struct ath_softc *sc) return ret; } + if (pdata->led_active_high) + ah->config.led_active_high = true; + if (pdata->tx_gain_buffalo) ah->config.tx_gain_buffalo = true; diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h index e66153d60bd5..76860a461ed2 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -40,6 +40,7 @@ struct ath9k_platform_data { bool tx_gain_buffalo; bool disable_2ghz; bool disable_5ghz; + bool led_active_high; int (*get_mac_revision)(void); int (*external_reset)(void); -- cgit v1.2.3 From d4a5f6d71e8bd32f268e738ed39b31a15334cdf7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 27 Jun 2016 00:03:00 +0200 Subject: rtc: ds1286: move header to linux/rtc Move ds1286.h to rtc specific folder. Signed-off-by: Alexandre Belloni --- arch/mips/sgi-ip22/ip22-reset.c | 2 +- drivers/rtc/rtc-ds1286.c | 2 +- include/linux/ds1286.h | 52 ----------------------------------------- include/linux/rtc/ds1286.h | 52 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 54 deletions(-) delete mode 100644 include/linux/ds1286.h create mode 100644 include/linux/rtc/ds1286.h (limited to 'include/linux') diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c index 063c2dd31e72..2f45b0357021 100644 --- a/arch/mips/sgi-ip22/ip22-reset.c +++ b/arch/mips/sgi-ip22/ip22-reset.c @@ -7,7 +7,7 @@ */ #include #include -#include +#include #include #include #include diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 756e509f6ed2..ef75c349dff9 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/linux/ds1286.h b/include/linux/ds1286.h deleted file mode 100644 index 45ea0aa0aeb9..000000000000 --- a/include/linux/ds1286.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 1998, 1999, 2003 Ralf Baechle - * - * 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. - */ -#ifndef __LINUX_DS1286_H -#define __LINUX_DS1286_H - -/********************************************************************** - * register summary - **********************************************************************/ -#define RTC_HUNDREDTH_SECOND 0 -#define RTC_SECONDS 1 -#define RTC_MINUTES 2 -#define RTC_MINUTES_ALARM 3 -#define RTC_HOURS 4 -#define RTC_HOURS_ALARM 5 -#define RTC_DAY 6 -#define RTC_DAY_ALARM 7 -#define RTC_DATE 8 -#define RTC_MONTH 9 -#define RTC_YEAR 10 -#define RTC_CMD 11 -#define RTC_WHSEC 12 -#define RTC_WSEC 13 -#define RTC_UNUSED 14 - -/* RTC_*_alarm is always true if 2 MSBs are set */ -# define RTC_ALARM_DONT_CARE 0xC0 - - -/* - * Bits in the month register - */ -#define RTC_EOSC 0x80 -#define RTC_ESQW 0x40 - -/* - * Bits in the Command register - */ -#define RTC_TDF 0x01 -#define RTC_WAF 0x02 -#define RTC_TDM 0x04 -#define RTC_WAM 0x08 -#define RTC_PU_LVL 0x10 -#define RTC_IBH_LO 0x20 -#define RTC_IPSW 0x40 -#define RTC_TE 0x80 - -#endif /* __LINUX_DS1286_H */ diff --git a/include/linux/rtc/ds1286.h b/include/linux/rtc/ds1286.h new file mode 100644 index 000000000000..45ea0aa0aeb9 --- /dev/null +++ b/include/linux/rtc/ds1286.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 1998, 1999, 2003 Ralf Baechle + * + * 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. + */ +#ifndef __LINUX_DS1286_H +#define __LINUX_DS1286_H + +/********************************************************************** + * register summary + **********************************************************************/ +#define RTC_HUNDREDTH_SECOND 0 +#define RTC_SECONDS 1 +#define RTC_MINUTES 2 +#define RTC_MINUTES_ALARM 3 +#define RTC_HOURS 4 +#define RTC_HOURS_ALARM 5 +#define RTC_DAY 6 +#define RTC_DAY_ALARM 7 +#define RTC_DATE 8 +#define RTC_MONTH 9 +#define RTC_YEAR 10 +#define RTC_CMD 11 +#define RTC_WHSEC 12 +#define RTC_WSEC 13 +#define RTC_UNUSED 14 + +/* RTC_*_alarm is always true if 2 MSBs are set */ +# define RTC_ALARM_DONT_CARE 0xC0 + + +/* + * Bits in the month register + */ +#define RTC_EOSC 0x80 +#define RTC_ESQW 0x40 + +/* + * Bits in the Command register + */ +#define RTC_TDF 0x01 +#define RTC_WAF 0x02 +#define RTC_TDM 0x04 +#define RTC_WAM 0x08 +#define RTC_PU_LVL 0x10 +#define RTC_IBH_LO 0x20 +#define RTC_IPSW 0x40 +#define RTC_TE 0x80 + +#endif /* __LINUX_DS1286_H */ -- cgit v1.2.3 From 486cf9899e311838b6ab95d19ff87c4da44d6508 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 6 Jul 2016 21:55:48 +0900 Subject: blk-mq: Introduce blk_mq_reinit_tagset The new nvme-rdma driver will need to reinitialize all the tags as part of the error recovery procedure (realloc the tag memory region). Add a helper in blk-mq for it that can iterate over all requests in a tagset to make this easier. Signed-off-by: Sagi Grimberg Tested-by: Ming Lin Reviewed-by: Stephen Bates Signed-off-by: Christoph Hellwig Reviewed-by: Steve Wise Tested-by: Steve Wise Signed-off-by: Jens Axboe --- block/blk-mq-tag.c | 26 ++++++++++++++++++++++++++ include/linux/blk-mq.h | 3 +++ 2 files changed, 29 insertions(+) (limited to 'include/linux') diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 56a0c37a3d06..729bac3a673b 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -485,6 +485,32 @@ void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset, } EXPORT_SYMBOL(blk_mq_tagset_busy_iter); +int blk_mq_reinit_tagset(struct blk_mq_tag_set *set) +{ + int i, j, ret = 0; + + if (!set->ops->reinit_request) + goto out; + + for (i = 0; i < set->nr_hw_queues; i++) { + struct blk_mq_tags *tags = set->tags[i]; + + for (j = 0; j < tags->nr_tags; j++) { + if (!tags->rqs[j]) + continue; + + ret = set->ops->reinit_request(set->driver_data, + tags->rqs[j]); + if (ret) + goto out; + } + } + +out: + return ret; +} +EXPORT_SYMBOL_GPL(blk_mq_reinit_tagset); + void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn, void *priv) { diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index cbfd8ca5f13e..e43bbffb5b7a 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -96,6 +96,7 @@ typedef int (init_request_fn)(void *, struct request *, unsigned int, unsigned int, unsigned int); typedef void (exit_request_fn)(void *, struct request *, unsigned int, unsigned int); +typedef int (reinit_request_fn)(void *, struct request *); typedef void (busy_iter_fn)(struct blk_mq_hw_ctx *, struct request *, void *, bool); @@ -145,6 +146,7 @@ struct blk_mq_ops { */ init_request_fn *init_request; exit_request_fn *exit_request; + reinit_request_fn *reinit_request; }; enum { @@ -245,6 +247,7 @@ void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset, void blk_mq_freeze_queue(struct request_queue *q); void blk_mq_unfreeze_queue(struct request_queue *q); void blk_mq_freeze_queue_start(struct request_queue *q); +int blk_mq_reinit_tagset(struct blk_mq_tag_set *set); void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues); -- cgit v1.2.3 From 931a6de4d734de6142142c82555e3f017adcb9f0 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 6 Jul 2016 21:55:50 +0900 Subject: nvme-rdma.h: Add includes for nvme rdma_cm negotiation NVMe over Fabrics RDMA transport defines a connection establishment protocol over the RDMA connection manager. This header will be used by both the host and target drivers to negotiate the connection establishment parameters. Signed-off-by: Jay Freyensee Signed-off-by: Ming Lin Signed-off-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Reviewed-by: Steve Wise Tested-by: Steve Wise Signed-off-by: Jens Axboe --- include/linux/nvme-rdma.h | 71 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 include/linux/nvme-rdma.h (limited to 'include/linux') diff --git a/include/linux/nvme-rdma.h b/include/linux/nvme-rdma.h new file mode 100644 index 000000000000..bf240a3cbf99 --- /dev/null +++ b/include/linux/nvme-rdma.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _LINUX_NVME_RDMA_H +#define _LINUX_NVME_RDMA_H + +enum nvme_rdma_cm_fmt { + NVME_RDMA_CM_FMT_1_0 = 0x0, +}; + +enum nvme_rdma_cm_status { + NVME_RDMA_CM_INVALID_LEN = 0x01, + NVME_RDMA_CM_INVALID_RECFMT = 0x02, + NVME_RDMA_CM_INVALID_QID = 0x03, + NVME_RDMA_CM_INVALID_HSQSIZE = 0x04, + NVME_RDMA_CM_INVALID_HRQSIZE = 0x05, + NVME_RDMA_CM_NO_RSC = 0x06, + NVME_RDMA_CM_INVALID_IRD = 0x07, + NVME_RDMA_CM_INVALID_ORD = 0x08, +}; + +/** + * struct nvme_rdma_cm_req - rdma connect request + * + * @recfmt: format of the RDMA Private Data + * @qid: queue Identifier for the Admin or I/O Queue + * @hrqsize: host receive queue size to be created + * @hsqsize: host send queue size to be created + */ +struct nvme_rdma_cm_req { + __le16 recfmt; + __le16 qid; + __le16 hrqsize; + __le16 hsqsize; + u8 rsvd[24]; +}; + +/** + * struct nvme_rdma_cm_rep - rdma connect reply + * + * @recfmt: format of the RDMA Private Data + * @crqsize: controller receive queue size + */ +struct nvme_rdma_cm_rep { + __le16 recfmt; + __le16 crqsize; + u8 rsvd[28]; +}; + +/** + * struct nvme_rdma_cm_rej - rdma connect reject + * + * @recfmt: format of the RDMA Private Data + * @fsts: error status for the associated connect request + */ +struct nvme_rdma_cm_rej { + __le16 recfmt; + __le16 sts; +}; + +#endif /* _LINUX_NVME_RDMA_H */ -- cgit v1.2.3 From a6a0dbbcfa469cf3e5c4d9522106c0b7b9e9e373 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 14 Jun 2016 11:13:09 +0200 Subject: pwm: Add a helper to prepare a new PWM state The pwm_init_state() helper prepares a new state object containing the current PWM state except for the polarity and period fields which are set to the reference values (those in struct pwm_args). This is particularly useful for PWM users who want to apply a new duty- cycle expressed relatively to the reference period without changing the enable state. Signed-off-by: Boris Brezillon Tested-by: Heiko Stuebner Signed-off-by: Thierry Reding --- include/linux/pwm.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 17018f3c066e..a100f6e80738 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -147,6 +147,39 @@ static inline void pwm_get_args(const struct pwm_device *pwm, *args = pwm->args; } +/** + * pwm_init_state() - prepare a new state to be applied with pwm_apply_state() + * @pwm: PWM device + * @state: state to fill with the prepared PWM state + * + * This functions prepares a state that can later be tweaked and applied + * to the PWM device with pwm_apply_state(). This is a convenient function + * that first retrieves the current PWM state and the replaces the period + * and polarity fields with the reference values defined in pwm->args. + * Once the function returns, you can adjust the ->enabled and ->duty_cycle + * fields according to your needs before calling pwm_apply_state(). + * + * ->duty_cycle is initially set to zero to avoid cases where the current + * ->duty_cycle value exceed the pwm_args->period one, which would trigger + * an error if the user calls pwm_apply_state() without adjusting ->duty_cycle + * first. + */ +static inline void pwm_init_state(const struct pwm_device *pwm, + struct pwm_state *state) +{ + struct pwm_args args; + + /* First get the current state. */ + pwm_get_state(pwm, state); + + /* Then fill it with the reference config */ + pwm_get_args(pwm, &args); + + state->period = args.period; + state->polarity = args.polarity; + state->duty_cycle = 0; +} + /** * struct pwm_ops - PWM controller operations * @request: optional hook for requesting a PWM -- cgit v1.2.3 From f6f3bddf7b2b994a927808fcc5a3d07069c35956 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 14 Jun 2016 11:13:10 +0200 Subject: pwm: Add relative duty cycle manipulation helpers The PWM framework expects PWM users to configure the duty cycle in nano- seconds, but many users want to express the duty cycle relatively to the period value (i.e. duty_cycle = 33% of the period). Add the pwm_{get,set}_relative_duty_cycle() helpers to ease this kind of conversion. Signed-off-by: Boris Brezillon Tested-by: Heiko Stuebner Signed-off-by: Thierry Reding --- include/linux/pwm.h | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pwm.h b/include/linux/pwm.h index a100f6e80738..fd1092729ed6 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -180,6 +180,61 @@ static inline void pwm_init_state(const struct pwm_device *pwm, state->duty_cycle = 0; } +/** + * pwm_get_relative_duty_cycle() - Get a relative duty cycle value + * @state: PWM state to extract the duty cycle from + * @scale: target scale of the relative duty cycle + * + * This functions converts the absolute duty cycle stored in @state (expressed + * in nanosecond) into a value relative to the period. + * + * For example if you want to get the duty_cycle expressed in percent, call: + * + * pwm_get_state(pwm, &state); + * duty = pwm_get_relative_duty_cycle(&state, 100); + */ +static inline unsigned int +pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale) +{ + if (!state->period) + return 0; + + return DIV_ROUND_CLOSEST_ULL((u64)state->duty_cycle * scale, + state->period); +} + +/** + * pwm_set_relative_duty_cycle() - Set a relative duty cycle value + * @state: PWM state to fill + * @duty_cycle: relative duty cycle value + * @scale: scale in which @duty_cycle is expressed + * + * This functions converts a relative into an absolute duty cycle (expressed + * in nanoseconds), and puts the result in state->duty_cycle. + * + * For example if you want to configure a 50% duty cycle, call: + * + * pwm_init_state(pwm, &state); + * pwm_set_relative_duty_cycle(&state, 50, 100); + * pwm_apply_state(pwm, &state); + * + * This functions returns -EINVAL if @duty_cycle and/or @scale are + * inconsistent (@scale == 0 or @duty_cycle > @scale). + */ +static inline int +pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle, + unsigned int scale) +{ + if (!scale || duty_cycle > scale) + return -EINVAL; + + state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_cycle * + state->period, + scale); + + return 0; +} + /** * struct pwm_ops - PWM controller operations * @request: optional hook for requesting a PWM -- cgit v1.2.3 From 2b77487f2e8ff7e6496a7f5a08839de9bbb39ab3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 10 Jun 2016 15:49:53 +0200 Subject: pwm: Remove gratuitous blank line Commit 5ec803edcb70 ("pwm: Add core infrastructure to allow atomic updates") introduced this double blank line by mistake. Signed-off-by: Thierry Reding --- include/linux/pwm.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/pwm.h b/include/linux/pwm.h index fd1092729ed6..83d8bcb7e1de 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -408,7 +408,6 @@ static inline void pwm_disable(struct pwm_device *pwm) pwm_apply_state(pwm, &state); } - /* PWM provider APIs */ int pwm_set_chip_data(struct pwm_device *pwm, void *data); void *pwm_get_chip_data(struct pwm_device *pwm); -- cgit v1.2.3 From 10c7e20b2ff3caa5a8c0e7d60aef5a9c86e60ce8 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 8 Jul 2016 19:13:08 +0300 Subject: ACPI / scan: fix enumeration (visited) flags for bus rescans If the ACPI tables change as a result of a dinamically loaded table and a bus rescan is required the enumeration/visited flag are not consistent. I2C/SPI are not directly enumerated in acpi_bus_attach(), however the visited flag is set. This makes it impossible to check if an ACPI device has already been enumerated by the I2C and SPI subsystems. To fix this issue we only set the visited flags if the device is not I2C or SPI. With this change we also need to remove setting visited to false from acpi_bus_attach(), otherwise if we rescan already enumerated I2C/SPI devices we try to re-enumerate them. Note that I2C/SPI devices can be enumerated either via a scan handler (when using PRP0001) or via regular device_attach(). In either case the flow goes through acpi_default_enumeration() which makes it the ideal place to mark the ACPI device as enumerated. Signed-off-by: Octavian Purdila Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 13 +++++++------ include/linux/acpi.h | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5f28cf778349..f80f8a747294 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1406,7 +1406,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, acpi_bus_get_flags(device); device->flags.match_driver = false; device->flags.initialized = true; - device->flags.visited = false; + acpi_device_clear_enumerated(device); device_initialize(&device->dev); dev_set_uevent_suppress(&device->dev, true); acpi_init_coherency(device); @@ -1683,8 +1683,10 @@ static void acpi_default_enumeration(struct acpi_device *device) acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave, &is_spi_i2c_slave); acpi_dev_free_resource_list(&resource_list); - if (!is_spi_i2c_slave) + if (!is_spi_i2c_slave) { acpi_create_platform_device(device); + acpi_device_set_enumerated(device); + } } static const struct acpi_device_id generic_device_ids[] = { @@ -1751,7 +1753,7 @@ static void acpi_bus_attach(struct acpi_device *device) acpi_bus_get_status(device); /* Skip devices that are not present. */ if (!acpi_device_is_present(device)) { - device->flags.visited = false; + acpi_device_clear_enumerated(device); device->flags.power_manageable = 0; return; } @@ -1766,7 +1768,7 @@ static void acpi_bus_attach(struct acpi_device *device) device->flags.initialized = true; } - device->flags.visited = false; + ret = acpi_scan_attach_handler(device); if (ret < 0) return; @@ -1780,7 +1782,6 @@ static void acpi_bus_attach(struct acpi_device *device) if (!ret && device->pnp.type.platform_id) acpi_default_enumeration(device); } - device->flags.visited = true; ok: list_for_each_entry(child, &device->children, node) @@ -1872,7 +1873,7 @@ void acpi_bus_trim(struct acpi_device *adev) */ acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->flags.initialized = false; - adev->flags.visited = false; + acpi_device_clear_enumerated(adev); } EXPORT_SYMBOL_GPL(acpi_bus_trim); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ef2ad26abede..db680e8788c4 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -531,6 +531,16 @@ void acpi_walk_dep_device_list(acpi_handle handle); struct platform_device *acpi_create_platform_device(struct acpi_device *); #define ACPI_PTR(_ptr) (_ptr) +static inline void acpi_device_set_enumerated(struct acpi_device *adev) +{ + adev->flags.visited = true; +} + +static inline void acpi_device_clear_enumerated(struct acpi_device *adev) +{ + adev->flags.visited = false; +} + #else /* !CONFIG_ACPI */ #define acpi_disabled 1 @@ -676,6 +686,14 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) #define ACPI_PTR(_ptr) (NULL) +static inline void acpi_device_set_enumerated(struct acpi_device *adev) +{ +} + +static inline void acpi_device_clear_enumerated(struct acpi_device *adev) +{ +} + #endif /* !CONFIG_ACPI */ #ifdef CONFIG_ACPI -- cgit v1.2.3 From 68bdb6773289f8c9a36633f9f6525b127c093258 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 8 Jul 2016 19:13:09 +0300 Subject: ACPI: add support for ACPI reconfiguration notifiers Add support for ACPI reconfiguration notifiers to allow subsystems to react to changes in the ACPI tables that happen after the initial enumeration. This is similar with the way dynamic device tree notifications work. The reconfigure notifications supported for now are device add and device remove. Since ACPICA allows only one table notification handler, this patch makes the table notifier function generic and moves it out of the sysfs specific code. Signed-off-by: Octavian Purdila Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 9 +++++++ drivers/acpi/internal.h | 3 +++ drivers/acpi/scan.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++- drivers/acpi/sysfs.c | 6 ++--- include/linux/acpi.h | 18 +++++++++++++ 5 files changed, 99 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 262ca31b86d9..97e270e06653 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -990,6 +990,13 @@ void __init acpi_subsystem_init(void) } } +static acpi_status acpi_bus_table_handler(u32 event, void *table, void *context) +{ + acpi_scan_table_handler(event, table, context); + + return acpi_sysfs_table_handler(event, table, context); +} + static int __init acpi_bus_init(void) { int result; @@ -1043,6 +1050,8 @@ static int __init acpi_bus_init(void) * _PDC control method may load dynamic SSDT tables, * and we need to install the table handler before that. */ + status = acpi_install_table_handler(acpi_bus_table_handler, NULL); + acpi_sysfs_init(); acpi_early_processor_set_pdc(); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 27cc7feabfe4..940218ff0193 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -87,6 +87,9 @@ bool acpi_queue_hotplug_work(struct work_struct *work); void acpi_device_hotplug(struct acpi_device *adev, u32 src); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); +acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context); +void acpi_scan_table_handler(u32 event, void *table, void *context); + /* -------------------------------------------------------------------------- Device Node Initialization / Removal -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index f80f8a747294..405056b95b05 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -494,6 +494,8 @@ static void acpi_device_del(struct acpi_device *device) device_del(&device->dev); } +static BLOCKING_NOTIFIER_HEAD(acpi_reconfig_chain); + static LIST_HEAD(acpi_device_del_list); static DEFINE_MUTEX(acpi_device_del_lock); @@ -514,6 +516,9 @@ static void acpi_device_del_work_fn(struct work_struct *work_not_used) mutex_unlock(&acpi_device_del_lock); + blocking_notifier_call_chain(&acpi_reconfig_chain, + ACPI_RECONFIG_DEVICE_REMOVE, adev); + acpi_device_del(adev); /* * Drop references to all power resources that might have been @@ -1676,7 +1681,7 @@ static void acpi_default_enumeration(struct acpi_device *device) bool is_spi_i2c_slave = false; /* - * Do not enemerate SPI/I2C slaves as they will be enuerated by their + * Do not enumerate SPI/I2C slaves as they will be enumerated by their * respective parents. */ INIT_LIST_HEAD(&resource_list); @@ -1686,6 +1691,9 @@ static void acpi_default_enumeration(struct acpi_device *device) if (!is_spi_i2c_slave) { acpi_create_platform_device(device); acpi_device_set_enumerated(device); + } else { + blocking_notifier_call_chain(&acpi_reconfig_chain, + ACPI_RECONFIG_DEVICE_ADD, device); } } @@ -1917,6 +1925,8 @@ static int acpi_bus_scan_fixed(void) return result < 0 ? result : 0; } +static bool acpi_scan_initialized; + int __init acpi_scan_init(void) { int result; @@ -1961,6 +1971,8 @@ int __init acpi_scan_init(void) acpi_update_all_gpes(); + acpi_scan_initialized = true; + out: mutex_unlock(&acpi_scan_lock); return result; @@ -2004,3 +2016,57 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr) return count; } + +struct acpi_table_events_work { + struct work_struct work; + void *table; + u32 event; +}; + +static void acpi_table_events_fn(struct work_struct *work) +{ + struct acpi_table_events_work *tew; + + tew = container_of(work, struct acpi_table_events_work, work); + + if (tew->event == ACPI_TABLE_EVENT_LOAD) { + acpi_scan_lock_acquire(); + acpi_bus_scan(ACPI_ROOT_OBJECT); + acpi_scan_lock_release(); + } + + kfree(tew); +} + +void acpi_scan_table_handler(u32 event, void *table, void *context) +{ + struct acpi_table_events_work *tew; + + if (!acpi_scan_initialized) + return; + + if (event != ACPI_TABLE_EVENT_LOAD) + return; + + tew = kmalloc(sizeof(*tew), GFP_KERNEL); + if (!tew) + return; + + INIT_WORK(&tew->work, acpi_table_events_fn); + tew->table = table; + tew->event = event; + + schedule_work(&tew->work); +} + +int acpi_reconfig_notifier_register(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&acpi_reconfig_chain, nb); +} +EXPORT_SYMBOL(acpi_reconfig_notifier_register); + +int acpi_reconfig_notifier_unregister(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&acpi_reconfig_chain, nb); +} +EXPORT_SYMBOL(acpi_reconfig_notifier_unregister); diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 4b3a9e27f1b6..358165e9f5b8 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -378,8 +378,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr, return; } -static acpi_status -acpi_sysfs_table_handler(u32 event, void *table, void *context) +acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context) { struct acpi_table_attr *table_attr; @@ -452,9 +451,8 @@ static int acpi_tables_sysfs_init(void) kobject_uevent(tables_kobj, KOBJ_ADD); kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); - status = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); - return ACPI_FAILURE(status) ? -EINVAL : 0; + return 0; err_dynamic_tables: kobject_put(tables_kobj); err: diff --git a/include/linux/acpi.h b/include/linux/acpi.h index db680e8788c4..8b48de17e388 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -541,6 +541,14 @@ static inline void acpi_device_clear_enumerated(struct acpi_device *adev) adev->flags.visited = false; } +enum acpi_reconfig_event { + ACPI_RECONFIG_DEVICE_ADD = 0, + ACPI_RECONFIG_DEVICE_REMOVE, +}; + +int acpi_reconfig_notifier_register(struct notifier_block *nb); +int acpi_reconfig_notifier_unregister(struct notifier_block *nb); + #else /* !CONFIG_ACPI */ #define acpi_disabled 1 @@ -694,6 +702,16 @@ static inline void acpi_device_clear_enumerated(struct acpi_device *adev) { } +static inline int acpi_reconfig_notifier_register(struct notifier_block *nb) +{ + return -EINVAL; +} + +static inline int acpi_reconfig_notifier_unregister(struct notifier_block *nb) +{ + return -EINVAL; +} + #endif /* !CONFIG_ACPI */ #ifdef CONFIG_ACPI -- cgit v1.2.3 From 12655445a2adc292db3352bbe80e43bd243517aa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 30 Jun 2016 07:01:41 -0300 Subject: [media] cec.h/cec-funcs.h: add option to use BSD license Like the videodev2.h and other headers, explicitly allow these headers to be used with the BSD license. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 16 ++++++++++++++++ include/linux/cec.h | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'include/linux') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h index 8ee1029b9b74..19486009693a 100644 --- a/include/linux/cec-funcs.h +++ b/include/linux/cec-funcs.h @@ -7,6 +7,22 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * + * Alternatively you can redistribute this file under the terms of the + * BSD license as stated below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND diff --git a/include/linux/cec.h b/include/linux/cec.h index 40924e79465d..6678afe26844 100644 --- a/include/linux/cec.h +++ b/include/linux/cec.h @@ -7,6 +7,22 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * + * Alternatively you can redistribute this file under the terms of the + * BSD license as stated below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -- cgit v1.2.3 From 0cb1f1e44cf5b013dd0991f509e332ac77ce2ddd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Jul 2016 05:49:26 -0300 Subject: [media] cec-funcs.h: add length checks Add msg->len sanity checks to fix static checker warning: include/linux/cec-funcs.h:1154 cec_ops_set_osd_string() warn: setting length 'msg->len - 3' to negative one Signed-off-by: Hans Verkuil Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h index 19486009693a..8d217ce53034 100644 --- a/include/linux/cec-funcs.h +++ b/include/linux/cec-funcs.h @@ -788,7 +788,7 @@ static inline void cec_msg_set_timer_program_title(struct cec_msg *msg, static inline void cec_ops_set_timer_program_title(const struct cec_msg *msg, char *prog_title) { - unsigned int len = msg->len - 2; + unsigned int len = msg->len > 2 ? msg->len - 2 : 0; if (len > 14) len = 14; @@ -1167,7 +1167,7 @@ static inline void cec_ops_set_osd_string(const struct cec_msg *msg, __u8 *disp_ctl, char *osd) { - unsigned int len = msg->len - 3; + unsigned int len = msg->len > 3 ? msg->len - 3 : 0; *disp_ctl = msg->msg[2]; if (len > 13) @@ -1192,7 +1192,7 @@ static inline void cec_msg_set_osd_name(struct cec_msg *msg, const char *name) static inline void cec_ops_set_osd_name(const struct cec_msg *msg, char *name) { - unsigned int len = msg->len - 2; + unsigned int len = msg->len > 2 ? msg->len - 2 : 0; if (len > 14) len = 14; -- cgit v1.2.3 From 0c1f8569942695b7a2735301efe45ecd69e2a41f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Jul 2016 05:36:26 -0300 Subject: [media] cec-funcs.h: add missing const modifier The cec_ops_* functions never touch cec_msg, so mark it as const. This was done for some of the cec_ops_ functions, but not all. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h index 8d217ce53034..455f9df86c43 100644 --- a/include/linux/cec-funcs.h +++ b/include/linux/cec-funcs.h @@ -420,7 +420,7 @@ static inline void cec_msg_timer_status(struct cec_msg *msg, } } -static inline void cec_ops_timer_status(struct cec_msg *msg, +static inline void cec_ops_timer_status(const struct cec_msg *msg, __u8 *timer_overlap_warning, __u8 *media_info, __u8 *prog_info, @@ -455,7 +455,7 @@ static inline void cec_msg_timer_cleared_status(struct cec_msg *msg, msg->msg[2] = timer_cleared_status; } -static inline void cec_ops_timer_cleared_status(struct cec_msg *msg, +static inline void cec_ops_timer_cleared_status(const struct cec_msg *msg, __u8 *timer_cleared_status) { *timer_cleared_status = msg->msg[2]; @@ -491,7 +491,7 @@ static inline void cec_msg_clear_analogue_timer(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; } -static inline void cec_ops_clear_analogue_timer(struct cec_msg *msg, +static inline void cec_ops_clear_analogue_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -541,7 +541,7 @@ static inline void cec_msg_clear_digital_timer(struct cec_msg *msg, cec_set_digital_service_id(msg->msg + 9, digital); } -static inline void cec_ops_clear_digital_timer(struct cec_msg *msg, +static inline void cec_ops_clear_digital_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -592,7 +592,7 @@ static inline void cec_msg_clear_ext_timer(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; } -static inline void cec_ops_clear_ext_timer(struct cec_msg *msg, +static inline void cec_ops_clear_ext_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -647,7 +647,7 @@ static inline void cec_msg_set_analogue_timer(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; } -static inline void cec_ops_set_analogue_timer(struct cec_msg *msg, +static inline void cec_ops_set_analogue_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -697,7 +697,7 @@ static inline void cec_msg_set_digital_timer(struct cec_msg *msg, cec_set_digital_service_id(msg->msg + 9, digital); } -static inline void cec_ops_set_digital_timer(struct cec_msg *msg, +static inline void cec_ops_set_digital_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -748,7 +748,7 @@ static inline void cec_msg_set_ext_timer(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; } -static inline void cec_ops_set_ext_timer(struct cec_msg *msg, +static inline void cec_ops_set_ext_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -853,7 +853,7 @@ static inline void cec_msg_set_menu_language(struct cec_msg *msg, memcpy(msg->msg + 2, language, 3); } -static inline void cec_ops_set_menu_language(struct cec_msg *msg, +static inline void cec_ops_set_menu_language(const struct cec_msg *msg, char *language) { memcpy(language, msg->msg + 2, 3); @@ -926,7 +926,7 @@ static inline void cec_msg_deck_control(struct cec_msg *msg, msg->msg[2] = deck_control_mode; } -static inline void cec_ops_deck_control(struct cec_msg *msg, +static inline void cec_ops_deck_control(const struct cec_msg *msg, __u8 *deck_control_mode) { *deck_control_mode = msg->msg[2]; @@ -940,7 +940,7 @@ static inline void cec_msg_deck_status(struct cec_msg *msg, msg->msg[2] = deck_info; } -static inline void cec_ops_deck_status(struct cec_msg *msg, +static inline void cec_ops_deck_status(const struct cec_msg *msg, __u8 *deck_info) { *deck_info = msg->msg[2]; @@ -956,7 +956,7 @@ static inline void cec_msg_give_deck_status(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_DECK_STATUS : 0; } -static inline void cec_ops_give_deck_status(struct cec_msg *msg, +static inline void cec_ops_give_deck_status(const struct cec_msg *msg, __u8 *status_req) { *status_req = msg->msg[2]; @@ -970,7 +970,7 @@ static inline void cec_msg_play(struct cec_msg *msg, msg->msg[2] = play_mode; } -static inline void cec_ops_play(struct cec_msg *msg, +static inline void cec_ops_play(const struct cec_msg *msg, __u8 *play_mode) { *play_mode = msg->msg[2]; @@ -1035,7 +1035,7 @@ static inline void cec_msg_tuner_device_status(struct cec_msg *msg, &tuner_dev_info->digital); } -static inline void cec_ops_tuner_device_status(struct cec_msg *msg, +static inline void cec_ops_tuner_device_status(const struct cec_msg *msg, struct cec_op_tuner_device_info *tuner_dev_info) { tuner_dev_info->is_analog = msg->len < 10; @@ -1060,7 +1060,7 @@ static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0; } -static inline void cec_ops_give_tuner_device_status(struct cec_msg *msg, +static inline void cec_ops_give_tuner_device_status(const struct cec_msg *msg, __u8 *status_req) { *status_req = msg->msg[2]; @@ -1079,7 +1079,7 @@ static inline void cec_msg_select_analogue_service(struct cec_msg *msg, msg->msg[5] = bcast_system; } -static inline void cec_ops_select_analogue_service(struct cec_msg *msg, +static inline void cec_ops_select_analogue_service(const struct cec_msg *msg, __u8 *ana_bcast_type, __u16 *ana_freq, __u8 *bcast_system) @@ -1097,7 +1097,7 @@ static inline void cec_msg_select_digital_service(struct cec_msg *msg, cec_set_digital_service_id(msg->msg + 2, digital); } -static inline void cec_ops_select_digital_service(struct cec_msg *msg, +static inline void cec_ops_select_digital_service(const struct cec_msg *msg, struct cec_op_digital_service_id *digital) { cec_get_digital_service_id(msg->msg + 2, digital); @@ -1218,7 +1218,7 @@ static inline void cec_msg_menu_status(struct cec_msg *msg, msg->msg[2] = menu_state; } -static inline void cec_ops_menu_status(struct cec_msg *msg, +static inline void cec_ops_menu_status(const struct cec_msg *msg, __u8 *menu_state) { *menu_state = msg->msg[2]; @@ -1234,7 +1234,7 @@ static inline void cec_msg_menu_request(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_MENU_STATUS : 0; } -static inline void cec_ops_menu_request(struct cec_msg *msg, +static inline void cec_ops_menu_request(const struct cec_msg *msg, __u8 *menu_req) { *menu_req = msg->msg[2]; @@ -1284,7 +1284,7 @@ static inline void cec_msg_user_control_pressed(struct cec_msg *msg, } } -static inline void cec_ops_user_control_pressed(struct cec_msg *msg, +static inline void cec_ops_user_control_pressed(const struct cec_msg *msg, struct cec_op_ui_command *ui_cmd) { ui_cmd->ui_cmd = msg->msg[2]; -- cgit v1.2.3 From 9ad52b4db79d168867a2ca105eca00fb9cb28fe5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Jul 2016 05:52:34 -0300 Subject: [media] cec-funcs.h: add missing 'reply' for short audio descriptor The cec_msg_request_short_audio_descriptor function was missing the reply argument. That's needed if you want the framework to wait for the reply message. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h index 455f9df86c43..82c3d3b7269d 100644 --- a/include/linux/cec-funcs.h +++ b/include/linux/cec-funcs.h @@ -1494,6 +1494,7 @@ static inline void cec_ops_report_short_audio_descriptor(const struct cec_msg *m } static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg, + bool reply, __u8 num_descriptors, const __u8 *audio_format_id, const __u8 *audio_format_code) @@ -1504,6 +1505,7 @@ static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg, num_descriptors = 4; msg->len = 2 + num_descriptors; msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR; + msg->reply = reply ? CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR : 0; for (i = 0; i < num_descriptors; i++) msg->msg[2 + i] = (audio_format_id[i] << 6) | (audio_format_code[i] & 0x3f); -- cgit v1.2.3 From cd9b518b98d3e989f523e63b2ffda78467a3679e Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 27 Jun 2016 00:03:03 +0200 Subject: rtc: v3020: move rtc-v3020.h to platform_data rtc-v3020.h belongs to include/linux/platform_data/ Acked-by: Robert Jarzmik Signed-off-by: Alexandre Belloni --- arch/arm/mach-pxa/cm-x270.c | 2 +- arch/arm/mach-pxa/cm-x300.c | 2 +- arch/arm/mach-pxa/em-x270.c | 2 +- drivers/rtc/rtc-v3020.c | 2 +- include/linux/platform_data/rtc-v3020.h | 41 +++++++++++++++++++++++++++++++++ include/linux/rtc-v3020.h | 41 --------------------------------- 6 files changed, 45 insertions(+), 45 deletions(-) create mode 100644 include/linux/platform_data/rtc-v3020.h delete mode 100644 include/linux/rtc-v3020.h (limited to 'include/linux') diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index fa5f51d633a3..be4a66166d61 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include