From 3367aa7d74d240261de2543ddb35531ccad9d884 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 11 May 2022 13:30:39 +0200 Subject: fbdev: Restart conflicting fb removal loop when unregistering devices Drivers that want to remove registered conflicting framebuffers prior to register their own framebuffer, call to remove_conflicting_framebuffers(). This function takes the registration_lock mutex, to prevent a race when drivers register framebuffer devices. But if a conflicting framebuffer device is found, the underlaying platform device is unregistered and this will lead to the platform driver .remove callback to be called. Which in turn will call to unregister_framebuffer() that takes the same lock. To prevent this, a struct fb_info.forced_out field was used as indication to unregister_framebuffer() whether the mutex has to be grabbed or not. But this could be unsafe, since the fbdev core is making assumptions about what drivers may or may not do in their .remove callbacks. Allowing to run these callbacks with the registration_lock held can cause deadlocks, since the fbdev core has no control over what drivers do in their removal path. A better solution is to drop the lock before platform_device_unregister(), so unregister_framebuffer() can take it when called from the fbdev driver. The lock is acquired again after the device has been unregistered and at this point the removal loop can be restarted. Since the conflicting framebuffer device has already been removed, the loop would just finish when no more conflicting framebuffers are found. Suggested-by: Daniel Vetter Signed-off-by: Javier Martinez Canillas Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220511113039.1252432-1-javierm@redhat.com --- include/linux/fb.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/fb.h b/include/linux/fb.h index 69c67c70fa78..bbe1e4571899 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -511,7 +511,6 @@ struct fb_info { } *apertures; bool skip_vt_switch; /* no VT switch on suspend/resume required */ - bool forced_out; /* set when being removed by another driver */ }; static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { -- cgit v1.2.3 From d9ba1b4cbb2989c919198832f4ebd6eb8ba94da0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 9 May 2022 15:03:23 +0300 Subject: drm/displayid: convert to drm_edid We'll need to propagate drm_edid everywhere. v2: Rebase Signed-off-by: Jani Nikula Reviewed-by: Ankit Nautiyal Link: https://patchwork.freedesktop.org/patch/msgid/a52a6882e87a4bb6b1670918f3aba13f9b52f6de.1652097712.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_displayid.c | 16 ++++++++-------- drivers/gpu/drm/drm_edid.c | 17 ++++++++++------- include/drm/drm_displayid.h | 6 +++--- include/drm/drm_edid.h | 6 ++++-- 4 files changed, 25 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 32da557b960f..38ea8203df45 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -33,11 +33,11 @@ static int validate_displayid(const u8 *displayid, int length, int idx) return 0; } -static const u8 *drm_find_displayid_extension(const struct edid *edid, +static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid, int *length, int *idx, int *ext_index) { - const u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT, ext_index); + const u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index); const struct displayid_header *base; int ret; @@ -58,12 +58,12 @@ static const u8 *drm_find_displayid_extension(const struct edid *edid, return displayid; } -void displayid_iter_edid_begin(const struct edid *edid, +void displayid_iter_edid_begin(const struct drm_edid *drm_edid, struct displayid_iter *iter) { memset(iter, 0, sizeof(*iter)); - iter->edid = edid; + iter->drm_edid = drm_edid; } static const struct displayid_block * @@ -88,7 +88,7 @@ __displayid_iter_next(struct displayid_iter *iter) { const struct displayid_block *block; - if (!iter->edid) + if (!iter->drm_edid) return NULL; if (iter->section) { @@ -96,7 +96,7 @@ __displayid_iter_next(struct displayid_iter *iter) block = displayid_iter_block(iter); if (WARN_ON(!block)) { iter->section = NULL; - iter->edid = NULL; + iter->drm_edid = NULL; return NULL; } @@ -109,12 +109,12 @@ __displayid_iter_next(struct displayid_iter *iter) } for (;;) { - iter->section = drm_find_displayid_extension(iter->edid, + iter->section = drm_find_displayid_extension(iter->drm_edid, &iter->length, &iter->idx, &iter->ext_index); if (!iter->section) { - iter->edid = NULL; + iter->drm_edid = NULL; return NULL; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 30c33fdc52fc..99d9eec27ca8 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3563,10 +3563,13 @@ static int add_detailed_modes(struct drm_connector *connector, /* * Search EDID for CEA extension block. + * + * FIXME: Prefer not returning pointers to raw EDID data. */ -const u8 *drm_find_edid_extension(const struct edid *edid, +const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, int ext_id, int *ext_index) { + const struct edid *edid = drm_edid ? drm_edid->edid : NULL; const u8 *edid_ext = NULL; int i; @@ -3598,11 +3601,11 @@ static bool drm_edid_has_cta_extension(const struct drm_edid *drm_edid) bool found = false; /* Look for a top level CEA extension block */ - if (drm_find_edid_extension(drm_edid->edid, CEA_EXT, &ext_index)) + if (drm_find_edid_extension(drm_edid, CEA_EXT, &ext_index)) return true; /* CEA blocks can also be found embedded in a DisplayID block */ - displayid_iter_edid_begin(drm_edid->edid, &iter); + displayid_iter_edid_begin(drm_edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_CTA) { found = true; @@ -4454,7 +4457,7 @@ static void cea_db_iter_edid_begin(const struct drm_edid *drm_edid, memset(iter, 0, sizeof(*iter)); drm_edid_iter_begin(drm_edid, &iter->edid_iter); - displayid_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter->displayid_iter); + displayid_iter_edid_begin(drm_edid, &iter->displayid_iter); } static const struct cea_db * @@ -5657,7 +5660,7 @@ static void drm_update_mso(struct drm_connector *connector, const struct displayid_block *block; struct displayid_iter iter; - displayid_iter_edid_begin(drm_edid->edid, &iter); + displayid_iter_edid_begin(drm_edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC) drm_parse_vesa_mso_data(connector, block); @@ -5872,7 +5875,7 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, struct displayid_iter iter; int num_modes = 0; - displayid_iter_edid_begin(drm_edid->edid, &iter); + displayid_iter_edid_begin(drm_edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING || block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING) @@ -6372,7 +6375,7 @@ static void _drm_update_tile_info(struct drm_connector *connector, connector->has_tile = false; - displayid_iter_edid_begin(drm_edid ? drm_edid->edid : NULL, &iter); + displayid_iter_edid_begin(drm_edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_TILED_DISPLAY) drm_parse_tiled_block(connector, block); diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h index 7ffbd9f7bfc7..49649eb8447e 100644 --- a/include/drm/drm_displayid.h +++ b/include/drm/drm_displayid.h @@ -25,7 +25,7 @@ #include #include -struct edid; +struct drm_edid; #define VESA_IEEE_OUI 0x3a0292 @@ -141,7 +141,7 @@ struct displayid_vesa_vendor_specific_block { /* DisplayID iteration */ struct displayid_iter { - const struct edid *edid; + const struct drm_edid *drm_edid; const u8 *section; int length; @@ -149,7 +149,7 @@ struct displayid_iter { int ext_index; }; -void displayid_iter_edid_begin(const struct edid *edid, +void displayid_iter_edid_begin(const struct drm_edid *drm_edid, struct displayid_iter *iter); const struct displayid_block * __displayid_iter_next(struct displayid_iter *iter); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index c3204a58fb09..c61e75ab8f63 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -28,6 +28,7 @@ #include struct drm_device; +struct drm_edid; struct i2c_adapter; #define EDID_LENGTH 128 @@ -578,8 +579,9 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, struct drm_display_mode * drm_display_mode_from_cea_vic(struct drm_device *dev, u8 video_code); -const u8 *drm_find_edid_extension(const struct edid *edid, - int ext_id, int *ext_index); +/* Interface based on struct drm_edid */ +const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, + int ext_id, int *ext_index); #endif /* __DRM_EDID_H__ */ -- cgit v1.2.3 From 7d64c40a7d96190d9d06e240305389e025295916 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 12 Apr 2022 01:15:36 +0300 Subject: drm/scheduler: Don't kill jobs in interrupt context Interrupt context can't sleep. Drivers like Panfrost and MSM are taking mutex when job is released, and thus, that code can sleep. This results into "BUG: scheduling while atomic" if locks are contented while job is freed. There is no good reason for releasing scheduler's jobs in IRQ context, hence use normal context to fix the trouble. Cc: stable@vger.kernel.org Fixes: 542cff7893a3 ("drm/sched: Avoid lockdep spalt on killing a processes") Signed-off-by: Dmitry Osipenko Signed-off-by: Andrey Grodzovsky Link: https://patchwork.freedesktop.org/patch/msgid/20220411221536.283312-1-dmitry.osipenko@collabora.com --- drivers/gpu/drm/scheduler/sched_entity.c | 6 +++--- include/drm/gpu_scheduler.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 191c56064f19..6b25b2f4f5a3 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -190,7 +190,7 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout) } EXPORT_SYMBOL(drm_sched_entity_flush); -static void drm_sched_entity_kill_jobs_irq_work(struct irq_work *wrk) +static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk) { struct drm_sched_job *job = container_of(wrk, typeof(*job), work); @@ -207,8 +207,8 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f, struct drm_sched_job *job = container_of(cb, struct drm_sched_job, finish_cb); - init_irq_work(&job->work, drm_sched_entity_kill_jobs_irq_work); - irq_work_queue(&job->work); + INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work); + schedule_work(&job->work); } static struct dma_fence * diff --git a/include/drm/gpu_scheduler.h b/include/drm/gpu_scheduler.h index 0fca8f38bee4..addb135eeea6 100644 --- a/include/drm/gpu_scheduler.h +++ b/include/drm/gpu_scheduler.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) @@ -295,7 +295,7 @@ struct drm_sched_job { */ union { struct dma_fence_cb finish_cb; - struct irq_work work; + struct work_struct work; }; uint64_t id; -- cgit v1.2.3 From 16f1456466c269ecda32b88c3f8fdd76f8ec370c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 16 May 2022 15:43:39 +0200 Subject: drm/mgag200: Implement connector's get_modes with helper Provide drm_connector_helper_get_modes_from_ddc() to implement the connector's get_modes callback. The new helper updates the connector from DDC-provided EDID data. v2: * clear property if EDID is NULL in helper Signed-off-by: Thomas Zimmermann Reviewed-by: Jocelyn Falempe Tested-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20220516134343.6085-4-tzimmermann@suse.de --- drivers/gpu/drm/drm_probe_helper.c | 36 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/mgag200/mgag200_mode.c | 17 ++++------------ include/drm/drm_probe_helper.h | 2 ++ 3 files changed, 42 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 682359512996..d77f17867195 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -964,3 +964,39 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) return changed; } EXPORT_SYMBOL(drm_helper_hpd_irq_event); + +/** + * drm_connector_helper_get_modes_from_ddc - Updates the connector's EDID + * property from the connector's + * DDC channel + * @connector: The connector + * + * Returns: + * The number of detected display modes. + * + * Uses a connector's DDC channel to retrieve EDID data and update the + * connector's EDID property and display modes. Drivers can use this + * function to implement struct &drm_connector_helper_funcs.get_modes + * for connectors with a DDC channel. + */ +int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector) +{ + struct edid *edid; + int count = 0; + + if (!connector->ddc) + return 0; + + edid = drm_get_edid(connector, connector->ddc); + + // clears property if EDID is NULL + drm_connector_update_edid_property(connector, edid); + + if (edid) { + count = drm_add_edid_modes(connector, edid); + kfree(edid); + } + + return count; +} +EXPORT_SYMBOL(drm_connector_helper_get_modes_from_ddc); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index b227891d01ec..4c0680dd1a78 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -689,26 +689,17 @@ static void mgag200_disable_display(struct mga_device *mdev) * Connector */ -static int mga_vga_get_modes(struct drm_connector *connector) +static int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector) { struct mga_device *mdev = to_mga_device(connector->dev); - struct mga_connector *mga_connector = to_mga_connector(connector); - struct edid *edid; - int ret = 0; + int ret; /* * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ mutex_lock(&mdev->rmmio_lock); - - edid = drm_get_edid(connector, &mga_connector->i2c->adapter); - if (edid) { - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - } - + ret = drm_connector_helper_get_modes_from_ddc(connector); mutex_unlock(&mdev->rmmio_lock); return ret; @@ -828,7 +819,7 @@ static void mga_connector_destroy(struct drm_connector *connector) } static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = { - .get_modes = mga_vga_get_modes, + .get_modes = mgag200_vga_connector_helper_get_modes, .mode_valid = mga_vga_mode_valid, }; diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h index 48300aa6ca71..c80cab7a53b7 100644 --- a/include/drm/drm_probe_helper.h +++ b/include/drm/drm_probe_helper.h @@ -26,4 +26,6 @@ void drm_kms_helper_poll_disable(struct drm_device *dev); void drm_kms_helper_poll_enable(struct drm_device *dev); bool drm_kms_helper_is_poll_worker(void); +int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector); + #endif -- cgit v1.2.3 From a50794f26f52c66cb793d5d392f5f19bc2962cdd Mon Sep 17 00:00:00 2001 From: Ramalingam C Date: Mon, 2 May 2022 19:45:08 +0530 Subject: uapi/drm/i915: Document memory residency and Flat-CCS capability of obj Capture the impact of memory region preference list of the objects, on their memory residency and Flat-CCS capability. v2: Fix the Flat-CCS capability of an obj with {lmem, smem} preference list [Thomas] v3: Reworded the doc [Matt] v4: Fixed Typos and spelling mistakes [Tvrtko, Joonas] Signed-off-by: Ramalingam C cc: Matthew Auld cc: Thomas Hellstrom cc: Daniel Vetter cc: Jon Bloomfield cc: Lionel Landwerlin cc: Kenneth Graunke cc: mesa-dev@lists.freedesktop.org cc: Jordan Justen cc: Tony Ye Reviewed-by: Matthew Auld Acked-by: Jordan Justen Link: https://patchwork.freedesktop.org/patch/msgid/20220502141508.2327-1-ramalingam.c@intel.com --- include/uapi/drm/i915_drm.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'include') diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index a2def7b27009..de49b68b4fc8 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -3443,6 +3443,22 @@ struct drm_i915_gem_create_ext { * At which point we get the object handle in &drm_i915_gem_create_ext.handle, * along with the final object size in &drm_i915_gem_create_ext.size, which * should account for any rounding up, if required. + * + * Note that userspace has no means of knowing the current backing region + * for objects where @num_regions is larger than one. The kernel will only + * ensure that the priority order of the @regions array is honoured, either + * when initially placing the object, or when moving memory around due to + * memory pressure + * + * On Flat-CCS capable HW, compression is supported for the objects residing + * in I915_MEMORY_CLASS_DEVICE. When such objects (compressed) have other + * memory class in @regions and migrated (by i915, due to memory + * constraints) to the non I915_MEMORY_CLASS_DEVICE region, then i915 needs to + * decompress the content. But i915 doesn't have the required information to + * decompress the userspace compressed objects. + * + * So i915 supports Flat-CCS, on the objects which can reside only on + * I915_MEMORY_CLASS_DEVICE regions. */ struct drm_i915_gem_create_ext_memory_regions { /** @base: Extension link. See struct i915_user_extension. */ -- cgit v1.2.3 From 746b9c62cc8614fa59c23f3332682b5e9e1d801c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 17 May 2022 13:33:24 +0200 Subject: drm/gem: Ignore color planes that are unused by framebuffer format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only handle color planes that exist in a framebuffer's color format. Ignore non-existing planes. So far, several helpers assumed that all 4 planes are available and silently ignored non-existing planes. This lead to subtil bugs with uninitialized data in instances of struct iosys_map. [1] Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Tested-by: Noralf Trønnes Acked-by: Christian König Link: https://lore.kernel.org/dri-devel/20210730183511.20080-1-tzimmermann@suse.de/T/#md0172b10bb588d8f20f4f456e304f08d2a4505f7 # 1 Link: https://patchwork.freedesktop.org/patch/msgid/20220517113327.26919-3-tzimmermann@suse.de --- drivers/gpu/drm/drm_gem_atomic_helper.c | 6 +++-- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 37 +++++++++++++++------------- include/drm/drm_gem_framebuffer_helper.h | 10 +++----- 3 files changed, 27 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index a5026f617739..f16d60217c6c 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -169,8 +169,10 @@ int drm_gem_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_gem_object *obj = drm_gem_fb_get_obj(state->fb, i); struct dma_fence *new; - if (WARN_ON_ONCE(!obj)) - continue; + if (!obj) { + ret = -EINVAL; + goto error; + } ret = dma_resv_get_singleton(obj->resv, usage, &new); if (ret) diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 931828784dfe..6d3c26efdeeb 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -92,9 +92,9 @@ drm_gem_fb_init(struct drm_device *dev, */ void drm_gem_fb_destroy(struct drm_framebuffer *fb) { - size_t i; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(fb->obj); i++) + for (i = 0; i < fb->format->num_planes; i++) drm_gem_object_put(fb->obj[i]); drm_framebuffer_cleanup(fb); @@ -329,24 +329,26 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); * The argument returns the addresses of the data stored in each BO. This * is different from @map if the framebuffer's offsets field is non-zero. * + * Both, @map and @data, must each refer to arrays with at least + * fb->format->num_planes elements. + * * See drm_gem_fb_vunmap() for unmapping. * * Returns: * 0 on success, or a negative errno code otherwise. */ -int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct iosys_map map[static DRM_FORMAT_MAX_PLANES], - struct iosys_map data[DRM_FORMAT_MAX_PLANES]) +int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map, + struct iosys_map *data) { struct drm_gem_object *obj; unsigned int i; int ret; - for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { obj = drm_gem_fb_get_obj(fb, i); if (!obj) { - iosys_map_clear(&map[i]); - continue; + ret = -EINVAL; + goto err_drm_gem_vunmap; } ret = drm_gem_vmap(obj, &map[i]); if (ret) @@ -354,7 +356,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, } if (data) { - for (i = 0; i < DRM_FORMAT_MAX_PLANES; ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { memcpy(&data[i], &map[i], sizeof(data[i])); if (iosys_map_is_null(&data[i])) continue; @@ -385,10 +387,9 @@ EXPORT_SYMBOL(drm_gem_fb_vmap); * * See drm_gem_fb_vmap() for more information. */ -void drm_gem_fb_vunmap(struct drm_framebuffer *fb, - struct iosys_map map[static DRM_FORMAT_MAX_PLANES]) +void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map) { - unsigned int i = DRM_FORMAT_MAX_PLANES; + unsigned int i = fb->format->num_planes; struct drm_gem_object *obj; while (i) { @@ -443,13 +444,15 @@ int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direct { struct dma_buf_attachment *import_attach; struct drm_gem_object *obj; - size_t i; + unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(fb->obj); ++i) { + for (i = 0; i < fb->format->num_planes; ++i) { obj = drm_gem_fb_get_obj(fb, i); - if (!obj) - continue; + if (!obj) { + ret = -EINVAL; + goto err___drm_gem_fb_end_cpu_access; + } import_attach = obj->import_attach; if (!import_attach) continue; @@ -479,7 +482,7 @@ EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access); */ void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir) { - __drm_gem_fb_end_cpu_access(fb, dir, ARRAY_SIZE(fb->obj)); + __drm_gem_fb_end_cpu_access(fb, dir, fb->format->num_planes); } EXPORT_SYMBOL(drm_gem_fb_end_cpu_access); diff --git a/include/drm/drm_gem_framebuffer_helper.h b/include/drm/drm_gem_framebuffer_helper.h index 1091e4fa08cb..d302521f3dd4 100644 --- a/include/drm/drm_gem_framebuffer_helper.h +++ b/include/drm/drm_gem_framebuffer_helper.h @@ -4,8 +4,6 @@ #include #include -#include - struct drm_afbc_framebuffer; struct drm_device; struct drm_fb_helper_surface_size; @@ -39,11 +37,9 @@ struct drm_framebuffer * drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); -int drm_gem_fb_vmap(struct drm_framebuffer *fb, - struct iosys_map map[static DRM_FORMAT_MAX_PLANES], - struct iosys_map data[DRM_FORMAT_MAX_PLANES]); -void drm_gem_fb_vunmap(struct drm_framebuffer *fb, - struct iosys_map map[static DRM_FORMAT_MAX_PLANES]); +int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map, + struct iosys_map *data); +void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map); int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir); -- cgit v1.2.3 From 69ef4a192bba0d76216198ec6d5fe82375337903 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 9 May 2022 16:18:09 -0700 Subject: drm: Document the power requirements for DP AUX transfers When doing DP AUX transfers there are two actors that need to be powered in order for the DP AUX transfer to work: the DP source and the DP sink. Commit bacbab58f09d ("drm: Mention the power state requirement on side-channel operations") added some documentation saying that the DP source is required to power itself up (if needed) to do AUX transfers. However, that commit doesn't talk anything about the DP sink. For full fledged DP the sink isn't really a problem. It's expected that if an external DP monitor isn't plugged in that attempting to do AUX transfers won't work. It's also expected that if a DP monitor is plugged in (and thus asserting HPD) then AUX transfers will work. When we're looking at eDP, however, things are less obvious. Let's add some documentation about expectations. Here's what we'll say: 1. We don't expect the DP AUX transfer function to power on an eDP panel. If an eDP panel is physically connected but powered off then it makes sense for the transfer to fail. 2. We'll document that the official way to power on a panel is via the bridge chain, specifically by making sure that the panel's prepare function has been called (which is called by panel_bridge_pre_enable()). It's already specified in the kernel doc of drm_panel_prepare() that this is the way to power the panel on and also that after this call "it is possible to communicate with any integrated circuitry via a command bus." 3. We'll also document that for code running in the panel driver itself that it is legal for the panel driver to power itself up however it wants (it doesn't need to officially call drm_panel_pre_enable()) and then it can do AUX bus transfers. This is currently the way that edp-panel works when it's running atop the DP AUX bus. NOTE: there was much discussion of all of this in response to v1 [1] of this patch. A summary of that is: * With the Intel i195 driver, apparently eDP panels do get powered up. We won't forbid this but it is expected that code that wants to run on a variety of platforms should ensure that the drm_panel's prepare() function has been called. * There is at least a reasonable amount of agreement that the transfer() functions itself shouldn't be responsible for powering the panel. It's proposed that if we need the DP AUX dev nodes to be robust for eDP that the code handling the DP AUX dev nodes could handle powering the panel by ensuring that the panel's prepare() call was made. Potentially drm_dp_aux_dev_get_by_minor() could be a good place to do this. This is left as a future exercise. Until that's fixed the DP AUX dev nodes for eDP are probably best just used for debugging. * If a panel could be in PSR and DP AUX via the dev node needs to be reliable then we need to be able to pull the panel out of PSR. On i915 this is also apparently handled as part of the transfer() function. [1] https://lore.kernel.org/r/20220503162033.1.Ia8651894026707e4fa61267da944ff739610d180@changeid Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Reviewed-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20220509161733.v2.1.Ia8651894026707e4fa61267da944ff739610d180@changeid --- include/drm/display/drm_dp_helper.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index dca40a045dd6..dc3c02225fcf 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -370,9 +370,19 @@ struct drm_dp_aux { * helpers assume this is the case. * * Also note that this callback can be called no matter the - * state @dev is in. Drivers that need that device to be powered - * to perform this operation will first need to make sure it's - * been properly enabled. + * state @dev is in and also no matter what state the panel is + * in. It's expected: + * - If the @dev providing the AUX bus is currently unpowered then + * it will power itself up for the transfer. + * - If we're on eDP (using a drm_panel) and the panel is not in a + * state where it can respond (it's not powered or it's in a + * low power state) then this function may return an error, but + * not crash. It's up to the caller of this code to make sure that + * the panel is powered on if getting an error back is not OK. If a + * drm_panel driver is initiating a DP AUX transfer it may power + * itself up however it wants. All other code should ensure that + * the pre_enable() bridge chain (which eventually calls the + * drm_panel prepare function) has powered the panel. */ ssize_t (*transfer)(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg); -- cgit v1.2.3 From 93984f19e7bce4c18084a6ef3dacafb155b806ed Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 21:00:23 +0000 Subject: KVM: Fully serialize gfn=>pfn cache refresh via mutex Protect gfn=>pfn cache refresh with a mutex to fully serialize refreshes. The refresh logic doesn't protect against - concurrent unmaps, or refreshes with different GPAs (which may or may not happen in practice, for example if a cache is only used under vcpu->mutex; but it's allowed in the code) - a false negative on the memslot generation. If the first refresh sees a stale memslot generation, it will refresh the hva and generation before moving on to the hva=>pfn translation. If it then drops gpc->lock, a different user of the cache can come along, acquire gpc->lock, see that the memslot generation is fresh, and skip the hva=>pfn update due to the userspace address also matching (because it too was updated). The refresh path can already sleep during hva=>pfn resolution, so wrap the refresh with a mutex to ensure that any given refresh runs to completion before other callers can start their refresh. Cc: stable@vger.kernel.org Cc: Lai Jiangshan Signed-off-by: Sean Christopherson Message-Id: <20220429210025.3293691-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_types.h | 2 ++ virt/kvm/pfncache.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) (limited to 'include') diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index ac1ebb37a0ff..f328a01db4fe 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -19,6 +19,7 @@ struct kvm_memslots; enum kvm_mr_change; #include +#include #include #include @@ -69,6 +70,7 @@ struct gfn_to_pfn_cache { struct kvm_vcpu *vcpu; struct list_head list; rwlock_t lock; + struct mutex refresh_lock; void *khva; kvm_pfn_t pfn; enum pfn_cache_usage usage; diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 05cb0bcbf662..f610d3945b69 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -157,6 +157,13 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, if (page_offset + len > PAGE_SIZE) return -EINVAL; + /* + * If another task is refreshing the cache, wait for it to complete. + * There is no guarantee that concurrent refreshes will see the same + * gpa, memslots generation, etc..., so they must be fully serialized. + */ + mutex_lock(&gpc->refresh_lock); + write_lock_irq(&gpc->lock); old_pfn = gpc->pfn; @@ -248,6 +255,8 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, out: write_unlock_irq(&gpc->lock); + mutex_unlock(&gpc->refresh_lock); + gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); return ret; @@ -259,6 +268,7 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) void *old_khva; kvm_pfn_t old_pfn; + mutex_lock(&gpc->refresh_lock); write_lock_irq(&gpc->lock); gpc->valid = false; @@ -274,6 +284,7 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) gpc->pfn = KVM_PFN_ERR_FAULT; write_unlock_irq(&gpc->lock); + mutex_unlock(&gpc->refresh_lock); gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); } @@ -288,6 +299,7 @@ int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, if (!gpc->active) { rwlock_init(&gpc->lock); + mutex_init(&gpc->refresh_lock); gpc->khva = NULL; gpc->pfn = KVM_PFN_ERR_FAULT; -- cgit v1.2.3 From ade1fc91eb99614c7155fec762ad5761bb470e06 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 10 May 2022 13:42:41 +0300 Subject: drm/edid: Extract drm_edid_decode_mfg_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the PNPID decoding available for other users. Cc: dri-devel@lists.freedesktop.org Reviewed-by: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-15-ville.syrjala@linux.intel.com --- include/drm/drm_edid.h | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index c61e75ab8f63..1d5950b5b407 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -497,6 +497,22 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld) return eld[DRM_ELD_SAD_COUNT_CONN_TYPE] & DRM_ELD_CONN_TYPE_MASK; } +/** + * drm_edid_decode_mfg_id - Decode the manufacturer ID + * @mfg_id: The manufacturer ID + * @vend: A 4-byte buffer to store the 3-letter vendor string plus a '\0' + * termination + */ +static inline const char *drm_edid_decode_mfg_id(u16 mfg_id, char vend[4]) +{ + vend[0] = '@' + ((mfg_id >> 10) & 0x1f); + vend[1] = '@' + ((mfg_id >> 5) & 0x1f); + vend[2] = '@' + ((mfg_id >> 0) & 0x1f); + vend[3] = '\0'; + + return vend; +} + /** * drm_edid_encode_panel_id - Encode an ID for matching against drm_edid_get_panel_id() * @vend_chr_0: First character of the vendor string. @@ -537,10 +553,7 @@ static inline u8 drm_eld_get_conn_type(const uint8_t *eld) static inline void drm_edid_decode_panel_id(u32 panel_id, char vend[4], u16 *product_id) { *product_id = (u16)(panel_id & 0xffff); - vend[0] = '@' + ((panel_id >> 26) & 0x1f); - vend[1] = '@' + ((panel_id >> 21) & 0x1f); - vend[2] = '@' + ((panel_id >> 16) & 0x1f); - vend[3] = '\0'; + drm_edid_decode_mfg_id(panel_id >> 16, vend); } bool drm_probe_ddc(struct i2c_adapter *adapter); -- cgit v1.2.3 From 01357a5a45ed8eb9543183f5c9c6713ae60fc1f3 Mon Sep 17 00:00:00 2001 From: Christian König Date: Sun, 24 Apr 2022 16:55:14 +0200 Subject: dma-buf: cleanup dma_fence_unwrap implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the code from the inline functions into exported functions. Signed-off-by: Christian König Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518135844.3338-3-christian.koenig@amd.com --- drivers/dma-buf/Makefile | 2 +- drivers/dma-buf/dma-fence-unwrap.c | 59 ++++++++++++++++++++++++++++++++++++++ include/linux/dma-fence-unwrap.h | 52 +++------------------------------ 3 files changed, 64 insertions(+), 49 deletions(-) create mode 100644 drivers/dma-buf/dma-fence-unwrap.c (limited to 'include') diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 4c9eb53ba3f8..70ec901edf2c 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ - dma-resv.o + dma-fence-unwrap.o dma-resv.o obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o obj-$(CONFIG_DMABUF_HEAPS) += heaps/ obj-$(CONFIG_SYNC_FILE) += sync_file.o diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c new file mode 100644 index 000000000000..711be125428c --- /dev/null +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * dma-fence-util: misc functions for dma_fence objects + * + * Copyright (C) 2022 Advanced Micro Devices, Inc. + * Authors: + * Christian König + */ + +#include +#include +#include +#include + +/* Internal helper to start new array iteration, don't use directly */ +static struct dma_fence * +__dma_fence_unwrap_array(struct dma_fence_unwrap *cursor) +{ + cursor->array = dma_fence_chain_contained(cursor->chain); + cursor->index = 0; + return dma_fence_array_first(cursor->array); +} + +/** + * dma_fence_unwrap_first - return the first fence from fence containers + * @head: the entrypoint into the containers + * @cursor: current position inside the containers + * + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the + * first fence. + */ +struct dma_fence *dma_fence_unwrap_first(struct dma_fence *head, + struct dma_fence_unwrap *cursor) +{ + cursor->chain = dma_fence_get(head); + return __dma_fence_unwrap_array(cursor); +} +EXPORT_SYMBOL_GPL(dma_fence_unwrap_first); + +/** + * dma_fence_unwrap_next - return the next fence from a fence containers + * @cursor: current position inside the containers + * + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return + * the next fence from them. + */ +struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor) +{ + struct dma_fence *tmp; + + ++cursor->index; + tmp = dma_fence_array_next(cursor->array, cursor->index); + if (tmp) + return tmp; + + cursor->chain = dma_fence_chain_walk(cursor->chain); + return __dma_fence_unwrap_array(cursor); +} +EXPORT_SYMBOL_GPL(dma_fence_unwrap_next); diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h index 77e335a1bcac..e7c219da4ed7 100644 --- a/include/linux/dma-fence-unwrap.h +++ b/include/linux/dma-fence-unwrap.h @@ -1,7 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * fence-chain: chain fences together in a timeline - * * Copyright (C) 2022 Advanced Micro Devices, Inc. * Authors: * Christian König @@ -10,8 +8,7 @@ #ifndef __LINUX_DMA_FENCE_UNWRAP_H #define __LINUX_DMA_FENCE_UNWRAP_H -#include -#include +struct dma_fence; /** * struct dma_fence_unwrap - cursor into the container structure @@ -33,50 +30,9 @@ struct dma_fence_unwrap { unsigned int index; }; -/* Internal helper to start new array iteration, don't use directly */ -static inline struct dma_fence * -__dma_fence_unwrap_array(struct dma_fence_unwrap * cursor) -{ - cursor->array = dma_fence_chain_contained(cursor->chain); - cursor->index = 0; - return dma_fence_array_first(cursor->array); -} - -/** - * dma_fence_unwrap_first - return the first fence from fence containers - * @head: the entrypoint into the containers - * @cursor: current position inside the containers - * - * Unwraps potential dma_fence_chain/dma_fence_array containers and return the - * first fence. - */ -static inline struct dma_fence * -dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor) -{ - cursor->chain = dma_fence_get(head); - return __dma_fence_unwrap_array(cursor); -} - -/** - * dma_fence_unwrap_next - return the next fence from a fence containers - * @cursor: current position inside the containers - * - * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return - * the next fence from them. - */ -static inline struct dma_fence * -dma_fence_unwrap_next(struct dma_fence_unwrap *cursor) -{ - struct dma_fence *tmp; - - ++cursor->index; - tmp = dma_fence_array_next(cursor->array, cursor->index); - if (tmp) - return tmp; - - cursor->chain = dma_fence_chain_walk(cursor->chain); - return __dma_fence_unwrap_array(cursor); -} +struct dma_fence *dma_fence_unwrap_first(struct dma_fence *head, + struct dma_fence_unwrap *cursor); +struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor); /** * dma_fence_unwrap_for_each - iterate over all fences in containers -- cgit v1.2.3 From 8f61973718485f3e89bc4f408f929048b7b47c83 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 4 May 2022 13:01:29 +0200 Subject: dma-buf: return only unsignaled fences in dma_fence_unwrap_for_each v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dma_fence_chain containers cleanup signaled fences automatically, so filter those out from arrays as well. v2: fix missing walk over the array v3: massively simplify the patch and actually update the description. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518135844.3338-4-christian.koenig@amd.com --- include/linux/dma-fence-unwrap.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h index e7c219da4ed7..a4d342fef8e0 100644 --- a/include/linux/dma-fence-unwrap.h +++ b/include/linux/dma-fence-unwrap.h @@ -43,9 +43,13 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor); * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all * potential fences in them. If @head is just a normal fence only that one is * returned. + * + * Note that signalled fences are opportunistically filtered out, which + * means the iteration is potentially over no fence at all. */ #define dma_fence_unwrap_for_each(fence, cursor, head) \ for (fence = dma_fence_unwrap_first(head, cursor); fence; \ - fence = dma_fence_unwrap_next(cursor)) + fence = dma_fence_unwrap_next(cursor)) \ + if (!dma_fence_is_signaled(fence)) #endif -- cgit v1.2.3 From 245a4a7b531cffb41233a716497c25b06835cf4b Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 25 Apr 2022 14:22:12 +0200 Subject: dma-buf: generalize dma_fence unwrap & merging v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a dma_fence_unwrap_merge() macro which allows to unwrap fences which potentially can be containers as well and then merge them back together into a flat dma_fence_array. v2: rename the function, add some more comments about how the wrapper is used, move filtering of signaled fences into the unwrap iterator, add complex selftest which covers more cases. v3: fix signaled fence filtering once more Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220518135844.3338-5-christian.koenig@amd.com --- drivers/dma-buf/dma-fence-unwrap.c | 103 +++++++++++++++++++++++++++++ drivers/dma-buf/st-dma-fence-unwrap.c | 109 +++++++++++++++++++++++++++++++ drivers/dma-buf/sync_file.c | 119 ++-------------------------------- include/linux/dma-fence-unwrap.h | 24 +++++++ 4 files changed, 242 insertions(+), 113 deletions(-) (limited to 'include') diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c index 711be125428c..502a65ea6d44 100644 --- a/drivers/dma-buf/dma-fence-unwrap.c +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -11,6 +11,7 @@ #include #include #include +#include /* Internal helper to start new array iteration, don't use directly */ static struct dma_fence * @@ -57,3 +58,105 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor) return __dma_fence_unwrap_array(cursor); } EXPORT_SYMBOL_GPL(dma_fence_unwrap_next); + +/* Implementation for the dma_fence_merge() marco, don't use directly */ +struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, + struct dma_fence **fences, + struct dma_fence_unwrap *iter) +{ + struct dma_fence_array *result; + struct dma_fence *tmp, **array; + unsigned int i; + size_t count; + + count = 0; + for (i = 0; i < num_fences; ++i) { + dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) + ++count; + } + + if (count == 0) + return dma_fence_get_stub(); + + array = kmalloc_array(count, sizeof(*array), GFP_KERNEL); + if (!array) + return NULL; + + /* + * This trashes the input fence array and uses it as position for the + * following merge loop. This works because the dma_fence_merge() + * wrapper macro is creating this temporary array on the stack together + * with the iterators. + */ + for (i = 0; i < num_fences; ++i) + fences[i] = dma_fence_unwrap_first(fences[i], &iter[i]); + + count = 0; + do { + unsigned int sel; + +restart: + tmp = NULL; + for (i = 0; i < num_fences; ++i) { + struct dma_fence *next; + + while (fences[i] && dma_fence_is_signaled(fences[i])) + fences[i] = dma_fence_unwrap_next(&iter[i]); + + next = fences[i]; + if (!next) + continue; + + /* + * We can't guarantee that inpute fences are ordered by + * context, but it is still quite likely when this + * function is used multiple times. So attempt to order + * the fences by context as we pass over them and merge + * fences with the same context. + */ + if (!tmp || tmp->context > next->context) { + tmp = next; + sel = i; + + } else if (tmp->context < next->context) { + continue; + + } else if (dma_fence_is_later(tmp, next)) { + fences[i] = dma_fence_unwrap_next(&iter[i]); + goto restart; + } else { + fences[sel] = dma_fence_unwrap_next(&iter[sel]); + goto restart; + } + } + + if (tmp) { + array[count++] = dma_fence_get(tmp); + fences[sel] = dma_fence_unwrap_next(&iter[sel]); + } + } while (tmp); + + if (count == 0) { + tmp = dma_fence_get_stub(); + goto return_tmp; + } + + if (count == 1) { + tmp = array[0]; + goto return_tmp; + } + + result = dma_fence_array_create(count, array, + dma_fence_context_alloc(1), + 1, false); + if (!result) { + tmp = NULL; + goto return_tmp; + } + return &result->base; + +return_tmp: + kfree(array); + return tmp; +} +EXPORT_SYMBOL_GPL(__dma_fence_unwrap_merge); diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c index e20c5a7dcfe4..4105d5ea8dde 100644 --- a/drivers/dma-buf/st-dma-fence-unwrap.c +++ b/drivers/dma-buf/st-dma-fence-unwrap.c @@ -238,6 +238,113 @@ static int unwrap_chain_array(void *arg) return err; } +static int unwrap_merge(void *arg) +{ + struct dma_fence *fence, *f1, *f2, *f3; + struct dma_fence_unwrap iter; + int err = 0; + + f1 = mock_fence(); + if (!f1) + return -ENOMEM; + + f2 = mock_fence(); + if (!f2) { + err = -ENOMEM; + goto error_put_f1; + } + + f3 = dma_fence_unwrap_merge(f1, f2); + if (!f3) { + err = -ENOMEM; + goto error_put_f2; + } + + dma_fence_unwrap_for_each(fence, &iter, f3) { + if (fence == f1) { + dma_fence_put(f1); + f1 = NULL; + } else if (fence == f2) { + dma_fence_put(f2); + f2 = NULL; + } else { + pr_err("Unexpected fence!\n"); + err = -EINVAL; + } + } + + if (f1 || f2) { + pr_err("Not all fences seen!\n"); + err = -EINVAL; + } + + dma_fence_put(f3); +error_put_f2: + dma_fence_put(f2); +error_put_f1: + dma_fence_put(f1); + return err; +} + +static int unwrap_merge_complex(void *arg) +{ + struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5; + struct dma_fence_unwrap iter; + int err = -ENOMEM; + + f1 = mock_fence(); + if (!f1) + return -ENOMEM; + + f2 = mock_fence(); + if (!f2) + goto error_put_f1; + + f3 = dma_fence_unwrap_merge(f1, f2); + if (!f3) + goto error_put_f2; + + /* The resulting array has the fences in reverse */ + f4 = dma_fence_unwrap_merge(f2, f1); + if (!f4) + goto error_put_f3; + + /* Signaled fences should be filtered, the two arrays merged. */ + f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub()); + if (!f5) + goto error_put_f4; + + err = 0; + dma_fence_unwrap_for_each(fence, &iter, f5) { + if (fence == f1) { + dma_fence_put(f1); + f1 = NULL; + } else if (fence == f2) { + dma_fence_put(f2); + f2 = NULL; + } else { + pr_err("Unexpected fence!\n"); + err = -EINVAL; + } + } + + if (f1 || f2) { + pr_err("Not all fences seen!\n"); + err = -EINVAL; + } + + dma_fence_put(f5); +error_put_f4: + dma_fence_put(f4); +error_put_f3: + dma_fence_put(f3); +error_put_f2: + dma_fence_put(f2); +error_put_f1: + dma_fence_put(f1); + return err; +} + int dma_fence_unwrap(void) { static const struct subtest tests[] = { @@ -245,6 +352,8 @@ int dma_fence_unwrap(void) SUBTEST(unwrap_array), SUBTEST(unwrap_chain), SUBTEST(unwrap_chain_array), + SUBTEST(unwrap_merge), + SUBTEST(unwrap_merge_complex), }; return subtests(tests, NULL); diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 0fe564539166..3ebec19a8e02 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -146,50 +146,6 @@ char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len) return buf; } -static int sync_file_set_fence(struct sync_file *sync_file, - struct dma_fence **fences, int num_fences) -{ - struct dma_fence_array *array; - - /* - * The reference for the fences in the new sync_file and held - * in add_fence() during the merge procedure, so for num_fences == 1 - * we already own a new reference to the fence. For num_fence > 1 - * we own the reference of the dma_fence_array creation. - */ - - if (num_fences == 0) { - sync_file->fence = dma_fence_get_stub(); - kfree(fences); - - } else if (num_fences == 1) { - sync_file->fence = fences[0]; - kfree(fences); - - } else { - array = dma_fence_array_create(num_fences, fences, - dma_fence_context_alloc(1), - 1, false); - if (!array) - return -ENOMEM; - - sync_file->fence = &array->base; - } - - return 0; -} - -static void add_fence(struct dma_fence **fences, - int *i, struct dma_fence *fence) -{ - fences[*i] = fence; - - if (!dma_fence_is_signaled(fence)) { - dma_fence_get(fence); - (*i)++; - } -} - /** * sync_file_merge() - merge two sync_files * @name: name of new fence @@ -203,84 +159,21 @@ static void add_fence(struct dma_fence **fences, static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, struct sync_file *b) { - struct dma_fence *a_fence, *b_fence, **fences; - struct dma_fence_unwrap a_iter, b_iter; - unsigned int index, num_fences; struct sync_file *sync_file; + struct dma_fence *fence; sync_file = sync_file_alloc(); if (!sync_file) return NULL; - num_fences = 0; - dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence) - ++num_fences; - dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence) - ++num_fences; - - if (num_fences > INT_MAX) - goto err_free_sync_file; - - fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); - if (!fences) - goto err_free_sync_file; - - /* - * We can't guarantee that fences in both a and b are ordered, but it is - * still quite likely. - * - * So attempt to order the fences as we pass over them and merge fences - * with the same context. - */ - - index = 0; - for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter), - b_fence = dma_fence_unwrap_first(b->fence, &b_iter); - a_fence || b_fence; ) { - - if (!b_fence) { - add_fence(fences, &index, a_fence); - a_fence = dma_fence_unwrap_next(&a_iter); - - } else if (!a_fence) { - add_fence(fences, &index, b_fence); - b_fence = dma_fence_unwrap_next(&b_iter); - - } else if (a_fence->context < b_fence->context) { - add_fence(fences, &index, a_fence); - a_fence = dma_fence_unwrap_next(&a_iter); - - } else if (b_fence->context < a_fence->context) { - add_fence(fences, &index, b_fence); - b_fence = dma_fence_unwrap_next(&b_iter); - - } else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno, - a_fence->ops)) { - add_fence(fences, &index, a_fence); - a_fence = dma_fence_unwrap_next(&a_iter); - b_fence = dma_fence_unwrap_next(&b_iter); - - } else { - add_fence(fences, &index, b_fence); - a_fence = dma_fence_unwrap_next(&a_iter); - b_fence = dma_fence_unwrap_next(&b_iter); - } + fence = dma_fence_unwrap_merge(a->fence, b->fence); + if (!fence) { + fput(sync_file->file); + return NULL; } - - if (sync_file_set_fence(sync_file, fences, index) < 0) - goto err_put_fences; - + sync_file->fence = fence; strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name)); return sync_file; - -err_put_fences: - while (index) - dma_fence_put(fences[--index]); - kfree(fences); - -err_free_sync_file: - fput(sync_file->file); - return NULL; } static int sync_file_release(struct inode *inode, struct file *file) diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h index a4d342fef8e0..390de1ee9d35 100644 --- a/include/linux/dma-fence-unwrap.h +++ b/include/linux/dma-fence-unwrap.h @@ -52,4 +52,28 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor); fence = dma_fence_unwrap_next(cursor)) \ if (!dma_fence_is_signaled(fence)) +struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, + struct dma_fence **fences, + struct dma_fence_unwrap *cursors); + +/** + * dma_fence_unwrap_merge - unwrap and merge fences + * + * All fences given as parameters are unwrapped and merged back together as flat + * dma_fence_array. Useful if multiple containers need to be merged together. + * + * Implemented as a macro to allocate the necessary arrays on the stack and + * account the stack frame size to the caller. + * + * Returns NULL on memory allocation failure, a dma_fence object representing + * all the given fences otherwise. + */ +#define dma_fence_unwrap_merge(...) \ + ({ \ + struct dma_fence *__f[] = { __VA_ARGS__ }; \ + struct dma_fence_unwrap __c[ARRAY_SIZE(__f)]; \ + \ + __dma_fence_unwrap_merge(ARRAY_SIZE(__f), __f, __c); \ + }) + #endif -- cgit v1.2.3 From 35d02493dba1ae6386fac07072908717affc3ff8 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:21 +0000 Subject: KVM: s390: pv: Add query interface Some of the query information is already available via sysfs but having a IOCTL makes the information easier to retrieve. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Reviewed-by: Steffen Eiden Link: https://lore.kernel.org/r/20220517163629.3443-4-frankja@linux.ibm.com Message-Id: <20220517163629.3443-4-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 25 ++++++++++++++++ 2 files changed, 101 insertions(+) (limited to 'include') diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 76ad6408cb2c..5859f243d287 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2224,6 +2224,42 @@ static int kvm_s390_cpus_to_pv(struct kvm *kvm, u16 *rc, u16 *rrc) return r; } +/* + * Here we provide user space with a direct interface to query UV + * related data like UV maxima and available features as well as + * feature specific data. + * + * To facilitate future extension of the data structures we'll try to + * write data up to the maximum requested length. + */ +static ssize_t kvm_s390_handle_pv_info(struct kvm_s390_pv_info *info) +{ + ssize_t len_min; + + switch (info->header.id) { + case KVM_PV_INFO_VM: { + len_min = sizeof(info->header) + sizeof(info->vm); + + if (info->header.len_max < len_min) + return -EINVAL; + + memcpy(info->vm.inst_calls_list, + uv_info.inst_calls_list, + sizeof(uv_info.inst_calls_list)); + + /* It's max cpuid not max cpus, so it's off by one */ + info->vm.max_cpus = uv_info.max_guest_cpu_id + 1; + info->vm.max_guests = uv_info.max_num_sec_conf; + info->vm.max_guest_addr = uv_info.max_sec_stor_addr; + info->vm.feature_indication = uv_info.uv_feature_indications; + + return len_min; + } + default: + return -EINVAL; + } +} + static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) { int r = 0; @@ -2360,6 +2396,46 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) cmd->rc, cmd->rrc); break; } + case KVM_PV_INFO: { + struct kvm_s390_pv_info info = {}; + ssize_t data_len; + + /* + * No need to check the VM protection here. + * + * Maybe user space wants to query some of the data + * when the VM is still unprotected. If we see the + * need to fence a new data command we can still + * return an error in the info handler. + */ + + r = -EFAULT; + if (copy_from_user(&info, argp, sizeof(info.header))) + break; + + r = -EINVAL; + if (info.header.len_max < sizeof(info.header)) + break; + + data_len = kvm_s390_handle_pv_info(&info); + if (data_len < 0) { + r = data_len; + break; + } + /* + * If a data command struct is extended (multiple + * times) this can be used to determine how much of it + * is valid. + */ + info.header.len_written = data_len; + + r = -EFAULT; + if (copy_to_user(argp, &info, data_len)) + break; + + r = 0; + break; + } default: r = -ENOTTY; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 5088bd9f1922..5a5f66026dd3 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1660,6 +1660,30 @@ struct kvm_s390_pv_unp { __u64 tweak; }; +enum pv_cmd_info_id { + KVM_PV_INFO_VM, +}; + +struct kvm_s390_pv_info_vm { + __u64 inst_calls_list[4]; + __u64 max_cpus; + __u64 max_guests; + __u64 max_guest_addr; + __u64 feature_indication; +}; + +struct kvm_s390_pv_info_header { + __u32 id; + __u32 len_max; + __u32 len_written; + __u32 reserved; +}; + +struct kvm_s390_pv_info { + struct kvm_s390_pv_info_header header; + struct kvm_s390_pv_info_vm vm; +}; + enum pv_cmd_id { KVM_PV_ENABLE, KVM_PV_DISABLE, @@ -1668,6 +1692,7 @@ enum pv_cmd_id { KVM_PV_VERIFY, KVM_PV_PREP_RESET, KVM_PV_UNSHARE_ALL, + KVM_PV_INFO, }; struct kvm_pv_cmd { -- cgit v1.2.3 From fe9a93e07ba4f29def2f8a4318b63e0c70a5c6c2 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:23 +0000 Subject: KVM: s390: pv: Add query dump information The dump API requires userspace to provide buffers into which we will store data. The dump information added in this patch tells userspace how big those buffers need to be. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Reviewed-by: Steffen Eiden Link: https://lore.kernel.org/r/20220517163629.3443-6-frankja@linux.ibm.com Message-Id: <20220517163629.3443-6-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 11 +++++++++++ include/uapi/linux/kvm.h | 12 +++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 5859f243d287..de54f14e081e 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2255,6 +2255,17 @@ static ssize_t kvm_s390_handle_pv_info(struct kvm_s390_pv_info *info) return len_min; } + case KVM_PV_INFO_DUMP: { + len_min = sizeof(info->header) + sizeof(info->dump); + + if (info->header.len_max < len_min) + return -EINVAL; + + info->dump.dump_cpu_buffer_len = uv_info.guest_cpu_stor_len; + info->dump.dump_config_mem_buffer_per_1m = uv_info.conf_dump_storage_state_len; + info->dump.dump_config_finalize_len = uv_info.conf_dump_finalize_len; + return len_min; + } default: return -EINVAL; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 5a5f66026dd3..065a05ec06b6 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1662,6 +1662,13 @@ struct kvm_s390_pv_unp { enum pv_cmd_info_id { KVM_PV_INFO_VM, + KVM_PV_INFO_DUMP, +}; + +struct kvm_s390_pv_info_dump { + __u64 dump_cpu_buffer_len; + __u64 dump_config_mem_buffer_per_1m; + __u64 dump_config_finalize_len; }; struct kvm_s390_pv_info_vm { @@ -1681,7 +1688,10 @@ struct kvm_s390_pv_info_header { struct kvm_s390_pv_info { struct kvm_s390_pv_info_header header; - struct kvm_s390_pv_info_vm vm; + union { + struct kvm_s390_pv_info_dump dump; + struct kvm_s390_pv_info_vm vm; + }; }; enum pv_cmd_id { -- cgit v1.2.3 From 0460eb35b443f73f8a8e3be1ea87bd690a852e20 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:24 +0000 Subject: KVM: s390: Add configuration dump functionality Sometimes dumping inside of a VM fails, is unavailable or doesn't yield the required data. For these occasions we dump the VM from the outside, writing memory and cpu data to a file. Up to now PV guests only supported dumping from the inside of the guest through dumpers like KDUMP. A PV guest can be dumped from the hypervisor but the data will be stale and / or encrypted. To get the actual state of the PV VM we need the help of the Ultravisor who safeguards the VM state. New UV calls have been added to initialize the dump, dump storage state data, dump cpu data and complete the dump process. We expose these calls in this patch via a new UV ioctl command. The sensitive parts of the dump data are encrypted, the dump key is derived from the Customer Communication Key (CCK). This ensures that only the owner of the VM who has the CCK can decrypt the dump data. The memory is dumped / read via a normal export call and a re-import after the dump initialization is not needed (no re-encryption with a dump key). Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-7-frankja@linux.ibm.com Message-Id: <20220517163629.3443-7-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 1 + arch/s390/kvm/kvm-s390.c | 93 ++++++++++++++++++++ arch/s390/kvm/kvm-s390.h | 4 + arch/s390/kvm/pv.c | 182 +++++++++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 15 ++++ 5 files changed, 295 insertions(+) (limited to 'include') diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 766028d54a3e..a0fbe4820e0a 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -923,6 +923,7 @@ struct kvm_s390_pv { u64 guest_len; unsigned long stor_base; void *stor_var; + bool dumping; }; struct kvm_arch{ diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index de54f14e081e..1d00aead6bc5 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2271,6 +2271,68 @@ static ssize_t kvm_s390_handle_pv_info(struct kvm_s390_pv_info *info) } } +static int kvm_s390_pv_dmp(struct kvm *kvm, struct kvm_pv_cmd *cmd, + struct kvm_s390_pv_dmp dmp) +{ + int r = -EINVAL; + void __user *result_buff = (void __user *)dmp.buff_addr; + + switch (dmp.subcmd) { + case KVM_PV_DUMP_INIT: { + if (kvm->arch.pv.dumping) + break; + + /* + * Block SIE entry as concurrent dump UVCs could lead + * to validities. + */ + kvm_s390_vcpu_block_all(kvm); + + r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), + UVC_CMD_DUMP_INIT, &cmd->rc, &cmd->rrc); + KVM_UV_EVENT(kvm, 3, "PROTVIRT DUMP INIT: rc %x rrc %x", + cmd->rc, cmd->rrc); + if (!r) { + kvm->arch.pv.dumping = true; + } else { + kvm_s390_vcpu_unblock_all(kvm); + r = -EINVAL; + } + break; + } + case KVM_PV_DUMP_CONFIG_STOR_STATE: { + if (!kvm->arch.pv.dumping) + break; + + /* + * gaddr is an output parameter since we might stop + * early. As dmp will be copied back in our caller, we + * don't need to do it ourselves. + */ + r = kvm_s390_pv_dump_stor_state(kvm, result_buff, &dmp.gaddr, dmp.buff_len, + &cmd->rc, &cmd->rrc); + break; + } + case KVM_PV_DUMP_COMPLETE: { + if (!kvm->arch.pv.dumping) + break; + + r = -EINVAL; + if (dmp.buff_len < uv_info.conf_dump_finalize_len) + break; + + r = kvm_s390_pv_dump_complete(kvm, result_buff, + &cmd->rc, &cmd->rrc); + break; + } + default: + r = -ENOTTY; + break; + } + + return r; +} + static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) { int r = 0; @@ -2447,6 +2509,28 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) r = 0; break; } + case KVM_PV_DUMP: { + struct kvm_s390_pv_dmp dmp; + + r = -EINVAL; + if (!kvm_s390_pv_is_protected(kvm)) + break; + + r = -EFAULT; + if (copy_from_user(&dmp, argp, sizeof(dmp))) + break; + + r = kvm_s390_pv_dmp(kvm, cmd, dmp); + if (r) + break; + + if (copy_to_user(argp, &dmp, sizeof(dmp))) { + r = -EFAULT; + break; + } + + break; + } default: r = -ENOTTY; } @@ -4564,6 +4648,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) struct kvm_run *kvm_run = vcpu->run; int rc; + /* + * Running a VM while dumping always has the potential to + * produce inconsistent dump data. But for PV vcpus a SIE + * entry while dumping could also lead to a fatal validity + * intercept which we absolutely want to avoid. + */ + if (vcpu->kvm->arch.pv.dumping) + return -EINVAL; + if (kvm_run->immediate_exit) return -EINTR; diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 497d52a83c78..2c11eb5ba3ef 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -250,6 +250,10 @@ int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, u16 *rc, int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size, unsigned long tweak, u16 *rc, u16 *rrc); int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state); +int kvm_s390_pv_dump_stor_state(struct kvm *kvm, void __user *buff_user, + u64 *gaddr, u64 buff_user_len, u16 *rc, u16 *rrc); +int kvm_s390_pv_dump_complete(struct kvm *kvm, void __user *buff_user, + u16 *rc, u16 *rrc); static inline u64 kvm_s390_pv_get_handle(struct kvm *kvm) { diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index cc7c9599f43e..e9912113879c 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -7,6 +7,7 @@ */ #include #include +#include #include #include #include @@ -298,3 +299,184 @@ int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state) return -EINVAL; return 0; } + +/* Size of the cache for the storage state dump data. 1MB for now */ +#define DUMP_BUFF_LEN HPAGE_SIZE + +/** + * kvm_s390_pv_dump_stor_state + * + * @kvm: pointer to the guest's KVM struct + * @buff_user: Userspace pointer where we will write the results to + * @gaddr: Starting absolute guest address for which the storage state + * is requested. + * @buff_user_len: Length of the buff_user buffer + * @rc: Pointer to where the uvcb return code is stored + * @rrc: Pointer to where the uvcb return reason code is stored + * + * Stores buff_len bytes of tweak component values to buff_user + * starting with the 1MB block specified by the absolute guest address + * (gaddr). The gaddr pointer will be updated with the last address + * for which data was written when returning to userspace. buff_user + * might be written to even if an error rc is returned. For instance + * if we encounter a fault after writing the first page of data. + * + * Context: kvm->lock needs to be held + * + * Return: + * 0 on success + * -ENOMEM if allocating the cache fails + * -EINVAL if gaddr is not aligned to 1MB + * -EINVAL if buff_user_len is not aligned to uv_info.conf_dump_storage_state_len + * -EINVAL if the UV call fails, rc and rrc will be set in this case + * -EFAULT if copying the result to buff_user failed + */ +int kvm_s390_pv_dump_stor_state(struct kvm *kvm, void __user *buff_user, + u64 *gaddr, u64 buff_user_len, u16 *rc, u16 *rrc) +{ + struct uv_cb_dump_stor_state uvcb = { + .header.cmd = UVC_CMD_DUMP_CONF_STOR_STATE, + .header.len = sizeof(uvcb), + .config_handle = kvm->arch.pv.handle, + .gaddr = *gaddr, + .dump_area_origin = 0, + }; + const u64 increment_len = uv_info.conf_dump_storage_state_len; + size_t buff_kvm_size; + size_t size_done = 0; + u8 *buff_kvm = NULL; + int cc, ret; + + ret = -EINVAL; + /* UV call processes 1MB guest storage chunks at a time */ + if (!IS_ALIGNED(*gaddr, HPAGE_SIZE)) + goto out; + + /* + * We provide the storage state for 1MB chunks of guest + * storage. The buffer will need to be aligned to + * conf_dump_storage_state_len so we don't end on a partial + * chunk. + */ + if (!buff_user_len || + !IS_ALIGNED(buff_user_len, increment_len)) + goto out; + + /* + * Allocate a buffer from which we will later copy to the user + * process. We don't want userspace to dictate our buffer size + * so we limit it to DUMP_BUFF_LEN. + */ + ret = -ENOMEM; + buff_kvm_size = min_t(u64, buff_user_len, DUMP_BUFF_LEN); + buff_kvm = vzalloc(buff_kvm_size); + if (!buff_kvm) + goto out; + + ret = 0; + uvcb.dump_area_origin = (u64)buff_kvm; + /* We will loop until the user buffer is filled or an error occurs */ + do { + /* Get 1MB worth of guest storage state data */ + cc = uv_call_sched(0, (u64)&uvcb); + + /* All or nothing */ + if (cc) { + ret = -EINVAL; + break; + } + + size_done += increment_len; + uvcb.dump_area_origin += increment_len; + buff_user_len -= increment_len; + uvcb.gaddr += HPAGE_SIZE; + + /* KVM Buffer full, time to copy to the process */ + if (!buff_user_len || size_done == DUMP_BUFF_LEN) { + if (copy_to_user(buff_user, buff_kvm, size_done)) { + ret = -EFAULT; + break; + } + + buff_user += size_done; + size_done = 0; + uvcb.dump_area_origin = (u64)buff_kvm; + } + } while (buff_user_len); + + /* Report back where we ended dumping */ + *gaddr = uvcb.gaddr; + + /* Lets only log errors, we don't want to spam */ +out: + if (ret) + KVM_UV_EVENT(kvm, 3, + "PROTVIRT DUMP STORAGE STATE: addr %llx ret %d, uvcb rc %x rrc %x", + uvcb.gaddr, ret, uvcb.header.rc, uvcb.header.rrc); + *rc = uvcb.header.rc; + *rrc = uvcb.header.rrc; + vfree(buff_kvm); + + return ret; +} + +/** + * kvm_s390_pv_dump_complete + * + * @kvm: pointer to the guest's KVM struct + * @buff_user: Userspace pointer where we will write the results to + * @rc: Pointer to where the uvcb return code is stored + * @rrc: Pointer to where the uvcb return reason code is stored + * + * Completes the dumping operation and writes the completion data to + * user space. + * + * Context: kvm->lock needs to be held + * + * Return: + * 0 on success + * -ENOMEM if allocating the completion buffer fails + * -EINVAL if the UV call fails, rc and rrc will be set in this case + * -EFAULT if copying the result to buff_user failed + */ +int kvm_s390_pv_dump_complete(struct kvm *kvm, void __user *buff_user, + u16 *rc, u16 *rrc) +{ + struct uv_cb_dump_complete complete = { + .header.len = sizeof(complete), + .header.cmd = UVC_CMD_DUMP_COMPLETE, + .config_handle = kvm_s390_pv_get_handle(kvm), + }; + u64 *compl_data; + int ret; + + /* Allocate dump area */ + compl_data = vzalloc(uv_info.conf_dump_finalize_len); + if (!compl_data) + return -ENOMEM; + complete.dump_area_origin = (u64)compl_data; + + ret = uv_call_sched(0, (u64)&complete); + *rc = complete.header.rc; + *rrc = complete.header.rrc; + KVM_UV_EVENT(kvm, 3, "PROTVIRT DUMP COMPLETE: rc %x rrc %x", + complete.header.rc, complete.header.rrc); + + if (!ret) { + /* + * kvm_s390_pv_dealloc_vm() will also (mem)set + * this to false on a reboot or other destroy + * operation for this vm. + */ + kvm->arch.pv.dumping = false; + kvm_s390_vcpu_unblock_all(kvm); + ret = copy_to_user(buff_user, compl_data, uv_info.conf_dump_finalize_len); + if (ret) + ret = -EFAULT; + } + vfree(compl_data); + /* If the UVC returned an error, translate it to -EINVAL */ + if (ret > 0) + ret = -EINVAL; + return ret; +} diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 065a05ec06b6..673be2061c6c 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1660,6 +1660,20 @@ struct kvm_s390_pv_unp { __u64 tweak; }; +enum pv_cmd_dmp_id { + KVM_PV_DUMP_INIT, + KVM_PV_DUMP_CONFIG_STOR_STATE, + KVM_PV_DUMP_COMPLETE, +}; + +struct kvm_s390_pv_dmp { + __u64 subcmd; + __u64 buff_addr; + __u64 buff_len; + __u64 gaddr; /* For dump storage state */ + __u64 reserved[4]; +}; + enum pv_cmd_info_id { KVM_PV_INFO_VM, KVM_PV_INFO_DUMP, @@ -1703,6 +1717,7 @@ enum pv_cmd_id { KVM_PV_PREP_RESET, KVM_PV_UNSHARE_ALL, KVM_PV_INFO, + KVM_PV_DUMP, }; struct kvm_pv_cmd { -- cgit v1.2.3 From 8aba09588d2af37c6cc1a781b87d1d91ebf389ae Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:25 +0000 Subject: KVM: s390: Add CPU dump functionality The previous patch introduced the per-VM dump functions now let's focus on dumping the VCPU state via the newly introduced KVM_S390_PV_CPU_COMMAND ioctl which mirrors the VM UV ioctl and can be extended with new commands later. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-8-frankja@linux.ibm.com Message-Id: <20220517163629.3443-8-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ arch/s390/kvm/kvm-s390.h | 1 + arch/s390/kvm/pv.c | 16 +++++++++++ include/uapi/linux/kvm.h | 4 +++ 4 files changed, 90 insertions(+) (limited to 'include') diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 1d00aead6bc5..37be2a33edb5 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -5096,6 +5096,48 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, return -ENOIOCTLCMD; } +static int kvm_s390_handle_pv_vcpu_dump(struct kvm_vcpu *vcpu, + struct kvm_pv_cmd *cmd) +{ + struct kvm_s390_pv_dmp dmp; + void *data; + int ret; + + /* Dump initialization is a prerequisite */ + if (!vcpu->kvm->arch.pv.dumping) + return -EINVAL; + + if (copy_from_user(&dmp, (__u8 __user *)cmd->data, sizeof(dmp))) + return -EFAULT; + + /* We only handle this subcmd right now */ + if (dmp.subcmd != KVM_PV_DUMP_CPU) + return -EINVAL; + + /* CPU dump length is the same as create cpu storage donation. */ + if (dmp.buff_len != uv_info.guest_cpu_stor_len) + return -EINVAL; + + data = kvzalloc(uv_info.guest_cpu_stor_len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = kvm_s390_pv_dump_cpu(vcpu, data, &cmd->rc, &cmd->rrc); + + VCPU_EVENT(vcpu, 3, "PROTVIRT DUMP CPU %d rc %x rrc %x", + vcpu->vcpu_id, cmd->rc, cmd->rrc); + + if (ret) + ret = -EINVAL; + + /* On success copy over the dump data */ + if (!ret && copy_to_user((__u8 __user *)dmp.buff_addr, data, uv_info.guest_cpu_stor_len)) + ret = -EFAULT; + + kvfree(data); + return ret; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -5260,6 +5302,33 @@ long kvm_arch_vcpu_ioctl(struct file *filp, irq_state.len); break; } + case KVM_S390_PV_CPU_COMMAND: { + struct kvm_pv_cmd cmd; + + r = -EINVAL; + if (!is_prot_virt_host()) + break; + + r = -EFAULT; + if (copy_from_user(&cmd, argp, sizeof(cmd))) + break; + + r = -EINVAL; + if (cmd.flags) + break; + + /* We only handle this cmd right now */ + if (cmd.cmd != KVM_PV_DUMP) + break; + + r = kvm_s390_handle_pv_vcpu_dump(vcpu, &cmd); + + /* Always copy over UV rc / rrc data */ + if (copy_to_user((__u8 __user *)argp, &cmd.rc, + sizeof(cmd.rc) + sizeof(cmd.rrc))) + r = -EFAULT; + break; + } default: r = -ENOTTY; } diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 2c11eb5ba3ef..dd01d989816f 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -250,6 +250,7 @@ int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, u16 *rc, int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size, unsigned long tweak, u16 *rc, u16 *rrc); int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state); +int kvm_s390_pv_dump_cpu(struct kvm_vcpu *vcpu, void *buff, u16 *rc, u16 *rrc); int kvm_s390_pv_dump_stor_state(struct kvm *kvm, void __user *buff_user, u64 *gaddr, u64 buff_user_len, u16 *rc, u16 *rrc); int kvm_s390_pv_dump_complete(struct kvm *kvm, void __user *buff_user, diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index e9912113879c..b4a499b10b67 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -300,6 +300,22 @@ int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state) return 0; } +int kvm_s390_pv_dump_cpu(struct kvm_vcpu *vcpu, void *buff, u16 *rc, u16 *rrc) +{ + struct uv_cb_dump_cpu uvcb = { + .header.cmd = UVC_CMD_DUMP_CPU, + .header.len = sizeof(uvcb), + .cpu_handle = vcpu->arch.pv.handle, + .dump_area_origin = (u64)buff, + }; + int cc; + + cc = uv_call_sched(0, (u64)&uvcb); + *rc = uvcb.header.rc; + *rrc = uvcb.header.rrc; + return cc; +} + /* Size of the cache for the storage state dump data. 1MB for now */ #define DUMP_BUFF_LEN HPAGE_SIZE diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 673be2061c6c..af5d254f8061 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1664,6 +1664,7 @@ enum pv_cmd_dmp_id { KVM_PV_DUMP_INIT, KVM_PV_DUMP_CONFIG_STOR_STATE, KVM_PV_DUMP_COMPLETE, + KVM_PV_DUMP_CPU, }; struct kvm_s390_pv_dmp { @@ -2168,4 +2169,7 @@ struct kvm_stats_desc { /* Available with KVM_CAP_XSAVE2 */ #define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) +/* Available with KVM_CAP_S390_PROTECTED_DUMP */ +#define KVM_S390_PV_CPU_COMMAND _IOWR(KVMIO, 0xd0, struct kvm_pv_cmd) + #endif /* __LINUX_KVM_H */ -- cgit v1.2.3 From e9bf3acb23f0a6e18438c35944d6cb618d16cf05 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:26 +0000 Subject: KVM: s390: Add KVM_CAP_S390_PROTECTED_DUMP The capability indicates dump support for protected VMs. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-9-frankja@linux.ibm.com Message-Id: <20220517163629.3443-9-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 20 ++++++++++++++++++++ include/uapi/linux/kvm.h | 1 + 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 37be2a33edb5..d1a32eb3cf5d 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -606,6 +606,26 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_PROTECTED: r = is_prot_virt_host(); break; + case KVM_CAP_S390_PROTECTED_DUMP: { + u64 pv_cmds_dump[] = { + BIT_UVC_CMD_DUMP_INIT, + BIT_UVC_CMD_DUMP_CONFIG_STOR_STATE, + BIT_UVC_CMD_DUMP_CPU, + BIT_UVC_CMD_DUMP_COMPLETE, + }; + int i; + + r = is_prot_virt_host(); + + for (i = 0; i < ARRAY_SIZE(pv_cmds_dump); i++) { + if (!test_bit_inv(pv_cmds_dump[i], + (unsigned long *)&uv_info.inst_calls_list)) { + r = 0; + break; + } + } + break; + } default: r = 0; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index af5d254f8061..c4a32910b88a 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1157,6 +1157,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_TSC_CONTROL 214 #define KVM_CAP_SYSTEM_EVENT_DATA 215 #define KVM_CAP_ARM_SYSTEM_SUSPEND 216 +#define KVM_CAP_S390_PROTECTED_DUMP 217 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.2.3 From 3800b1710946f7db3cb3a29cb2e218cf5df999d0 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 10 May 2022 12:29:42 -0700 Subject: drm/dp: Add callbacks to make using DP AUX bus properly easier As talked about in this patch in the kerneldoc of of_dp_aux_populate_ep_device() and also in the past in commit a1e3667a9835 ("drm/bridge: ti-sn65dsi86: Promote the AUX channel to its own sub-dev"), it can be difficult for eDP controller drivers to know when the panel has finished probing when they're using of_dp_aux_populate_ep_devices(). The ti-sn65dsi86 driver managed to solve this because it was already broken up into a bunch of sub-drivers. That means we could solve the problem there by adding a new sub-driver to get the panel. We could use the traditional -EPROBE_DEFER retry mechansim to handle the case where the panel hadn't probed yet. In parade-ps8640 we didn't really solve this. The code just expects the panel to be ready right away. While reviewing the code originally I had managed to convince myself it was fine to just expect the panel right away, but additional testing has shown that not to be the case. We could fix parade-ps8640 like we did ti-sn65dsi86 but it's pretty cumbersome (since we're not already broken into multiple drivers) and requires a bunch of boilerplate code. After discussion [1] it seems like the best solution for most people is: - Accept that there's always at most one device that will probe as a result of the DP AUX bus (it may have sub-devices, but there will be one device _directly_ probed). - When that device finishes probing, we can just have a call back. This patch implements that idea. We'll now take a callback as an argument to the populate function. To make this easier to land in pieces, we'll make wrappers for the old functions. The functions with the new name (which make it clear that we only have one child) will take the callback and the functions with the old name will temporarily wrap. [1] https://lore.kernel.org/r/CAD=FV=Ur3afHhsXe7a3baWEnD=MFKFeKRbhFU+bt3P67G0MVzQ@mail.gmail.com Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20220510122726.v3.2.I4182ae27e00792842cb86f1433990a0ef9c0a073@changeid --- drivers/gpu/drm/display/drm_dp_aux_bus.c | 209 ++++++++++++++++++++----------- include/drm/display/drm_dp_aux_bus.h | 34 ++++- 2 files changed, 168 insertions(+), 75 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/display/drm_dp_aux_bus.c b/drivers/gpu/drm/display/drm_dp_aux_bus.c index 552f949cff59..f5741b45ca07 100644 --- a/drivers/gpu/drm/display/drm_dp_aux_bus.c +++ b/drivers/gpu/drm/display/drm_dp_aux_bus.c @@ -3,10 +3,10 @@ * Copyright 2021 Google Inc. * * The DP AUX bus is used for devices that are connected over a DisplayPort - * AUX bus. The devices on the far side of the bus are referred to as - * endpoints in this code. + * AUX bus. The device on the far side of the bus is referred to as an + * endpoint in this code. * - * Commonly there is only one device connected to the DP AUX bus: a panel. + * There is only one device connected to the DP AUX bus: an eDP panel. * Though historically panels (even DP panels) have been modeled as simple * platform devices, putting them under the DP AUX bus allows the panel driver * to perform transactions on that bus. @@ -22,6 +22,11 @@ #include #include +struct dp_aux_ep_device_with_data { + struct dp_aux_ep_device aux_ep; + int (*done_probing)(struct drm_dp_aux *aux); +}; + /** * dp_aux_ep_match() - The match function for the dp_aux_bus. * @dev: The device to match. @@ -48,6 +53,8 @@ static int dp_aux_ep_probe(struct device *dev) { struct dp_aux_ep_driver *aux_ep_drv = to_dp_aux_ep_drv(dev->driver); struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(dev); + struct dp_aux_ep_device_with_data *aux_ep_with_data = + container_of(aux_ep, struct dp_aux_ep_device_with_data, aux_ep); int ret; ret = dev_pm_domain_attach(dev, true); @@ -56,7 +63,32 @@ static int dp_aux_ep_probe(struct device *dev) ret = aux_ep_drv->probe(aux_ep); if (ret) - dev_pm_domain_detach(dev, true); + goto err_attached; + + if (aux_ep_with_data->done_probing) { + ret = aux_ep_with_data->done_probing(aux_ep->aux); + if (ret) { + /* + * The done_probing() callback should not return + * -EPROBE_DEFER to us. If it does, we treat it as an + * error. Passing it on as-is would cause the _panel_ + * to defer. + */ + if (ret == -EPROBE_DEFER) { + dev_err(dev, + "DP AUX done_probing() can't defer\n"); + ret = -EINVAL; + } + goto err_probed; + } + } + + return 0; +err_probed: + if (aux_ep_drv->remove) + aux_ep_drv->remove(aux_ep); +err_attached: + dev_pm_domain_detach(dev, true); return ret; } @@ -122,7 +154,11 @@ ATTRIBUTE_GROUPS(dp_aux_ep_dev); */ static void dp_aux_ep_dev_release(struct device *dev) { - kfree(to_dp_aux_ep_dev(dev)); + struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(dev); + struct dp_aux_ep_device_with_data *aux_ep_with_data = + container_of(aux_ep, struct dp_aux_ep_device_with_data, aux_ep); + + kfree(aux_ep_with_data); } static struct device_type dp_aux_device_type_type = { @@ -136,12 +172,14 @@ static struct device_type dp_aux_device_type_type = { * @dev: The device to destroy. * @data: Not used * - * This is just used as a callback by of_dp_aux_depopulate_ep_devices() and + * This is just used as a callback by of_dp_aux_depopulate_bus() and * is called for _all_ of the child devices of the device providing the AUX bus. * We'll only act on those that are of type "dp_aux_bus_type". * - * This function is effectively an inverse of what's in the loop - * in of_dp_aux_populate_ep_devices(). + * This function is effectively an inverse of what's in + * of_dp_aux_populate_bus(). NOTE: since we only populate one child + * then it's expected that only one device will match all the "if" tests in + * this function and get to the device_unregister(). * * Return: 0 if no error or negative error code. */ @@ -164,123 +202,150 @@ static int of_dp_aux_ep_destroy(struct device *dev, void *data) } /** - * of_dp_aux_depopulate_ep_devices() - Undo of_dp_aux_populate_ep_devices - * @aux: The AUX channel whose devices we want to depopulate + * of_dp_aux_depopulate_bus() - Undo of_dp_aux_populate_bus + * @aux: The AUX channel whose device we want to depopulate * - * This will destroy all devices that were created - * by of_dp_aux_populate_ep_devices(). + * This will destroy the device that was created + * by of_dp_aux_populate_bus(). */ -void of_dp_aux_depopulate_ep_devices(struct drm_dp_aux *aux) +void of_dp_aux_depopulate_bus(struct drm_dp_aux *aux) { device_for_each_child_reverse(aux->dev, NULL, of_dp_aux_ep_destroy); } -EXPORT_SYMBOL_GPL(of_dp_aux_depopulate_ep_devices); +EXPORT_SYMBOL_GPL(of_dp_aux_depopulate_bus); /** - * of_dp_aux_populate_ep_devices() - Populate the endpoint devices on the DP AUX - * @aux: The AUX channel whose devices we want to populate. It is required that + * of_dp_aux_populate_bus() - Populate the endpoint device on the DP AUX + * @aux: The AUX channel whose device we want to populate. It is required that * drm_dp_aux_init() has already been called for this AUX channel. + * @done_probing: Callback functions to call after EP device finishes probing. + * Will not be called if there are no EP devices and this + * function will return -ENODEV. * - * This will populate all the devices under the "aux-bus" node of the device - * providing the AUX channel (AKA aux->dev). + * This will populate the device (expected to be an eDP panel) under the + * "aux-bus" node of the device providing the AUX channel (AKA aux->dev). * * When this function finishes, it is _possible_ (but not guaranteed) that - * our sub-devices will have finished probing. It should be noted that if our - * sub-devices return -EPROBE_DEFER that we will not return any error codes - * ourselves but our sub-devices will _not_ have actually probed successfully - * yet. There may be other cases (maybe added in the future?) where sub-devices - * won't have been probed yet when this function returns, so it's best not to - * rely on that. + * our sub-device will have finished probing. It should be noted that if our + * sub-device returns -EPROBE_DEFER or is probing asynchronously for some + * reason that we will not return any error codes ourselves but our + * sub-device will _not_ have actually probed successfully yet. + * + * In many cases it's important for the caller of this function to be notified + * when our sub device finishes probing. Our sub device is expected to be an + * eDP panel and the caller is expected to be an eDP controller. The eDP + * controller needs to be able to get a reference to the panel when it finishes + * probing. For this reason the caller can pass in a function pointer that + * will be called when our sub-device finishes probing. * * If this function succeeds you should later make sure you call - * of_dp_aux_depopulate_ep_devices() to undo it, or just use the devm version + * of_dp_aux_depopulate_bus() to undo it, or just use the devm version * of this function. * - * Return: 0 if no error or negative error code. + * Return: 0 if no error or negative error code; returns -ENODEV if there are + * no children. The done_probing() function won't be called in that + * case. */ -int of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) +int of_dp_aux_populate_bus(struct drm_dp_aux *aux, + int (*done_probing)(struct drm_dp_aux *aux)) { - struct device_node *bus, *np; + struct device_node *bus = NULL, *np = NULL; struct dp_aux_ep_device *aux_ep; + struct dp_aux_ep_device_with_data *aux_ep_with_data; int ret; /* drm_dp_aux_init() should have been called already; warn if not */ WARN_ON_ONCE(!aux->ddc.algo); if (!aux->dev->of_node) - return 0; - + return -ENODEV; bus = of_get_child_by_name(aux->dev->of_node, "aux-bus"); if (!bus) - return 0; + return -ENODEV; - for_each_available_child_of_node(bus, np) { - if (of_node_test_and_set_flag(np, OF_POPULATED)) - continue; + np = of_get_next_available_child(bus, NULL); + of_node_put(bus); + if (!np) + return -ENODEV; - aux_ep = kzalloc(sizeof(*aux_ep), GFP_KERNEL); - if (!aux_ep) - continue; - aux_ep->aux = aux; + if (of_node_test_and_set_flag(np, OF_POPULATED)) { + dev_err(aux->dev, "DP AUX EP device already populated\n"); + ret = -EINVAL; + goto err_did_get_np; + } - aux_ep->dev.parent = aux->dev; - aux_ep->dev.bus = &dp_aux_bus_type; - aux_ep->dev.type = &dp_aux_device_type_type; - aux_ep->dev.of_node = of_node_get(np); - dev_set_name(&aux_ep->dev, "aux-%s", dev_name(aux->dev)); + aux_ep_with_data = kzalloc(sizeof(*aux_ep_with_data), GFP_KERNEL); + if (!aux_ep_with_data) { + ret = -ENOMEM; + goto err_did_set_populated; + } - ret = device_register(&aux_ep->dev); - if (ret) { - dev_err(aux->dev, "Failed to create AUX EP for %pOF: %d\n", np, ret); - of_node_clear_flag(np, OF_POPULATED); - of_node_put(np); + aux_ep_with_data->done_probing = done_probing; - /* - * As per docs of device_register(), call this instead - * of kfree() directly for error cases. - */ - put_device(&aux_ep->dev); + aux_ep = &aux_ep_with_data->aux_ep; + aux_ep->aux = aux; + aux_ep->dev.parent = aux->dev; + aux_ep->dev.bus = &dp_aux_bus_type; + aux_ep->dev.type = &dp_aux_device_type_type; + aux_ep->dev.of_node = of_node_get(np); + dev_set_name(&aux_ep->dev, "aux-%s", dev_name(aux->dev)); - /* - * Following in the footsteps of of_i2c_register_devices(), - * we won't fail the whole function here--we'll just - * continue registering any other devices we find. - */ - } - } + ret = device_register(&aux_ep->dev); + if (ret) { + dev_err(aux->dev, "Failed to create AUX EP for %pOF: %d\n", np, ret); - of_node_put(bus); + /* + * As per docs of device_register(), call this instead + * of kfree() directly for error cases. + */ + put_device(&aux_ep->dev); + + goto err_did_set_populated; + } return 0; + +err_did_set_populated: + of_node_clear_flag(np, OF_POPULATED); + +err_did_get_np: + of_node_put(np); + + return ret; } -EXPORT_SYMBOL_GPL(of_dp_aux_populate_ep_devices); +EXPORT_SYMBOL_GPL(of_dp_aux_populate_bus); -static void of_dp_aux_depopulate_ep_devices_void(void *data) +static void of_dp_aux_depopulate_bus_void(void *data) { - of_dp_aux_depopulate_ep_devices(data); + of_dp_aux_depopulate_bus(data); } /** - * devm_of_dp_aux_populate_ep_devices() - devm wrapper for of_dp_aux_populate_ep_devices() - * @aux: The AUX channel whose devices we want to populate + * devm_of_dp_aux_populate_bus() - devm wrapper for of_dp_aux_populate_bus() + * @aux: The AUX channel whose device we want to populate + * @done_probing: Callback functions to call after EP device finishes probing. + * Will not be called if there are no EP devices and this + * function will return -ENODEV. * * Handles freeing w/ devm on the device "aux->dev". * - * Return: 0 if no error or negative error code. + * Return: 0 if no error or negative error code; returns -ENODEV if there are + * no children. The done_probing() function won't be called in that + * case. */ -int devm_of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) +int devm_of_dp_aux_populate_bus(struct drm_dp_aux *aux, + int (*done_probing)(struct drm_dp_aux *aux)) { int ret; - ret = of_dp_aux_populate_ep_devices(aux); + ret = of_dp_aux_populate_bus(aux, done_probing); if (ret) return ret; return devm_add_action_or_reset(aux->dev, - of_dp_aux_depopulate_ep_devices_void, - aux); + of_dp_aux_depopulate_bus_void, aux); } -EXPORT_SYMBOL_GPL(devm_of_dp_aux_populate_ep_devices); +EXPORT_SYMBOL_GPL(devm_of_dp_aux_populate_bus); int __dp_aux_dp_driver_register(struct dp_aux_ep_driver *drv, struct module *owner) { diff --git a/include/drm/display/drm_dp_aux_bus.h b/include/drm/display/drm_dp_aux_bus.h index 4f19b20b1dd6..8a0a486383c5 100644 --- a/include/drm/display/drm_dp_aux_bus.h +++ b/include/drm/display/drm_dp_aux_bus.h @@ -44,9 +44,37 @@ static inline struct dp_aux_ep_driver *to_dp_aux_ep_drv(struct device_driver *dr return container_of(drv, struct dp_aux_ep_driver, driver); } -int of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux); -void of_dp_aux_depopulate_ep_devices(struct drm_dp_aux *aux); -int devm_of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux); +int of_dp_aux_populate_bus(struct drm_dp_aux *aux, + int (*done_probing)(struct drm_dp_aux *aux)); +void of_dp_aux_depopulate_bus(struct drm_dp_aux *aux); +int devm_of_dp_aux_populate_bus(struct drm_dp_aux *aux, + int (*done_probing)(struct drm_dp_aux *aux)); + +/* Deprecated versions of the above functions. To be removed when no callers. */ +static inline int of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) +{ + int ret; + + ret = of_dp_aux_populate_bus(aux, NULL); + + /* New API returns -ENODEV for no child case; adapt to old assumption */ + return (ret != -ENODEV) ? ret : 0; +} + +static inline int devm_of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux) +{ + int ret; + + ret = devm_of_dp_aux_populate_bus(aux, NULL); + + /* New API returns -ENODEV for no child case; adapt to old assumption */ + return (ret != -ENODEV) ? ret : 0; +} + +static inline void of_dp_aux_depopulate_ep_devices(struct drm_dp_aux *aux) +{ + of_dp_aux_depopulate_bus(aux); +} #define dp_aux_dp_driver_register(aux_ep_drv) \ __dp_aux_dp_driver_register(aux_ep_drv, THIS_MODULE) -- cgit v1.2.3 From 50e156bd8a9d0910ac4bae5fcff00ddb798db967 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 10 May 2022 12:29:43 -0700 Subject: drm/bridge: Add devm_drm_bridge_add() This adds a devm managed version of drm_bridge_add(). Like other "devm" function listed in drm_bridge.h, this function takes an explicit "dev" to use for the lifetime management. A few notes: * In general we have a "struct device" for bridges that makes a good candidate for where the lifetime matches exactly what we want. * The "bridge->dev->dev" device appears to be the encoder device. That's not the right device to use for lifetime management. Suggested-by: Dmitry Baryshkov Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20220510122726.v3.3.Iba4b9bf6c7a1ee5ea2835ad7bd5eaf84d7688520@changeid --- drivers/gpu/drm/drm_bridge.c | 23 +++++++++++++++++++++++ include/drm/drm_bridge.h | 1 + 2 files changed, 24 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index c96847fc0ebc..e275b4ca344b 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -170,6 +170,29 @@ void drm_bridge_add(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_add); +static void drm_bridge_remove_void(void *bridge) +{ + drm_bridge_remove(bridge); +} + +/** + * devm_drm_bridge_add - devm managed version of drm_bridge_add() + * + * @dev: device to tie the bridge lifetime to + * @bridge: bridge control structure + * + * This is the managed version of drm_bridge_add() which automatically + * calls drm_bridge_remove() when @dev is unbound. + * + * Return: 0 if no error or negative error code. + */ +int devm_drm_bridge_add(struct device *dev, struct drm_bridge *bridge) +{ + drm_bridge_add(bridge); + return devm_add_action_or_reset(dev, drm_bridge_remove_void, bridge); +} +EXPORT_SYMBOL(devm_drm_bridge_add); + /** * drm_bridge_remove - remove the given bridge from the global bridge list * diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index f27b4060faa2..42aec8612f37 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -796,6 +796,7 @@ drm_priv_to_bridge(struct drm_private_obj *priv) } void drm_bridge_add(struct drm_bridge *bridge); +int devm_drm_bridge_add(struct device *dev, struct drm_bridge *bridge); void drm_bridge_remove(struct drm_bridge *bridge); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous, -- cgit v1.2.3 From d8616ee2affcff37c5d315310da557a694a3303d Mon Sep 17 00:00:00 2001 From: Wang Yufen Date: Tue, 24 May 2022 15:53:11 +0800 Subject: bpf, sockmap: Fix sk->sk_forward_alloc warn_on in sk_stream_kill_queues During TCP sockmap redirect pressure test, the following warning is triggered: WARNING: CPU: 3 PID: 2145 at net/core/stream.c:205 sk_stream_kill_queues+0xbc/0xd0 CPU: 3 PID: 2145 Comm: iperf Kdump: loaded Tainted: G W 5.10.0+ #9 Call Trace: inet_csk_destroy_sock+0x55/0x110 inet_csk_listen_stop+0xbb/0x380 tcp_close+0x41b/0x480 inet_release+0x42/0x80 __sock_release+0x3d/0xa0 sock_close+0x11/0x20 __fput+0x9d/0x240 task_work_run+0x62/0x90 exit_to_user_mode_prepare+0x110/0x120 syscall_exit_to_user_mode+0x27/0x190 entry_SYSCALL_64_after_hwframe+0x44/0xa9 The reason we observed is that: When the listener is closing, a connection may have completed the three-way handshake but not accepted, and the client has sent some packets. The child sks in accept queue release by inet_child_forget()->inet_csk_destroy_sock(), but psocks of child sks have not released. To fix, add sock_map_destroy to release psocks. Signed-off-by: Wang Yufen Signed-off-by: Daniel Borkmann Signed-off-by: Andrii Nakryiko Acked-by: Jakub Sitnicki Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20220524075311.649153-1-wangyufen@huawei.com --- include/linux/bpf.h | 1 + include/linux/skmsg.h | 1 + net/core/skmsg.c | 1 + net/core/sock_map.c | 23 +++++++++++++++++++++++ net/ipv4/tcp_bpf.c | 1 + 5 files changed, 27 insertions(+) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 2b914a56a2c5..8e6092d0ea95 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2104,6 +2104,7 @@ int sock_map_bpf_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr); void sock_map_unhash(struct sock *sk); +void sock_map_destroy(struct sock *sk); void sock_map_close(struct sock *sk, long timeout); #else static inline int bpf_prog_offload_init(struct bpf_prog *prog, diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index c5a2d6f50f25..153b6dec9b6a 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -95,6 +95,7 @@ struct sk_psock { spinlock_t link_lock; refcount_t refcnt; void (*saved_unhash)(struct sock *sk); + void (*saved_destroy)(struct sock *sk); void (*saved_close)(struct sock *sk, long timeout); void (*saved_write_space)(struct sock *sk); void (*saved_data_ready)(struct sock *sk); diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 22b983ade0e7..7e03f96e441b 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -715,6 +715,7 @@ struct sk_psock *sk_psock_init(struct sock *sk, int node) psock->eval = __SK_NONE; psock->sk_proto = prot; psock->saved_unhash = prot->unhash; + psock->saved_destroy = prot->destroy; psock->saved_close = prot->close; psock->saved_write_space = sk->sk_write_space; diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 81d4b4756a02..9f08ccfaf6da 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -1561,6 +1561,29 @@ void sock_map_unhash(struct sock *sk) } EXPORT_SYMBOL_GPL(sock_map_unhash); +void sock_map_destroy(struct sock *sk) +{ + void (*saved_destroy)(struct sock *sk); + struct sk_psock *psock; + + rcu_read_lock(); + psock = sk_psock_get(sk); + if (unlikely(!psock)) { + rcu_read_unlock(); + if (sk->sk_prot->destroy) + sk->sk_prot->destroy(sk); + return; + } + + saved_destroy = psock->saved_destroy; + sock_map_remove_links(sk, psock); + rcu_read_unlock(); + sk_psock_stop(psock, true); + sk_psock_put(sk, psock); + saved_destroy(sk); +} +EXPORT_SYMBOL_GPL(sock_map_destroy); + void sock_map_close(struct sock *sk, long timeout) { void (*saved_close)(struct sock *sk, long timeout); diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index be3947e70fec..38550bb1b90b 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -540,6 +540,7 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS], struct proto *base) { prot[TCP_BPF_BASE] = *base; + prot[TCP_BPF_BASE].destroy = sock_map_destroy; prot[TCP_BPF_BASE].close = sock_map_close; prot[TCP_BPF_BASE].recvmsg = tcp_bpf_recvmsg; prot[TCP_BPF_BASE].sock_is_readable = sk_msg_is_readable; -- cgit v1.2.3 From 543036a2de71f14f8ad566c858e5e9ff61736a86 Mon Sep 17 00:00:00 2001 From: Aurabindo Pillai Date: Mon, 21 Feb 2022 15:33:05 -0500 Subject: drm/amd: Add GFX11 modifiers support to AMDGPU (v3) GFX11 IP introduces new tiling mode. Various combinations of DCC settings are possible and the most preferred settings must be exposed for optimal use of the hardware. add_gfx11_modifiers() is based on recommendation from Marek for the preferred tiling modifier that are most efficient for the hardware. v2: microtiling fix noticed by Marek v3: keep Z tiling check Signed-off-by: Aurabindo Pillai Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 52 +++++++++++++--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 76 ++++++++++++++++++++++- include/uapi/drm/drm_fourcc.h | 2 + 3 files changed, 117 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 17c9bbe0cbc5..8ef489fad707 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -30,6 +30,9 @@ #include "atom.h" #include "amdgpu_connectors.h" #include "amdgpu_display.h" +#include "soc15_common.h" +#include "gc/gc_11_0_0_offset.h" +#include "gc/gc_11_0_0_sh_mask.h" #include #include @@ -663,6 +666,11 @@ static int convert_tiling_flags_to_modifier(struct amdgpu_framebuffer *afb) { struct amdgpu_device *adev = drm_to_adev(afb->base.dev); uint64_t modifier = 0; + int num_pipes = 0; + int num_pkrs = 0; + + num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs; + num_pipes = adev->gfx.config.gb_addr_config_fields.num_pipes; if (!afb->tiling_flags || !AMDGPU_TILING_GET(afb->tiling_flags, SWIZZLE_MODE)) { modifier = DRM_FORMAT_MOD_LINEAR; @@ -675,7 +683,7 @@ static int convert_tiling_flags_to_modifier(struct amdgpu_framebuffer *afb) int bank_xor_bits = 0; int packers = 0; int rb = 0; - int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes); + int pipes = ilog2(num_pipes); uint32_t dcc_offset = AMDGPU_TILING_GET(afb->tiling_flags, DCC_OFFSET_256B); switch (swizzle >> 2) { @@ -691,12 +699,17 @@ static int convert_tiling_flags_to_modifier(struct amdgpu_framebuffer *afb) case 6: /* 64 KiB _X */ block_size_bits = 16; break; + case 7: /* 256 KiB */ + block_size_bits = 18; + break; default: /* RESERVED or VAR */ return -EINVAL; } - if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0)) + if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(11, 0, 0)) + version = AMD_FMT_MOD_TILE_VER_GFX11; + else if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0)) version = AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS; else if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 0, 0)) version = AMD_FMT_MOD_TILE_VER_GFX10; @@ -707,19 +720,33 @@ static int convert_tiling_flags_to_modifier(struct amdgpu_framebuffer *afb) case 0: /* Z microtiling */ return -EINVAL; case 1: /* S microtiling */ - if (!has_xor) - version = AMD_FMT_MOD_TILE_VER_GFX9; + if (adev->ip_versions[GC_HWIP][0] < IP_VERSION(11, 0, 0)) { + if (!has_xor) + version = AMD_FMT_MOD_TILE_VER_GFX9; + } break; case 2: - if (!has_xor && afb->base.format->cpp[0] != 4) - version = AMD_FMT_MOD_TILE_VER_GFX9; + if (adev->ip_versions[GC_HWIP][0] < IP_VERSION(11, 0, 0)) { + if (!has_xor && afb->base.format->cpp[0] != 4) + version = AMD_FMT_MOD_TILE_VER_GFX9; + } break; case 3: break; } if (has_xor) { + if (num_pipes == num_pkrs && num_pkrs == 0) { + DRM_ERROR("invalid number of pipes and packers\n"); + return -EINVAL; + } + switch (version) { + case AMD_FMT_MOD_TILE_VER_GFX11: + pipe_xor_bits = min(block_size_bits - 8, pipes); + packers = min(block_size_bits - 8 - pipe_xor_bits, + ilog2(adev->gfx.config.gb_addr_config_fields.num_pkrs)); + break; case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: pipe_xor_bits = min(block_size_bits - 8, pipes); packers = min(block_size_bits - 8 - pipe_xor_bits, @@ -753,9 +780,10 @@ static int convert_tiling_flags_to_modifier(struct amdgpu_framebuffer *afb) u64 render_dcc_offset; /* Enable constant encode on RAVEN2 and later. */ - bool dcc_constant_encode = adev->asic_type > CHIP_RAVEN || + bool dcc_constant_encode = (adev->asic_type > CHIP_RAVEN || (adev->asic_type == CHIP_RAVEN && - adev->external_rev_id >= 0x81); + adev->external_rev_id >= 0x81)) && + adev->ip_versions[GC_HWIP][0] < IP_VERSION(11, 0, 0); int max_cblock_size = dcc_i64b ? AMD_FMT_MOD_DCC_BLOCK_64B : dcc_i128b ? AMD_FMT_MOD_DCC_BLOCK_128B : @@ -870,10 +898,11 @@ static unsigned int get_dcc_block_size(uint64_t modifier, bool rb_aligned, return max(10 + (rb_aligned ? (int)AMD_FMT_MOD_GET(RB, modifier) : 0), 12); } case AMD_FMT_MOD_TILE_VER_GFX10: - case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: { + case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: + case AMD_FMT_MOD_TILE_VER_GFX11: { int pipes_log2 = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); - if (ver == AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS && pipes_log2 > 1 && + if (ver >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS && pipes_log2 > 1 && AMD_FMT_MOD_GET(PACKERS, modifier) == pipes_log2) ++pipes_log2; @@ -966,6 +995,9 @@ static int amdgpu_display_verify_sizes(struct amdgpu_framebuffer *rfb) case DC_SW_64KB_S_X: block_size_log2 = 16; break; + case DC_SW_VAR_S_X: + block_size_log2 = 18; + break; default: drm_dbg_kms(rfb->base.dev, "Swizzle mode with unknown block size: %d\n", swizzle); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 7280db2821ef..872b7899b645 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -89,10 +89,14 @@ #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" #include "soc15_hw_ip.h" +#include "soc15_common.h" #include "vega10_ip_offset.h" #include "soc15_common.h" +#include "gc/gc_11_0_0_offset.h" +#include "gc/gc_11_0_0_sh_mask.h" + #include "modules/inc/mod_freesync.h" #include "modules/power/power_helpers.h" #include "modules/inc/mod_info_packet.h" @@ -4888,7 +4892,9 @@ fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev, unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier); - unsigned int pipes_log2 = min(4u, mod_pipe_xor_bits); + unsigned int pipes_log2; + + pipes_log2 = min(5u, mod_pipe_xor_bits); fill_gfx9_tiling_info_from_device(adev, tiling_info); @@ -5224,8 +5230,69 @@ add_gfx10_3_modifiers(const struct amdgpu_device *adev, AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9)); } +static void +add_gfx11_modifiers(struct amdgpu_device *adev, + uint64_t **mods, uint64_t *size, uint64_t *capacity) +{ + int num_pipes = 0; + int pipe_xor_bits = 0; + int num_pkrs = 0; + int pkrs = 0; + u32 gb_addr_config; + unsigned swizzle_r_x; + uint64_t modifier_r_x; + uint64_t modifier_dcc_best; + uint64_t modifier_dcc_4k; + + /* TODO: GFX11 IP HW init hasnt finish and we get zero if we read from + * adev->gfx.config.gb_addr_config_fields.num_{pkrs,pipes} */ + gb_addr_config = RREG32_SOC15(GC, 0, regGB_ADDR_CONFIG); + ASSERT(gb_addr_config != 0); + + num_pkrs = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PKRS); + pkrs = ilog2(num_pkrs); + num_pipes = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PIPES); + pipe_xor_bits = ilog2(num_pipes); + + /* R_X swizzle modes are the best for rendering and DCC requires them. */ + swizzle_r_x = num_pipes > 16 ? AMD_FMT_MOD_TILE_GFX11_256K_R_X : + AMD_FMT_MOD_TILE_GFX9_64K_R_X; + + modifier_r_x = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) | + AMD_FMT_MOD_SET(TILE, swizzle_r_x) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) | + AMD_FMT_MOD_SET(PACKERS, pkrs); + + /* DCC_CONSTANT_ENCODE is not set because it can't vary with gfx11 (it's implied to be 1). */ + modifier_dcc_best = modifier_r_x | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 0) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B); + + /* DCC settings for 4K and greater resolutions. (required by display hw) */ + modifier_dcc_4k = modifier_r_x | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) | + AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B); + + add_modifier(mods, size, capacity, modifier_dcc_best); + add_modifier(mods, size, capacity, modifier_dcc_4k); + + add_modifier(mods, size, capacity, modifier_dcc_best | AMD_FMT_MOD_SET(DCC_RETILE, 1)); + add_modifier(mods, size, capacity, modifier_dcc_4k | AMD_FMT_MOD_SET(DCC_RETILE, 1)); + + add_modifier(mods, size, capacity, modifier_r_x); + + add_modifier(mods, size, capacity, AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D)); +} + static int -get_plane_modifiers(const struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods) +get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods) { uint64_t size = 0, capacity = 128; *mods = NULL; @@ -5257,6 +5324,9 @@ get_plane_modifiers(const struct amdgpu_device *adev, unsigned int plane_type, u else add_gfx10_1_modifiers(adev, mods, &size, &capacity); break; + case AMDGPU_FAMILY_GC_11_0_0: + add_gfx11_modifiers(adev, mods, &size, &capacity); + break; } add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR); @@ -5295,7 +5365,7 @@ fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev, dcc->enable = 1; dcc->meta_pitch = afb->base.pitches[1]; dcc->independent_64b_blks = independent_64b_blks; - if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) == AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) { + if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) { if (independent_64b_blks && independent_128b_blks) dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl; else if (independent_128b_blks) diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index f1972154a594..1d717c75e171 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -1363,6 +1363,7 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) #define AMD_FMT_MOD_TILE_VER_GFX9 1 #define AMD_FMT_MOD_TILE_VER_GFX10 2 #define AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS 3 +#define AMD_FMT_MOD_TILE_VER_GFX11 4 /* * 64K_S is the same for GFX9/GFX10/GFX10_RBPLUS and hence has GFX9 as canonical @@ -1378,6 +1379,7 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) #define AMD_FMT_MOD_TILE_GFX9_64K_S_X 25 #define AMD_FMT_MOD_TILE_GFX9_64K_D_X 26 #define AMD_FMT_MOD_TILE_GFX9_64K_R_X 27 +#define AMD_FMT_MOD_TILE_GFX11_256K_R_X 31 #define AMD_FMT_MOD_DCC_BLOCK_64B 0 #define AMD_FMT_MOD_DCC_BLOCK_128B 1 -- cgit v1.2.3 From 8d5976089c97a4beeeda4de59e2fba9862946893 Mon Sep 17 00:00:00 2001 From: Xiang wangx Date: Mon, 6 Jun 2022 10:23:13 +0800 Subject: platform/chrome: cros_ec_commands: Fix syntax errors in comments Delete the redundant word 'using'. Signed-off-by: Xiang wangx Reviewed-by: Tzung-Bi Shih Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220606022313.22912-1-wangxiang@cdjrlc.com --- include/linux/platform_data/cros_ec_commands.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 8cfa8cfca77e..e59f51c41a1c 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -787,7 +787,7 @@ struct ec_host_response { * * Packets always start with a request or response header. They are followed * by data_len bytes of data. If the data_crc_present flag is set, the data - * bytes are followed by a CRC-8 of that data, using using x^8 + x^2 + x + 1 + * bytes are followed by a CRC-8 of that data, using x^8 + x^2 + x + 1 * polynomial. * * Host algorithm when sending a request q: -- cgit v1.2.3 From 95099951557c9eb2f180d6bcb9885eecaca97d24 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Mon, 23 May 2022 21:12:43 +0900 Subject: dt-bindings: soc: add samsung,boot-mode definitions Adds samsung,boot-mode.h header file which contains boot mode definitions for bootloader. As for now, there are only boot mode definitions for Exynos Auto v9 SoC. Signed-off-by: Chanho Park Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220523121244.67341-2-chanho61.park@samsung.com Signed-off-by: Krzysztof Kozlowski --- include/dt-bindings/soc/samsung,boot-mode.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 include/dt-bindings/soc/samsung,boot-mode.h (limited to 'include') diff --git a/include/dt-bindings/soc/samsung,boot-mode.h b/include/dt-bindings/soc/samsung,boot-mode.h new file mode 100644 index 000000000000..47ef1cdd3916 --- /dev/null +++ b/include/dt-bindings/soc/samsung,boot-mode.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Author: Chanho Park + * + * Device Tree bindings for Samsung Boot Mode. + */ + +#ifndef __DT_BINDINGS_SAMSUNG_BOOT_MODE_H +#define __DT_BINDINGS_SAMSUNG_BOOT_MODE_H + +/* Boot mode definitions for Exynos Auto v9 SoC */ + +#define EXYNOSAUTOV9_BOOT_FASTBOOT 0xfa +#define EXYNOSAUTOV9_BOOT_BOOTLOADER 0xfc +#define EXYNOSAUTOV9_BOOT_RECOVERY 0xff + +#endif /* __DT_BINDINGS_SAMSUNG_BOOT_MODE_H */ -- cgit v1.2.3 From 90b12a88b710cdc80c00552dfbd589228978bffe Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Wed, 11 May 2022 18:23:50 +0200 Subject: ALSA: Add snd_pcm_direction_name() helper Allow for retrieving string naming a direction of a stream without the need of substream pointer. Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220511162403.3987658-2-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- include/sound/pcm.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 6b99310b5b88..26523cfe428d 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1392,6 +1392,20 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) const char *snd_pcm_format_name(snd_pcm_format_t format); +/** + * snd_pcm_direction_name - Get a string naming the direction of a stream + * @direction: Stream's direction, one of SNDRV_PCM_STREAM_XXX + * + * Returns a string naming the direction of the stream. + */ +static inline const char *snd_pcm_direction_name(int direction) +{ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + return "Playback"; + else + return "Capture"; +} + /** * snd_pcm_stream_str - Get a string naming the direction of a stream * @substream: the pcm substream instance @@ -1400,10 +1414,7 @@ const char *snd_pcm_format_name(snd_pcm_format_t format); */ static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream) { - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return "Playback"; - else - return "Capture"; + return snd_pcm_direction_name(substream->stream); } /* -- cgit v1.2.3 From 905f3a04e184854555fc248ca4e692fdbf2f2547 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 May 2022 16:42:23 +0100 Subject: ASoC: core: Add set_fmt_new callback that directly specifies provider The original set_fmt callback always passes clock provider/consumer with respect to the CODEC. This made sense when the framework was directly broken down into platforms and CODECs. Now everything is componentised it simplifies things if each side of the link is just told if it is provider or consumer of the clocks. To start this migration add a new callback that can be used to receive a direct specification of clocking. As there are more CODEC drivers than platform drivers, we make the new flags identical to the old CODEC flags meaning CODEC drivers will not require an update. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20220519154318.2153729-2-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 7 +++++++ sound/soc/soc-core.c | 3 ++- sound/soc/soc-dai.c | 5 ++++- 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index bbd821d2df9c..9c1d92d5a373 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -124,6 +124,12 @@ struct snd_compr_stream; #define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC #define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC +/* when passed to set_fmt directly indicate if the device is provider or consumer */ +#define SND_SOC_DAIFMT_BP_FP SND_SOC_DAIFMT_CBP_CFP +#define SND_SOC_DAIFMT_BC_FP SND_SOC_DAIFMT_CBC_CFP +#define SND_SOC_DAIFMT_BP_FC SND_SOC_DAIFMT_CBP_CFC +#define SND_SOC_DAIFMT_BC_FC SND_SOC_DAIFMT_CBC_CFC + /* Describes the possible PCM format */ #define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT 48 #define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT) @@ -282,6 +288,7 @@ struct snd_soc_dai_ops { * Called by soc_card drivers, normally in their hw_params. */ int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); + int (*set_fmt_new)(struct snd_soc_dai *dai, unsigned int fmt); int (*xlate_tdm_slot_mask)(unsigned int slots, unsigned int *tx_mask, unsigned int *rx_mask); int (*set_tdm_slot)(struct snd_soc_dai *dai, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9574f86dd4de..90f4265bea50 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1235,7 +1235,8 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, for_each_rtd_cpu_dais(rtd, i, cpu_dai) { unsigned int fmt = dai_fmt; - if (snd_soc_component_is_codec(cpu_dai->component)) + if (cpu_dai->driver->ops->set_fmt_new || + snd_soc_component_is_codec(cpu_dai->component)) fmt = inv_dai_fmt; ret = snd_soc_dai_set_fmt(cpu_dai, fmt); diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 6078afe335f8..996712f4d9bf 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -209,7 +209,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) int ret = -ENOTSUPP; if (dai->driver->ops && - dai->driver->ops->set_fmt) + dai->driver->ops->set_fmt_new) + ret = dai->driver->ops->set_fmt_new(dai, fmt); + else if (dai->driver->ops && + dai->driver->ops->set_fmt) ret = dai->driver->ops->set_fmt(dai, fmt); return soc_dai_ret(dai, ret); -- cgit v1.2.3 From 19423951a4b5c4f0ca107d6a4bed23f3f63718ca Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 May 2022 16:43:17 +0100 Subject: ASoC: soc-dai: Remove set_fmt_new callback Now the behaviour of the core and all drivers is updated to the new direct clock specification the temporary set_fmt_new callback can be completely removed. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20220519154318.2153729-56-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 - sound/soc/soc-dai.c | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 9c1d92d5a373..ea7509672086 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -288,7 +288,6 @@ struct snd_soc_dai_ops { * Called by soc_card drivers, normally in their hw_params. */ int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); - int (*set_fmt_new)(struct snd_soc_dai *dai, unsigned int fmt); int (*xlate_tdm_slot_mask)(unsigned int slots, unsigned int *tx_mask, unsigned int *rx_mask); int (*set_tdm_slot)(struct snd_soc_dai *dai, diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 996712f4d9bf..d530e8c2b77b 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -208,11 +208,7 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { int ret = -ENOTSUPP; - if (dai->driver->ops && - dai->driver->ops->set_fmt_new) - ret = dai->driver->ops->set_fmt_new(dai, fmt); - else if (dai->driver->ops && - dai->driver->ops->set_fmt) + if (dai->driver->ops && dai->driver->ops->set_fmt) ret = dai->driver->ops->set_fmt(dai, fmt); return soc_dai_ret(dai, ret); -- cgit v1.2.3 From 28086d05ada6d03daa886aad0e469854b811311c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 May 2022 16:43:18 +0100 Subject: ASoC: simple-card-utils: Move snd_soc_component_is_codec to be local The helper function snd_soc_component_is_codec is based off the presence of the non_legacy_dai_naming flag. This isn't super robust as CPU side components may also specify this flag, and indeed the kernel already contains a couple that do. After componentisation there isn't really a totally robust solution to identifying what is a CODEC driver, without introducing a flag specifically for that purpose, and really the desirable direction to move in is that the distinction doesn't matter. This patch does two things to try to mitigate these problems. Firstly, now that all the other users of the helper function have been removed, it makes the helper function local to the driver rather, than being part of the core. This should help to discourage any new code from being created that depends on the CODEC driver distinction. Secondly, it updates the helper function itself to use the endianness flag rather than the non_legacy_dai_naming flag. The endianness flag is definitely invalid on a CPU side component, so it a more reliable indicator that the device is definitely a CODEC. The vast majority of buses require the CODEC to set the endianness flag, so the number of corner cases should be fairly minimal. It is worth noting that CODECs sending audio over SPI, or built into the CPU CODECs are potential corner cases, however the hope is that in most cases those types of devices do not consitute a simple audio card. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20220519154318.2153729-57-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 5 ----- sound/soc/generic/simple-card-utils.c | 7 ++++++- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 5a764c3099d3..5c4cfa70b018 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -348,11 +348,6 @@ static inline int snd_soc_component_cache_sync( return regcache_sync(component->regmap); } -static inline int snd_soc_component_is_codec(struct snd_soc_component *component) -{ - return component->driver->non_legacy_dai_naming; -} - void snd_soc_component_set_aux(struct snd_soc_component *component, struct snd_soc_aux_dev *aux); int snd_soc_component_init(struct snd_soc_component *component); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 539d7f081bd7..50a982708933 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -513,6 +513,11 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai, return 0; } +static inline int asoc_simple_component_is_codec(struct snd_soc_component *component) +{ + return component->driver->endianness; +} + static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, struct simple_dai_props *dai_props) { @@ -524,7 +529,7 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, /* Only Codecs */ for_each_rtd_components(rtd, i, component) { - if (!snd_soc_component_is_codec(component)) + if (!asoc_simple_component_is_codec(component)) return 0; } -- cgit v1.2.3 From 94e0bc317ad241c022a6bb311b3a28b4d51ea8b6 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 25 May 2022 14:16:30 +0100 Subject: ASoC: cs35l41: Move cs35l41 exit hibernate function into shared code CS35L41 HDA Driver will support hibernation using DSP firmware, move the exit hibernate function into shared code so this can be reused. Acked-by: Charles Keepax Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20220525131638.5512-10-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 1 + sound/soc/codecs/cs35l41-lib.c | 60 +++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l41.c | 61 +----------------------------------------- 3 files changed, 62 insertions(+), 60 deletions(-) (limited to 'include') diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index 8972fa697622..7759f2e14d96 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -881,6 +881,7 @@ void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_ int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap, enum cs35l41_cspl_mbox_cmd cmd); int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap); +int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap); int cs35l41_init_boost(struct device *dev, struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg); bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type); diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index 6d3070ea9e06..cc5366c8bdd6 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -1321,6 +1321,66 @@ int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap) } EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata); +static void cs35l41_wait_for_pwrmgt_sts(struct device *dev, struct regmap *regmap) +{ + const int pwrmgt_retries = 10; + unsigned int sts; + int i, ret; + + for (i = 0; i < pwrmgt_retries; i++) { + ret = regmap_read(regmap, CS35L41_PWRMGT_STS, &sts); + if (ret) + dev_err(dev, "Failed to read PWRMGT_STS: %d\n", ret); + else if (!(sts & CS35L41_WR_PEND_STS_MASK)) + return; + + udelay(20); + } + + dev_err(dev, "Timed out reading PWRMGT_STS\n"); +} + +int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap) +{ + const int wake_retries = 20; + const int sleep_retries = 5; + int ret, i, j; + + for (i = 0; i < sleep_retries; i++) { + dev_dbg(dev, "Exit hibernate\n"); + + for (j = 0; j < wake_retries; j++) { + ret = cs35l41_set_cspl_mbox_cmd(dev, regmap, + CSPL_MBOX_CMD_OUT_OF_HIBERNATE); + if (!ret) + break; + + usleep_range(100, 200); + } + + if (j < wake_retries) { + dev_dbg(dev, "Wake success at cycle: %d\n", j); + return 0; + } + + dev_err(dev, "Wake failed, re-enter hibernate: %d\n", ret); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188); + + cs35l41_wait_for_pwrmgt_sts(dev, regmap); + regmap_write(regmap, CS35L41_PWRMGT_CTL, 0x3); + } + + dev_err(dev, "Timed out waking device\n"); + + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(cs35l41_exit_hibernate); + MODULE_DESCRIPTION("CS35L41 library"); MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index 3e68a07a3c8e..be7d02517739 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1351,65 +1351,6 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) return 0; } -static void cs35l41_wait_for_pwrmgt_sts(struct cs35l41_private *cs35l41) -{ - const int pwrmgt_retries = 10; - unsigned int sts; - int i, ret; - - for (i = 0; i < pwrmgt_retries; i++) { - ret = regmap_read(cs35l41->regmap, CS35L41_PWRMGT_STS, &sts); - if (ret) - dev_err(cs35l41->dev, "Failed to read PWRMGT_STS: %d\n", ret); - else if (!(sts & CS35L41_WR_PEND_STS_MASK)) - return; - - udelay(20); - } - - dev_err(cs35l41->dev, "Timed out reading PWRMGT_STS\n"); -} - -static int cs35l41_exit_hibernate(struct cs35l41_private *cs35l41) -{ - const int wake_retries = 20; - const int sleep_retries = 5; - int ret, i, j; - - for (i = 0; i < sleep_retries; i++) { - dev_dbg(cs35l41->dev, "Exit hibernate\n"); - - for (j = 0; j < wake_retries; j++) { - ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, - CSPL_MBOX_CMD_OUT_OF_HIBERNATE); - if (!ret) - break; - - usleep_range(100, 200); - } - - if (j < wake_retries) { - dev_dbg(cs35l41->dev, "Wake success at cycle: %d\n", j); - return 0; - } - - dev_err(cs35l41->dev, "Wake failed, re-enter hibernate: %d\n", ret); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188); - - cs35l41_wait_for_pwrmgt_sts(cs35l41); - regmap_write(cs35l41->regmap, CS35L41_PWRMGT_CTL, 0x3); - } - - dev_err(cs35l41->dev, "Timed out waking device\n"); - - return -ETIMEDOUT; -} - static int __maybe_unused cs35l41_runtime_resume(struct device *dev) { struct cs35l41_private *cs35l41 = dev_get_drvdata(dev); @@ -1422,7 +1363,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev) regcache_cache_only(cs35l41->regmap, false); - ret = cs35l41_exit_hibernate(cs35l41); + ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap); if (ret) return ret; -- cgit v1.2.3 From e341efc308e5374ded6b471f9e1ec01450bcc93e Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Wed, 25 May 2022 14:16:32 +0100 Subject: ASoC: cs35l41: Add common cs35l41 enter hibernate function Since the CS35L41 HDA driver also support hibernation, it makes sense to move code from the ASoC driver to enter hibernation into common code. Since HDA must support laptops which do not support hibernation due to lack of external boost GPIO it is necessary to ensure the function returns an error when an unsupported boost type is in use. Acked-by: Charles Keepax Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20220525131638.5512-12-vitalyr@opensource.cirrus.com Signed-off-by: Mark Brown --- include/sound/cs35l41.h | 2 ++ sound/soc/codecs/cs35l41-lib.c | 19 +++++++++++++++++++ sound/soc/codecs/cs35l41.c | 10 +--------- 3 files changed, 22 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h index 7759f2e14d96..a66ef37184fd 100644 --- a/include/sound/cs35l41.h +++ b/include/sound/cs35l41.h @@ -881,6 +881,8 @@ void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_ int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap, enum cs35l41_cspl_mbox_cmd cmd); int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap); +int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap, + enum cs35l41_boost_type b_type); int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap); int cs35l41_init_boost(struct device *dev, struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg); diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index cc5366c8bdd6..10b754481ca2 100644 --- a/sound/soc/codecs/cs35l41-lib.c +++ b/sound/soc/codecs/cs35l41-lib.c @@ -1321,6 +1321,25 @@ int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap) } EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata); +int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap, + enum cs35l41_boost_type b_type) +{ + if (!cs35l41_safe_reset(regmap, b_type)) { + dev_dbg(dev, "System does not support Suspend\n"); + return -EINVAL; + } + + dev_dbg(dev, "Enter hibernate\n"); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088); + regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188); + + // Don't wait for ACK since bus activity would wake the device + regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE); + + return 0; +} +EXPORT_SYMBOL_GPL(cs35l41_enter_hibernate); + static void cs35l41_wait_for_pwrmgt_sts(struct device *dev, struct regmap *regmap) { const int pwrmgt_retries = 10; diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index be7d02517739..a115ea35b92d 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1335,15 +1335,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev) if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running) return 0; - dev_dbg(cs35l41->dev, "Enter hibernate\n"); - - cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088); - regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188); - - // Don't wait for ACK since bus activity would wake the device - regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1, - CSPL_MBOX_CMD_HIBERNATE); + cs35l41_enter_hibernate(dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type); regcache_cache_only(cs35l41->regmap, true); regcache_mark_dirty(cs35l41->regmap); -- cgit v1.2.3 From 657f8bd88cb5a968d907fd1c891cee52dc156caa Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:10:23 +0200 Subject: spi: fix typo in comment Spelling mistake (triple letters) in comment. Detected with the help of Coccinelle. Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20220521111145.81697-13-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index d361ba26203b..eadfd3ba3cbc 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1127,7 +1127,7 @@ spi_max_transfer_size(struct spi_device *spi) if (ctlr->max_transfer_size) tr_max = ctlr->max_transfer_size(spi); - /* transfer size limit must not be greater than messsage size limit */ + /* transfer size limit must not be greater than message size limit */ return min(tr_max, msg_max); } -- cgit v1.2.3 From 6598b91b5ac32bc756d7c3000a31f775d4ead1c4 Mon Sep 17 00:00:00 2001 From: David Jander Date: Tue, 24 May 2022 11:18:08 +0200 Subject: spi: spi.c: Convert statistics to per-cpu u64_stats_t This change gives a dramatic performance improvement in the hot path, since many costly spin_lock_irqsave() calls can be avoided. On an i.MX8MM system with a MCP2518FD CAN controller connected via SPI, the time the driver takes to handle interrupts, or in other words the time the IRQ line of the CAN controller stays low is mainly dominated by the time it takes to do 3 relatively short sync SPI transfers. The effect of this patch is a reduction of this time from 136us down to only 98us. Suggested-by: Andrew Lunn Signed-off-by: David Jander Link: https://lore.kernel.org/r/20220524091808.2269898-1-david@protonic.nl Signed-off-by: Mark Brown --- drivers/spi/spi.c | 143 +++++++++++++++++++++++++++++++++--------------- include/linux/spi/spi.h | 52 ++++++++++-------- 2 files changed, 127 insertions(+), 68 deletions(-) (limited to 'include') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ea09d1b42bf6..d94822bf3cec 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -33,6 +33,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -49,6 +50,7 @@ static void spidev_release(struct device *dev) spi_controller_put(spi->controller); kfree(spi->driver_override); + free_percpu(spi->pcpu_statistics); kfree(spi); } @@ -93,6 +95,47 @@ static ssize_t driver_override_show(struct device *dev, } static DEVICE_ATTR_RW(driver_override); +static struct spi_statistics *spi_alloc_pcpu_stats(struct device *dev) +{ + struct spi_statistics __percpu *pcpu_stats; + + if (dev) + pcpu_stats = devm_alloc_percpu(dev, struct spi_statistics); + else + pcpu_stats = alloc_percpu_gfp(struct spi_statistics, GFP_KERNEL); + + if (pcpu_stats) { + int cpu; + + for_each_possible_cpu(cpu) { + struct spi_statistics *stat; + + stat = per_cpu_ptr(pcpu_stats, cpu); + u64_stats_init(&stat->syncp); + } + } + return pcpu_stats; +} + +#define spi_pcpu_stats_totalize(ret, in, field) \ +do { \ + int i; \ + ret = 0; \ + for_each_possible_cpu(i) { \ + const struct spi_statistics *pcpu_stats; \ + u64 inc; \ + unsigned int start; \ + pcpu_stats = per_cpu_ptr(in, i); \ + do { \ + start = u64_stats_fetch_begin_irq( \ + &pcpu_stats->syncp); \ + inc = u64_stats_read(&pcpu_stats->field); \ + } while (u64_stats_fetch_retry_irq( \ + &pcpu_stats->syncp, start)); \ + ret += inc; \ + } \ +} while (0) + #define SPI_STATISTICS_ATTRS(field, file) \ static ssize_t spi_controller_##field##_show(struct device *dev, \ struct device_attribute *attr, \ @@ -100,7 +143,7 @@ static ssize_t spi_controller_##field##_show(struct device *dev, \ { \ struct spi_controller *ctlr = container_of(dev, \ struct spi_controller, dev); \ - return spi_statistics_##field##_show(&ctlr->statistics, buf); \ + return spi_statistics_##field##_show(ctlr->pcpu_statistics, buf); \ } \ static struct device_attribute dev_attr_spi_controller_##field = { \ .attr = { .name = file, .mode = 0444 }, \ @@ -111,47 +154,46 @@ static ssize_t spi_device_##field##_show(struct device *dev, \ char *buf) \ { \ struct spi_device *spi = to_spi_device(dev); \ - return spi_statistics_##field##_show(&spi->statistics, buf); \ + return spi_statistics_##field##_show(spi->pcpu_statistics, buf); \ } \ static struct device_attribute dev_attr_spi_device_##field = { \ .attr = { .name = file, .mode = 0444 }, \ .show = spi_device_##field##_show, \ } -#define SPI_STATISTICS_SHOW_NAME(name, file, field, format_string) \ +#define SPI_STATISTICS_SHOW_NAME(name, file, field) \ static ssize_t spi_statistics_##name##_show(struct spi_statistics *stat, \ char *buf) \ { \ - unsigned long flags; \ ssize_t len; \ - spin_lock_irqsave(&stat->lock, flags); \ - len = sysfs_emit(buf, format_string "\n", stat->field); \ - spin_unlock_irqrestore(&stat->lock, flags); \ + u64 val; \ + spi_pcpu_stats_totalize(val, stat, field); \ + len = sysfs_emit(buf, "%llu\n", val); \ return len; \ } \ SPI_STATISTICS_ATTRS(name, file) -#define SPI_STATISTICS_SHOW(field, format_string) \ +#define SPI_STATISTICS_SHOW(field) \ SPI_STATISTICS_SHOW_NAME(field, __stringify(field), \ - field, format_string) + field) -SPI_STATISTICS_SHOW(messages, "%lu"); -SPI_STATISTICS_SHOW(transfers, "%lu"); -SPI_STATISTICS_SHOW(errors, "%lu"); -SPI_STATISTICS_SHOW(timedout, "%lu"); +SPI_STATISTICS_SHOW(messages); +SPI_STATISTICS_SHOW(transfers); +SPI_STATISTICS_SHOW(errors); +SPI_STATISTICS_SHOW(timedout); -SPI_STATISTICS_SHOW(spi_sync, "%lu"); -SPI_STATISTICS_SHOW(spi_sync_immediate, "%lu"); -SPI_STATISTICS_SHOW(spi_async, "%lu"); +SPI_STATISTICS_SHOW(spi_sync); +SPI_STATISTICS_SHOW(spi_sync_immediate); +SPI_STATISTICS_SHOW(spi_async); -SPI_STATISTICS_SHOW(bytes, "%llu"); -SPI_STATISTICS_SHOW(bytes_rx, "%llu"); -SPI_STATISTICS_SHOW(bytes_tx, "%llu"); +SPI_STATISTICS_SHOW(bytes); +SPI_STATISTICS_SHOW(bytes_rx); +SPI_STATISTICS_SHOW(bytes_tx); #define SPI_STATISTICS_TRANSFER_BYTES_HISTO(index, number) \ SPI_STATISTICS_SHOW_NAME(transfer_bytes_histo##index, \ "transfer_bytes_histo_" number, \ - transfer_bytes_histo[index], "%lu") + transfer_bytes_histo[index]) SPI_STATISTICS_TRANSFER_BYTES_HISTO(0, "0-1"); SPI_STATISTICS_TRANSFER_BYTES_HISTO(1, "2-3"); SPI_STATISTICS_TRANSFER_BYTES_HISTO(2, "4-7"); @@ -170,7 +212,7 @@ SPI_STATISTICS_TRANSFER_BYTES_HISTO(14, "16384-32767"); SPI_STATISTICS_TRANSFER_BYTES_HISTO(15, "32768-65535"); SPI_STATISTICS_TRANSFER_BYTES_HISTO(16, "65536+"); -SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu"); +SPI_STATISTICS_SHOW(transfers_split_maxsize); static struct attribute *spi_dev_attrs[] = { &dev_attr_modalias.attr, @@ -267,30 +309,30 @@ static const struct attribute_group *spi_master_groups[] = { NULL, }; -static void spi_statistics_add_transfer_stats(struct spi_statistics *stats, +static void spi_statistics_add_transfer_stats(struct spi_statistics *pcpu_stats, struct spi_transfer *xfer, struct spi_controller *ctlr) { - unsigned long flags; int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1; + struct spi_statistics *stats = this_cpu_ptr(pcpu_stats); if (l2len < 0) l2len = 0; - spin_lock_irqsave(&stats->lock, flags); + u64_stats_update_begin(&stats->syncp); - stats->transfers++; - stats->transfer_bytes_histo[l2len]++; + u64_stats_inc(&stats->transfers); + u64_stats_inc(&stats->transfer_bytes_histo[l2len]); - stats->bytes += xfer->len; + u64_stats_add(&stats->bytes, xfer->len); if ((xfer->tx_buf) && (xfer->tx_buf != ctlr->dummy_tx)) - stats->bytes_tx += xfer->len; + u64_stats_add(&stats->bytes_tx, xfer->len); if ((xfer->rx_buf) && (xfer->rx_buf != ctlr->dummy_rx)) - stats->bytes_rx += xfer->len; + u64_stats_add(&stats->bytes_rx, xfer->len); - spin_unlock_irqrestore(&stats->lock, flags); + u64_stats_update_end(&stats->syncp); } /* @@ -519,14 +561,19 @@ struct spi_device *spi_alloc_device(struct spi_controller *ctlr) return NULL; } + spi->pcpu_statistics = spi_alloc_pcpu_stats(NULL); + if (!spi->pcpu_statistics) { + kfree(spi); + spi_controller_put(ctlr); + return NULL; + } + spi->master = spi->controller = ctlr; spi->dev.parent = &ctlr->dev; spi->dev.bus = &spi_bus_type; spi->dev.release = spidev_release; spi->mode = ctlr->buswidth_override_bits; - spin_lock_init(&spi->statistics.lock); - device_initialize(&spi->dev); return spi; } @@ -1225,8 +1272,8 @@ static int spi_transfer_wait(struct spi_controller *ctlr, struct spi_message *msg, struct spi_transfer *xfer) { - struct spi_statistics *statm = &ctlr->statistics; - struct spi_statistics *stats = &msg->spi->statistics; + struct spi_statistics *statm = ctlr->pcpu_statistics; + struct spi_statistics *stats = msg->spi->pcpu_statistics; u32 speed_hz = xfer->speed_hz; unsigned long long ms; @@ -1382,8 +1429,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, struct spi_transfer *xfer; bool keep_cs = false; int ret = 0; - struct spi_statistics *statm = &ctlr->statistics; - struct spi_statistics *stats = &msg->spi->statistics; + struct spi_statistics *statm = ctlr->pcpu_statistics; + struct spi_statistics *stats = msg->spi->pcpu_statistics; spi_set_cs(msg->spi, true, false); @@ -3029,7 +3076,11 @@ int spi_register_controller(struct spi_controller *ctlr) } } /* add statistics */ - spin_lock_init(&ctlr->statistics.lock); + ctlr->pcpu_statistics = spi_alloc_pcpu_stats(dev); + if (!ctlr->pcpu_statistics) { + dev_err(dev, "Error allocating per-cpu statistics\n"); + goto destroy_queue; + } mutex_lock(&board_lock); list_add_tail(&ctlr->list, &spi_controller_list); @@ -3042,6 +3093,8 @@ int spi_register_controller(struct spi_controller *ctlr) acpi_register_spi_devices(ctlr); return status; +destroy_queue: + spi_destroy_queue(ctlr); free_bus_id: mutex_lock(&board_lock); idr_remove(&spi_master_idr, ctlr->bus_num); @@ -3367,9 +3420,9 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr, *xferp = &xfers[count - 1]; /* increment statistics counters */ - SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, + SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, transfers_split_maxsize); - SPI_STATISTICS_INCREMENT_FIELD(&msg->spi->statistics, + SPI_STATISTICS_INCREMENT_FIELD(msg->spi->pcpu_statistics, transfers_split_maxsize); return 0; @@ -3760,8 +3813,8 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) message->spi = spi; - SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_async); - SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_async); + SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_async); + SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_async); trace_spi_message_submit(message); @@ -3908,8 +3961,8 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) message->context = &done; message->spi = spi; - SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync); - SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync); + SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_sync); + SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_sync); /* * If we're not using the legacy transfer method then we will @@ -3932,9 +3985,9 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) if (status == 0) { /* Push out the messages in the calling context if we can */ if (ctlr->transfer == spi_queued_transfer) { - SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, + SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_sync_immediate); - SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, + SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_sync_immediate); __spi_pump_messages(ctlr, false); } diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index eadfd3ba3cbc..eac8d3caf954 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -17,6 +17,7 @@ #include #include +#include struct dma_chan; struct software_node; @@ -59,37 +60,42 @@ extern struct bus_type spi_bus_type; * maxsize limit */ struct spi_statistics { - spinlock_t lock; /* lock for the whole structure */ + struct u64_stats_sync syncp; - unsigned long messages; - unsigned long transfers; - unsigned long errors; - unsigned long timedout; + u64_stats_t messages; + u64_stats_t transfers; + u64_stats_t errors; + u64_stats_t timedout; - unsigned long spi_sync; - unsigned long spi_sync_immediate; - unsigned long spi_async; + u64_stats_t spi_sync; + u64_stats_t spi_sync_immediate; + u64_stats_t spi_async; - unsigned long long bytes; - unsigned long long bytes_rx; - unsigned long long bytes_tx; + u64_stats_t bytes; + u64_stats_t bytes_rx; + u64_stats_t bytes_tx; #define SPI_STATISTICS_HISTO_SIZE 17 - unsigned long transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE]; + u64_stats_t transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE]; - unsigned long transfers_split_maxsize; + u64_stats_t transfers_split_maxsize; }; -#define SPI_STATISTICS_ADD_TO_FIELD(stats, field, count) \ - do { \ - unsigned long flags; \ - spin_lock_irqsave(&(stats)->lock, flags); \ - (stats)->field += count; \ - spin_unlock_irqrestore(&(stats)->lock, flags); \ +#define SPI_STATISTICS_ADD_TO_FIELD(pcpu_stats, field, count) \ + do { \ + struct spi_statistics *__lstats = this_cpu_ptr(pcpu_stats); \ + u64_stats_update_begin(&__lstats->syncp); \ + u64_stats_add(&__lstats->field, count); \ + u64_stats_update_end(&__lstats->syncp); \ } while (0) -#define SPI_STATISTICS_INCREMENT_FIELD(stats, field) \ - SPI_STATISTICS_ADD_TO_FIELD(stats, field, 1) +#define SPI_STATISTICS_INCREMENT_FIELD(pcpu_stats, field) \ + do { \ + struct spi_statistics *__lstats = this_cpu_ptr(pcpu_stats); \ + u64_stats_update_begin(&__lstats->syncp); \ + u64_stats_inc(&__lstats->field); \ + u64_stats_update_end(&__lstats->syncp); \ + } while (0) /** * struct spi_delay - SPI delay information @@ -194,7 +200,7 @@ struct spi_device { struct spi_delay cs_inactive; /* the statistics */ - struct spi_statistics statistics; + struct spi_statistics __percpu *pcpu_statistics; /* * likely need more hooks for more protocol options affecting how @@ -647,7 +653,7 @@ struct spi_controller { s8 max_native_cs; /* statistics */ - struct spi_statistics statistics; + struct spi_statistics __percpu *pcpu_statistics; /* DMA channels for use with core dmaengine helpers */ struct dma_chan *dma_tx; -- cgit v1.2.3 From fc602b4f692cb83c937b5f79628bca32b60c4402 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Sat, 4 Jun 2022 12:32:50 +0100 Subject: mtd: spinand: Add support for ATO25D1GA Add support for the ATO25D1GA SPI NAND flash. Datasheet: - https://atta.szlcsc.com/upload/public/pdf/source/20191212/C469320_04599D67B03B078044EB65FF5AEDDDE9.pdf Signed-off-by: Aidan MacDonald Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20220604113250.4745-1-aidanmacdonald.0x0@gmail.com --- drivers/mtd/nand/spi/Makefile | 2 +- drivers/mtd/nand/spi/ato.c | 86 +++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/nand/spi/core.c | 1 + include/linux/mtd/spinand.h | 1 + 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/spi/ato.c (limited to 'include') diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 80dabe6ff0f3..b520fe634041 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o +spinand-objs := core.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/ato.c b/drivers/mtd/nand/spi/ato.c new file mode 100644 index 000000000000..82b377c06812 --- /dev/null +++ b/drivers/mtd/nand/spi/ato.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Aidan MacDonald + * + * Author: Aidan MacDonald + */ + +#include +#include +#include + + +#define SPINAND_MFR_ATO 0x9b + + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), + SPINAND_PROG_LOAD(false, 0, NULL, 0)); + + +static int ato25d1ga_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = (16 * section) + 8; + region->length = 8; + return 0; +} + +static int ato25d1ga_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + if (section) { + region->offset = (16 * section); + region->length = 8; + } else { + /* first byte of section 0 is reserved for the BBM */ + region->offset = 1; + region->length = 7; + } + + return 0; +} + +static const struct mtd_ooblayout_ops ato25d1ga_ooblayout = { + .ecc = ato25d1ga_ooblayout_ecc, + .free = ato25d1ga_ooblayout_free, +}; + + +static const struct spinand_info ato_spinand_table[] = { + SPINAND_INFO("ATO25D1GA", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x12), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&ato25d1ga_ooblayout, NULL)), +}; + +static const struct spinand_manufacturer_ops ato_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer ato_spinand_manufacturer = { + .id = SPINAND_MFR_ATO, + .name = "ATO", + .chips = ato_spinand_table, + .nchips = ARRAY_SIZE(ato_spinand_table), + .ops = &ato_spinand_manuf_ops, +}; diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index d5b685d1605e..9d73910a7ae8 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -927,6 +927,7 @@ static const struct nand_ops spinand_ops = { }; static const struct spinand_manufacturer *spinand_manufacturers[] = { + &ato_spinand_manufacturer, &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, µn_spinand_manufacturer, diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 5584d3bb6556..6d3392a7edc6 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -260,6 +260,7 @@ struct spinand_manufacturer { }; /* SPI NAND manufacturers */ +extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; extern const struct spinand_manufacturer micron_spinand_manufacturer; -- cgit v1.2.3 From 39d649602be2ceb3f8f8e98483d09e4d71133c6a Mon Sep 17 00:00:00 2001 From: Clément Léger Date: Wed, 1 Jun 2022 10:17:58 +0200 Subject: of: constify of_property_check_flags() prop argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This argument is not modified and thus can be set as const. Signed-off-by: Clément Léger Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220601081801.348571-2-clement.leger@bootlin.com --- include/linux/of.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/of.h b/include/linux/of.h index f0a5d6b10c5a..d74fd82a6963 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -207,7 +207,7 @@ static inline void of_node_clear_flag(struct device_node *n, unsigned long flag) } #if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC) -static inline int of_property_check_flag(struct property *p, unsigned long flag) +static inline int of_property_check_flag(const struct property *p, unsigned long flag) { return test_bit(flag, &p->_flags); } @@ -814,7 +814,8 @@ static inline void of_node_clear_flag(struct device_node *n, unsigned long flag) { } -static inline int of_property_check_flag(struct property *p, unsigned long flag) +static inline int of_property_check_flag(const struct property *p, + unsigned long flag) { return 0; } -- cgit v1.2.3 From 11fe58c4450a8108b498d2f849976ba2686820fc Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 6 Jun 2022 15:46:20 -0500 Subject: ASoC: SOF: Intel: add MeteorLake machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for MeteorLake (MTL) machines support, starting with mockup devices. Reviewed-by: Péter Ujfalusi Reviewed-by: Rander Wang Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220606204622.144424-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 2 ++ sound/soc/intel/common/Makefile | 1 + sound/soc/intel/common/soc-acpi-intel-mtl-match.c | 41 +++++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 sound/soc/intel/common/soc-acpi-intel-mtl-match.c (limited to 'include') diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 59551b1f22f3..bc7fd46ec2bc 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -30,6 +30,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[]; @@ -37,6 +38,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index fef0b2d1de68..8ca8f872ec80 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -9,6 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \ + soc-acpi-intel-mtl-match.o \ soc-acpi-intel-hda-match.o \ soc-acpi-intel-sdw-mockup-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c new file mode 100644 index 000000000000..cc594b27e03b --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-mtl-match.c - tables and support for MTL ACPI enumeration. + * + * Copyright (c) 2022, Intel Corporation. + * + */ + +#include +#include +#include "soc-acpi-intel-sdw-mockup-match.h" + +struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines); + +/* this table is used when there is no I2S codec present */ +struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { + /* mockup tests need to be first */ + { + .link_mask = GENMASK(3, 0), + .links = sdw_mockup_headset_2amps_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = sdw_mockup_headset_1amp_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = GENMASK(2, 0), + .links = sdw_mockup_mic_headset_1amp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines); -- cgit v1.2.3 From ff8372a467fa28752610f57a6512c5365413faa2 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 6 Jun 2022 10:24:34 +0800 Subject: net: skb: move enum skb_drop_reason to standalone header file As the skb drop reasons are getting more and more, move the enum 'skb_drop_reason' and related function to the standalone header 'dropreason.h', as Jakub Kicinski suggested. Signed-off-by: Menglong Dong Signed-off-by: Paolo Abeni --- include/linux/skbuff.h | 179 +-------------------------------------------- include/net/dropreason.h | 184 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 178 deletions(-) create mode 100644 include/net/dropreason.h (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d3d10556f0fa..82edf0359ab3 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -43,6 +43,7 @@ #include #endif #include +#include /** * DOC: skb checksums @@ -337,184 +338,6 @@ struct sk_buff_head { struct sk_buff; -/* The reason of skb drop, which is used in kfree_skb_reason(). - * en...maybe they should be splited by group? - * - * Each item here should also be in 'TRACE_SKB_DROP_REASON', which is - * used to translate the reason to string. - */ -enum skb_drop_reason { - SKB_NOT_DROPPED_YET = 0, - SKB_DROP_REASON_NOT_SPECIFIED, /* drop reason is not specified */ - SKB_DROP_REASON_NO_SOCKET, /* socket not found */ - SKB_DROP_REASON_PKT_TOO_SMALL, /* packet size is too small */ - SKB_DROP_REASON_TCP_CSUM, /* TCP checksum error */ - SKB_DROP_REASON_SOCKET_FILTER, /* dropped by socket filter */ - SKB_DROP_REASON_UDP_CSUM, /* UDP checksum error */ - SKB_DROP_REASON_NETFILTER_DROP, /* dropped by netfilter */ - SKB_DROP_REASON_OTHERHOST, /* packet don't belong to current - * host (interface is in promisc - * mode) - */ - SKB_DROP_REASON_IP_CSUM, /* IP checksum error */ - SKB_DROP_REASON_IP_INHDR, /* there is something wrong with - * IP header (see - * IPSTATS_MIB_INHDRERRORS) - */ - SKB_DROP_REASON_IP_RPFILTER, /* IP rpfilter validate failed. - * see the document for rp_filter - * in ip-sysctl.rst for more - * information - */ - SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, /* destination address of L2 - * is multicast, but L3 is - * unicast. - */ - SKB_DROP_REASON_XFRM_POLICY, /* xfrm policy check failed */ - SKB_DROP_REASON_IP_NOPROTO, /* no support for IP protocol */ - SKB_DROP_REASON_SOCKET_RCVBUFF, /* socket receive buff is full */ - SKB_DROP_REASON_PROTO_MEM, /* proto memory limition, such as - * udp packet drop out of - * udp_memory_allocated. - */ - SKB_DROP_REASON_TCP_MD5NOTFOUND, /* no MD5 hash and one - * expected, corresponding - * to LINUX_MIB_TCPMD5NOTFOUND - */ - SKB_DROP_REASON_TCP_MD5UNEXPECTED, /* MD5 hash and we're not - * expecting one, corresponding - * to LINUX_MIB_TCPMD5UNEXPECTED - */ - SKB_DROP_REASON_TCP_MD5FAILURE, /* MD5 hash and its wrong, - * corresponding to - * LINUX_MIB_TCPMD5FAILURE - */ - SKB_DROP_REASON_SOCKET_BACKLOG, /* failed to add skb to socket - * backlog (see - * LINUX_MIB_TCPBACKLOGDROP) - */ - SKB_DROP_REASON_TCP_FLAGS, /* TCP flags invalid */ - SKB_DROP_REASON_TCP_ZEROWINDOW, /* TCP receive window size is zero, - * see LINUX_MIB_TCPZEROWINDOWDROP - */ - SKB_DROP_REASON_TCP_OLD_DATA, /* the TCP data reveived is already - * received before (spurious retrans - * may happened), see - * LINUX_MIB_DELAYEDACKLOST - */ - SKB_DROP_REASON_TCP_OVERWINDOW, /* the TCP data is out of window, - * the seq of the first byte exceed - * the right edges of receive - * window - */ - SKB_DROP_REASON_TCP_OFOMERGE, /* the data of skb is already in - * the ofo queue, corresponding to - * LINUX_MIB_TCPOFOMERGE - */ - SKB_DROP_REASON_TCP_RFC7323_PAWS, /* PAWS check, corresponding to - * LINUX_MIB_PAWSESTABREJECTED - */ - SKB_DROP_REASON_TCP_INVALID_SEQUENCE, /* Not acceptable SEQ field */ - SKB_DROP_REASON_TCP_RESET, /* Invalid RST packet */ - SKB_DROP_REASON_TCP_INVALID_SYN, /* Incoming packet has unexpected SYN flag */ - SKB_DROP_REASON_TCP_CLOSE, /* TCP socket in CLOSE state */ - SKB_DROP_REASON_TCP_FASTOPEN, /* dropped by FASTOPEN request socket */ - SKB_DROP_REASON_TCP_OLD_ACK, /* TCP ACK is old, but in window */ - SKB_DROP_REASON_TCP_TOO_OLD_ACK, /* TCP ACK is too old */ - SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, /* TCP ACK for data we haven't sent yet */ - SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, /* pruned from TCP OFO queue */ - SKB_DROP_REASON_TCP_OFO_DROP, /* data already in receive queue */ - SKB_DROP_REASON_IP_OUTNOROUTES, /* route lookup failed */ - SKB_DROP_REASON_BPF_CGROUP_EGRESS, /* dropped by - * BPF_PROG_TYPE_CGROUP_SKB - * eBPF program - */ - SKB_DROP_REASON_IPV6DISABLED, /* IPv6 is disabled on the device */ - SKB_DROP_REASON_NEIGH_CREATEFAIL, /* failed to create neigh - * entry - */ - SKB_DROP_REASON_NEIGH_FAILED, /* neigh entry in failed state */ - SKB_DROP_REASON_NEIGH_QUEUEFULL, /* arp_queue for neigh - * entry is full - */ - SKB_DROP_REASON_NEIGH_DEAD, /* neigh entry is dead */ - SKB_DROP_REASON_TC_EGRESS, /* dropped in TC egress HOOK */ - SKB_DROP_REASON_QDISC_DROP, /* dropped by qdisc when packet - * outputting (failed to enqueue to - * current qdisc) - */ - SKB_DROP_REASON_CPU_BACKLOG, /* failed to enqueue the skb to - * the per CPU backlog queue. This - * can be caused by backlog queue - * full (see netdev_max_backlog in - * net.rst) or RPS flow limit - */ - SKB_DROP_REASON_XDP, /* dropped by XDP in input path */ - SKB_DROP_REASON_TC_INGRESS, /* dropped in TC ingress HOOK */ - SKB_DROP_REASON_UNHANDLED_PROTO, /* protocol not implemented - * or not supported - */ - SKB_DROP_REASON_SKB_CSUM, /* sk_buff checksum computation - * error - */ - SKB_DROP_REASON_SKB_GSO_SEG, /* gso segmentation error */ - SKB_DROP_REASON_SKB_UCOPY_FAULT, /* failed to copy data from - * user space, e.g., via - * zerocopy_sg_from_iter() - * or skb_orphan_frags_rx() - */ - SKB_DROP_REASON_DEV_HDR, /* device driver specific - * header/metadata is invalid - */ - /* the device is not ready to xmit/recv due to any of its data - * structure that is not up/ready/initialized, e.g., the IFF_UP is - * not set, or driver specific tun->tfiles[txq] is not initialized - */ - SKB_DROP_REASON_DEV_READY, - SKB_DROP_REASON_FULL_RING, /* ring buffer is full */ - SKB_DROP_REASON_NOMEM, /* error due to OOM */ - SKB_DROP_REASON_HDR_TRUNC, /* failed to trunc/extract the header - * from networking data, e.g., failed - * to pull the protocol header from - * frags via pskb_may_pull() - */ - SKB_DROP_REASON_TAP_FILTER, /* dropped by (ebpf) filter directly - * attached to tun/tap, e.g., via - * TUNSETFILTEREBPF - */ - SKB_DROP_REASON_TAP_TXFILTER, /* dropped by tx filter implemented - * at tun/tap, e.g., check_filter() - */ - SKB_DROP_REASON_ICMP_CSUM, /* ICMP checksum error */ - SKB_DROP_REASON_INVALID_PROTO, /* the packet doesn't follow RFC - * 2211, such as a broadcasts - * ICMP_TIMESTAMP - */ - SKB_DROP_REASON_IP_INADDRERRORS, /* host unreachable, corresponding - * to IPSTATS_MIB_INADDRERRORS - */ - SKB_DROP_REASON_IP_INNOROUTES, /* network unreachable, corresponding - * to IPSTATS_MIB_INADDRERRORS - */ - SKB_DROP_REASON_PKT_TOO_BIG, /* packet size is too big (maybe exceed - * the MTU) - */ - SKB_DROP_REASON_MAX, -}; - -#define SKB_DR_INIT(name, reason) \ - enum skb_drop_reason name = SKB_DROP_REASON_##reason -#define SKB_DR(name) \ - SKB_DR_INIT(name, NOT_SPECIFIED) -#define SKB_DR_SET(name, reason) \ - (name = SKB_DROP_REASON_##reason) -#define SKB_DR_OR(name, reason) \ - do { \ - if (name == SKB_DROP_REASON_NOT_SPECIFIED || \ - name == SKB_NOT_DROPPED_YET) \ - SKB_DR_SET(name, reason); \ - } while (0) - /* To allow 64K frame to be packed as single skb without frag_list we * require 64K/PAGE_SIZE pages plus 1 additional page to allow for * buffers which do not start on a page boundary. diff --git a/include/net/dropreason.h b/include/net/dropreason.h new file mode 100644 index 000000000000..ecd18b7b1364 --- /dev/null +++ b/include/net/dropreason.h @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _LINUX_DROPREASON_H +#define _LINUX_DROPREASON_H + +/* The reason of skb drop, which is used in kfree_skb_reason(). + * en...maybe they should be splited by group? + * + * Each item here should also be in 'TRACE_SKB_DROP_REASON', which is + * used to translate the reason to string. + */ +enum skb_drop_reason { + SKB_NOT_DROPPED_YET = 0, + SKB_DROP_REASON_NOT_SPECIFIED, /* drop reason is not specified */ + SKB_DROP_REASON_NO_SOCKET, /* socket not found */ + SKB_DROP_REASON_PKT_TOO_SMALL, /* packet size is too small */ + SKB_DROP_REASON_TCP_CSUM, /* TCP checksum error */ + SKB_DROP_REASON_SOCKET_FILTER, /* dropped by socket filter */ + SKB_DROP_REASON_UDP_CSUM, /* UDP checksum error */ + SKB_DROP_REASON_NETFILTER_DROP, /* dropped by netfilter */ + SKB_DROP_REASON_OTHERHOST, /* packet don't belong to current + * host (interface is in promisc + * mode) + */ + SKB_DROP_REASON_IP_CSUM, /* IP checksum error */ + SKB_DROP_REASON_IP_INHDR, /* there is something wrong with + * IP header (see + * IPSTATS_MIB_INHDRERRORS) + */ + SKB_DROP_REASON_IP_RPFILTER, /* IP rpfilter validate failed. + * see the document for rp_filter + * in ip-sysctl.rst for more + * information + */ + SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, /* destination address of L2 + * is multicast, but L3 is + * unicast. + */ + SKB_DROP_REASON_XFRM_POLICY, /* xfrm policy check failed */ + SKB_DROP_REASON_IP_NOPROTO, /* no support for IP protocol */ + SKB_DROP_REASON_SOCKET_RCVBUFF, /* socket receive buff is full */ + SKB_DROP_REASON_PROTO_MEM, /* proto memory limition, such as + * udp packet drop out of + * udp_memory_allocated. + */ + SKB_DROP_REASON_TCP_MD5NOTFOUND, /* no MD5 hash and one + * expected, corresponding + * to LINUX_MIB_TCPMD5NOTFOUND + */ + SKB_DROP_REASON_TCP_MD5UNEXPECTED, /* MD5 hash and we're not + * expecting one, corresponding + * to LINUX_MIB_TCPMD5UNEXPECTED + */ + SKB_DROP_REASON_TCP_MD5FAILURE, /* MD5 hash and its wrong, + * corresponding to + * LINUX_MIB_TCPMD5FAILURE + */ + SKB_DROP_REASON_SOCKET_BACKLOG, /* failed to add skb to socket + * backlog (see + * LINUX_MIB_TCPBACKLOGDROP) + */ + SKB_DROP_REASON_TCP_FLAGS, /* TCP flags invalid */ + SKB_DROP_REASON_TCP_ZEROWINDOW, /* TCP receive window size is zero, + * see LINUX_MIB_TCPZEROWINDOWDROP + */ + SKB_DROP_REASON_TCP_OLD_DATA, /* the TCP data reveived is already + * received before (spurious retrans + * may happened), see + * LINUX_MIB_DELAYEDACKLOST + */ + SKB_DROP_REASON_TCP_OVERWINDOW, /* the TCP data is out of window, + * the seq of the first byte exceed + * the right edges of receive + * window + */ + SKB_DROP_REASON_TCP_OFOMERGE, /* the data of skb is already in + * the ofo queue, corresponding to + * LINUX_MIB_TCPOFOMERGE + */ + SKB_DROP_REASON_TCP_RFC7323_PAWS, /* PAWS check, corresponding to + * LINUX_MIB_PAWSESTABREJECTED + */ + SKB_DROP_REASON_TCP_INVALID_SEQUENCE, /* Not acceptable SEQ field */ + SKB_DROP_REASON_TCP_RESET, /* Invalid RST packet */ + SKB_DROP_REASON_TCP_INVALID_SYN, /* Incoming packet has unexpected SYN flag */ + SKB_DROP_REASON_TCP_CLOSE, /* TCP socket in CLOSE state */ + SKB_DROP_REASON_TCP_FASTOPEN, /* dropped by FASTOPEN request socket */ + SKB_DROP_REASON_TCP_OLD_ACK, /* TCP ACK is old, but in window */ + SKB_DROP_REASON_TCP_TOO_OLD_ACK, /* TCP ACK is too old */ + SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, /* TCP ACK for data we haven't sent yet */ + SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, /* pruned from TCP OFO queue */ + SKB_DROP_REASON_TCP_OFO_DROP, /* data already in receive queue */ + SKB_DROP_REASON_IP_OUTNOROUTES, /* route lookup failed */ + SKB_DROP_REASON_BPF_CGROUP_EGRESS, /* dropped by + * BPF_PROG_TYPE_CGROUP_SKB + * eBPF program + */ + SKB_DROP_REASON_IPV6DISABLED, /* IPv6 is disabled on the device */ + SKB_DROP_REASON_NEIGH_CREATEFAIL, /* failed to create neigh + * entry + */ + SKB_DROP_REASON_NEIGH_FAILED, /* neigh entry in failed state */ + SKB_DROP_REASON_NEIGH_QUEUEFULL, /* arp_queue for neigh + * entry is full + */ + SKB_DROP_REASON_NEIGH_DEAD, /* neigh entry is dead */ + SKB_DROP_REASON_TC_EGRESS, /* dropped in TC egress HOOK */ + SKB_DROP_REASON_QDISC_DROP, /* dropped by qdisc when packet + * outputting (failed to enqueue to + * current qdisc) + */ + SKB_DROP_REASON_CPU_BACKLOG, /* failed to enqueue the skb to + * the per CPU backlog queue. This + * can be caused by backlog queue + * full (see netdev_max_backlog in + * net.rst) or RPS flow limit + */ + SKB_DROP_REASON_XDP, /* dropped by XDP in input path */ + SKB_DROP_REASON_TC_INGRESS, /* dropped in TC ingress HOOK */ + SKB_DROP_REASON_UNHANDLED_PROTO, /* protocol not implemented + * or not supported + */ + SKB_DROP_REASON_SKB_CSUM, /* sk_buff checksum computation + * error + */ + SKB_DROP_REASON_SKB_GSO_SEG, /* gso segmentation error */ + SKB_DROP_REASON_SKB_UCOPY_FAULT, /* failed to copy data from + * user space, e.g., via + * zerocopy_sg_from_iter() + * or skb_orphan_frags_rx() + */ + SKB_DROP_REASON_DEV_HDR, /* device driver specific + * header/metadata is invalid + */ + /* the device is not ready to xmit/recv due to any of its data + * structure that is not up/ready/initialized, e.g., the IFF_UP is + * not set, or driver specific tun->tfiles[txq] is not initialized + */ + SKB_DROP_REASON_DEV_READY, + SKB_DROP_REASON_FULL_RING, /* ring buffer is full */ + SKB_DROP_REASON_NOMEM, /* error due to OOM */ + SKB_DROP_REASON_HDR_TRUNC, /* failed to trunc/extract the header + * from networking data, e.g., failed + * to pull the protocol header from + * frags via pskb_may_pull() + */ + SKB_DROP_REASON_TAP_FILTER, /* dropped by (ebpf) filter directly + * attached to tun/tap, e.g., via + * TUNSETFILTEREBPF + */ + SKB_DROP_REASON_TAP_TXFILTER, /* dropped by tx filter implemented + * at tun/tap, e.g., check_filter() + */ + SKB_DROP_REASON_ICMP_CSUM, /* ICMP checksum error */ + SKB_DROP_REASON_INVALID_PROTO, /* the packet doesn't follow RFC + * 2211, such as a broadcasts + * ICMP_TIMESTAMP + */ + SKB_DROP_REASON_IP_INADDRERRORS, /* host unreachable, corresponding + * to IPSTATS_MIB_INADDRERRORS + */ + SKB_DROP_REASON_IP_INNOROUTES, /* network unreachable, corresponding + * to IPSTATS_MIB_INADDRERRORS + */ + SKB_DROP_REASON_PKT_TOO_BIG, /* packet size is too big (maybe exceed + * the MTU) + */ + SKB_DROP_REASON_MAX, +}; + +#define SKB_DR_INIT(name, reason) \ + enum skb_drop_reason name = SKB_DROP_REASON_##reason +#define SKB_DR(name) \ + SKB_DR_INIT(name, NOT_SPECIFIED) +#define SKB_DR_SET(name, reason) \ + (name = SKB_DROP_REASON_##reason) +#define SKB_DR_OR(name, reason) \ + do { \ + if (name == SKB_DROP_REASON_NOT_SPECIFIED || \ + name == SKB_NOT_DROPPED_YET) \ + SKB_DR_SET(name, reason); \ + } while (0) + +#endif -- cgit v1.2.3 From ec43908dd556b2292f028c6e412261689405ba6e Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 6 Jun 2022 10:24:35 +0800 Subject: net: skb: use auto-generation to convert skb drop reason to string It is annoying to add new skb drop reasons to 'enum skb_drop_reason' and TRACE_SKB_DROP_REASON in trace/event/skb.h, and it's easy to forget to add the new reasons we added to TRACE_SKB_DROP_REASON. TRACE_SKB_DROP_REASON is used to convert drop reason of type number to string. For now, the string we passed to user space is exactly the same as the name in 'enum skb_drop_reason' with a 'SKB_DROP_REASON_' prefix. Therefore, we can use 'auto-generation' to generate these drop reasons to string at build time. The new source 'dropreason_str.c' will be auto generated during build time, which contains the string array 'const char * const drop_reasons[]'. Signed-off-by: Menglong Dong Signed-off-by: Paolo Abeni --- include/net/dropreason.h | 2 ++ include/trace/events/skb.h | 89 +--------------------------------------------- net/core/.gitignore | 1 + net/core/Makefile | 23 +++++++++++- net/core/drop_monitor.c | 13 ------- net/core/skbuff.c | 3 ++ 6 files changed, 29 insertions(+), 102 deletions(-) create mode 100644 net/core/.gitignore (limited to 'include') diff --git a/include/net/dropreason.h b/include/net/dropreason.h index ecd18b7b1364..013ff0f2543e 100644 --- a/include/net/dropreason.h +++ b/include/net/dropreason.h @@ -181,4 +181,6 @@ enum skb_drop_reason { SKB_DR_SET(name, reason); \ } while (0) +extern const char * const drop_reasons[]; + #endif diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index a477bf907498..45264e4bb254 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -9,92 +9,6 @@ #include #include -#define TRACE_SKB_DROP_REASON \ - EM(SKB_DROP_REASON_NOT_SPECIFIED, NOT_SPECIFIED) \ - EM(SKB_DROP_REASON_NO_SOCKET, NO_SOCKET) \ - EM(SKB_DROP_REASON_PKT_TOO_SMALL, PKT_TOO_SMALL) \ - EM(SKB_DROP_REASON_TCP_CSUM, TCP_CSUM) \ - EM(SKB_DROP_REASON_SOCKET_FILTER, SOCKET_FILTER) \ - EM(SKB_DROP_REASON_UDP_CSUM, UDP_CSUM) \ - EM(SKB_DROP_REASON_NETFILTER_DROP, NETFILTER_DROP) \ - EM(SKB_DROP_REASON_OTHERHOST, OTHERHOST) \ - EM(SKB_DROP_REASON_IP_CSUM, IP_CSUM) \ - EM(SKB_DROP_REASON_IP_INHDR, IP_INHDR) \ - EM(SKB_DROP_REASON_IP_RPFILTER, IP_RPFILTER) \ - EM(SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, \ - UNICAST_IN_L2_MULTICAST) \ - EM(SKB_DROP_REASON_XFRM_POLICY, XFRM_POLICY) \ - EM(SKB_DROP_REASON_IP_NOPROTO, IP_NOPROTO) \ - EM(SKB_DROP_REASON_SOCKET_RCVBUFF, SOCKET_RCVBUFF) \ - EM(SKB_DROP_REASON_PROTO_MEM, PROTO_MEM) \ - EM(SKB_DROP_REASON_TCP_MD5NOTFOUND, TCP_MD5NOTFOUND) \ - EM(SKB_DROP_REASON_TCP_MD5UNEXPECTED, \ - TCP_MD5UNEXPECTED) \ - EM(SKB_DROP_REASON_TCP_MD5FAILURE, TCP_MD5FAILURE) \ - EM(SKB_DROP_REASON_SOCKET_BACKLOG, SOCKET_BACKLOG) \ - EM(SKB_DROP_REASON_TCP_FLAGS, TCP_FLAGS) \ - EM(SKB_DROP_REASON_TCP_ZEROWINDOW, TCP_ZEROWINDOW) \ - EM(SKB_DROP_REASON_TCP_OLD_DATA, TCP_OLD_DATA) \ - EM(SKB_DROP_REASON_TCP_OVERWINDOW, TCP_OVERWINDOW) \ - EM(SKB_DROP_REASON_TCP_OFOMERGE, TCP_OFOMERGE) \ - EM(SKB_DROP_REASON_TCP_OFO_DROP, TCP_OFO_DROP) \ - EM(SKB_DROP_REASON_TCP_RFC7323_PAWS, TCP_RFC7323_PAWS) \ - EM(SKB_DROP_REASON_TCP_INVALID_SEQUENCE, \ - TCP_INVALID_SEQUENCE) \ - EM(SKB_DROP_REASON_TCP_RESET, TCP_RESET) \ - EM(SKB_DROP_REASON_TCP_INVALID_SYN, TCP_INVALID_SYN) \ - EM(SKB_DROP_REASON_TCP_CLOSE, TCP_CLOSE) \ - EM(SKB_DROP_REASON_TCP_FASTOPEN, TCP_FASTOPEN) \ - EM(SKB_DROP_REASON_TCP_OLD_ACK, TCP_OLD_ACK) \ - EM(SKB_DROP_REASON_TCP_TOO_OLD_ACK, TCP_TOO_OLD_ACK) \ - EM(SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, \ - TCP_ACK_UNSENT_DATA) \ - EM(SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, \ - TCP_OFO_QUEUE_PRUNE) \ - EM(SKB_DROP_REASON_IP_OUTNOROUTES, IP_OUTNOROUTES) \ - EM(SKB_DROP_REASON_BPF_CGROUP_EGRESS, \ - BPF_CGROUP_EGRESS) \ - EM(SKB_DROP_REASON_IPV6DISABLED, IPV6DISABLED) \ - EM(SKB_DROP_REASON_NEIGH_CREATEFAIL, NEIGH_CREATEFAIL) \ - EM(SKB_DROP_REASON_NEIGH_FAILED, NEIGH_FAILED) \ - EM(SKB_DROP_REASON_NEIGH_QUEUEFULL, NEIGH_QUEUEFULL) \ - EM(SKB_DROP_REASON_NEIGH_DEAD, NEIGH_DEAD) \ - EM(SKB_DROP_REASON_TC_EGRESS, TC_EGRESS) \ - EM(SKB_DROP_REASON_QDISC_DROP, QDISC_DROP) \ - EM(SKB_DROP_REASON_CPU_BACKLOG, CPU_BACKLOG) \ - EM(SKB_DROP_REASON_XDP, XDP) \ - EM(SKB_DROP_REASON_TC_INGRESS, TC_INGRESS) \ - EM(SKB_DROP_REASON_UNHANDLED_PROTO, UNHANDLED_PROTO) \ - EM(SKB_DROP_REASON_SKB_CSUM, SKB_CSUM) \ - EM(SKB_DROP_REASON_SKB_GSO_SEG, SKB_GSO_SEG) \ - EM(SKB_DROP_REASON_SKB_UCOPY_FAULT, SKB_UCOPY_FAULT) \ - EM(SKB_DROP_REASON_DEV_HDR, DEV_HDR) \ - EM(SKB_DROP_REASON_DEV_READY, DEV_READY) \ - EM(SKB_DROP_REASON_FULL_RING, FULL_RING) \ - EM(SKB_DROP_REASON_NOMEM, NOMEM) \ - EM(SKB_DROP_REASON_HDR_TRUNC, HDR_TRUNC) \ - EM(SKB_DROP_REASON_TAP_FILTER, TAP_FILTER) \ - EM(SKB_DROP_REASON_TAP_TXFILTER, TAP_TXFILTER) \ - EM(SKB_DROP_REASON_ICMP_CSUM, ICMP_CSUM) \ - EM(SKB_DROP_REASON_INVALID_PROTO, INVALID_PROTO) \ - EM(SKB_DROP_REASON_IP_INADDRERRORS, IP_INADDRERRORS) \ - EM(SKB_DROP_REASON_IP_INNOROUTES, IP_INNOROUTES) \ - EM(SKB_DROP_REASON_PKT_TOO_BIG, PKT_TOO_BIG) \ - EMe(SKB_DROP_REASON_MAX, MAX) - -#undef EM -#undef EMe - -#define EM(a, b) TRACE_DEFINE_ENUM(a); -#define EMe(a, b) TRACE_DEFINE_ENUM(a); - -TRACE_SKB_DROP_REASON - -#undef EM -#undef EMe -#define EM(a, b) { a, #b }, -#define EMe(a, b) { a, #b } - /* * Tracepoint for free an sk_buff: */ @@ -121,8 +35,7 @@ TRACE_EVENT(kfree_skb, TP_printk("skbaddr=%p protocol=%u location=%p reason: %s", __entry->skbaddr, __entry->protocol, __entry->location, - __print_symbolic(__entry->reason, - TRACE_SKB_DROP_REASON)) + drop_reasons[__entry->reason]) ); TRACE_EVENT(consume_skb, diff --git a/net/core/.gitignore b/net/core/.gitignore new file mode 100644 index 000000000000..df1e74372cce --- /dev/null +++ b/net/core/.gitignore @@ -0,0 +1 @@ +dropreason_str.c diff --git a/net/core/Makefile b/net/core/Makefile index a8e4f737692b..e8ce3bd283a6 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -4,7 +4,8 @@ # obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \ - gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o + gen_stats.o gen_estimator.o net_namespace.o secure_seq.o \ + flow_dissector.o dropreason_str.o obj-$(CONFIG_SYSCTL) += sysctl_net_core.o @@ -39,3 +40,23 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o obj-$(CONFIG_BPF_SYSCALL) += sock_map.o obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o obj-$(CONFIG_OF) += of_net.o + +clean-files := dropreason_str.c + +quiet_cmd_dropreason_str = GEN $@ +cmd_dropreason_str = awk -F ',' 'BEGIN{ print "\#include \n"; \ + print "const char * const drop_reasons[] = {" }\ + /^enum skb_drop/ { dr=1; }\ + /^\};/ { dr=0; }\ + /^\tSKB_DROP_REASON_/ {\ + if (dr) {\ + sub(/\tSKB_DROP_REASON_/, "", $$1);\ + printf "\t[SKB_DROP_REASON_%s] = \"%s\",\n", $$1, $$1;\ + }\ + }\ + END{ print "};" }' $< > $@ + +$(obj)/dropreason_str.c: $(srctree)/include/net/dropreason.h + $(call cmd,dropreason_str) + +$(obj)/dropreason_str.o: $(obj)/dropreason_str.c diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 41cac0e4834e..4ad1decce724 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -48,19 +48,6 @@ static int trace_state = TRACE_OFF; static bool monitor_hw; -#undef EM -#undef EMe - -#define EM(a, b) [a] = #b, -#define EMe(a, b) [a] = #b - -/* drop_reasons is used to translate 'enum skb_drop_reason' to string, - * which is reported to user space. - */ -static const char * const drop_reasons[] = { - TRACE_SKB_DROP_REASON -}; - /* net_dm_mutex * * An overall lock guarding every operation coming from userspace. diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 5b3559cb1d82..b661040c100e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -91,6 +91,9 @@ static struct kmem_cache *skbuff_ext_cache __ro_after_init; int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; EXPORT_SYMBOL(sysctl_max_skb_frags); +/* The array 'drop_reasons' is auto-generated in dropreason_str.c */ +EXPORT_SYMBOL(drop_reasons); + /** * skb_panic - private function for out-of-line support * @skb: buffer -- cgit v1.2.3 From b160f7270e6df0f4ccadcf6750696b380eb3b811 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 6 Jun 2022 10:24:36 +0800 Subject: net: dropreason: reformat the comment fo skb drop reasons To make the code clear, reformat the comment in dropreason.h to k-doc style. Now, the comment can pass the check of kernel-doc without warnning: $ ./scripts/kernel-doc -v -none include/linux/dropreason.h include/linux/dropreason.h:7: info: Scanning doc for enum skb_drop_reason Signed-off-by: Menglong Dong Signed-off-by: Paolo Abeni --- include/net/dropreason.h | 382 ++++++++++++++++++++++++++++------------------- 1 file changed, 226 insertions(+), 156 deletions(-) (limited to 'include') diff --git a/include/net/dropreason.h b/include/net/dropreason.h index 013ff0f2543e..fae9b40e54fa 100644 --- a/include/net/dropreason.h +++ b/include/net/dropreason.h @@ -3,168 +3,238 @@ #ifndef _LINUX_DROPREASON_H #define _LINUX_DROPREASON_H -/* The reason of skb drop, which is used in kfree_skb_reason(). - * en...maybe they should be splited by group? +/** + * enum skb_drop_reason - the reasons of skb drops * - * Each item here should also be in 'TRACE_SKB_DROP_REASON', which is - * used to translate the reason to string. + * The reason of skb drop, which is used in kfree_skb_reason(). */ enum skb_drop_reason { + /** + * @SKB_NOT_DROPPED_YET: skb is not dropped yet (used for no-drop case) + */ SKB_NOT_DROPPED_YET = 0, - SKB_DROP_REASON_NOT_SPECIFIED, /* drop reason is not specified */ - SKB_DROP_REASON_NO_SOCKET, /* socket not found */ - SKB_DROP_REASON_PKT_TOO_SMALL, /* packet size is too small */ - SKB_DROP_REASON_TCP_CSUM, /* TCP checksum error */ - SKB_DROP_REASON_SOCKET_FILTER, /* dropped by socket filter */ - SKB_DROP_REASON_UDP_CSUM, /* UDP checksum error */ - SKB_DROP_REASON_NETFILTER_DROP, /* dropped by netfilter */ - SKB_DROP_REASON_OTHERHOST, /* packet don't belong to current - * host (interface is in promisc - * mode) - */ - SKB_DROP_REASON_IP_CSUM, /* IP checksum error */ - SKB_DROP_REASON_IP_INHDR, /* there is something wrong with - * IP header (see - * IPSTATS_MIB_INHDRERRORS) - */ - SKB_DROP_REASON_IP_RPFILTER, /* IP rpfilter validate failed. - * see the document for rp_filter - * in ip-sysctl.rst for more - * information - */ - SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, /* destination address of L2 - * is multicast, but L3 is - * unicast. - */ - SKB_DROP_REASON_XFRM_POLICY, /* xfrm policy check failed */ - SKB_DROP_REASON_IP_NOPROTO, /* no support for IP protocol */ - SKB_DROP_REASON_SOCKET_RCVBUFF, /* socket receive buff is full */ - SKB_DROP_REASON_PROTO_MEM, /* proto memory limition, such as - * udp packet drop out of - * udp_memory_allocated. - */ - SKB_DROP_REASON_TCP_MD5NOTFOUND, /* no MD5 hash and one - * expected, corresponding - * to LINUX_MIB_TCPMD5NOTFOUND - */ - SKB_DROP_REASON_TCP_MD5UNEXPECTED, /* MD5 hash and we're not - * expecting one, corresponding - * to LINUX_MIB_TCPMD5UNEXPECTED - */ - SKB_DROP_REASON_TCP_MD5FAILURE, /* MD5 hash and its wrong, - * corresponding to - * LINUX_MIB_TCPMD5FAILURE - */ - SKB_DROP_REASON_SOCKET_BACKLOG, /* failed to add skb to socket - * backlog (see - * LINUX_MIB_TCPBACKLOGDROP) - */ - SKB_DROP_REASON_TCP_FLAGS, /* TCP flags invalid */ - SKB_DROP_REASON_TCP_ZEROWINDOW, /* TCP receive window size is zero, - * see LINUX_MIB_TCPZEROWINDOWDROP - */ - SKB_DROP_REASON_TCP_OLD_DATA, /* the TCP data reveived is already - * received before (spurious retrans - * may happened), see - * LINUX_MIB_DELAYEDACKLOST - */ - SKB_DROP_REASON_TCP_OVERWINDOW, /* the TCP data is out of window, - * the seq of the first byte exceed - * the right edges of receive - * window - */ - SKB_DROP_REASON_TCP_OFOMERGE, /* the data of skb is already in - * the ofo queue, corresponding to - * LINUX_MIB_TCPOFOMERGE - */ - SKB_DROP_REASON_TCP_RFC7323_PAWS, /* PAWS check, corresponding to - * LINUX_MIB_PAWSESTABREJECTED - */ - SKB_DROP_REASON_TCP_INVALID_SEQUENCE, /* Not acceptable SEQ field */ - SKB_DROP_REASON_TCP_RESET, /* Invalid RST packet */ - SKB_DROP_REASON_TCP_INVALID_SYN, /* Incoming packet has unexpected SYN flag */ - SKB_DROP_REASON_TCP_CLOSE, /* TCP socket in CLOSE state */ - SKB_DROP_REASON_TCP_FASTOPEN, /* dropped by FASTOPEN request socket */ - SKB_DROP_REASON_TCP_OLD_ACK, /* TCP ACK is old, but in window */ - SKB_DROP_REASON_TCP_TOO_OLD_ACK, /* TCP ACK is too old */ - SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, /* TCP ACK for data we haven't sent yet */ - SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, /* pruned from TCP OFO queue */ - SKB_DROP_REASON_TCP_OFO_DROP, /* data already in receive queue */ - SKB_DROP_REASON_IP_OUTNOROUTES, /* route lookup failed */ - SKB_DROP_REASON_BPF_CGROUP_EGRESS, /* dropped by - * BPF_PROG_TYPE_CGROUP_SKB - * eBPF program - */ - SKB_DROP_REASON_IPV6DISABLED, /* IPv6 is disabled on the device */ - SKB_DROP_REASON_NEIGH_CREATEFAIL, /* failed to create neigh - * entry - */ - SKB_DROP_REASON_NEIGH_FAILED, /* neigh entry in failed state */ - SKB_DROP_REASON_NEIGH_QUEUEFULL, /* arp_queue for neigh - * entry is full - */ - SKB_DROP_REASON_NEIGH_DEAD, /* neigh entry is dead */ - SKB_DROP_REASON_TC_EGRESS, /* dropped in TC egress HOOK */ - SKB_DROP_REASON_QDISC_DROP, /* dropped by qdisc when packet - * outputting (failed to enqueue to - * current qdisc) - */ - SKB_DROP_REASON_CPU_BACKLOG, /* failed to enqueue the skb to - * the per CPU backlog queue. This - * can be caused by backlog queue - * full (see netdev_max_backlog in - * net.rst) or RPS flow limit - */ - SKB_DROP_REASON_XDP, /* dropped by XDP in input path */ - SKB_DROP_REASON_TC_INGRESS, /* dropped in TC ingress HOOK */ - SKB_DROP_REASON_UNHANDLED_PROTO, /* protocol not implemented - * or not supported - */ - SKB_DROP_REASON_SKB_CSUM, /* sk_buff checksum computation - * error - */ - SKB_DROP_REASON_SKB_GSO_SEG, /* gso segmentation error */ - SKB_DROP_REASON_SKB_UCOPY_FAULT, /* failed to copy data from - * user space, e.g., via - * zerocopy_sg_from_iter() - * or skb_orphan_frags_rx() - */ - SKB_DROP_REASON_DEV_HDR, /* device driver specific - * header/metadata is invalid - */ - /* the device is not ready to xmit/recv due to any of its data - * structure that is not up/ready/initialized, e.g., the IFF_UP is - * not set, or driver specific tun->tfiles[txq] is not initialized + /** @SKB_DROP_REASON_NOT_SPECIFIED: drop reason is not specified */ + SKB_DROP_REASON_NOT_SPECIFIED, + /** @SKB_DROP_REASON_NO_SOCKET: socket not found */ + SKB_DROP_REASON_NO_SOCKET, + /** @SKB_DROP_REASON_PKT_TOO_SMALL: packet size is too small */ + SKB_DROP_REASON_PKT_TOO_SMALL, + /** @SKB_DROP_REASON_TCP_CSUM: TCP checksum error */ + SKB_DROP_REASON_TCP_CSUM, + /** @SKB_DROP_REASON_SOCKET_FILTER: dropped by socket filter */ + SKB_DROP_REASON_SOCKET_FILTER, + /** @SKB_DROP_REASON_UDP_CSUM: UDP checksum error */ + SKB_DROP_REASON_UDP_CSUM, + /** @SKB_DROP_REASON_NETFILTER_DROP: dropped by netfilter */ + SKB_DROP_REASON_NETFILTER_DROP, + /** + * @SKB_DROP_REASON_OTHERHOST: packet don't belong to current host + * (interface is in promisc mode) + */ + SKB_DROP_REASON_OTHERHOST, + /** @SKB_DROP_REASON_IP_CSUM: IP checksum error */ + SKB_DROP_REASON_IP_CSUM, + /** + * @SKB_DROP_REASON_IP_INHDR: there is something wrong with IP header (see + * IPSTATS_MIB_INHDRERRORS) + */ + SKB_DROP_REASON_IP_INHDR, + /** + * @SKB_DROP_REASON_IP_RPFILTER: IP rpfilter validate failed. see the + * document for rp_filter in ip-sysctl.rst for more information + */ + SKB_DROP_REASON_IP_RPFILTER, + /** + * @SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST: destination address of L2 is + * multicast, but L3 is unicast. + */ + SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, + /** @SKB_DROP_REASON_XFRM_POLICY: xfrm policy check failed */ + SKB_DROP_REASON_XFRM_POLICY, + /** @SKB_DROP_REASON_IP_NOPROTO: no support for IP protocol */ + SKB_DROP_REASON_IP_NOPROTO, + /** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */ + SKB_DROP_REASON_SOCKET_RCVBUFF, + /** + * @SKB_DROP_REASON_PROTO_MEM: proto memory limition, such as udp packet + * drop out of udp_memory_allocated. + */ + SKB_DROP_REASON_PROTO_MEM, + /** + * @SKB_DROP_REASON_TCP_MD5NOTFOUND: no MD5 hash and one expected, + * corresponding to LINUX_MIB_TCPMD5NOTFOUND + */ + SKB_DROP_REASON_TCP_MD5NOTFOUND, + /** + * @SKB_DROP_REASON_TCP_MD5UNEXPECTED: MD5 hash and we're not expecting + * one, corresponding to LINUX_MIB_TCPMD5UNEXPECTED + */ + SKB_DROP_REASON_TCP_MD5UNEXPECTED, + /** + * @SKB_DROP_REASON_TCP_MD5FAILURE: MD5 hash and its wrong, corresponding + * to LINUX_MIB_TCPMD5FAILURE + */ + SKB_DROP_REASON_TCP_MD5FAILURE, + /** + * @SKB_DROP_REASON_SOCKET_BACKLOG: failed to add skb to socket backlog ( + * see LINUX_MIB_TCPBACKLOGDROP) + */ + SKB_DROP_REASON_SOCKET_BACKLOG, + /** @SKB_DROP_REASON_TCP_FLAGS: TCP flags invalid */ + SKB_DROP_REASON_TCP_FLAGS, + /** + * @SKB_DROP_REASON_TCP_ZEROWINDOW: TCP receive window size is zero, + * see LINUX_MIB_TCPZEROWINDOWDROP + */ + SKB_DROP_REASON_TCP_ZEROWINDOW, + /** + * @SKB_DROP_REASON_TCP_OLD_DATA: the TCP data reveived is already + * received before (spurious retrans may happened), see + * LINUX_MIB_DELAYEDACKLOST + */ + SKB_DROP_REASON_TCP_OLD_DATA, + /** + * @SKB_DROP_REASON_TCP_OVERWINDOW: the TCP data is out of window, + * the seq of the first byte exceed the right edges of receive + * window + */ + SKB_DROP_REASON_TCP_OVERWINDOW, + /** + * @SKB_DROP_REASON_TCP_OFOMERGE: the data of skb is already in the ofo + * queue, corresponding to LINUX_MIB_TCPOFOMERGE + */ + SKB_DROP_REASON_TCP_OFOMERGE, + /** + * @SKB_DROP_REASON_TCP_RFC7323_PAWS: PAWS check, corresponding to + * LINUX_MIB_PAWSESTABREJECTED + */ + SKB_DROP_REASON_TCP_RFC7323_PAWS, + /** @SKB_DROP_REASON_TCP_INVALID_SEQUENCE: Not acceptable SEQ field */ + SKB_DROP_REASON_TCP_INVALID_SEQUENCE, + /** @SKB_DROP_REASON_TCP_RESET: Invalid RST packet */ + SKB_DROP_REASON_TCP_RESET, + /** + * @SKB_DROP_REASON_TCP_INVALID_SYN: Incoming packet has unexpected + * SYN flag + */ + SKB_DROP_REASON_TCP_INVALID_SYN, + /** @SKB_DROP_REASON_TCP_CLOSE: TCP socket in CLOSE state */ + SKB_DROP_REASON_TCP_CLOSE, + /** @SKB_DROP_REASON_TCP_FASTOPEN: dropped by FASTOPEN request socket */ + SKB_DROP_REASON_TCP_FASTOPEN, + /** @SKB_DROP_REASON_TCP_OLD_ACK: TCP ACK is old, but in window */ + SKB_DROP_REASON_TCP_OLD_ACK, + /** @SKB_DROP_REASON_TCP_TOO_OLD_ACK: TCP ACK is too old */ + SKB_DROP_REASON_TCP_TOO_OLD_ACK, + /** + * @SKB_DROP_REASON_TCP_ACK_UNSENT_DATA: TCP ACK for data we haven't + * sent yet + */ + SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, + /** @SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE: pruned from TCP OFO queue */ + SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, + /** @SKB_DROP_REASON_TCP_OFO_DROP: data already in receive queue */ + SKB_DROP_REASON_TCP_OFO_DROP, + /** @SKB_DROP_REASON_IP_OUTNOROUTES: route lookup failed */ + SKB_DROP_REASON_IP_OUTNOROUTES, + /** + * @SKB_DROP_REASON_BPF_CGROUP_EGRESS: dropped by BPF_PROG_TYPE_CGROUP_SKB + * eBPF program + */ + SKB_DROP_REASON_BPF_CGROUP_EGRESS, + /** @SKB_DROP_REASON_IPV6DISABLED: IPv6 is disabled on the device */ + SKB_DROP_REASON_IPV6DISABLED, + /** @SKB_DROP_REASON_NEIGH_CREATEFAIL: failed to create neigh entry */ + SKB_DROP_REASON_NEIGH_CREATEFAIL, + /** @SKB_DROP_REASON_NEIGH_FAILED: neigh entry in failed state */ + SKB_DROP_REASON_NEIGH_FAILED, + /** @SKB_DROP_REASON_NEIGH_QUEUEFULL: arp_queue for neigh entry is full */ + SKB_DROP_REASON_NEIGH_QUEUEFULL, + /** @SKB_DROP_REASON_NEIGH_DEAD: neigh entry is dead */ + SKB_DROP_REASON_NEIGH_DEAD, + /** @SKB_DROP_REASON_TC_EGRESS: dropped in TC egress HOOK */ + SKB_DROP_REASON_TC_EGRESS, + /** + * @SKB_DROP_REASON_QDISC_DROP: dropped by qdisc when packet outputting ( + * failed to enqueue to current qdisc) + */ + SKB_DROP_REASON_QDISC_DROP, + /** + * @SKB_DROP_REASON_CPU_BACKLOG: failed to enqueue the skb to the per CPU + * backlog queue. This can be caused by backlog queue full (see + * netdev_max_backlog in net.rst) or RPS flow limit + */ + SKB_DROP_REASON_CPU_BACKLOG, + /** @SKB_DROP_REASON_XDP: dropped by XDP in input path */ + SKB_DROP_REASON_XDP, + /** @SKB_DROP_REASON_TC_INGRESS: dropped in TC ingress HOOK */ + SKB_DROP_REASON_TC_INGRESS, + /** @SKB_DROP_REASON_UNHANDLED_PROTO: protocol not implemented or not supported */ + SKB_DROP_REASON_UNHANDLED_PROTO, + /** @SKB_DROP_REASON_SKB_CSUM: sk_buff checksum computation error */ + SKB_DROP_REASON_SKB_CSUM, + /** @SKB_DROP_REASON_SKB_GSO_SEG: gso segmentation error */ + SKB_DROP_REASON_SKB_GSO_SEG, + /** + * @SKB_DROP_REASON_SKB_UCOPY_FAULT: failed to copy data from user space, + * e.g., via zerocopy_sg_from_iter() or skb_orphan_frags_rx() + */ + SKB_DROP_REASON_SKB_UCOPY_FAULT, + /** @SKB_DROP_REASON_DEV_HDR: device driver specific header/metadata is invalid */ + SKB_DROP_REASON_DEV_HDR, + /** + * @SKB_DROP_REASON_DEV_READY: the device is not ready to xmit/recv due to + * any of its data structure that is not up/ready/initialized, + * e.g., the IFF_UP is not set, or driver specific tun->tfiles[txq] + * is not initialized */ SKB_DROP_REASON_DEV_READY, - SKB_DROP_REASON_FULL_RING, /* ring buffer is full */ - SKB_DROP_REASON_NOMEM, /* error due to OOM */ - SKB_DROP_REASON_HDR_TRUNC, /* failed to trunc/extract the header - * from networking data, e.g., failed - * to pull the protocol header from - * frags via pskb_may_pull() - */ - SKB_DROP_REASON_TAP_FILTER, /* dropped by (ebpf) filter directly - * attached to tun/tap, e.g., via - * TUNSETFILTEREBPF - */ - SKB_DROP_REASON_TAP_TXFILTER, /* dropped by tx filter implemented - * at tun/tap, e.g., check_filter() - */ - SKB_DROP_REASON_ICMP_CSUM, /* ICMP checksum error */ - SKB_DROP_REASON_INVALID_PROTO, /* the packet doesn't follow RFC - * 2211, such as a broadcasts - * ICMP_TIMESTAMP - */ - SKB_DROP_REASON_IP_INADDRERRORS, /* host unreachable, corresponding - * to IPSTATS_MIB_INADDRERRORS - */ - SKB_DROP_REASON_IP_INNOROUTES, /* network unreachable, corresponding - * to IPSTATS_MIB_INADDRERRORS - */ - SKB_DROP_REASON_PKT_TOO_BIG, /* packet size is too big (maybe exceed - * the MTU) - */ + /** @SKB_DROP_REASON_FULL_RING: ring buffer is full */ + SKB_DROP_REASON_FULL_RING, + /** @SKB_DROP_REASON_NOMEM: error due to OOM */ + SKB_DROP_REASON_NOMEM, + /** + * @SKB_DROP_REASON_HDR_TRUNC: failed to trunc/extract the header from + * networking data, e.g., failed to pull the protocol header from + * frags via pskb_may_pull() + */ + SKB_DROP_REASON_HDR_TRUNC, + /** + * @SKB_DROP_REASON_TAP_FILTER: dropped by (ebpf) filter directly attached + * to tun/tap, e.g., via TUNSETFILTEREBPF + */ + SKB_DROP_REASON_TAP_FILTER, + /** + * @SKB_DROP_REASON_TAP_TXFILTER: dropped by tx filter implemented at + * tun/tap, e.g., check_filter() + */ + SKB_DROP_REASON_TAP_TXFILTER, + /** @SKB_DROP_REASON_ICMP_CSUM: ICMP checksum error */ + SKB_DROP_REASON_ICMP_CSUM, + /** + * @SKB_DROP_REASON_INVALID_PROTO: the packet doesn't follow RFC 2211, + * such as a broadcasts ICMP_TIMESTAMP + */ + SKB_DROP_REASON_INVALID_PROTO, + /** + * @SKB_DROP_REASON_IP_INADDRERRORS: host unreachable, corresponding to + * IPSTATS_MIB_INADDRERRORS + */ + SKB_DROP_REASON_IP_INADDRERRORS, + /** + * @SKB_DROP_REASON_IP_INNOROUTES: network unreachable, corresponding to + * IPSTATS_MIB_INADDRERRORS + */ + SKB_DROP_REASON_IP_INNOROUTES, + /** + * @SKB_DROP_REASON_PKT_TOO_BIG: packet size is too big (maybe exceed the + * MTU) + */ + SKB_DROP_REASON_PKT_TOO_BIG, + /** + * @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be + * used as a real 'reason' + */ SKB_DROP_REASON_MAX, }; -- cgit v1.2.3 From e6f08af6340eaf88e9eeff71bd4533eee9a04119 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 5 Jun 2022 17:35:37 +0200 Subject: ASoC: simple-card-utils: Make asoc_simple_clean_reference() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit asoc_simple_clean_reference() returns zero unconditionally. Letting it return void instead makes it easier to see in the caller that there is no error to handle. This is a preparation for making platform remove callbacks return void. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220605153537.26591-1-u.kleine-koenig@pengutronix.de Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/simple-card-utils.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 8faa649f712b..fe2337fde1f4 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -173,7 +173,7 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platfo void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, int is_single_links); -int asoc_simple_clean_reference(struct snd_soc_card *card); +void asoc_simple_clean_reference(struct snd_soc_card *card); void asoc_simple_convert_fixup(struct asoc_simple_data *data, struct snd_pcm_hw_params *params); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index fa080f166345..0beda9739ebe 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -609,7 +609,7 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, } EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu); -int asoc_simple_clean_reference(struct snd_soc_card *card) +void asoc_simple_clean_reference(struct snd_soc_card *card) { struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link_component *cpu; @@ -622,7 +622,6 @@ int asoc_simple_clean_reference(struct snd_soc_card *card) for_each_link_codecs(dai_link, j, codec) of_node_put(codec->of_node); } - return 0; } EXPORT_SYMBOL_GPL(asoc_simple_clean_reference); @@ -877,7 +876,9 @@ int asoc_simple_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - return asoc_simple_clean_reference(card); + asoc_simple_clean_reference(card); + + return 0; } EXPORT_SYMBOL_GPL(asoc_simple_remove); -- cgit v1.2.3 From 5f69a6577bc33d8f6d6bbe02bccdeb357b287f56 Mon Sep 17 00:00:00 2001 From: Chen Wandun Date: Thu, 26 May 2022 20:26:56 +0800 Subject: psi: dont alloc memory for psi by default Memory about struct psi_group is allocated by default for each cgroup even if psi_disabled is true, in this case, these allocated memory is waste, so alloc memory for struct psi_group only when psi_disabled is false. Signed-off-by: Chen Wandun Acked-by: Johannes Weiner Signed-off-by: Tejun Heo --- include/linux/cgroup-defs.h | 2 +- include/linux/cgroup.h | 2 +- kernel/cgroup/cgroup.c | 8 ++++---- kernel/sched/psi.c | 19 +++++++++++++------ 4 files changed, 19 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 1bfcfb1af352..672de25e3ec8 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -475,7 +475,7 @@ struct cgroup { struct work_struct release_agent_work; /* used to track pressure stalls */ - struct psi_group psi; + struct psi_group *psi; /* used to store eBPF programs */ struct cgroup_bpf bpf; diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 0d1ada8968d7..ed53bfe7c46c 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -674,7 +674,7 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp) static inline struct psi_group *cgroup_psi(struct cgroup *cgrp) { - return &cgrp->psi; + return cgrp->psi; } bool cgroup_psi_enabled(void); diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 1779ccddb734..90a654cb8a1e 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -3609,21 +3609,21 @@ static int cpu_stat_show(struct seq_file *seq, void *v) static int cgroup_io_pressure_show(struct seq_file *seq, void *v) { struct cgroup *cgrp = seq_css(seq)->cgroup; - struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi; + struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi; return psi_show(seq, psi, PSI_IO); } static int cgroup_memory_pressure_show(struct seq_file *seq, void *v) { struct cgroup *cgrp = seq_css(seq)->cgroup; - struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi; + struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi; return psi_show(seq, psi, PSI_MEM); } static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) { struct cgroup *cgrp = seq_css(seq)->cgroup; - struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi; + struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi; return psi_show(seq, psi, PSI_CPU); } @@ -3649,7 +3649,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf, return -EBUSY; } - psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi; + psi = cgroup_ino(cgrp) == 1 ? &psi_system : cgrp->psi; new = psi_trigger_create(psi, buf, nbytes, res); if (IS_ERR(new)) { cgroup_put(cgrp); diff --git a/kernel/sched/psi.c b/kernel/sched/psi.c index a337f3e35997..ec66b40bdd40 100644 --- a/kernel/sched/psi.c +++ b/kernel/sched/psi.c @@ -957,10 +957,16 @@ int psi_cgroup_alloc(struct cgroup *cgroup) if (static_branch_likely(&psi_disabled)) return 0; - cgroup->psi.pcpu = alloc_percpu(struct psi_group_cpu); - if (!cgroup->psi.pcpu) + cgroup->psi = kmalloc(sizeof(struct psi_group), GFP_KERNEL); + if (!cgroup->psi) return -ENOMEM; - group_init(&cgroup->psi); + + cgroup->psi->pcpu = alloc_percpu(struct psi_group_cpu); + if (!cgroup->psi->pcpu) { + kfree(cgroup->psi); + return -ENOMEM; + } + group_init(cgroup->psi); return 0; } @@ -969,10 +975,11 @@ void psi_cgroup_free(struct cgroup *cgroup) if (static_branch_likely(&psi_disabled)) return; - cancel_delayed_work_sync(&cgroup->psi.avgs_work); - free_percpu(cgroup->psi.pcpu); + cancel_delayed_work_sync(&cgroup->psi->avgs_work); + free_percpu(cgroup->psi->pcpu); /* All triggers must be removed by now */ - WARN_ONCE(cgroup->psi.poll_states, "psi: trigger leak\n"); + WARN_ONCE(cgroup->psi->poll_states, "psi: trigger leak\n"); + kfree(cgroup->psi); } /** -- cgit v1.2.3 From 6089fb325cf737eeb2c4d236c94697112ca860da Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Mon, 6 Jun 2022 23:26:00 -0700 Subject: bpf: Add btf enum64 support Currently, BTF only supports upto 32bit enum value with BTF_KIND_ENUM. But in kernel, some enum indeed has 64bit values, e.g., in uapi bpf.h, we have enum { BPF_F_INDEX_MASK = 0xffffffffULL, BPF_F_CURRENT_CPU = BPF_F_INDEX_MASK, BPF_F_CTXLEN_MASK = (0xfffffULL << 32), }; In this case, BTF_KIND_ENUM will encode the value of BPF_F_CTXLEN_MASK as 0, which certainly is incorrect. This patch added a new btf kind, BTF_KIND_ENUM64, which permits 64bit value to cover the above use case. The BTF_KIND_ENUM64 has the following three fields followed by the common type: struct bpf_enum64 { __u32 nume_off; __u32 val_lo32; __u32 val_hi32; }; Currently, btf type section has an alignment of 4 as all element types are u32. Representing the value with __u64 will introduce a pad for bpf_enum64 and may also introduce misalignment for the 64bit value. Hence, two members of val_hi32 and val_lo32 are chosen to avoid these issues. The kflag is also introduced for BTF_KIND_ENUM and BTF_KIND_ENUM64 to indicate whether the value is signed or unsigned. The kflag intends to provide consistent output of BTF C fortmat with the original source code. For example, the original BTF_KIND_ENUM bit value is 0xffffffff. The format C has two choices, printing out 0xffffffff or -1 and current libbpf prints out as unsigned value. But if the signedness is preserved in btf, the value can be printed the same as the original source code. The kflag value 0 means unsigned values, which is consistent to the default by libbpf and should also cover most cases as well. The new BTF_KIND_ENUM64 is intended to support the enum value represented as 64bit value. But it can represent all BTF_KIND_ENUM values as well. The compiler ([1]) and pahole will generate BTF_KIND_ENUM64 only if the value has to be represented with 64 bits. In addition, a static inline function btf_kind_core_compat() is introduced which will be used later when libbpf relo_core.c changed. Here the kernel shares the same relo_core.c with libbpf. [1] https://reviews.llvm.org/D124641 Acked-by: Andrii Nakryiko Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20220607062600.3716578-1-yhs@fb.com Signed-off-by: Alexei Starovoitov --- include/linux/btf.h | 28 ++++++++ include/uapi/linux/btf.h | 17 ++++- kernel/bpf/btf.c | 142 +++++++++++++++++++++++++++++++++++++---- kernel/bpf/verifier.c | 2 +- tools/include/uapi/linux/btf.h | 17 ++++- 5 files changed, 185 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/linux/btf.h b/include/linux/btf.h index 2611cea2c2b6..1bfed7fa0428 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -177,6 +177,19 @@ static inline bool btf_type_is_enum(const struct btf_type *t) return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM; } +static inline bool btf_is_any_enum(const struct btf_type *t) +{ + return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM || + BTF_INFO_KIND(t->info) == BTF_KIND_ENUM64; +} + +static inline bool btf_kind_core_compat(const struct btf_type *t1, + const struct btf_type *t2) +{ + return BTF_INFO_KIND(t1->info) == BTF_INFO_KIND(t2->info) || + (btf_is_any_enum(t1) && btf_is_any_enum(t2)); +} + static inline bool str_is_empty(const char *s) { return !s || !s[0]; @@ -192,6 +205,16 @@ static inline bool btf_is_enum(const struct btf_type *t) return btf_kind(t) == BTF_KIND_ENUM; } +static inline bool btf_is_enum64(const struct btf_type *t) +{ + return btf_kind(t) == BTF_KIND_ENUM64; +} + +static inline u64 btf_enum64_value(const struct btf_enum64 *e) +{ + return ((u64)e->val_hi32 << 32) | e->val_lo32; +} + static inline bool btf_is_composite(const struct btf_type *t) { u16 kind = btf_kind(t); @@ -332,6 +355,11 @@ static inline struct btf_enum *btf_enum(const struct btf_type *t) return (struct btf_enum *)(t + 1); } +static inline struct btf_enum64 *btf_enum64(const struct btf_type *t) +{ + return (struct btf_enum64 *)(t + 1); +} + static inline const struct btf_var_secinfo *btf_type_var_secinfo( const struct btf_type *t) { diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h index a9162a6c0284..ec1798b6d3ff 100644 --- a/include/uapi/linux/btf.h +++ b/include/uapi/linux/btf.h @@ -36,10 +36,10 @@ struct btf_type { * bits 24-28: kind (e.g. int, ptr, array...etc) * bits 29-30: unused * bit 31: kind_flag, currently used by - * struct, union and fwd + * struct, union, enum, fwd and enum64 */ __u32 info; - /* "size" is used by INT, ENUM, STRUCT, UNION and DATASEC. + /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64. * "size" tells the size of the type it is describing. * * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, @@ -63,7 +63,7 @@ enum { BTF_KIND_ARRAY = 3, /* Array */ BTF_KIND_STRUCT = 4, /* Struct */ BTF_KIND_UNION = 5, /* Union */ - BTF_KIND_ENUM = 6, /* Enumeration */ + BTF_KIND_ENUM = 6, /* Enumeration up to 32-bit values */ BTF_KIND_FWD = 7, /* Forward */ BTF_KIND_TYPEDEF = 8, /* Typedef */ BTF_KIND_VOLATILE = 9, /* Volatile */ @@ -76,6 +76,7 @@ enum { BTF_KIND_FLOAT = 16, /* Floating point */ BTF_KIND_DECL_TAG = 17, /* Decl Tag */ BTF_KIND_TYPE_TAG = 18, /* Type Tag */ + BTF_KIND_ENUM64 = 19, /* Enumeration up to 64-bit values */ NR_BTF_KINDS, BTF_KIND_MAX = NR_BTF_KINDS - 1, @@ -186,4 +187,14 @@ struct btf_decl_tag { __s32 component_idx; }; +/* BTF_KIND_ENUM64 is followed by multiple "struct btf_enum64". + * The exact number of btf_enum64 is stored in the vlen (of the + * info in "struct btf_type"). + */ +struct btf_enum64 { + __u32 name_off; + __u32 val_lo32; + __u32 val_hi32; +}; + #endif /* _UAPI__LINUX_BTF_H__ */ diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 7bccaa4646e5..6c0d8480e15c 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -309,6 +309,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { [BTF_KIND_FLOAT] = "FLOAT", [BTF_KIND_DECL_TAG] = "DECL_TAG", [BTF_KIND_TYPE_TAG] = "TYPE_TAG", + [BTF_KIND_ENUM64] = "ENUM64", }; const char *btf_type_str(const struct btf_type *t) @@ -666,6 +667,7 @@ static bool btf_type_has_size(const struct btf_type *t) case BTF_KIND_ENUM: case BTF_KIND_DATASEC: case BTF_KIND_FLOAT: + case BTF_KIND_ENUM64: return true; } @@ -711,6 +713,11 @@ static const struct btf_decl_tag *btf_type_decl_tag(const struct btf_type *t) return (const struct btf_decl_tag *)(t + 1); } +static const struct btf_enum64 *btf_type_enum64(const struct btf_type *t) +{ + return (const struct btf_enum64 *)(t + 1); +} + static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) { return kind_ops[BTF_INFO_KIND(t->info)]; @@ -1019,6 +1026,7 @@ static const char *btf_show_name(struct btf_show *show) parens = "{"; break; case BTF_KIND_ENUM: + case BTF_KIND_ENUM64: prefix = "enum"; break; default: @@ -1834,6 +1842,7 @@ __btf_resolve_size(const struct btf *btf, const struct btf_type *type, case BTF_KIND_UNION: case BTF_KIND_ENUM: case BTF_KIND_FLOAT: + case BTF_KIND_ENUM64: size = type->size; goto resolved; @@ -3670,6 +3679,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env, { const struct btf_enum *enums = btf_type_enum(t); struct btf *btf = env->btf; + const char *fmt_str; u16 i, nr_enums; u32 meta_needed; @@ -3683,11 +3693,6 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env, return -EINVAL; } - if (btf_type_kflag(t)) { - btf_verifier_log_type(env, t, "Invalid btf_info kind_flag"); - return -EINVAL; - } - if (t->size > 8 || !is_power_of_2(t->size)) { btf_verifier_log_type(env, t, "Unexpected size"); return -EINVAL; @@ -3718,7 +3723,8 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env, if (env->log.level == BPF_LOG_KERNEL) continue; - btf_verifier_log(env, "\t%s val=%d\n", + fmt_str = btf_type_kflag(t) ? "\t%s val=%d\n" : "\t%s val=%u\n"; + btf_verifier_log(env, fmt_str, __btf_name_by_offset(btf, enums[i].name_off), enums[i].val); } @@ -3759,7 +3765,10 @@ static void btf_enum_show(const struct btf *btf, const struct btf_type *t, return; } - btf_show_type_value(show, "%d", v); + if (btf_type_kflag(t)) + btf_show_type_value(show, "%d", v); + else + btf_show_type_value(show, "%u", v); btf_show_end_type(show); } @@ -3772,6 +3781,109 @@ static struct btf_kind_operations enum_ops = { .show = btf_enum_show, }; +static s32 btf_enum64_check_meta(struct btf_verifier_env *env, + const struct btf_type *t, + u32 meta_left) +{ + const struct btf_enum64 *enums = btf_type_enum64(t); + struct btf *btf = env->btf; + const char *fmt_str; + u16 i, nr_enums; + u32 meta_needed; + + nr_enums = btf_type_vlen(t); + meta_needed = nr_enums * sizeof(*enums); + + if (meta_left < meta_needed) { + btf_verifier_log_basic(env, t, + "meta_left:%u meta_needed:%u", + meta_left, meta_needed); + return -EINVAL; + } + + if (t->size > 8 || !is_power_of_2(t->size)) { + btf_verifier_log_type(env, t, "Unexpected size"); + return -EINVAL; + } + + /* enum type either no name or a valid one */ + if (t->name_off && + !btf_name_valid_identifier(env->btf, t->name_off)) { + btf_verifier_log_type(env, t, "Invalid name"); + return -EINVAL; + } + + btf_verifier_log_type(env, t, NULL); + + for (i = 0; i < nr_enums; i++) { + if (!btf_name_offset_valid(btf, enums[i].name_off)) { + btf_verifier_log(env, "\tInvalid name_offset:%u", + enums[i].name_off); + return -EINVAL; + } + + /* enum member must have a valid name */ + if (!enums[i].name_off || + !btf_name_valid_identifier(btf, enums[i].name_off)) { + btf_verifier_log_type(env, t, "Invalid name"); + return -EINVAL; + } + + if (env->log.level == BPF_LOG_KERNEL) + continue; + + fmt_str = btf_type_kflag(t) ? "\t%s val=%lld\n" : "\t%s val=%llu\n"; + btf_verifier_log(env, fmt_str, + __btf_name_by_offset(btf, enums[i].name_off), + btf_enum64_value(enums + i)); + } + + return meta_needed; +} + +static void btf_enum64_show(const struct btf *btf, const struct btf_type *t, + u32 type_id, void *data, u8 bits_offset, + struct btf_show *show) +{ + const struct btf_enum64 *enums = btf_type_enum64(t); + u32 i, nr_enums = btf_type_vlen(t); + void *safe_data; + s64 v; + + safe_data = btf_show_start_type(show, t, type_id, data); + if (!safe_data) + return; + + v = *(u64 *)safe_data; + + for (i = 0; i < nr_enums; i++) { + if (v != btf_enum64_value(enums + i)) + continue; + + btf_show_type_value(show, "%s", + __btf_name_by_offset(btf, + enums[i].name_off)); + + btf_show_end_type(show); + return; + } + + if (btf_type_kflag(t)) + btf_show_type_value(show, "%lld", v); + else + btf_show_type_value(show, "%llu", v); + btf_show_end_type(show); +} + +static struct btf_kind_operations enum64_ops = { + .check_meta = btf_enum64_check_meta, + .resolve = btf_df_resolve, + .check_member = btf_enum_check_member, + .check_kflag_member = btf_enum_check_kflag_member, + .log_details = btf_enum_log, + .show = btf_enum64_show, +}; + static s32 btf_func_proto_check_meta(struct btf_verifier_env *env, const struct btf_type *t, u32 meta_left) @@ -4438,6 +4550,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = { [BTF_KIND_FLOAT] = &float_ops, [BTF_KIND_DECL_TAG] = &decl_tag_ops, [BTF_KIND_TYPE_TAG] = &modifier_ops, + [BTF_KIND_ENUM64] = &enum64_ops, }; static s32 btf_check_meta(struct btf_verifier_env *env, @@ -5299,7 +5412,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type, /* skip modifiers */ while (btf_type_is_modifier(t)) t = btf_type_by_id(btf, t->type); - if (btf_type_is_small_int(t) || btf_type_is_enum(t)) + if (btf_type_is_small_int(t) || btf_is_any_enum(t)) /* accessing a scalar */ return true; if (!btf_type_is_ptr(t)) { @@ -5763,7 +5876,7 @@ static int __get_type_size(struct btf *btf, u32 btf_id, if (btf_type_is_ptr(t)) /* kernel size of pointer. Not BPF's size of pointer*/ return sizeof(void *); - if (btf_type_is_int(t) || btf_type_is_enum(t)) + if (btf_type_is_int(t) || btf_is_any_enum(t)) return t->size; *bad_type = t; return -EINVAL; @@ -5911,7 +6024,7 @@ static int btf_check_func_type_match(struct bpf_verifier_log *log, * to context only. And only global functions can be replaced. * Hence type check only those types. */ - if (btf_type_is_int(t1) || btf_type_is_enum(t1)) + if (btf_type_is_int(t1) || btf_is_any_enum(t1)) continue; if (!btf_type_is_ptr(t1)) { bpf_log(log, @@ -6408,7 +6521,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog, t = btf_type_by_id(btf, t->type); while (btf_type_is_modifier(t)) t = btf_type_by_id(btf, t->type); - if (!btf_type_is_int(t) && !btf_type_is_enum(t)) { + if (!btf_type_is_int(t) && !btf_is_any_enum(t)) { bpf_log(log, "Global function %s() doesn't return scalar. Only those are supported.\n", tname); @@ -6423,7 +6536,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog, t = btf_type_by_id(btf, args[i].type); while (btf_type_is_modifier(t)) t = btf_type_by_id(btf, t->type); - if (btf_type_is_int(t) || btf_type_is_enum(t)) { + if (btf_type_is_int(t) || btf_is_any_enum(t)) { reg->type = SCALAR_VALUE; continue; } @@ -7335,6 +7448,7 @@ recur: case BTF_KIND_UNION: case BTF_KIND_ENUM: case BTF_KIND_FWD: + case BTF_KIND_ENUM64: return 1; case BTF_KIND_INT: /* just reject deprecated bitfield-like integers; all other @@ -7387,10 +7501,10 @@ recur: * field-based relocations. This function assumes that root types were already * checked for name match. Beyond that initial root-level name check, names * are completely ignored. Compatibility rules are as follows: - * - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs are considered compatible, but + * - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs/ENUM64s are considered compatible, but * kind should match for local and target types (i.e., STRUCT is not * compatible with UNION); - * - for ENUMs, the size is ignored; + * - for ENUMs/ENUM64s, the size is ignored; * - for INT, size and signedness are ignored; * - for ARRAY, dimensionality is ignored, element types are checked for * compatibility recursively; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index aedac2ac02b9..2d2872682278 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10901,7 +10901,7 @@ static int check_btf_func(struct bpf_verifier_env *env, goto err_free; ret_type = btf_type_skip_modifiers(btf, func_proto->type, NULL); scalar_return = - btf_type_is_small_int(ret_type) || btf_type_is_enum(ret_type); + btf_type_is_small_int(ret_type) || btf_is_any_enum(ret_type); if (i && !scalar_return && env->subprog_info[i].has_ld_abs) { verbose(env, "LD_ABS is only allowed in functions that return 'int'.\n"); goto err_free; diff --git a/tools/include/uapi/linux/btf.h b/tools/include/uapi/linux/btf.h index a9162a6c0284..ec1798b6d3ff 100644 --- a/tools/include/uapi/linux/btf.h +++ b/tools/include/uapi/linux/btf.h @@ -36,10 +36,10 @@ struct btf_type { * bits 24-28: kind (e.g. int, ptr, array...etc) * bits 29-30: unused * bit 31: kind_flag, currently used by - * struct, union and fwd + * struct, union, enum, fwd and enum64 */ __u32 info; - /* "size" is used by INT, ENUM, STRUCT, UNION and DATASEC. + /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64. * "size" tells the size of the type it is describing. * * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, @@ -63,7 +63,7 @@ enum { BTF_KIND_ARRAY = 3, /* Array */ BTF_KIND_STRUCT = 4, /* Struct */ BTF_KIND_UNION = 5, /* Union */ - BTF_KIND_ENUM = 6, /* Enumeration */ + BTF_KIND_ENUM = 6, /* Enumeration up to 32-bit values */ BTF_KIND_FWD = 7, /* Forward */ BTF_KIND_TYPEDEF = 8, /* Typedef */ BTF_KIND_VOLATILE = 9, /* Volatile */ @@ -76,6 +76,7 @@ enum { BTF_KIND_FLOAT = 16, /* Floating point */ BTF_KIND_DECL_TAG = 17, /* Decl Tag */ BTF_KIND_TYPE_TAG = 18, /* Type Tag */ + BTF_KIND_ENUM64 = 19, /* Enumeration up to 64-bit values */ NR_BTF_KINDS, BTF_KIND_MAX = NR_BTF_KINDS - 1, @@ -186,4 +187,14 @@ struct btf_decl_tag { __s32 component_idx; }; +/* BTF_KIND_ENUM64 is followed by multiple "struct btf_enum64". + * The exact number of btf_enum64 is stored in the vlen (of the + * info in "struct btf_type"). + */ +struct btf_enum64 { + __u32 name_off; + __u32 val_lo32; + __u32 val_hi32; +}; + #endif /* _UAPI__LINUX_BTF_H__ */ -- cgit v1.2.3 From 0e3c3b901c00364198d31482fa2552ccf2d5c899 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 6 Jun 2022 18:42:59 -0400 Subject: No need of likely/unlikely on calls of check_copy_size() it's inline and unlikely() inside of it (including the implicit one in WARN_ON_ONCE()) suffice to convince the compiler that getting false from check_copy_size() is unlikely. Spotted-by: Jens Axboe Reviewed-by: Christoph Hellwig Reviewed-by: Christian Brauner (Microsoft) Signed-off-by: Al Viro --- arch/powerpc/include/asm/uaccess.h | 2 +- arch/s390/include/asm/uaccess.h | 4 ++-- include/linux/uaccess.h | 4 ++-- include/linux/uio.h | 15 ++++++--------- 4 files changed, 11 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index 9b82b38ff867..105f200b1e31 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -348,7 +348,7 @@ copy_mc_to_kernel(void *to, const void *from, unsigned long size) static inline unsigned long __must_check copy_mc_to_user(void __user *to, const void *from, unsigned long n) { - if (likely(check_copy_size(from, n, true))) { + if (check_copy_size(from, n, true)) { if (access_ok(to, n)) { allow_write_to_user(to, n); n = copy_mc_generic((void *)to, from, n); diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index f4511e21d646..c2c9995466e0 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -39,7 +39,7 @@ _copy_from_user_key(void *to, const void __user *from, unsigned long n, unsigned static __always_inline unsigned long __must_check copy_from_user_key(void *to, const void __user *from, unsigned long n, unsigned long key) { - if (likely(check_copy_size(to, n, false))) + if (check_copy_size(to, n, false)) n = _copy_from_user_key(to, from, n, key); return n; } @@ -50,7 +50,7 @@ _copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned l static __always_inline unsigned long __must_check copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned long key) { - if (likely(check_copy_size(from, n, true))) + if (check_copy_size(from, n, true)) n = _copy_to_user_key(to, from, n, key); return n; } diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index 5a328cf02b75..47e5d374c7eb 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -148,7 +148,7 @@ _copy_to_user(void __user *, const void *, unsigned long); static __always_inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { - if (likely(check_copy_size(to, n, false))) + if (check_copy_size(to, n, false)) n = _copy_from_user(to, from, n); return n; } @@ -156,7 +156,7 @@ copy_from_user(void *to, const void __user *from, unsigned long n) static __always_inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) { - if (likely(check_copy_size(from, n, true))) + if (check_copy_size(from, n, true)) n = _copy_to_user(to, from, n); return n; } diff --git a/include/linux/uio.h b/include/linux/uio.h index 739285fe5a2f..76d305f3d4c2 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -156,19 +156,17 @@ static inline size_t copy_folio_to_iter(struct folio *folio, size_t offset, static __always_inline __must_check size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) { - if (unlikely(!check_copy_size(addr, bytes, true))) - return 0; - else + if (check_copy_size(addr, bytes, true)) return _copy_to_iter(addr, bytes, i); + return 0; } static __always_inline __must_check size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) { - if (unlikely(!check_copy_size(addr, bytes, false))) - return 0; - else + if (check_copy_size(addr, bytes, false)) return _copy_from_iter(addr, bytes, i); + return 0; } static __always_inline __must_check @@ -184,10 +182,9 @@ bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) static __always_inline __must_check size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) { - if (unlikely(!check_copy_size(addr, bytes, false))) - return 0; - else + if (check_copy_size(addr, bytes, false)) return _copy_from_iter_nocache(addr, bytes, i); + return 0; } static __always_inline __must_check -- cgit v1.2.3 From a11b80692be5c408a33ea89e3fe1a240bef8c820 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Mon, 23 May 2022 12:59:03 +0300 Subject: scsi: target: iscsi: Add upcast helpers iSCSI target is cluttered with open-coded container_of() conversions from se_nacl to iscsi_node_acl. The code could be cleaned by introducing a helper - to_iscsi_nacl() (similar to other helpers in target core). While at it, make another iSCSI conversion helper consistent and rename iscsi_tpg() helper to to_iscsi_tpg(). Link: https://lore.kernel.org/r/20220523095905.26070-2-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Konstantin Shelekhin Reviewed-by: Mike Christie Reviewed-by: Lee Duncan Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_configfs.c | 82 ++++++++++------------------ drivers/target/iscsi/iscsi_target_nego.c | 14 ++--- drivers/target/iscsi/iscsi_target_tpg.c | 3 +- include/target/iscsi/iscsi_target_core.h | 12 ++++ 4 files changed, 49 insertions(+), 62 deletions(-) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index ce14540ba650..b01b6701c144 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -210,7 +210,7 @@ static struct se_tpg_np *lio_target_call_addnptotpg( return ERR_PTR(ret); } - tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); + tpg = to_iscsi_tpg(se_tpg); ret = iscsit_get_tpg(tpg); if (ret < 0) return ERR_PTR(-EINVAL); @@ -281,9 +281,7 @@ static ssize_t iscsi_nacl_attrib_##name##_show(struct config_item *item,\ char *page) \ { \ struct se_node_acl *se_nacl = attrib_to_nacl(item); \ - struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \ - se_node_acl); \ - \ + struct iscsi_node_acl *nacl = to_iscsi_nacl(se_nacl); \ return sprintf(page, "%u\n", nacl->node_attrib.name); \ } \ \ @@ -291,8 +289,7 @@ static ssize_t iscsi_nacl_attrib_##name##_store(struct config_item *item,\ const char *page, size_t count) \ { \ struct se_node_acl *se_nacl = attrib_to_nacl(item); \ - struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \ - se_node_acl); \ + struct iscsi_node_acl *nacl = to_iscsi_nacl(se_nacl); \ u32 val; \ int ret; \ \ @@ -377,15 +374,14 @@ static ssize_t iscsi_nacl_auth_##name##_show(struct config_item *item, \ char *page) \ { \ struct se_node_acl *nacl = auth_to_nacl(item); \ - return __iscsi_nacl_auth_##name##_show(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page); \ + return __iscsi_nacl_auth_##name##_show(to_iscsi_nacl(nacl), page); \ } \ static ssize_t iscsi_nacl_auth_##name##_store(struct config_item *item, \ const char *page, size_t count) \ { \ struct se_node_acl *nacl = auth_to_nacl(item); \ - return __iscsi_nacl_auth_##name##_store(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page, count); \ + return __iscsi_nacl_auth_##name##_store(to_iscsi_nacl(nacl), \ + page, count); \ } \ \ CONFIGFS_ATTR(iscsi_nacl_auth_, name) @@ -417,8 +413,7 @@ static ssize_t iscsi_nacl_auth_##name##_show(struct config_item *item, \ char *page) \ { \ struct se_node_acl *nacl = auth_to_nacl(item); \ - return __iscsi_nacl_auth_##name##_show(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page); \ + return __iscsi_nacl_auth_##name##_show(to_iscsi_nacl(nacl), page); \ } \ \ CONFIGFS_ATTR_RO(iscsi_nacl_auth_, name) @@ -623,8 +618,7 @@ static ssize_t lio_target_nacl_cmdsn_depth_store(struct config_item *item, { struct se_node_acl *se_nacl = acl_to_nacl(item); struct se_portal_group *se_tpg = se_nacl->se_tpg; - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); struct config_item *acl_ci, *tpg_ci, *wwn_ci; u32 cmdsn_depth = 0; int ret; @@ -700,8 +694,7 @@ static struct configfs_attribute *lio_target_initiator_attrs[] = { static int lio_target_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { - struct iscsi_node_acl *acl = - container_of(se_nacl, struct iscsi_node_acl, se_node_acl); + struct iscsi_node_acl *acl = to_iscsi_nacl(se_nacl); config_group_init_type_name(&acl->node_stat_grps.iscsi_sess_stats_group, "iscsi_sess_stats", &iscsi_stat_sess_cit); @@ -720,8 +713,7 @@ static ssize_t iscsi_tpg_attrib_##name##_show(struct config_item *item, \ char *page) \ { \ struct se_portal_group *se_tpg = attrib_to_tpg(item); \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); \ ssize_t rb; \ \ if (iscsit_get_tpg(tpg) < 0) \ @@ -736,8 +728,7 @@ static ssize_t iscsi_tpg_attrib_##name##_store(struct config_item *item,\ const char *page, size_t count) \ { \ struct se_portal_group *se_tpg = attrib_to_tpg(item); \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); \ u32 val; \ int ret; \ \ @@ -800,8 +791,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { static ssize_t __iscsi_##prefix##_##name##_show(struct se_portal_group *se_tpg, \ char *page) \ { \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); \ struct iscsi_node_auth *auth = &tpg->tpg_demo_auth; \ \ if (!capable(CAP_SYS_ADMIN)) \ @@ -813,8 +803,7 @@ static ssize_t __iscsi_##prefix##_##name##_show(struct se_portal_group *se_tpg, static ssize_t __iscsi_##prefix##_##name##_store(struct se_portal_group *se_tpg,\ const char *page, size_t count) \ { \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); \ struct iscsi_node_auth *auth = &tpg->tpg_demo_auth; \ \ if (!capable(CAP_SYS_ADMIN)) \ @@ -861,8 +850,7 @@ DEF_TPG_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); static ssize_t __iscsi_##prefix##_##name##_show(struct se_portal_group *se_tpg, \ char *page) \ { \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); \ struct iscsi_node_auth *auth = &tpg->tpg_demo_auth; \ \ if (!capable(CAP_SYS_ADMIN)) \ @@ -900,8 +888,7 @@ static ssize_t iscsi_tpg_param_##name##_show(struct config_item *item, \ char *page) \ { \ struct se_portal_group *se_tpg = param_to_tpg(item); \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); \ struct iscsi_param *param; \ ssize_t rb; \ \ @@ -923,8 +910,7 @@ static ssize_t iscsi_tpg_param_##name##_store(struct config_item *item, \ const char *page, size_t count) \ { \ struct se_portal_group *se_tpg = param_to_tpg(item); \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); \ char *buf; \ int ret, len; \ \ @@ -1073,8 +1059,7 @@ free_out: static int lio_target_tiqn_enabletpg(struct se_portal_group *se_tpg, bool enable) { - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); int ret; ret = iscsit_get_tpg(tpg); @@ -1106,7 +1091,7 @@ static void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg) struct iscsi_portal_group *tpg; struct iscsi_tiqn *tiqn; - tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); + tpg = to_iscsi_tpg(se_tpg); tiqn = tpg->tpg_tiqn; /* * iscsit_tpg_del_portal_group() assumes force=1 @@ -1416,46 +1401,41 @@ static void lio_aborted_task(struct se_cmd *se_cmd) cmd->conn->conn_transport->iscsit_aborted_task(cmd->conn, cmd); } -static inline struct iscsi_portal_group *iscsi_tpg(struct se_portal_group *se_tpg) -{ - return container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); -} - static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg) { - return iscsi_tpg(se_tpg)->tpg_tiqn->tiqn; + return to_iscsi_tpg(se_tpg)->tpg_tiqn->tiqn; } static u16 lio_tpg_get_tag(struct se_portal_group *se_tpg) { - return iscsi_tpg(se_tpg)->tpgt; + return to_iscsi_tpg(se_tpg)->tpgt; } static u32 lio_tpg_get_default_depth(struct se_portal_group *se_tpg) { - return iscsi_tpg(se_tpg)->tpg_attrib.default_cmdsn_depth; + return to_iscsi_tpg(se_tpg)->tpg_attrib.default_cmdsn_depth; } static int lio_tpg_check_demo_mode(struct se_portal_group *se_tpg) { - return iscsi_tpg(se_tpg)->tpg_attrib.generate_node_acls; + return to_iscsi_tpg(se_tpg)->tpg_attrib.generate_node_acls; } static int lio_tpg_check_demo_mode_cache(struct se_portal_group *se_tpg) { - return iscsi_tpg(se_tpg)->tpg_attrib.cache_dynamic_acls; + return to_iscsi_tpg(se_tpg)->tpg_attrib.cache_dynamic_acls; } static int lio_tpg_check_demo_mode_write_protect( struct se_portal_group *se_tpg) { - return iscsi_tpg(se_tpg)->tpg_attrib.demo_mode_write_protect; + return to_iscsi_tpg(se_tpg)->tpg_attrib.demo_mode_write_protect; } static int lio_tpg_check_prod_mode_write_protect( struct se_portal_group *se_tpg) { - return iscsi_tpg(se_tpg)->tpg_attrib.prod_mode_write_protect; + return to_iscsi_tpg(se_tpg)->tpg_attrib.prod_mode_write_protect; } static int lio_tpg_check_prot_fabric_only( @@ -1465,9 +1445,9 @@ static int lio_tpg_check_prot_fabric_only( * Only report fabric_prot_type if t10_pi has also been enabled * for incoming ib_isert sessions. */ - if (!iscsi_tpg(se_tpg)->tpg_attrib.t10_pi) + if (!to_iscsi_tpg(se_tpg)->tpg_attrib.t10_pi) return 0; - return iscsi_tpg(se_tpg)->tpg_attrib.fabric_prot_type; + return to_iscsi_tpg(se_tpg)->tpg_attrib.fabric_prot_type; } /* @@ -1504,16 +1484,14 @@ static void lio_tpg_close_session(struct se_session *se_sess) static u32 lio_tpg_get_inst_index(struct se_portal_group *se_tpg) { - return iscsi_tpg(se_tpg)->tpg_tiqn->tiqn_index; + return to_iscsi_tpg(se_tpg)->tpg_tiqn->tiqn_index; } static void lio_set_default_node_attributes(struct se_node_acl *se_acl) { - struct iscsi_node_acl *acl = container_of(se_acl, struct iscsi_node_acl, - se_node_acl); + struct iscsi_node_acl *acl = to_iscsi_nacl(se_acl); struct se_portal_group *se_tpg = se_acl->se_tpg; - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); + struct iscsi_portal_group *tpg = to_iscsi_tpg(se_tpg); acl->node_attrib.nacl = acl; iscsit_set_default_node_attribues(acl, tpg); diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index b34ac9ecac31..d853bacf1cfc 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -104,8 +104,8 @@ static u32 iscsi_handle_authentication( { struct iscsit_session *sess = conn->sess; struct iscsi_node_auth *auth; - struct iscsi_node_acl *iscsi_nacl; - struct iscsi_portal_group *iscsi_tpg; + struct iscsi_node_acl *nacl; + struct iscsi_portal_group *tpg; struct se_node_acl *se_nacl; if (!sess->sess_ops->SessionType) { @@ -120,15 +120,13 @@ static u32 iscsi_handle_authentication( } if (se_nacl->dynamic_node_acl) { - iscsi_tpg = container_of(se_nacl->se_tpg, - struct iscsi_portal_group, tpg_se_tpg); + tpg = to_iscsi_tpg(se_nacl->se_tpg); - auth = &iscsi_tpg->tpg_demo_auth; + auth = &tpg->tpg_demo_auth; } else { - iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, - se_node_acl); + nacl = to_iscsi_nacl(se_nacl); - auth = &iscsi_nacl->node_auth; + auth = &nacl->node_auth; } } else { /* diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 4339ee517434..3cac1aafef68 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -394,8 +394,7 @@ struct iscsi_node_attrib *iscsit_tpg_get_node_attrib( { struct se_session *se_sess = sess->se_sess; struct se_node_acl *se_nacl = se_sess->se_node_acl; - struct iscsi_node_acl *acl = container_of(se_nacl, struct iscsi_node_acl, - se_node_acl); + struct iscsi_node_acl *acl = to_iscsi_nacl(se_nacl); return &acl->node_attrib; } diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 8e68ace428d9..4dd62947f8db 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -758,6 +758,12 @@ struct iscsi_node_acl { struct iscsi_node_stat_grps node_stat_grps; }; +static inline struct iscsi_node_acl * +to_iscsi_nacl(struct se_node_acl *se_nacl) +{ + return container_of(se_nacl, struct iscsi_node_acl, se_node_acl); +} + struct iscsi_tpg_attrib { u32 authentication; u32 login_timeout; @@ -839,6 +845,12 @@ struct iscsi_portal_group { struct list_head tpg_list; } ____cacheline_aligned; +static inline struct iscsi_portal_group * +to_iscsi_tpg(struct se_portal_group *se_tpg) +{ + return container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); +} + struct iscsi_wwn_stat_grps { struct config_group iscsi_stat_group; struct config_group iscsi_instance_group; -- cgit v1.2.3 From a6e0d179764cb31b2981c85e6fd156adc777e4ed Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Mon, 23 May 2022 12:59:05 +0300 Subject: scsi: target: iscsi: Control authentication per ACL Add acls/{ACL}/attrib/authentication attribute that controls authentication for particular ACL. By default, this attribute inherits a value of the authentication attribute of the target port group to keep backward compatibility. Authentication attribute has 3 states: "0" - authentication is turned off for this ACL "1" - authentication is required for this ACL "-1" - authentication is inherited from TPG Link: https://lore.kernel.org/r/20220523095905.26070-4-d.bogdanov@yadro.com Reviewed-by: Roman Bolshakov Reviewed-by: Konstantin Shelekhin Reviewed-by: Mike Christie Signed-off-by: Dmitry Bogdanov Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_configfs.c | 31 ++++++++++++++++++++++++++ drivers/target/iscsi/iscsi_target_nego.c | 8 ++++++- drivers/target/iscsi/iscsi_target_nodeattrib.c | 1 + include/target/iscsi/iscsi_target_core.h | 2 ++ 4 files changed, 41 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index b01b6701c144..5d0f51822414 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -314,6 +314,36 @@ ISCSI_NACL_ATTR(random_datain_pdu_offsets); ISCSI_NACL_ATTR(random_datain_seq_offsets); ISCSI_NACL_ATTR(random_r2t_offsets); +static ssize_t iscsi_nacl_attrib_authentication_show(struct config_item *item, + char *page) +{ + struct se_node_acl *se_nacl = attrib_to_nacl(item); + struct iscsi_node_acl *nacl = to_iscsi_nacl(se_nacl); + + return sprintf(page, "%d\n", nacl->node_attrib.authentication); +} + +static ssize_t iscsi_nacl_attrib_authentication_store(struct config_item *item, + const char *page, size_t count) +{ + struct se_node_acl *se_nacl = attrib_to_nacl(item); + struct iscsi_node_acl *nacl = to_iscsi_nacl(se_nacl); + s32 val; + int ret; + + ret = kstrtos32(page, 0, &val); + if (ret) + return ret; + if (val != 0 && val != 1 && val != NA_AUTHENTICATION_INHERITED) + return -EINVAL; + + nacl->node_attrib.authentication = val; + + return count; +} + +CONFIGFS_ATTR(iscsi_nacl_attrib_, authentication); + static struct configfs_attribute *lio_target_nacl_attrib_attrs[] = { &iscsi_nacl_attrib_attr_dataout_timeout, &iscsi_nacl_attrib_attr_dataout_timeout_retries, @@ -323,6 +353,7 @@ static struct configfs_attribute *lio_target_nacl_attrib_attrs[] = { &iscsi_nacl_attrib_attr_random_datain_pdu_offsets, &iscsi_nacl_attrib_attr_random_datain_seq_offsets, &iscsi_nacl_attrib_attr_random_r2t_offsets, + &iscsi_nacl_attrib_attr_authentication, NULL, }; diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index f06f16d63fe6..9ce35a59962b 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -813,6 +813,7 @@ static int iscsi_target_do_authentication( static bool iscsi_conn_auth_required(struct iscsit_conn *conn) { + struct iscsi_node_acl *nacl; struct se_node_acl *se_nacl; if (conn->sess->sess_ops->SessionType) { @@ -839,7 +840,12 @@ static bool iscsi_conn_auth_required(struct iscsit_conn *conn) pr_debug("Known ACL %s is trying to connect\n", se_nacl->initiatorname); - return conn->tpg->tpg_attrib.authentication; + + nacl = to_iscsi_nacl(se_nacl); + if (nacl->node_attrib.authentication == NA_AUTHENTICATION_INHERITED) + return conn->tpg->tpg_attrib.authentication; + + return nacl->node_attrib.authentication; } static int iscsi_target_handle_csg_zero( diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.c b/drivers/target/iscsi/iscsi_target_nodeattrib.c index 874cb33c9be0..d63efdefb18e 100644 --- a/drivers/target/iscsi/iscsi_target_nodeattrib.c +++ b/drivers/target/iscsi/iscsi_target_nodeattrib.c @@ -30,6 +30,7 @@ void iscsit_set_default_node_attribues( { struct iscsi_node_attrib *a = &acl->node_attrib; + a->authentication = NA_AUTHENTICATION_INHERITED; a->dataout_timeout = NA_DATAOUT_TIMEOUT; a->dataout_timeout_retries = NA_DATAOUT_TIMEOUT_RETRIES; a->nopin_timeout = NA_NOPIN_TIMEOUT; diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 4dd62947f8db..94d06ddfd80a 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -26,6 +26,7 @@ struct sock; #define ISCSI_RX_THREAD_NAME "iscsi_trx" #define ISCSI_TX_THREAD_NAME "iscsi_ttx" #define ISCSI_IQN_LEN 224 +#define NA_AUTHENTICATION_INHERITED -1 /* struct iscsi_node_attrib sanity values */ #define NA_DATAOUT_TIMEOUT 3 @@ -715,6 +716,7 @@ struct iscsi_login { } ____cacheline_aligned; struct iscsi_node_attrib { + s32 authentication; u32 dataout_timeout; u32 dataout_timeout_retries; u32 default_erl; -- cgit v1.2.3 From b1d288d9c3c5ca28df062214656a59cf7ee370e0 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 6 Jun 2022 20:18:03 +0000 Subject: platform/chrome: cros_ec_proto: Rename cros_ec_command function cros_ec_command() is the name of a function as well as a struct, as such it can confuse indexing tools (like ctags). Avoid this by renaming it to cros_ec_cmd(). Update all the callsites to use the new name. This patch is a find-and-replace, so should not introduce any functional changes. Suggested-by: Stephen Boyd Signed-off-by: Prashant Malani Acked-by: Lee Jones Reviewed-by: Stephen Boyd Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220606201825.763788-3-pmalani@chromium.org --- drivers/mfd/cros_ec_dev.c | 4 +-- drivers/platform/chrome/cros_ec_proto.c | 22 ++++++++-------- drivers/platform/chrome/cros_ec_typec.c | 39 ++++++++++++++--------------- drivers/platform/chrome/cros_usbpd_notify.c | 4 +-- drivers/regulator/cros-ec-regulator.c | 24 +++++++++--------- include/linux/platform_data/cros_ec_proto.h | 2 +- 6 files changed, 47 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 596731caf407..02d4271dfe06 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -250,8 +250,8 @@ static int ec_device_probe(struct platform_device *pdev) * The PCHG device cannot be detected by sending EC_FEATURE_GET_CMD, but * it can be detected by querying the number of peripheral chargers. */ - retval = cros_ec_command(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0, - &pchg_count, sizeof(pchg_count)); + retval = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0, + &pchg_count, sizeof(pchg_count)); if (retval >= 0 && pchg_count.port_count) { retval = mfd_add_hotplug_devices(ec->dev, cros_ec_pchg_cells, diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 13ced9d2dd71..b6bea183ee28 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -860,8 +860,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature) if (features->flags[0] == -1U && features->flags[1] == -1U) { /* features bitmap not read yet */ - ret = cros_ec_command(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset, - NULL, 0, features, sizeof(*features)); + ret = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset, + NULL, 0, features, sizeof(*features)); if (ret < 0) { dev_warn(ec->dev, "cannot get EC features: %d\n", ret); memset(features, 0, sizeof(*features)); @@ -942,7 +942,7 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec) EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); /** - * cros_ec_command - Send a command to the EC. + * cros_ec_cmd - Send a command to the EC. * * @ec_dev: EC device * @version: EC command version @@ -954,13 +954,13 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); * * Return: >= 0 on success, negative error number on failure. */ -int cros_ec_command(struct cros_ec_device *ec_dev, - unsigned int version, - int command, - void *outdata, - int outsize, - void *indata, - int insize) +int cros_ec_cmd(struct cros_ec_device *ec_dev, + unsigned int version, + int command, + void *outdata, + int outsize, + void *indata, + int insize) { struct cros_ec_command *msg; int ret; @@ -987,4 +987,4 @@ error: kfree(msg); return ret; } -EXPORT_SYMBOL_GPL(cros_ec_command); +EXPORT_SYMBOL_GPL(cros_ec_cmd); diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 7cb2e35c4ded..d6088ba447af 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -525,8 +525,8 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, enum typec_orientation orientation; int ret; - ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO, - &req, sizeof(req), &resp, sizeof(resp)); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO, + &req, sizeof(req), &resp, sizeof(resp)); if (ret < 0) { dev_warn(typec->dev, "Failed to get mux info for port: %d, err = %d\n", port_num, ret); @@ -585,8 +585,8 @@ mux_ack: /* Sending Acknowledgment to EC */ mux_ack.port = port_num; - if (cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack, - sizeof(mux_ack), NULL, 0) < 0) + if (cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack, + sizeof(mux_ack), NULL, 0) < 0) dev_warn(typec->dev, "Failed to send Mux ACK to EC for port: %d\n", port_num); @@ -754,8 +754,8 @@ static int cros_typec_handle_sop_prime_disc(struct cros_typec_data *typec, int p int ret = 0; memset(disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE); - ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), - disc, EC_PROTO2_MAX_RESPONSE_SIZE); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), + disc, EC_PROTO2_MAX_RESPONSE_SIZE); if (ret < 0) { dev_err(typec->dev, "Failed to get SOP' discovery data for port: %d\n", port_num); goto sop_prime_disc_exit; @@ -837,8 +837,8 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu typec_partner_set_pd_revision(port->partner, pd_revision); memset(sop_disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE); - ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), - sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), + sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE); if (ret < 0) { dev_err(typec->dev, "Failed to get SOP discovery data for port: %d\n", port_num); goto disc_exit; @@ -870,8 +870,8 @@ static int cros_typec_send_clear_event(struct cros_typec_data *typec, int port_n .clear_events_mask = events_mask, }; - return cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req, - sizeof(req), NULL, 0); + return cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req, + sizeof(req), NULL, 0); } static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num) @@ -882,8 +882,8 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num }; int ret; - ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), - &resp, sizeof(resp)); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), + &resp, sizeof(resp)); if (ret < 0) { dev_warn(typec->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num); return; @@ -960,9 +960,9 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) req.mux = USB_PD_CTRL_MUX_NO_CHANGE; req.swap = USB_PD_CTRL_SWAP_NONE; - ret = cros_ec_command(typec->ec, typec->pd_ctrl_ver, - EC_CMD_USB_PD_CONTROL, &req, sizeof(req), - &resp, sizeof(resp)); + ret = cros_ec_cmd(typec->ec, typec->pd_ctrl_ver, + EC_CMD_USB_PD_CONTROL, &req, sizeof(req), + &resp, sizeof(resp)); if (ret < 0) return ret; @@ -997,9 +997,8 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec) /* We're interested in the PD control command version. */ req_v1.cmd = EC_CMD_USB_PD_CONTROL; - ret = cros_ec_command(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS, - &req_v1, sizeof(req_v1), &resp, - sizeof(resp)); + ret = cros_ec_cmd(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS, + &req_v1, sizeof(req_v1), &resp, sizeof(resp)); if (ret < 0) return ret; @@ -1090,8 +1089,8 @@ static int cros_typec_probe(struct platform_device *pdev) typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD); typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK); - ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, - &resp, sizeof(resp)); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, + &resp, sizeof(resp)); if (ret < 0) return ret; diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index 91ce6be91aac..4b5a81c9dc6d 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -71,8 +71,8 @@ static void cros_usbpd_get_event_and_notify(struct device *dev, } /* Check for PD host events on EC. */ - ret = cros_ec_command(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS, - NULL, 0, &host_event_status, sizeof(host_event_status)); + ret = cros_ec_cmd(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS, + NULL, 0, &host_event_status, sizeof(host_event_status)); if (ret < 0) { dev_warn(dev, "Can't get host event status (err: %d)\n", ret); goto send_notify; diff --git a/drivers/regulator/cros-ec-regulator.c b/drivers/regulator/cros-ec-regulator.c index 1c5fc74a4776..1591636f86c3 100644 --- a/drivers/regulator/cros-ec-regulator.c +++ b/drivers/regulator/cros-ec-regulator.c @@ -30,8 +30,8 @@ static int cros_ec_regulator_enable(struct regulator_dev *dev) .enable = 1, }; - return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, + sizeof(cmd), NULL, 0); } static int cros_ec_regulator_disable(struct regulator_dev *dev) @@ -42,8 +42,8 @@ static int cros_ec_regulator_disable(struct regulator_dev *dev) .enable = 0, }; - return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, + sizeof(cmd), NULL, 0); } static int cros_ec_regulator_is_enabled(struct regulator_dev *dev) @@ -55,8 +55,8 @@ static int cros_ec_regulator_is_enabled(struct regulator_dev *dev) struct ec_response_regulator_is_enabled resp; int ret; - ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_IS_ENABLED, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_IS_ENABLED, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; return resp.enabled; @@ -82,8 +82,8 @@ static int cros_ec_regulator_get_voltage(struct regulator_dev *dev) struct ec_response_regulator_get_voltage resp; int ret; - ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_GET_VOLTAGE, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_VOLTAGE, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; return resp.voltage_mv * 1000; @@ -108,8 +108,8 @@ static int cros_ec_regulator_set_voltage(struct regulator_dev *dev, int min_uV, if (min_mV > max_mV) return -EINVAL; - return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_SET_VOLTAGE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_SET_VOLTAGE, &cmd, + sizeof(cmd), NULL, 0); } static const struct regulator_ops cros_ec_regulator_voltage_ops = { @@ -130,8 +130,8 @@ static int cros_ec_regulator_init_info(struct device *dev, struct ec_response_regulator_get_info resp; int ret; - ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 138fd912c808..816da4eef3e5 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -231,7 +231,7 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); -int cros_ec_command(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, +int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, int outsize, void *indata, int insize); /** -- cgit v1.2.3 From f87e15fbf6d8cdb51f953338d41a4a52ad1aca14 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 6 Jun 2022 20:18:05 +0000 Subject: platform/chrome: cros_ec_proto: Update size arg types cros_ec_cmd() takes 2 size arguments. Update them to be of the more appropriate type size_t. Suggested-by: Stephen Boyd Signed-off-by: Prashant Malani Reviewed-by: Stephen Boyd Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220606201825.763788-4-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_proto.c | 4 ++-- include/linux/platform_data/cros_ec_proto.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index b6bea183ee28..cefabfe45551 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -958,9 +958,9 @@ int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, - int outsize, + size_t outsize, void *indata, - int insize) + size_t insize) { struct cros_ec_command *msg; int ret; diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 816da4eef3e5..85e29300f63d 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -232,7 +232,7 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, - int outsize, void *indata, int insize); + size_t outsize, void *indata, size_t insize); /** * cros_ec_get_time_ns() - Return time in ns. -- cgit v1.2.3 From ed2351174e38ad4febbbc0dba802803e6cff8ae0 Mon Sep 17 00:00:00 2001 From: Chenyi Qiang Date: Tue, 24 May 2022 21:56:21 +0800 Subject: KVM: x86: Extend KVM_{G,S}ET_VCPU_EVENTS to support pending triple fault For the triple fault sythesized by KVM, e.g. the RSM path or nested_vmx_abort(), if KVM exits to userspace before the request is serviced, userspace could migrate the VM and lose the triple fault. Extend KVM_{G,S}ET_VCPU_EVENTS to support pending triple fault with a new event KVM_VCPUEVENT_VALID_FAULT_FAULT so that userspace can save and restore the triple fault event. This extension is guarded by a new KVM capability KVM_CAP_TRIPLE_FAULT_EVENT. Note that in the set_vcpu_events path, userspace is able to set/clear the triple fault request through triple_fault.pending field. Signed-off-by: Chenyi Qiang Message-Id: <20220524135624.22988-2-chenyi.qiang@intel.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 8 ++++++++ arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/include/uapi/asm/kvm.h | 6 +++++- arch/x86/kvm/x86.c | 21 ++++++++++++++++++++- include/uapi/linux/kvm.h | 1 + 5 files changed, 36 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 421479a67da5..f67e367c4059 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -1150,6 +1150,10 @@ The following bits are defined in the flags field: fields contain a valid state. This bit will be set whenever KVM_CAP_EXCEPTION_PAYLOAD is enabled. +- KVM_VCPUEVENT_VALID_TRIPLE_FAULT may be set to signal that the + triple_fault_pending field contains a valid state. This bit will + be set whenever KVM_CAP_TRIPLE_FAULT_EVENT is enabled. + ARM64: ^^^^^^ @@ -1245,6 +1249,10 @@ can be set in the flags field to signal that the exception_has_payload, exception_payload, and exception.pending fields contain a valid state and shall be written into the VCPU. +If KVM_CAP_TRIPLE_FAULT_EVENT is enabled, KVM_VCPUEVENT_VALID_TRIPLE_FAULT +can be set in flags field to signal that the triple_fault field contains +a valid state and shall be written into the VCPU. + ARM64: ^^^^^^ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 032278f0ee6d..d6c62276e131 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1174,6 +1174,8 @@ struct kvm_arch { bool guest_can_read_msr_platform_info; bool exception_payload_enabled; + bool triple_fault_event; + bool bus_lock_detection_enabled; bool enable_pmu; /* diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 21614807a2cb..24c807c8d5f7 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -325,6 +325,7 @@ struct kvm_reinject_control { #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 #define KVM_VCPUEVENT_VALID_SMM 0x00000008 #define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010 +#define KVM_VCPUEVENT_VALID_TRIPLE_FAULT 0x00000020 /* Interrupt shadow states */ #define KVM_X86_SHADOW_INT_MOV_SS 0x01 @@ -359,7 +360,10 @@ struct kvm_vcpu_events { __u8 smm_inside_nmi; __u8 latched_init; } smi; - __u8 reserved[27]; + struct { + __u8 pending; + } triple_fault; + __u8 reserved[26]; __u8 exception_has_payload; __u64 exception_payload; }; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c8dfdef9e52f..422fbb0d7518 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4296,6 +4296,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_GET_MSR_FEATURES: case KVM_CAP_MSR_PLATFORM_INFO: case KVM_CAP_EXCEPTION_PAYLOAD: + case KVM_CAP_X86_TRIPLE_FAULT_EVENT: case KVM_CAP_SET_GUEST_DEBUG: case KVM_CAP_LAST_CPU: case KVM_CAP_X86_USER_SPACE_MSR: @@ -4942,6 +4943,10 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, | KVM_VCPUEVENT_VALID_SMM); if (vcpu->kvm->arch.exception_payload_enabled) events->flags |= KVM_VCPUEVENT_VALID_PAYLOAD; + if (vcpu->kvm->arch.triple_fault_event) { + events->triple_fault.pending = kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu); + events->flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT; + } memset(&events->reserved, 0, sizeof(events->reserved)); } @@ -4955,7 +4960,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, | KVM_VCPUEVENT_VALID_SIPI_VECTOR | KVM_VCPUEVENT_VALID_SHADOW | KVM_VCPUEVENT_VALID_SMM - | KVM_VCPUEVENT_VALID_PAYLOAD)) + | KVM_VCPUEVENT_VALID_PAYLOAD + | KVM_VCPUEVENT_VALID_TRIPLE_FAULT)) return -EINVAL; if (events->flags & KVM_VCPUEVENT_VALID_PAYLOAD) { @@ -5028,6 +5034,15 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, } } + if (events->flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT) { + if (!vcpu->kvm->arch.triple_fault_event) + return -EINVAL; + if (events->triple_fault.pending) + kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); + else + kvm_clear_request(KVM_REQ_TRIPLE_FAULT, vcpu); + } + kvm_make_request(KVM_REQ_EVENT, vcpu); return 0; @@ -6029,6 +6044,10 @@ split_irqchip_unlock: kvm->arch.exception_payload_enabled = cap->args[0]; r = 0; break; + case KVM_CAP_X86_TRIPLE_FAULT_EVENT: + kvm->arch.triple_fault_event = cap->args[0]; + r = 0; + break; case KVM_CAP_X86_USER_SPACE_MSR: kvm->arch.user_space_msr_mask = cap->args[0]; r = 0; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index c4a32910b88a..ca799319acfd 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1158,6 +1158,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SYSTEM_EVENT_DATA 215 #define KVM_CAP_ARM_SYSTEM_SUSPEND 216 #define KVM_CAP_S390_PROTECTED_DUMP 217 +#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 #ifdef KVM_CAP_IRQ_ROUTING -- cgit v1.2.3 From 2f4073e08f4cc5a41e35d777c240aaadd0257051 Mon Sep 17 00:00:00 2001 From: Tao Xu Date: Tue, 24 May 2022 21:56:24 +0800 Subject: KVM: VMX: Enable Notify VM exit There are cases that malicious virtual machines can cause CPU stuck (due to event windows don't open up), e.g., infinite loop in microcode when nested #AC (CVE-2015-5307). No event window means no event (NMI, SMI and IRQ) can be delivered. It leads the CPU to be unavailable to host or other VMs. VMM can enable notify VM exit that a VM exit generated if no event window occurs in VM non-root mode for a specified amount of time (notify window). Feature enabling: - The new vmcs field SECONDARY_EXEC_NOTIFY_VM_EXITING is introduced to enable this feature. VMM can set NOTIFY_WINDOW vmcs field to adjust the expected notify window. - Add a new KVM capability KVM_CAP_X86_NOTIFY_VMEXIT so that user space can query and enable this feature in per-VM scope. The argument is a 64bit value: bits 63:32 are used for notify window, and bits 31:0 are for flags. Current supported flags: - KVM_X86_NOTIFY_VMEXIT_ENABLED: enable the feature with the notify window provided. - KVM_X86_NOTIFY_VMEXIT_USER: exit to userspace once the exits happen. - It's safe to even set notify window to zero since an internal hardware threshold is added to vmcs.notify_window. VM exit handling: - Introduce a vcpu state notify_window_exits to records the count of notify VM exits and expose it through the debugfs. - Notify VM exit can happen incident to delivery of a vector event. Allow it in KVM. - Exit to userspace unconditionally for handling when VM_CONTEXT_INVALID bit is set. Nested handling - Nested notify VM exits are not supported yet. Keep the same notify window control in vmcs02 as vmcs01, so that L1 can't escape the restriction of notify VM exits through launching L2 VM. Notify VM exit is defined in latest Intel Architecture Instruction Set Extensions Programming Reference, chapter 9.2. Co-developed-by: Xiaoyao Li Signed-off-by: Xiaoyao Li Signed-off-by: Tao Xu Co-developed-by: Chenyi Qiang Signed-off-by: Chenyi Qiang Message-Id: <20220524135624.22988-5-chenyi.qiang@intel.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 49 ++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/kvm_host.h | 7 ++++++ arch/x86/include/asm/vmx.h | 7 ++++++ arch/x86/include/asm/vmxfeatures.h | 1 + arch/x86/include/uapi/asm/vmx.h | 4 +++- arch/x86/kvm/vmx/capabilities.h | 6 +++++ arch/x86/kvm/vmx/nested.c | 8 +++++++ arch/x86/kvm/vmx/vmx.c | 40 +++++++++++++++++++++++++++++-- arch/x86/kvm/x86.c | 22 ++++++++++++++++- arch/x86/kvm/x86.h | 7 ++++++ include/uapi/linux/kvm.h | 11 +++++++++ 11 files changed, 158 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index f67e367c4059..30e31a886422 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6557,6 +6557,26 @@ array field represents return values. The userspace should update the return values of SBI call before resuming the VCPU. For more details on RISC-V SBI spec refer, https://github.com/riscv/riscv-sbi-doc. +:: + + /* KVM_EXIT_NOTIFY */ + struct { + #define KVM_NOTIFY_CONTEXT_INVALID (1 << 0) + __u32 flags; + } notify; + +Used on x86 systems. When the VM capability KVM_CAP_X86_NOTIFY_VMEXIT is +enabled, a VM exit generated if no event window occurs in VM non-root mode +for a specified amount of time. Once KVM_X86_NOTIFY_VMEXIT_USER is set when +enabling the cap, it would exit to userspace with the exit reason +KVM_EXIT_NOTIFY for further handling. The "flags" field contains more +detailed info. + +The valid value for 'flags' is: + + - KVM_NOTIFY_CONTEXT_INVALID -- the VM context is corrupted and not valid + in VMCS. It would run into unknown result if resume the target VM. + :: /* Fix the size of the union. */ @@ -7523,6 +7543,35 @@ if the value was set to zero or KVM_ENABLE_CAP was not invoked, KVM uses the return value of KVM_CHECK_EXTENSION(KVM_CAP_MAX_VCPU_ID) as the maximum APIC ID. +7.33 KVM_CAP_X86_NOTIFY_VMEXIT +------------------------------ + +:Architectures: x86 +:Target: VM +:Parameters: args[0] is the value of notify window as well as some flags +:Returns: 0 on success, -EINVAL if args[0] contains invalid flags or notify + VM exit is unsupported. + +Bits 63:32 of args[0] are used for notify window. +Bits 31:0 of args[0] are for some flags. Valid bits are:: + + #define KVM_X86_NOTIFY_VMEXIT_ENABLED (1 << 0) + #define KVM_X86_NOTIFY_VMEXIT_USER (1 << 1) + +This capability allows userspace to configure the notify VM exit on/off +in per-VM scope during VM creation. Notify VM exit is disabled by default. +When userspace sets KVM_X86_NOTIFY_VMEXIT_ENABLED bit in args[0], VMM will +enable this feature with the notify window provided, which will generate +a VM exit if no event window occurs in VM non-root mode for a specified of +time (notify window). + +If KVM_X86_NOTIFY_VMEXIT_USER is set in args[0], upon notify VM exits happen, +KVM would exit to userspace for handling. + +This capability is aimed to mitigate the threat that malicious VMs can +cause CPU stuck (due to event windows don't open up) and make the CPU +unavailable to host or other VMs. + 8. Other capabilities. ====================== diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4e00bca08cfa..6cf5d77d7896 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -65,6 +65,9 @@ #define KVM_BUS_LOCK_DETECTION_VALID_MODE (KVM_BUS_LOCK_DETECTION_OFF | \ KVM_BUS_LOCK_DETECTION_EXIT) +#define KVM_X86_NOTIFY_VMEXIT_VALID_BITS (KVM_X86_NOTIFY_VMEXIT_ENABLED | \ + KVM_X86_NOTIFY_VMEXIT_USER) + /* x86-specific vcpu->requests bit members */ #define KVM_REQ_MIGRATE_TIMER KVM_ARCH_REQ(0) #define KVM_REQ_REPORT_TPR_ACCESS KVM_ARCH_REQ(1) @@ -1178,6 +1181,9 @@ struct kvm_arch { bool bus_lock_detection_enabled; bool enable_pmu; + + u32 notify_window; + u32 notify_vmexit_flags; /* * If exit_on_emulation_error is set, and the in-kernel instruction * emulator fails to emulate an instruction, allow userspace @@ -1325,6 +1331,7 @@ struct kvm_vcpu_stat { u64 directed_yield_attempted; u64 directed_yield_successful; u64 guest_mode; + u64 notify_window_exits; }; struct x86_instruction_info; diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 89d2172787c5..c371ef695fcc 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -75,6 +75,7 @@ #define SECONDARY_EXEC_TSC_SCALING VMCS_CONTROL_BIT(TSC_SCALING) #define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE VMCS_CONTROL_BIT(USR_WAIT_PAUSE) #define SECONDARY_EXEC_BUS_LOCK_DETECTION VMCS_CONTROL_BIT(BUS_LOCK_DETECTION) +#define SECONDARY_EXEC_NOTIFY_VM_EXITING VMCS_CONTROL_BIT(NOTIFY_VM_EXITING) /* * Definitions of Tertiary Processor-Based VM-Execution Controls. @@ -280,6 +281,7 @@ enum vmcs_field { SECONDARY_VM_EXEC_CONTROL = 0x0000401e, PLE_GAP = 0x00004020, PLE_WINDOW = 0x00004022, + NOTIFY_WINDOW = 0x00004024, VM_INSTRUCTION_ERROR = 0x00004400, VM_EXIT_REASON = 0x00004402, VM_EXIT_INTR_INFO = 0x00004404, @@ -564,6 +566,11 @@ enum vm_entry_failure_code { #define EPT_VIOLATION_GVA_IS_VALID (1 << EPT_VIOLATION_GVA_IS_VALID_BIT) #define EPT_VIOLATION_GVA_TRANSLATED (1 << EPT_VIOLATION_GVA_TRANSLATED_BIT) +/* + * Exit Qualifications for NOTIFY VM EXIT + */ +#define NOTIFY_VM_CONTEXT_INVALID BIT(0) + /* * VM-instruction error numbers */ diff --git a/arch/x86/include/asm/vmxfeatures.h b/arch/x86/include/asm/vmxfeatures.h index 589608c157bf..c6a7eed03914 100644 --- a/arch/x86/include/asm/vmxfeatures.h +++ b/arch/x86/include/asm/vmxfeatures.h @@ -85,6 +85,7 @@ #define VMX_FEATURE_USR_WAIT_PAUSE ( 2*32+ 26) /* Enable TPAUSE, UMONITOR, UMWAIT in guest */ #define VMX_FEATURE_ENCLV_EXITING ( 2*32+ 28) /* "" VM-Exit on ENCLV (leaf dependent) */ #define VMX_FEATURE_BUS_LOCK_DETECTION ( 2*32+ 30) /* "" VM-Exit when bus lock caused */ +#define VMX_FEATURE_NOTIFY_VM_EXITING ( 2*32+ 31) /* VM-Exit when no event windows after notify window */ /* Tertiary Processor-Based VM-Execution Controls, word 3 */ #define VMX_FEATURE_IPI_VIRT ( 3*32+ 4) /* Enable IPI virtualization */ diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h index 946d761adbd3..a5faf6d88f1b 100644 --- a/arch/x86/include/uapi/asm/vmx.h +++ b/arch/x86/include/uapi/asm/vmx.h @@ -91,6 +91,7 @@ #define EXIT_REASON_UMWAIT 67 #define EXIT_REASON_TPAUSE 68 #define EXIT_REASON_BUS_LOCK 74 +#define EXIT_REASON_NOTIFY 75 #define VMX_EXIT_REASONS \ { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ @@ -153,7 +154,8 @@ { EXIT_REASON_XRSTORS, "XRSTORS" }, \ { EXIT_REASON_UMWAIT, "UMWAIT" }, \ { EXIT_REASON_TPAUSE, "TPAUSE" }, \ - { EXIT_REASON_BUS_LOCK, "BUS_LOCK" } + { EXIT_REASON_BUS_LOCK, "BUS_LOCK" }, \ + { EXIT_REASON_NOTIFY, "NOTIFY" } #define VMX_EXIT_REASON_FLAGS \ { VMX_EXIT_REASONS_FAILED_VMENTRY, "FAILED_VMENTRY" } diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index f14c4bef97e0..2d3f13b18714 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -436,4 +436,10 @@ static inline u64 vmx_supported_debugctl(void) return debugctl; } +static inline bool cpu_has_notify_vmexit(void) +{ + return vmcs_config.cpu_based_2nd_exec_ctrl & + SECONDARY_EXEC_NOTIFY_VM_EXITING; +} + #endif /* __KVM_X86_VMX_CAPS_H */ diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 5c5f4e3762f5..7d8cd0ebcc75 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -2133,6 +2133,8 @@ static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx) { + struct kvm *kvm = vmx->vcpu.kvm; + /* * If vmcs02 hasn't been initialized, set the constant vmcs02 state * according to L0's settings (vmcs12 is irrelevant here). Host @@ -2175,6 +2177,9 @@ static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx) if (cpu_has_vmx_encls_vmexit()) vmcs_write64(ENCLS_EXITING_BITMAP, INVALID_GPA); + if (kvm_notify_vmexit_enabled(kvm)) + vmcs_write32(NOTIFY_WINDOW, kvm->arch.notify_window); + /* * Set the MSR load/store lists to match L0's settings. Only the * addresses are constant (for vmcs02), the counts can change based @@ -6112,6 +6117,9 @@ static bool nested_vmx_l1_wants_exit(struct kvm_vcpu *vcpu, SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE); case EXIT_REASON_ENCLS: return nested_vmx_exit_handled_encls(vcpu, vmcs12); + case EXIT_REASON_NOTIFY: + /* Notify VM exit is not exposed to L1 */ + return false; default: return true; } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 6d631941ac1a..2e00890d752a 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2499,7 +2499,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, SECONDARY_EXEC_PT_USE_GPA | SECONDARY_EXEC_PT_CONCEAL_VMX | SECONDARY_EXEC_ENABLE_VMFUNC | - SECONDARY_EXEC_BUS_LOCK_DETECTION; + SECONDARY_EXEC_BUS_LOCK_DETECTION | + SECONDARY_EXEC_NOTIFY_VM_EXITING; if (cpu_has_sgx()) opt2 |= SECONDARY_EXEC_ENCLS_EXITING; if (adjust_vmx_controls(min2, opt2, @@ -4417,6 +4418,9 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx) if (!vcpu->kvm->arch.bus_lock_detection_enabled) exec_control &= ~SECONDARY_EXEC_BUS_LOCK_DETECTION; + if (!kvm_notify_vmexit_enabled(vcpu->kvm)) + exec_control &= ~SECONDARY_EXEC_NOTIFY_VM_EXITING; + return exec_control; } @@ -4498,6 +4502,9 @@ static void init_vmcs(struct vcpu_vmx *vmx) vmx->ple_window_dirty = true; } + if (kvm_notify_vmexit_enabled(kvm)) + vmcs_write32(NOTIFY_WINDOW, kvm->arch.notify_window); + vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */ @@ -5784,6 +5791,32 @@ static int handle_bus_lock_vmexit(struct kvm_vcpu *vcpu) return 1; } +static int handle_notify(struct kvm_vcpu *vcpu) +{ + unsigned long exit_qual = vmx_get_exit_qual(vcpu); + bool context_invalid = exit_qual & NOTIFY_VM_CONTEXT_INVALID; + + ++vcpu->stat.notify_window_exits; + + /* + * Notify VM exit happened while executing iret from NMI, + * "blocked by NMI" bit has to be set before next VM entry. + */ + if (enable_vnmi && (exit_qual & INTR_INFO_UNBLOCK_NMI)) + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + + if (vcpu->kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_USER || + context_invalid) { + vcpu->run->exit_reason = KVM_EXIT_NOTIFY; + vcpu->run->notify.flags = context_invalid ? + KVM_NOTIFY_CONTEXT_INVALID : 0; + return 0; + } + + return 1; +} + /* * The exit handlers return 1 if the exit was handled fully and guest execution * may resume. Otherwise they set the kvm_run parameter to indicate what needs @@ -5841,6 +5874,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { [EXIT_REASON_PREEMPTION_TIMER] = handle_preemption_timer, [EXIT_REASON_ENCLS] = handle_encls, [EXIT_REASON_BUS_LOCK] = handle_bus_lock_vmexit, + [EXIT_REASON_NOTIFY] = handle_notify, }; static const int kvm_vmx_max_exit_handlers = @@ -6214,7 +6248,8 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) exit_reason.basic != EXIT_REASON_EPT_VIOLATION && exit_reason.basic != EXIT_REASON_PML_FULL && exit_reason.basic != EXIT_REASON_APIC_ACCESS && - exit_reason.basic != EXIT_REASON_TASK_SWITCH)) { + exit_reason.basic != EXIT_REASON_TASK_SWITCH && + exit_reason.basic != EXIT_REASON_NOTIFY)) { int ndata = 3; vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; @@ -8137,6 +8172,7 @@ static __init int hardware_setup(void) kvm_caps.max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX; kvm_caps.tsc_scaling_ratio_frac_bits = 48; kvm_caps.has_bus_lock_exit = cpu_has_vmx_bus_lock_detection(); + kvm_caps.has_notify_vmexit = cpu_has_notify_vmexit(); set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 53e5f2ad2422..a8014233fd57 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -284,7 +284,8 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { STATS_DESC_COUNTER(VCPU, nested_run), STATS_DESC_COUNTER(VCPU, directed_yield_attempted), STATS_DESC_COUNTER(VCPU, directed_yield_successful), - STATS_DESC_ICOUNTER(VCPU, guest_mode) + STATS_DESC_ICOUNTER(VCPU, guest_mode), + STATS_DESC_COUNTER(VCPU, notify_window_exits), }; const struct kvm_stats_header kvm_vcpu_stats_header = { @@ -4402,6 +4403,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_DISABLE_QUIRKS2: r = KVM_X86_VALID_QUIRKS; break; + case KVM_CAP_X86_NOTIFY_VMEXIT: + r = kvm_caps.has_notify_vmexit; + break; default: break; } @@ -6125,6 +6129,22 @@ split_irqchip_unlock: } mutex_unlock(&kvm->lock); break; + case KVM_CAP_X86_NOTIFY_VMEXIT: + r = -EINVAL; + if ((u32)cap->args[0] & ~KVM_X86_NOTIFY_VMEXIT_VALID_BITS) + break; + if (!kvm_caps.has_notify_vmexit) + break; + if (!((u32)cap->args[0] & KVM_X86_NOTIFY_VMEXIT_ENABLED)) + break; + mutex_lock(&kvm->lock); + if (!kvm->created_vcpus) { + kvm->arch.notify_window = cap->args[0] >> 32; + kvm->arch.notify_vmexit_flags = (u32)cap->args[0]; + r = 0; + } + mutex_unlock(&kvm->lock); + break; default: r = -EINVAL; break; diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 359d0454ad28..501b884b8cc4 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -21,6 +21,8 @@ struct kvm_caps { u64 default_tsc_scaling_ratio; /* bus lock detection supported? */ bool has_bus_lock_exit; + /* notify VM exit supported? */ + bool has_notify_vmexit; u64 supported_mce_cap; u64 supported_xcr0; @@ -364,6 +366,11 @@ static inline bool kvm_cstate_in_guest(struct kvm *kvm) return kvm->arch.cstate_in_guest; } +static inline bool kvm_notify_vmexit_enabled(struct kvm *kvm) +{ + return kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_ENABLED; +} + enum kvm_intr_type { /* Values are arbitrary, but must be non-zero. */ KVM_HANDLING_IRQ = 1, diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index ca799319acfd..7569b4ec199c 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -270,6 +270,7 @@ struct kvm_xen_exit { #define KVM_EXIT_X86_BUS_LOCK 33 #define KVM_EXIT_XEN 34 #define KVM_EXIT_RISCV_SBI 35 +#define KVM_EXIT_NOTIFY 36 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -496,6 +497,11 @@ struct kvm_run { unsigned long args[6]; unsigned long ret[2]; } riscv_sbi; + /* KVM_EXIT_NOTIFY */ + struct { +#define KVM_NOTIFY_CONTEXT_INVALID (1 << 0) + __u32 flags; + } notify; /* Fix the size of the union. */ char padding[256]; }; @@ -1159,6 +1165,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_ARM_SYSTEM_SUSPEND 216 #define KVM_CAP_S390_PROTECTED_DUMP 217 #define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 +#define KVM_CAP_X86_NOTIFY_VMEXIT 219 #ifdef KVM_CAP_IRQ_ROUTING @@ -2174,4 +2181,8 @@ struct kvm_stats_desc { /* Available with KVM_CAP_S390_PROTECTED_DUMP */ #define KVM_S390_PV_CPU_COMMAND _IOWR(KVMIO, 0xd0, struct kvm_pv_cmd) +/* Available with KVM_CAP_X86_NOTIFY_VMEXIT */ +#define KVM_X86_NOTIFY_VMEXIT_ENABLED (1ULL << 0) +#define KVM_X86_NOTIFY_VMEXIT_USER (1ULL << 1) + #endif /* __LINUX_KVM_H */ -- cgit v1.2.3 From 3ffb20f5c7891ab5bc61cb4044465d3ad1aebf49 Mon Sep 17 00:00:00 2001 From: Akhil R Date: Tue, 17 May 2022 13:10:47 +0530 Subject: dt-bindings: Add headers for Tegra234 GPCDMA Add reset and IOMMU header for Tegra234 GPCDMA Signed-off-by: Akhil R Reviewed-by: Jon Hunter Acked-by: Krzysztof Kozlowski Signed-off-by: Thierry Reding --- include/dt-bindings/memory/tegra234-mc.h | 1 + include/dt-bindings/reset/tegra234-reset.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/include/dt-bindings/memory/tegra234-mc.h b/include/dt-bindings/memory/tegra234-mc.h index e3b0e9da295d..4bc84a312ad6 100644 --- a/include/dt-bindings/memory/tegra234-mc.h +++ b/include/dt-bindings/memory/tegra234-mc.h @@ -11,6 +11,7 @@ /* NISO0 stream IDs */ #define TEGRA234_SID_APE 0x02 #define TEGRA234_SID_HDA 0x03 +#define TEGRA234_SID_GPCDMA 0x04 #define TEGRA234_SID_PCIE0 0x12 #define TEGRA234_SID_PCIE4 0x13 #define TEGRA234_SID_PCIE5 0x14 diff --git a/include/dt-bindings/reset/tegra234-reset.h b/include/dt-bindings/reset/tegra234-reset.h index 547ca3b60caa..5809245e4e21 100644 --- a/include/dt-bindings/reset/tegra234-reset.h +++ b/include/dt-bindings/reset/tegra234-reset.h @@ -15,6 +15,7 @@ #define TEGRA234_RESET_PEX1_COMMON_APB 13U #define TEGRA234_RESET_PEX2_CORE_7 14U #define TEGRA234_RESET_PEX2_CORE_7_APB 15U +#define TEGRA234_RESET_GPCDMA 18U #define TEGRA234_RESET_HDA 20U #define TEGRA234_RESET_HDACODEC 21U #define TEGRA234_RESET_I2C1 24U -- cgit v1.2.3 From 20e10881a043af63f2962a9e6bca64661225b383 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 8 Jun 2022 10:21:41 -0500 Subject: dma-buf: Add an API for exporting sync files (v14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modern userspace APIs like Vulkan are built on an explicit synchronization model. This doesn't always play nicely with the implicit synchronization used in the kernel and assumed by X11 and Wayland. The client -> compositor half of the synchronization isn't too bad, at least on intel, because we can control whether or not i915 synchronizes on the buffer and whether or not it's considered written. The harder part is the compositor -> client synchronization when we get the buffer back from the compositor. We're required to be able to provide the client with a VkSemaphore and VkFence representing the point in time where the window system (compositor and/or display) finished using the buffer. With current APIs, it's very hard to do this in such a way that we don't get confused by the Vulkan driver's access of the buffer. In particular, once we tell the kernel that we're rendering to the buffer again, any CPU waits on the buffer or GPU dependencies will wait on some of the client rendering and not just the compositor. This new IOCTL solves this problem by allowing us to get a snapshot of the implicit synchronization state of a given dma-buf in the form of a sync file. It's effectively the same as a poll() or I915_GEM_WAIT only, instead of CPU waiting directly, it encapsulates the wait operation, at the current moment in time, in a sync_file so we can check/wait on it later. As long as the Vulkan driver does the sync_file export from the dma-buf before we re-introduce it for rendering, it will only contain fences from the compositor or display. This allows to accurately turn it into a VkFence or VkSemaphore without any over-synchronization. By making this an ioctl on the dma-buf itself, it allows this new functionality to be used in an entirely driver-agnostic way without having access to a DRM fd. This makes it ideal for use in driver-generic code in Mesa or in a client such as a compositor where the DRM fd may be hard to reach. v2 (Jason Ekstrand): - Use a wrapper dma_fence_array of all fences including the new one when importing an exclusive fence. v3 (Jason Ekstrand): - Lock around setting shared fences as well as exclusive - Mark SIGNAL_SYNC_FILE as a read-write ioctl. - Initialize ret to 0 in dma_buf_wait_sync_file v4 (Jason Ekstrand): - Use the new dma_resv_get_singleton helper v5 (Jason Ekstrand): - Rename the IOCTLs to import/export rather than wait/signal - Drop the WRITE flag and always get/set the exclusive fence v6 (Jason Ekstrand): - Drop the sync_file import as it was all-around sketchy and not nearly as useful as import. - Re-introduce READ/WRITE flag support for export - Rework the commit message v7 (Jason Ekstrand): - Require at least one sync flag - Fix a refcounting bug: dma_resv_get_excl() doesn't take a reference - Use _rcu helpers since we're accessing the dma_resv read-only v8 (Jason Ekstrand): - Return -ENOMEM if the sync_file_create fails - Predicate support on IS_ENABLED(CONFIG_SYNC_FILE) v9 (Jason Ekstrand): - Add documentation for the new ioctl v10 (Jason Ekstrand): - Go back to dma_buf_sync_file as the ioctl struct name v11 (Daniel Vetter): - Go back to dma_buf_export_sync_file as the ioctl struct name - Better kerneldoc describing what the read/write flags do v12 (Christian König): - Document why we chose to make it an ioctl on dma-buf v13 (Jason Ekstrand): - Rebase on Christian König's fence rework v14 (Daniel Vetter & Christian König): - Use dma_rev_usage_rw to get the properly inverted usage to pass to dma_resv_get_singleton() - Clean up the sync_file and fd if copy_to_user() fails Signed-off-by: Jason Ekstrand Signed-off-by: Jason Ekstrand Signed-off-by: Jason Ekstrand Acked-by: Simon Ser Reviewed-by: Christian König Reviewed-by: Daniel Vetter Cc: Sumit Semwal Cc: Maarten Lankhorst Signed-off-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20220608152142.14495-2-jason@jlekstrand.net --- drivers/dma-buf/dma-buf.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/dma-buf.h | 35 +++++++++++++++++++++++ 2 files changed, 102 insertions(+) (limited to 'include') diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index a2f9a1815e38..491797a5dfc8 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -192,6 +193,9 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence) * Note that this only signals the completion of the respective fences, i.e. the * DMA transfers are complete. Cache flushing and any other necessary * preparations before CPU access can begin still need to happen. + * + * As an alternative to poll(), the set of fences on DMA buffer can be + * exported as a &sync_file using &dma_buf_sync_file_export. */ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb) @@ -326,6 +330,64 @@ static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf) return 0; } +#if IS_ENABLED(CONFIG_SYNC_FILE) +static long dma_buf_export_sync_file(struct dma_buf *dmabuf, + void __user *user_data) +{ + struct dma_buf_export_sync_file arg; + enum dma_resv_usage usage; + struct dma_fence *fence = NULL; + struct sync_file *sync_file; + int fd, ret; + + if (copy_from_user(&arg, user_data, sizeof(arg))) + return -EFAULT; + + if (arg.flags & ~DMA_BUF_SYNC_RW) + return -EINVAL; + + if ((arg.flags & DMA_BUF_SYNC_RW) == 0) + return -EINVAL; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) + return fd; + + usage = dma_resv_usage_rw(arg.flags & DMA_BUF_SYNC_WRITE); + ret = dma_resv_get_singleton(dmabuf->resv, usage, &fence); + if (ret) + goto err_put_fd; + + if (!fence) + fence = dma_fence_get_stub(); + + sync_file = sync_file_create(fence); + + dma_fence_put(fence); + + if (!sync_file) { + ret = -ENOMEM; + goto err_put_fd; + } + + arg.fd = fd; + if (copy_to_user(user_data, &arg, sizeof(arg))) { + ret = -EFAULT; + goto err_put_file; + } + + fd_install(fd, sync_file->file); + + return 0; + +err_put_file: + fput(sync_file->file); +err_put_fd: + put_unused_fd(fd); + return ret; +} +#endif + static long dma_buf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -369,6 +431,11 @@ static long dma_buf_ioctl(struct file *file, case DMA_BUF_SET_NAME_B: return dma_buf_set_name(dmabuf, (const char __user *)arg); +#if IS_ENABLED(CONFIG_SYNC_FILE) + case DMA_BUF_IOCTL_EXPORT_SYNC_FILE: + return dma_buf_export_sync_file(dmabuf, (void __user *)arg); +#endif + default: return -ENOTTY; } diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h index 8e4a2ca0bcbf..46f1e3e98b02 100644 --- a/include/uapi/linux/dma-buf.h +++ b/include/uapi/linux/dma-buf.h @@ -85,6 +85,40 @@ struct dma_buf_sync { #define DMA_BUF_NAME_LEN 32 +/** + * struct dma_buf_export_sync_file - Get a sync_file from a dma-buf + * + * Userspace can perform a DMA_BUF_IOCTL_EXPORT_SYNC_FILE to retrieve the + * current set of fences on a dma-buf file descriptor as a sync_file. CPU + * waits via poll() or other driver-specific mechanisms typically wait on + * whatever fences are on the dma-buf at the time the wait begins. This + * is similar except that it takes a snapshot of the current fences on the + * dma-buf for waiting later instead of waiting immediately. This is + * useful for modern graphics APIs such as Vulkan which assume an explicit + * synchronization model but still need to inter-operate with dma-buf. + */ +struct dma_buf_export_sync_file { + /** + * @flags: Read/write flags + * + * Must be DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, or both. + * + * If DMA_BUF_SYNC_READ is set and DMA_BUF_SYNC_WRITE is not set, + * the returned sync file waits on any writers of the dma-buf to + * complete. Waiting on the returned sync file is equivalent to + * poll() with POLLIN. + * + * If DMA_BUF_SYNC_WRITE is set, the returned sync file waits on + * any users of the dma-buf (read or write) to complete. Waiting + * on the returned sync file is equivalent to poll() with POLLOUT. + * If both DMA_BUF_SYNC_WRITE and DMA_BUF_SYNC_READ are set, this + * is equivalent to just DMA_BUF_SYNC_WRITE. + */ + __u32 flags; + /** @fd: Returned sync file descriptor */ + __s32 fd; +}; + #define DMA_BUF_BASE 'b' #define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync) @@ -94,5 +128,6 @@ struct dma_buf_sync { #define DMA_BUF_SET_NAME _IOW(DMA_BUF_BASE, 1, const char *) #define DMA_BUF_SET_NAME_A _IOW(DMA_BUF_BASE, 1, u32) #define DMA_BUF_SET_NAME_B _IOW(DMA_BUF_BASE, 1, u64) +#define DMA_BUF_IOCTL_EXPORT_SYNC_FILE _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file) #endif -- cgit v1.2.3 From 594740497e998d30477ab26093bfb81c28cd3ff1 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 8 Jun 2022 10:21:42 -0500 Subject: dma-buf: Add an API for importing sync files (v10) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is analogous to the previous sync file export patch in that it allows you to import a sync_file into a dma-buf. Unlike the previous patch, however, this does add genuinely new functionality to dma-buf. Without this, the only way to attach a sync_file to a dma-buf is to submit a batch to your driver of choice which waits on the sync_file and claims to write to the dma-buf. Even if said batch is a no-op, a submit is typically way more overhead than just attaching a fence. A submit may also imply extra synchronization with other work because it happens on a hardware queue. In the Vulkan world, this is useful for dealing with the out-fence from vkQueuePresent. Current Linux window-systems (X11, Wayland, etc.) all rely on dma-buf implicit sync. Since Vulkan is an explicit sync API, we get a set of fences (VkSemaphores) in vkQueuePresent and have to stash those as an exclusive (write) fence on the dma-buf. We handle it in Mesa today with the above mentioned dummy submit trick. This ioctl would allow us to set it directly without the dummy submit. This may also open up possibilities for GPU drivers to move away from implicit sync for their kernel driver uAPI and instead provide sync files and rely on dma-buf import/export for communicating with other implicit sync clients. We make the explicit choice here to only allow setting RW fences which translates to an exclusive fence on the dma_resv. There's no use for read-only fences for communicating with other implicit sync userspace and any such attempts are likely to be racy at best. When we got to insert the RW fence, the actual fence we set as the new exclusive fence is a combination of the sync_file provided by the user and all the other fences on the dma_resv. This ensures that the newly added exclusive fence will never signal before the old one would have and ensures that we don't break any dma_resv contracts. We require userspace to specify RW in the flags for symmetry with the export ioctl and in case we ever want to support read fences in the future. There is one downside here that's worth documenting: If two clients writing to the same dma-buf using this API race with each other, their actions on the dma-buf may happen in parallel or in an undefined order. Both with and without this API, the pattern is the same: Collect all the fences on dma-buf, submit work which depends on said fences, and then set a new exclusive (write) fence on the dma-buf which depends on said work. The difference is that, when it's all handled by the GPU driver's submit ioctl, the three operations happen atomically under the dma_resv lock. If two userspace submits race, one will happen before the other. You aren't guaranteed which but you are guaranteed that they're strictly ordered. If userspace manages the fences itself, then these three operations happen separately and the two render operations may happen genuinely in parallel or get interleaved. However, this is a case of userspace racing with itself. As long as we ensure userspace can't back the kernel into a corner, it should be fine. v2 (Jason Ekstrand): - Use a wrapper dma_fence_array of all fences including the new one when importing an exclusive fence. v3 (Jason Ekstrand): - Lock around setting shared fences as well as exclusive - Mark SIGNAL_SYNC_FILE as a read-write ioctl. - Initialize ret to 0 in dma_buf_wait_sync_file v4 (Jason Ekstrand): - Use the new dma_resv_get_singleton helper v5 (Jason Ekstrand): - Rename the IOCTLs to import/export rather than wait/signal - Drop the WRITE flag and always get/set the exclusive fence v6 (Jason Ekstrand): - Split import and export into separate patches - New commit message v7 (Daniel Vetter): - Fix the uapi header to use the right struct in the ioctl - Use a separate dma_buf_import_sync_file struct - Add kerneldoc for dma_buf_import_sync_file v8 (Jason Ekstrand): - Rebase on Christian König's fence rework v9 (Daniel Vetter): - Fix -EINVAL checks for the flags parameter - Add documentation about read/write fences - Add documentation about the expected usage of import/export and specifically call out the possible userspace race. v10 (Simon Ser): - Fix a typo in the docs Signed-off-by: Jason Ekstrand Signed-off-by: Jason Ekstrand Signed-off-by: Jason Ekstrand Reviewed-by: Christian König Reviewed-by: Daniel Vetter Cc: Sumit Semwal Cc: Maarten Lankhorst Signed-off-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20220608152142.14495-3-jason@jlekstrand.net --- drivers/dma-buf/dma-buf.c | 39 +++++++++++++++++++++++++++++++++++ include/uapi/linux/dma-buf.h | 49 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) (limited to 'include') diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 491797a5dfc8..5e1b0534b3ce 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -386,6 +386,43 @@ err_put_fd: put_unused_fd(fd); return ret; } + +static long dma_buf_import_sync_file(struct dma_buf *dmabuf, + const void __user *user_data) +{ + struct dma_buf_import_sync_file arg; + struct dma_fence *fence; + enum dma_resv_usage usage; + int ret = 0; + + if (copy_from_user(&arg, user_data, sizeof(arg))) + return -EFAULT; + + if (arg.flags & ~DMA_BUF_SYNC_RW) + return -EINVAL; + + if ((arg.flags & DMA_BUF_SYNC_RW) == 0) + return -EINVAL; + + fence = sync_file_get_fence(arg.fd); + if (!fence) + return -EINVAL; + + usage = (arg.flags & DMA_BUF_SYNC_WRITE) ? DMA_RESV_USAGE_WRITE : + DMA_RESV_USAGE_READ; + + dma_resv_lock(dmabuf->resv, NULL); + + ret = dma_resv_reserve_fences(dmabuf->resv, 1); + if (!ret) + dma_resv_add_fence(dmabuf->resv, fence, usage); + + dma_resv_unlock(dmabuf->resv); + + dma_fence_put(fence); + + return ret; +} #endif static long dma_buf_ioctl(struct file *file, @@ -434,6 +471,8 @@ static long dma_buf_ioctl(struct file *file, #if IS_ENABLED(CONFIG_SYNC_FILE) case DMA_BUF_IOCTL_EXPORT_SYNC_FILE: return dma_buf_export_sync_file(dmabuf, (void __user *)arg); + case DMA_BUF_IOCTL_IMPORT_SYNC_FILE: + return dma_buf_import_sync_file(dmabuf, (const void __user *)arg); #endif default: diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h index 46f1e3e98b02..30fb8834aa3c 100644 --- a/include/uapi/linux/dma-buf.h +++ b/include/uapi/linux/dma-buf.h @@ -96,6 +96,24 @@ struct dma_buf_sync { * dma-buf for waiting later instead of waiting immediately. This is * useful for modern graphics APIs such as Vulkan which assume an explicit * synchronization model but still need to inter-operate with dma-buf. + * + * The intended usage pattern is the following: + * + * 1. Export a sync_file with flags corresponding to the expected GPU usage + * via DMA_BUF_IOCTL_EXPORT_SYNC_FILE. + * + * 2. Submit rendering work which uses the dma-buf. The work should wait on + * the exported sync file before rendering and produce another sync_file + * when complete. + * + * 3. Import the rendering-complete sync_file into the dma-buf with flags + * corresponding to the GPU usage via DMA_BUF_IOCTL_IMPORT_SYNC_FILE. + * + * Unlike doing implicit synchronization via a GPU kernel driver's exec ioctl, + * the above is not a single atomic operation. If userspace wants to ensure + * ordering via these fences, it is the respnosibility of userspace to use + * locks or other mechanisms to ensure that no other context adds fences or + * submits work between steps 1 and 3 above. */ struct dma_buf_export_sync_file { /** @@ -119,6 +137,36 @@ struct dma_buf_export_sync_file { __s32 fd; }; +/** + * struct dma_buf_import_sync_file - Insert a sync_file into a dma-buf + * + * Userspace can perform a DMA_BUF_IOCTL_IMPORT_SYNC_FILE to insert a + * sync_file into a dma-buf for the purposes of implicit synchronization + * with other dma-buf consumers. This allows clients using explicitly + * synchronized APIs such as Vulkan to inter-op with dma-buf consumers + * which expect implicit synchronization such as OpenGL or most media + * drivers/video. + */ +struct dma_buf_import_sync_file { + /** + * @flags: Read/write flags + * + * Must be DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, or both. + * + * If DMA_BUF_SYNC_READ is set and DMA_BUF_SYNC_WRITE is not set, + * this inserts the sync_file as a read-only fence. Any subsequent + * implicitly synchronized writes to this dma-buf will wait on this + * fence but reads will not. + * + * If DMA_BUF_SYNC_WRITE is set, this inserts the sync_file as a + * write fence. All subsequent implicitly synchronized access to + * this dma-buf will wait on this fence. + */ + __u32 flags; + /** @fd: Sync file descriptor */ + __s32 fd; +}; + #define DMA_BUF_BASE 'b' #define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync) @@ -129,5 +177,6 @@ struct dma_buf_export_sync_file { #define DMA_BUF_SET_NAME_A _IOW(DMA_BUF_BASE, 1, u32) #define DMA_BUF_SET_NAME_B _IOW(DMA_BUF_BASE, 1, u64) #define DMA_BUF_IOCTL_EXPORT_SYNC_FILE _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file) +#define DMA_BUF_IOCTL_IMPORT_SYNC_FILE _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file) #endif -- cgit v1.2.3 From 5dfac65b621733e69b789150a0a3f1bf2f9095a3 Mon Sep 17 00:00:00 2001 From: David Jander Date: Wed, 8 Jun 2022 17:33:09 +0200 Subject: spi: : Add missing documentation for struct members Fixes these "make htmldocs" warnings: include/linux/spi/spi.h:82: warning: Function parameter or member 'syncp' not described in 'spi_statistics' include/linux/spi/spi.h:213: warning: Function parameter or member 'pcpu_statistics' not described in 'spi_device' include/linux/spi/spi.h:676: warning: Function parameter or member 'pcpu_statistics' not described in 'spi_controller' Fixes: 6598b91b5ac3 ("spi: spi.c: Convert statistics to per-cpu u64_stats_t") Reported-by: Stephen Rothwell Signed-off-by: David Jander Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220608153309.2899565-1-david@protonic.nl Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index eac8d3caf954..2e63b4935deb 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -35,7 +35,8 @@ extern struct bus_type spi_bus_type; /** * struct spi_statistics - statistics for spi transfers - * @lock: lock protecting this structure + * @syncp: seqcount to protect members in this struct for per-cpu udate + * on 32-bit systems * * @messages: number of spi-messages handled * @transfers: number of spi_transfers handled @@ -155,7 +156,7 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer); * @cs_inactive: delay to be introduced by the controller after CS is * deasserted. If @cs_change_delay is used from @spi_transfer, then the * two delays will be added up. - * @statistics: statistics for the spi_device + * @pcpu_statistics: statistics for the spi_device * * A @spi_device is used to interchange data between an SPI slave * (usually a discrete chip) and CPU memory. @@ -439,7 +440,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch * @max_native_cs: When cs_gpiods is used, and this field is filled in, * spi_register_controller() will validate all native CS (including the * unused native CS) against this value. - * @statistics: statistics for the spi_controller + * @pcpu_statistics: statistics for the spi_controller * @dma_tx: DMA transmit channel * @dma_rx: DMA receive channel * @dummy_rx: dummy receive buffer for full-duplex devices -- cgit v1.2.3 From a84a434baf9427a1c49782fb1f0973d1308016df Mon Sep 17 00:00:00 2001 From: Peter Lafreniere Date: Mon, 6 Jun 2022 07:34:58 -0400 Subject: net: constify some inline functions in sock.h Despite these inline functions having full visibility to the compiler at compile time, they still strip const from passed pointers. This change allows for functions in various network drivers to be marked as const that could not be marked const before. Signed-off-by: Peter Lafreniere Link: https://lore.kernel.org/r/20220606113458.35953-1-pjlafren@mtu.edu Signed-off-by: Jakub Kicinski --- include/net/sock.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index c585ef6565d9..657873e2d90f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -611,7 +611,7 @@ void sock_net_set(struct sock *sk, struct net *net) int sk_set_peek_off(struct sock *sk, int val); -static inline int sk_peek_offset(struct sock *sk, int flags) +static inline int sk_peek_offset(const struct sock *sk, int flags) { if (unlikely(flags & MSG_PEEK)) { return READ_ONCE(sk->sk_peek_off); @@ -863,7 +863,7 @@ static inline void sk_add_bind2_node(struct sock *sk, struct hlist_head *list) ({ tpos = (typeof(*tpos) *)((void *)pos - offset); 1;}); \ pos = rcu_dereference(hlist_next_rcu(pos))) -static inline struct user_namespace *sk_user_ns(struct sock *sk) +static inline struct user_namespace *sk_user_ns(const struct sock *sk) { /* Careful only use this in a context where these parameters * can not change and must all be valid, such as recvmsg from @@ -909,7 +909,7 @@ enum sock_flags { #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) -static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) +static inline void sock_copy_flags(struct sock *nsk, const struct sock *osk) { nsk->sk_flags = osk->sk_flags; } -- cgit v1.2.3 From a1eda864c04cf24ea1130334963c6199318f6f95 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Mon, 16 May 2022 09:06:00 +0200 Subject: mtdchar: prevent integer overflow in a safety check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6420ac0af95d ("mtdchar: prevent unbounded allocation in MEMWRITE ioctl") added a safety check to mtdchar_write_ioctl() which attempts to ensure that the write request sent by user space does not extend beyond the MTD device's size. However, that check contains an addition of two struct mtd_write_req fields, 'start' and 'len', both of which are u64 variables. The result of that addition can overflow, allowing the safety check to be bypassed. The arguably simplest fix - changing the data types of the relevant struct mtd_write_req fields - is not feasible as it would break user space. Fix by making mtdchar_write_ioctl() truncate the value provided by user space in the 'len' field of struct mtd_write_req, so that only the lower 32 bits of that field are used, preventing the overflow. While the 'ooblen' field of struct mtd_write_req is not currently used in any similarly flawed safety check, also truncate it to 32 bits, for consistency with the 'len' field and with other MTD routines handling OOB data. Update include/uapi/mtd/mtd-abi.h accordingly. Suggested-by: Richard Weinberger Signed-off-by: Michał Kępień Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20220516070601.11428-2-kernel@kempniu.pl --- drivers/mtd/mtdchar.c | 3 +++ include/uapi/mtd/mtd-abi.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d0f9c4b0285c..b2700f8467ff 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -615,6 +615,9 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd, if (!usr_oob) req.ooblen = 0; + req.len &= 0xffffffff; + req.ooblen &= 0xffffffff; + if (req.start + req.len > mtd->size) return -EINVAL; diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h index b869990c2db2..890d9e5b76d7 100644 --- a/include/uapi/mtd/mtd-abi.h +++ b/include/uapi/mtd/mtd-abi.h @@ -69,8 +69,8 @@ enum { * struct mtd_write_req - data structure for requesting a write operation * * @start: start address - * @len: length of data buffer - * @ooblen: length of OOB buffer + * @len: length of data buffer (only lower 32 bits are used) + * @ooblen: length of OOB buffer (only lower 32 bits are used) * @usr_data: user-provided data buffer * @usr_oob: user-provided OOB buffer * @mode: MTD mode (see "MTD operation modes") -- cgit v1.2.3 From 0c90466a7985d39355f743e9cd2139da3e86c4d8 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 3 Jun 2022 23:07:45 +0200 Subject: mtd: hyperbus: Make hyperbus_unregister_device() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only thing that could theoretically fail in that function is mtd_device_unregister(). However it's not supposed to fail and when used correctly it doesn't. So wail loudly if it does anyhow. This matches how other drivers (e.g. nand/raw/nandsim.c) use mtd_device_unregister(). This is a preparation for making platform remove callbacks return void. Signed-off-by: Uwe Kleine-König Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20220603210758.148493-2-u.kleine-koenig@pengutronix.de --- drivers/mtd/hyperbus/hbmc-am654.c | 6 +++--- drivers/mtd/hyperbus/hyperbus-core.c | 8 ++------ drivers/mtd/hyperbus/rpc-if.c | 5 +++-- include/linux/mtd/hyperbus.h | 4 +--- 4 files changed, 9 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/mtd/hyperbus/hbmc-am654.c b/drivers/mtd/hyperbus/hbmc-am654.c index a3439b791eeb..a6161ce340d4 100644 --- a/drivers/mtd/hyperbus/hbmc-am654.c +++ b/drivers/mtd/hyperbus/hbmc-am654.c @@ -233,16 +233,16 @@ static int am654_hbmc_remove(struct platform_device *pdev) { struct am654_hbmc_priv *priv = platform_get_drvdata(pdev); struct am654_hbmc_device_priv *dev_priv = priv->hbdev.priv; - int ret; - ret = hyperbus_unregister_device(&priv->hbdev); + hyperbus_unregister_device(&priv->hbdev); + if (priv->mux_ctrl) mux_control_deselect(priv->mux_ctrl); if (dev_priv->rx_chan) dma_release_channel(dev_priv->rx_chan); - return ret; + return 0; } static const struct of_device_id am654_hbmc_dt_ids[] = { diff --git a/drivers/mtd/hyperbus/hyperbus-core.c b/drivers/mtd/hyperbus/hyperbus-core.c index 2f9fc4e17d53..4d8047d43e48 100644 --- a/drivers/mtd/hyperbus/hyperbus-core.c +++ b/drivers/mtd/hyperbus/hyperbus-core.c @@ -126,16 +126,12 @@ int hyperbus_register_device(struct hyperbus_device *hbdev) } EXPORT_SYMBOL_GPL(hyperbus_register_device); -int hyperbus_unregister_device(struct hyperbus_device *hbdev) +void hyperbus_unregister_device(struct hyperbus_device *hbdev) { - int ret = 0; - if (hbdev && hbdev->mtd) { - ret = mtd_device_unregister(hbdev->mtd); + WARN_ON(mtd_device_unregister(hbdev->mtd)); map_destroy(hbdev->mtd); } - - return ret; } EXPORT_SYMBOL_GPL(hyperbus_unregister_device); diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index 6e08ec1d4f09..15a0be63ede1 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -153,11 +153,12 @@ static int rpcif_hb_probe(struct platform_device *pdev) static int rpcif_hb_remove(struct platform_device *pdev) { struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev); - int error = hyperbus_unregister_device(&hyperbus->hbdev); + + hyperbus_unregister_device(&hyperbus->hbdev); rpcif_disable_rpm(&hyperbus->rpc); - return error; + return 0; } static struct platform_driver rpcif_platform_driver = { diff --git a/include/linux/mtd/hyperbus.h b/include/linux/mtd/hyperbus.h index 0ce612428aea..bb6b7121a542 100644 --- a/include/linux/mtd/hyperbus.h +++ b/include/linux/mtd/hyperbus.h @@ -89,9 +89,7 @@ int hyperbus_register_device(struct hyperbus_device *hbdev); /** * hyperbus_unregister_device - deregister HyperBus slave memory device * @hbdev: hyperbus_device to be unregistered - * - * Return: 0 for success, others for failure. */ -int hyperbus_unregister_device(struct hyperbus_device *hbdev); +void hyperbus_unregister_device(struct hyperbus_device *hbdev); #endif /* __LINUX_MTD_HYPERBUS_H__ */ -- cgit v1.2.3 From 0949ee75da6c918fcbd567e1bfa4943a56ab4e5d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 7 Jun 2022 20:23:34 +0200 Subject: firmware: sysfb: Make sysfb_create_simplefb() return a pdev pointer This function just returned 0 on success or an errno code on error, but it could be useful for sysfb_init() callers to have a pointer to the device. Signed-off-by: Javier Martinez Canillas Reviewed-by: Daniel Vetter Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20220607182338.344270-2-javierm@redhat.com --- drivers/firmware/sysfb.c | 4 ++-- drivers/firmware/sysfb_simplefb.c | 16 ++++++++-------- include/linux/sysfb.h | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c index 2bfbb05f7d89..b032f40a92de 100644 --- a/drivers/firmware/sysfb.c +++ b/drivers/firmware/sysfb.c @@ -46,8 +46,8 @@ static __init int sysfb_init(void) /* try to create a simple-framebuffer device */ compatible = sysfb_parse_mode(si, &mode); if (compatible) { - ret = sysfb_create_simplefb(si, &mode); - if (!ret) + pd = sysfb_create_simplefb(si, &mode); + if (!IS_ERR(pd)) return 0; } diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c index bda8712bfd8c..a353e27f83f5 100644 --- a/drivers/firmware/sysfb_simplefb.c +++ b/drivers/firmware/sysfb_simplefb.c @@ -57,8 +57,8 @@ __init bool sysfb_parse_mode(const struct screen_info *si, return false; } -__init int sysfb_create_simplefb(const struct screen_info *si, - const struct simplefb_platform_data *mode) +__init struct platform_device *sysfb_create_simplefb(const struct screen_info *si, + const struct simplefb_platform_data *mode) { struct platform_device *pd; struct resource res; @@ -76,7 +76,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si, base |= (u64)si->ext_lfb_base << 32; if (!base || (u64)(resource_size_t)base != base) { printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); } /* @@ -93,7 +93,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si, length = mode->height * mode->stride; if (length > size) { printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); } length = PAGE_ALIGN(length); @@ -104,11 +104,11 @@ __init int sysfb_create_simplefb(const struct screen_info *si, res.start = base; res.end = res.start + length - 1; if (res.end <= res.start) - return -EINVAL; + return ERR_PTR(-EINVAL); pd = platform_device_alloc("simple-framebuffer", 0); if (!pd) - return -ENOMEM; + return ERR_PTR(-ENOMEM); sysfb_apply_efi_quirks(pd); @@ -124,10 +124,10 @@ __init int sysfb_create_simplefb(const struct screen_info *si, if (ret) goto err_put_device; - return 0; + return pd; err_put_device: platform_device_put(pd); - return ret; + return ERR_PTR(ret); } diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h index b0dcfa26d07b..708152e9037b 100644 --- a/include/linux/sysfb.h +++ b/include/linux/sysfb.h @@ -72,8 +72,8 @@ static inline void sysfb_apply_efi_quirks(struct platform_device *pd) bool sysfb_parse_mode(const struct screen_info *si, struct simplefb_platform_data *mode); -int sysfb_create_simplefb(const struct screen_info *si, - const struct simplefb_platform_data *mode); +struct platform_device *sysfb_create_simplefb(const struct screen_info *si, + const struct simplefb_platform_data *mode); #else /* CONFIG_SYSFB_SIMPLE */ @@ -83,10 +83,10 @@ static inline bool sysfb_parse_mode(const struct screen_info *si, return false; } -static inline int sysfb_create_simplefb(const struct screen_info *si, - const struct simplefb_platform_data *mode) +static inline struct platform_device *sysfb_create_simplefb(const struct screen_info *si, + const struct simplefb_platform_data *mode) { - return -EINVAL; + return ERR_PTR(-EINVAL); } #endif /* CONFIG_SYSFB_SIMPLE */ -- cgit v1.2.3 From bc824922b264aff40eba8c160972ee07a95e7dd4 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 7 Jun 2022 20:23:35 +0200 Subject: firmware: sysfb: Add sysfb_disable() helper function This can be used by subsystems to unregister a platform device registered by sysfb and also to disable future platform device registration in sysfb. Suggested-by: Daniel Vetter Signed-off-by: Javier Martinez Canillas Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20220607182338.344270-3-javierm@redhat.com --- .../driver-api/firmware/other_interfaces.rst | 6 +++ drivers/firmware/sysfb.c | 54 +++++++++++++++++++--- include/linux/sysfb.h | 12 +++++ 3 files changed, 66 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/firmware/other_interfaces.rst b/Documentation/driver-api/firmware/other_interfaces.rst index b81794e0cfbb..06ac89adaafb 100644 --- a/Documentation/driver-api/firmware/other_interfaces.rst +++ b/Documentation/driver-api/firmware/other_interfaces.rst @@ -13,6 +13,12 @@ EDD Interfaces .. kernel-doc:: drivers/firmware/edd.c :internal: +Generic System Framebuffers Interface +------------------------------------- + +.. kernel-doc:: drivers/firmware/sysfb.c + :export: + Intel Stratix10 SoC Service Layer --------------------------------- Some features of the Intel Stratix10 SoC require a level of privilege diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c index b032f40a92de..1f276f108cc9 100644 --- a/drivers/firmware/sysfb.c +++ b/drivers/firmware/sysfb.c @@ -34,21 +34,59 @@ #include #include +static struct platform_device *pd; +static DEFINE_MUTEX(disable_lock); +static bool disabled; + +static bool sysfb_unregister(void) +{ + if (IS_ERR_OR_NULL(pd)) + return false; + + platform_device_unregister(pd); + pd = NULL; + + return true; +} + +/** + * sysfb_disable() - disable the Generic System Framebuffers support + * + * This disables the registration of system framebuffer devices that match the + * generic drivers that make use of the system framebuffer set up by firmware. + * + * It also unregisters a device if this was already registered by sysfb_init(). + * + * Context: The function can sleep. A @disable_lock mutex is acquired to serialize + * against sysfb_init(), that registers a system framebuffer device. + */ +void sysfb_disable(void) +{ + mutex_lock(&disable_lock); + sysfb_unregister(); + disabled = true; + mutex_unlock(&disable_lock); +} +EXPORT_SYMBOL_GPL(sysfb_disable); + static __init int sysfb_init(void) { struct screen_info *si = &screen_info; struct simplefb_platform_data mode; - struct platform_device *pd; const char *name; bool compatible; - int ret; + int ret = 0; + + mutex_lock(&disable_lock); + if (disabled) + goto unlock_mutex; /* try to create a simple-framebuffer device */ compatible = sysfb_parse_mode(si, &mode); if (compatible) { pd = sysfb_create_simplefb(si, &mode); if (!IS_ERR(pd)) - return 0; + goto unlock_mutex; } /* if the FB is incompatible, create a legacy framebuffer device */ @@ -60,8 +98,10 @@ static __init int sysfb_init(void) name = "platform-framebuffer"; pd = platform_device_alloc(name, 0); - if (!pd) - return -ENOMEM; + if (!pd) { + ret = -ENOMEM; + goto unlock_mutex; + } sysfb_apply_efi_quirks(pd); @@ -73,9 +113,11 @@ static __init int sysfb_init(void) if (ret) goto err; - return 0; + goto unlock_mutex; err: platform_device_put(pd); +unlock_mutex: + mutex_unlock(&disable_lock); return ret; } diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h index 708152e9037b..8ba8b5be5567 100644 --- a/include/linux/sysfb.h +++ b/include/linux/sysfb.h @@ -55,6 +55,18 @@ struct efifb_dmi_info { int flags; }; +#ifdef CONFIG_SYSFB + +void sysfb_disable(void); + +#else /* CONFIG_SYSFB */ + +static inline void sysfb_disable(void) +{ +} + +#endif /* CONFIG_SYSFB */ + #ifdef CONFIG_EFI extern struct efifb_dmi_info efifb_dmi_list[]; -- cgit v1.2.3 From ea7f0f777d28db6e500a05836f2a9d467c7012de Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:37 +0000 Subject: platform/chrome: cros_ec_commands: fix compile errors Fix compile errors when including cros_ec_commands.h solely. 1. cros_ec_commands.h:587:9: error: unknown type name 'uint8_t' 587 | uint8_t flags; | ^~~~~~~ 2. cros_ec_commands.h:1105:43: error: implicit declaration of function 'BIT' 1105 | EC_COMMS_STATUS_PROCESSING = BIT(0), | ^~~ Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-2-tzungbi@kernel.org --- include/linux/platform_data/cros_ec_commands.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index e59f51c41a1c..f13568b3e247 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -13,8 +13,8 @@ #ifndef __CROS_EC_COMMANDS_H #define __CROS_EC_COMMANDS_H - - +#include +#include #define BUILD_ASSERT(_cond) -- cgit v1.2.3 From 3db0c9e5de7bd9dbe52580eb9752b2b3049e38da Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:39 +0000 Subject: platform/chrome: use macros for passthru indexes Move passthru indexes for EC and PD devices to common header. Also use them instead of literal constants. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-4-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec.c | 3 --- drivers/platform/chrome/cros_ec_proto.c | 6 +++--- drivers/platform/chrome/cros_ec_proto_test.c | 15 ++++++++++----- drivers/platform/chrome/cros_ec_trace.h | 8 ++++---- include/linux/platform_data/cros_ec_proto.h | 3 +++ 5 files changed, 20 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index b3e94cdf7d1a..e51a3f2176c7 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -19,9 +19,6 @@ #include "cros_ec.h" -#define CROS_EC_DEV_EC_INDEX 0 -#define CROS_EC_DEV_PD_INDEX 1 - static struct cros_ec_platform ec_p = { .ec_name = CROS_EC_DEV_NAME, .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX), diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index cefabfe45551..cfa3dacce4e5 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -433,7 +433,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) /* First try sending with proto v3. */ ec_dev->proto_version = 3; - ret = cros_ec_host_command_proto_query(ec_dev, 0, proto_msg); + ret = cros_ec_host_command_proto_query(ec_dev, CROS_EC_DEV_EC_INDEX, proto_msg); if (ret == 0) { proto_info = (struct ec_response_get_protocol_info *) @@ -459,7 +459,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) /* * Check for PD */ - ret = cros_ec_host_command_proto_query(ec_dev, 1, proto_msg); + ret = cros_ec_host_command_proto_query(ec_dev, CROS_EC_DEV_PD_INDEX, proto_msg); if (ret) { dev_dbg(ec_dev->dev, "no PD chip found: %d\n", ret); @@ -609,7 +609,7 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) msg->insize = ec_dev->max_response; } - if (msg->command < EC_CMD_PASSTHRU_OFFSET(1)) { + if (msg->command < EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX)) { if (msg->outsize > ec_dev->max_request) { dev_err(ec_dev->dev, "request of size %u is too big (max: %u)\n", diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 675306c16d47..f8dbfb0d8dc8 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -281,7 +281,8 @@ static void cros_ec_proto_test_query_all_normal(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); @@ -396,7 +397,8 @@ static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); @@ -685,7 +687,8 @@ static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); @@ -783,7 +786,8 @@ static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); @@ -889,7 +893,8 @@ static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct k KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); diff --git a/drivers/platform/chrome/cros_ec_trace.h b/drivers/platform/chrome/cros_ec_trace.h index 9bb5cd2c98b8..d7e407de88df 100644 --- a/drivers/platform/chrome/cros_ec_trace.h +++ b/drivers/platform/chrome/cros_ec_trace.h @@ -30,8 +30,8 @@ TRACE_EVENT(cros_ec_request_start, ), TP_fast_assign( __entry->version = cmd->version; - __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1); - __entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1); + __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX); + __entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX); __entry->outsize = cmd->outsize; __entry->insize = cmd->insize; ), @@ -55,8 +55,8 @@ TRACE_EVENT(cros_ec_request_done, ), TP_fast_assign( __entry->version = cmd->version; - __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1); - __entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1); + __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX); + __entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX); __entry->outsize = cmd->outsize; __entry->insize = cmd->insize; __entry->result = cmd->result; diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 85e29300f63d..c82a8285d936 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -21,6 +21,9 @@ #define CROS_EC_DEV_SCP_NAME "cros_scp" #define CROS_EC_DEV_TP_NAME "cros_tp" +#define CROS_EC_DEV_EC_INDEX 0 +#define CROS_EC_DEV_PD_INDEX 1 + /* * The EC is unresponsive for a time after a reboot command. Add a * simple delay to make sure that the bus stays locked. -- cgit v1.2.3 From d62607c3fe45911b2331fac073355a8c914bbde2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 7 Jun 2022 21:39:55 -0700 Subject: net: rename reference+tracking helpers Netdev reference helpers have a dev_ prefix for historic reasons. Renaming the old helpers would be too much churn but we can rename the tracking ones which are relatively recent and should be the default for new code. Rename: dev_hold_track() -> netdev_hold() dev_put_track() -> netdev_put() dev_replace_track() -> netdev_ref_replace() Link: https://lore.kernel.org/r/20220608043955.919359-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/eql.c | 4 ++-- drivers/net/macsec.c | 4 ++-- drivers/net/macvlan.c | 4 ++-- drivers/net/netconsole.c | 2 +- drivers/net/vrf.c | 8 ++++---- include/linux/netdevice.h | 24 ++++++++++++------------ include/net/xfrm.h | 2 +- net/8021q/vlan_dev.c | 4 ++-- net/ax25/af_ax25.c | 7 ++++--- net/ax25/ax25_dev.c | 6 +++--- net/bridge/br_if.c | 10 +++++----- net/core/dev.c | 10 +++++----- net/core/dev_ioctl.c | 4 ++-- net/core/drop_monitor.c | 5 +++-- net/core/dst.c | 8 ++++---- net/core/failover.c | 4 ++-- net/core/link_watch.c | 2 +- net/core/neighbour.c | 18 +++++++++--------- net/core/net-sysfs.c | 8 ++++---- net/core/netpoll.c | 2 +- net/core/pktgen.c | 6 +++--- net/ethtool/ioctl.c | 4 ++-- net/ethtool/netlink.c | 6 +++--- net/ethtool/netlink.h | 2 +- net/ipv4/devinet.c | 4 ++-- net/ipv4/fib_semantics.c | 11 ++++++----- net/ipv4/ipmr.c | 2 +- net/ipv4/route.c | 7 +++---- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 4 ++-- net/ipv6/addrconf_core.c | 2 +- net/ipv6/ip6_gre.c | 8 ++++---- net/ipv6/ip6_tunnel.c | 4 ++-- net/ipv6/ip6_vti.c | 4 ++-- net/ipv6/ip6mr.c | 2 +- net/ipv6/route.c | 10 +++++----- net/ipv6/sit.c | 4 ++-- net/ipv6/xfrm6_policy.c | 4 ++-- net/llc/af_llc.c | 2 +- net/openvswitch/vport-netdev.c | 6 +++--- net/packet/af_packet.c | 12 ++++++------ net/sched/act_mirred.c | 6 +++--- net/sched/sch_api.c | 2 +- net/sched/sch_generic.c | 11 ++++++----- net/smc/smc_pnet.c | 7 ++++--- net/switchdev/switchdev.c | 4 ++-- net/tipc/bearer.c | 4 ++-- net/xfrm/xfrm_device.c | 2 +- 48 files changed, 141 insertions(+), 137 deletions(-) (limited to 'include') diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 557ca8ff9dec..ca3e4700a813 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -225,7 +225,7 @@ static void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave) list_del(&slave->list); queue->num_slaves--; slave->dev->flags &= ~IFF_SLAVE; - dev_put_track(slave->dev, &slave->dev_tracker); + netdev_put(slave->dev, &slave->dev_tracker); kfree(slave); } @@ -399,7 +399,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave) if (duplicate_slave) eql_kill_one_slave(queue, duplicate_slave); - dev_hold_track(slave->dev, &slave->dev_tracker, GFP_ATOMIC); + netdev_hold(slave->dev, &slave->dev_tracker, GFP_ATOMIC); list_add(&slave->list, &queue->all_slaves); queue->num_slaves++; slave->dev->flags |= IFF_SLAVE; diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 817577e713d7..815738c0e067 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3462,7 +3462,7 @@ static int macsec_dev_init(struct net_device *dev) memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len); /* Get macsec's reference to real_dev */ - dev_hold_track(real_dev, &macsec->dev_tracker, GFP_KERNEL); + netdev_hold(real_dev, &macsec->dev_tracker, GFP_KERNEL); return 0; } @@ -3710,7 +3710,7 @@ static void macsec_free_netdev(struct net_device *dev) free_percpu(macsec->secy.tx_sc.stats); /* Get rid of the macsec's reference to real_dev */ - dev_put_track(macsec->real_dev, &macsec->dev_tracker); + netdev_put(macsec->real_dev, &macsec->dev_tracker); } static void macsec_setup(struct net_device *dev) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index eff75beb1395..5b46a6526fc6 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -915,7 +915,7 @@ static int macvlan_init(struct net_device *dev) port->count += 1; /* Get macvlan's reference to lowerdev */ - dev_hold_track(lowerdev, &vlan->dev_tracker, GFP_KERNEL); + netdev_hold(lowerdev, &vlan->dev_tracker, GFP_KERNEL); return 0; } @@ -1185,7 +1185,7 @@ static void macvlan_dev_free(struct net_device *dev) struct macvlan_dev *vlan = netdev_priv(dev); /* Get rid of the macvlan's reference to lowerdev */ - dev_put_track(vlan->lowerdev, &vlan->dev_tracker); + netdev_put(vlan->lowerdev, &vlan->dev_tracker); } void macvlan_common_setup(struct net_device *dev) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index ab8cd5551020..ddac61d79145 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -721,7 +721,7 @@ restart: __netpoll_cleanup(&nt->np); spin_lock_irqsave(&target_list_lock, flags); - dev_put_track(nt->np.dev, &nt->np.dev_tracker); + netdev_put(nt->np.dev, &nt->np.dev_tracker); nt->np.dev = NULL; nt->enabled = false; stopped = true; diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index cfc30ce4c6e1..40445a12c682 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -814,8 +814,8 @@ static void vrf_rt6_release(struct net_device *dev, struct net_vrf *vrf) */ if (rt6) { dst = &rt6->dst; - dev_replace_track(dst->dev, net->loopback_dev, - &dst->dev_tracker, GFP_KERNEL); + netdev_ref_replace(dst->dev, net->loopback_dev, + &dst->dev_tracker, GFP_KERNEL); dst->dev = net->loopback_dev; dst_release(dst); } @@ -1061,8 +1061,8 @@ static void vrf_rtable_release(struct net_device *dev, struct net_vrf *vrf) */ if (rth) { dst = &rth->dst; - dev_replace_track(dst->dev, net->loopback_dev, - &dst->dev_tracker, GFP_KERNEL); + netdev_ref_replace(dst->dev, net->loopback_dev, + &dst->dev_tracker, GFP_KERNEL); dst->dev = net->loopback_dev; dst_release(dst); } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f615a66c89e9..e2e5088888b1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3981,8 +3981,8 @@ static inline void netdev_tracker_free(struct net_device *dev, #endif } -static inline void dev_hold_track(struct net_device *dev, - netdevice_tracker *tracker, gfp_t gfp) +static inline void netdev_hold(struct net_device *dev, + netdevice_tracker *tracker, gfp_t gfp) { if (dev) { __dev_hold(dev); @@ -3990,8 +3990,8 @@ static inline void dev_hold_track(struct net_device *dev, } } -static inline void dev_put_track(struct net_device *dev, - netdevice_tracker *tracker) +static inline void netdev_put(struct net_device *dev, + netdevice_tracker *tracker) { if (dev) { netdev_tracker_free(dev, tracker); @@ -4004,11 +4004,11 @@ static inline void dev_put_track(struct net_device *dev, * @dev: network device * * Hold reference to device to keep it from being freed. - * Try using dev_hold_track() instead. + * Try using netdev_hold() instead. */ static inline void dev_hold(struct net_device *dev) { - dev_hold_track(dev, NULL, GFP_ATOMIC); + netdev_hold(dev, NULL, GFP_ATOMIC); } /** @@ -4016,17 +4016,17 @@ static inline void dev_hold(struct net_device *dev) * @dev: network device * * Release reference to device to allow it to be freed. - * Try using dev_put_track() instead. + * Try using netdev_put() instead. */ static inline void dev_put(struct net_device *dev) { - dev_put_track(dev, NULL); + netdev_put(dev, NULL); } -static inline void dev_replace_track(struct net_device *odev, - struct net_device *ndev, - netdevice_tracker *tracker, - gfp_t gfp) +static inline void netdev_ref_replace(struct net_device *odev, + struct net_device *ndev, + netdevice_tracker *tracker, + gfp_t gfp) { if (odev) netdev_tracker_free(odev, tracker); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index c39d910d4b45..9287712ad977 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1923,7 +1923,7 @@ static inline void xfrm_dev_state_free(struct xfrm_state *x) if (dev->xfrmdev_ops->xdo_dev_state_free) dev->xfrmdev_ops->xdo_dev_state_free(x); xso->dev = NULL; - dev_put_track(dev, &xso->dev_tracker); + netdev_put(dev, &xso->dev_tracker); } } #else diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 839f2020b015..e3dff2df6f54 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -615,7 +615,7 @@ static int vlan_dev_init(struct net_device *dev) return -ENOMEM; /* Get vlan's reference to real_dev */ - dev_hold_track(real_dev, &vlan->dev_tracker, GFP_KERNEL); + netdev_hold(real_dev, &vlan->dev_tracker, GFP_KERNEL); return 0; } @@ -852,7 +852,7 @@ static void vlan_dev_free(struct net_device *dev) vlan->vlan_pcpu_stats = NULL; /* Get rid of the vlan's reference to real_dev */ - dev_put_track(vlan->real_dev, &vlan->dev_tracker); + netdev_put(vlan->real_dev, &vlan->dev_tracker); } void vlan_setup(struct net_device *dev) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 95393bb2760b..1a5c0b071aa3 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -102,7 +102,8 @@ again: ax25_disconnect(s, ENETUNREACH); s->ax25_dev = NULL; if (sk->sk_socket) { - dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker); + netdev_put(ax25_dev->dev, + &ax25_dev->dev_tracker); ax25_dev_put(ax25_dev); } ax25_cb_del(s); @@ -1065,7 +1066,7 @@ static int ax25_release(struct socket *sock) del_timer_sync(&ax25->t3timer); del_timer_sync(&ax25->idletimer); } - dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker); + netdev_put(ax25_dev->dev, &ax25_dev->dev_tracker); ax25_dev_put(ax25_dev); } @@ -1146,7 +1147,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (ax25_dev) { ax25_fillin_cb(ax25, ax25_dev); - dev_hold_track(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC); + netdev_hold(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC); } done: diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c index 95a76d571c44..ab88b6ac5401 100644 --- a/net/ax25/ax25_dev.c +++ b/net/ax25/ax25_dev.c @@ -60,7 +60,7 @@ void ax25_dev_device_up(struct net_device *dev) refcount_set(&ax25_dev->refcount, 1); dev->ax25_ptr = ax25_dev; ax25_dev->dev = dev; - dev_hold_track(dev, &ax25_dev->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &ax25_dev->dev_tracker, GFP_ATOMIC); ax25_dev->forward = NULL; ax25_dev->device_up = true; @@ -136,7 +136,7 @@ unlock_put: spin_unlock_bh(&ax25_dev_lock); ax25_dev_put(ax25_dev); dev->ax25_ptr = NULL; - dev_put_track(dev, &ax25_dev->dev_tracker); + netdev_put(dev, &ax25_dev->dev_tracker); ax25_dev_put(ax25_dev); } @@ -205,7 +205,7 @@ void __exit ax25_dev_free(void) ax25_dev = ax25_dev_list; while (ax25_dev != NULL) { s = ax25_dev; - dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker); + netdev_put(ax25_dev->dev, &ax25_dev->dev_tracker); ax25_dev = ax25_dev->next; kfree(s); } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 47fcbade7389..a84a7cfb9d6d 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -274,7 +274,7 @@ static void destroy_nbp(struct net_bridge_port *p) p->br = NULL; p->dev = NULL; - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kobject_put(&p->kobj); } @@ -423,7 +423,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, return ERR_PTR(-ENOMEM); p->br = br; - dev_hold_track(dev, &p->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &p->dev_tracker, GFP_KERNEL); p->dev = dev; p->path_cost = port_cost(dev); p->priority = 0x8000 >> BR_PORT_BITS; @@ -434,7 +434,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, br_stp_port_timer_init(p); err = br_multicast_add_port(p); if (err) { - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kfree(p); p = ERR_PTR(err); } @@ -615,7 +615,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, err = dev_set_allmulti(dev, 1); if (err) { br_multicast_del_port(p); - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kfree(p); /* kobject not yet init'd, manually free */ goto err1; } @@ -725,7 +725,7 @@ err3: sysfs_remove_link(br->ifobj, p->dev->name); err2: br_multicast_del_port(p); - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kobject_put(&p->kobj); dev_set_allmulti(dev, -1); err1: diff --git a/net/core/dev.c b/net/core/dev.c index 08ce317fcec8..c9d96b85a825 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -7463,7 +7463,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, adj->ref_nr = 1; adj->private = private; adj->ignore = false; - dev_hold_track(adj_dev, &adj->dev_tracker, GFP_KERNEL); + netdev_hold(adj_dev, &adj->dev_tracker, GFP_KERNEL); pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", dev->name, adj_dev->name, adj->ref_nr, adj_dev->name); @@ -7492,7 +7492,7 @@ remove_symlinks: if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); free_adj: - dev_put_track(adj_dev, &adj->dev_tracker); + netdev_put(adj_dev, &adj->dev_tracker); kfree(adj); return ret; @@ -7534,7 +7534,7 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, list_del_rcu(&adj->list); pr_debug("adjacency: dev_put for %s, because link removed from %s to %s\n", adj_dev->name, dev->name, adj_dev->name); - dev_put_track(adj_dev, &adj->dev_tracker); + netdev_put(adj_dev, &adj->dev_tracker); kfree_rcu(adj, rcu); } @@ -10062,7 +10062,7 @@ int register_netdevice(struct net_device *dev) dev_init_scheduler(dev); - dev_hold_track(dev, &dev->dev_registered_tracker, GFP_KERNEL); + netdev_hold(dev, &dev->dev_registered_tracker, GFP_KERNEL); list_netdevice(dev); add_device_randomness(dev->dev_addr, dev->addr_len); @@ -10868,7 +10868,7 @@ void unregister_netdevice_many(struct list_head *head) synchronize_net(); list_for_each_entry(dev, head, unreg_list) { - dev_put_track(dev, &dev->dev_registered_tracker); + netdev_put(dev, &dev->dev_registered_tracker); net_set_todo(dev); } diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 4f6be442ae7e..7674bb9f3076 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -384,10 +384,10 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data, return -ENODEV; if (!netif_is_bridge_master(dev)) return -EOPNOTSUPP; - dev_hold_track(dev, &dev_tracker, GFP_KERNEL); + netdev_hold(dev, &dev_tracker, GFP_KERNEL); rtnl_unlock(); err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL); - dev_put_track(dev, &dev_tracker); + netdev_put(dev, &dev_tracker); rtnl_lock(); return err; diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 4ad1decce724..804d02fc245f 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -864,7 +864,8 @@ net_dm_hw_metadata_copy(const struct devlink_trap_metadata *metadata) } hw_metadata->input_dev = metadata->input_dev; - dev_hold_track(hw_metadata->input_dev, &hw_metadata->dev_tracker, GFP_ATOMIC); + netdev_hold(hw_metadata->input_dev, &hw_metadata->dev_tracker, + GFP_ATOMIC); return hw_metadata; @@ -880,7 +881,7 @@ free_hw_metadata: static void net_dm_hw_metadata_free(struct devlink_trap_metadata *hw_metadata) { - dev_put_track(hw_metadata->input_dev, &hw_metadata->dev_tracker); + netdev_put(hw_metadata->input_dev, &hw_metadata->dev_tracker); kfree(hw_metadata->fa_cookie); kfree(hw_metadata->trap_name); kfree(hw_metadata->trap_group_name); diff --git a/net/core/dst.c b/net/core/dst.c index d16c2c9bfebd..bc9c9be4e080 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -49,7 +49,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops, unsigned short flags) { dst->dev = dev; - dev_hold_track(dev, &dst->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &dst->dev_tracker, GFP_ATOMIC); dst->ops = ops; dst_init_metrics(dst, dst_default_metrics.metrics, true); dst->expires = 0UL; @@ -117,7 +117,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst) if (dst->ops->destroy) dst->ops->destroy(dst); - dev_put_track(dst->dev, &dst->dev_tracker); + netdev_put(dst->dev, &dst->dev_tracker); lwtstate_put(dst->lwtstate); @@ -159,8 +159,8 @@ void dst_dev_put(struct dst_entry *dst) dst->input = dst_discard; dst->output = dst_discard_out; dst->dev = blackhole_netdev; - dev_replace_track(dev, blackhole_netdev, &dst->dev_tracker, - GFP_ATOMIC); + netdev_ref_replace(dev, blackhole_netdev, &dst->dev_tracker, + GFP_ATOMIC); } EXPORT_SYMBOL(dst_dev_put); diff --git a/net/core/failover.c b/net/core/failover.c index dcaa92a85ea2..864d2d83eff4 100644 --- a/net/core/failover.c +++ b/net/core/failover.c @@ -252,7 +252,7 @@ struct failover *failover_register(struct net_device *dev, return ERR_PTR(-ENOMEM); rcu_assign_pointer(failover->ops, ops); - dev_hold_track(dev, &failover->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &failover->dev_tracker, GFP_KERNEL); dev->priv_flags |= IFF_FAILOVER; rcu_assign_pointer(failover->failover_dev, dev); @@ -285,7 +285,7 @@ void failover_unregister(struct failover *failover) failover_dev->name); failover_dev->priv_flags &= ~IFF_FAILOVER; - dev_put_track(failover_dev, &failover->dev_tracker); + netdev_put(failover_dev, &failover->dev_tracker); spin_lock(&failover_lock); list_del(&failover->list); diff --git a/net/core/link_watch.c b/net/core/link_watch.c index a244d3bade7d..aa6cb1f90966 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -110,7 +110,7 @@ static void linkwatch_add_event(struct net_device *dev) spin_lock_irqsave(&lweventlist_lock, flags); if (list_empty(&dev->link_watch_list)) { list_add_tail(&dev->link_watch_list, &lweventlist); - dev_hold_track(dev, &dev->linkwatch_dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &dev->linkwatch_dev_tracker, GFP_ATOMIC); } spin_unlock_irqrestore(&lweventlist_lock, flags); } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 54625287ee5b..d8ec70622ecb 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -624,7 +624,7 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey, memcpy(n->primary_key, pkey, key_len); n->dev = dev; - dev_hold_track(dev, &n->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &n->dev_tracker, GFP_ATOMIC); /* Protocol specific setup. */ if (tbl->constructor && (error = tbl->constructor(n)) < 0) { @@ -770,10 +770,10 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, write_pnet(&n->net, net); memcpy(n->key, pkey, key_len); n->dev = dev; - dev_hold_track(dev, &n->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &n->dev_tracker, GFP_KERNEL); if (tbl->pconstructor && tbl->pconstructor(n)) { - dev_put_track(dev, &n->dev_tracker); + netdev_put(dev, &n->dev_tracker); kfree(n); n = NULL; goto out; @@ -805,7 +805,7 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, write_unlock_bh(&tbl->lock); if (tbl->pdestructor) tbl->pdestructor(n); - dev_put_track(n->dev, &n->dev_tracker); + netdev_put(n->dev, &n->dev_tracker); kfree(n); return 0; } @@ -838,7 +838,7 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, n->next = NULL; if (tbl->pdestructor) tbl->pdestructor(n); - dev_put_track(n->dev, &n->dev_tracker); + netdev_put(n->dev, &n->dev_tracker); kfree(n); } return -ENOENT; @@ -879,7 +879,7 @@ void neigh_destroy(struct neighbour *neigh) if (dev->netdev_ops->ndo_neigh_destroy) dev->netdev_ops->ndo_neigh_destroy(dev, neigh); - dev_put_track(dev, &neigh->dev_tracker); + netdev_put(dev, &neigh->dev_tracker); neigh_parms_put(neigh->parms); neigh_dbg(2, "neigh %p is destroyed\n", neigh); @@ -1671,13 +1671,13 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, refcount_set(&p->refcnt, 1); p->reachable_time = neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); - dev_hold_track(dev, &p->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &p->dev_tracker, GFP_KERNEL); p->dev = dev; write_pnet(&p->net, net); p->sysctl_table = NULL; if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) { - dev_put_track(dev, &p->dev_tracker); + netdev_put(dev, &p->dev_tracker); kfree(p); return NULL; } @@ -1708,7 +1708,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) list_del(&parms->list); parms->dead = 1; write_unlock_bh(&tbl->lock); - dev_put_track(parms->dev, &parms->dev_tracker); + netdev_put(parms->dev, &parms->dev_tracker); call_rcu(&parms->rcu_head, neigh_rcu_free_parms); } EXPORT_SYMBOL(neigh_parms_release); diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index e319e242dddf..d49fc974e630 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1016,7 +1016,7 @@ static void rx_queue_release(struct kobject *kobj) #endif memset(kobj, 0, sizeof(*kobj)); - dev_put_track(queue->dev, &queue->dev_tracker); + netdev_put(queue->dev, &queue->dev_tracker); } static const void *rx_queue_namespace(struct kobject *kobj) @@ -1056,7 +1056,7 @@ static int rx_queue_add_kobject(struct net_device *dev, int index) /* Kobject_put later will trigger rx_queue_release call which * decreases dev refcount: Take that reference here */ - dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL); + netdev_hold(queue->dev, &queue->dev_tracker, GFP_KERNEL); kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, @@ -1619,7 +1619,7 @@ static void netdev_queue_release(struct kobject *kobj) struct netdev_queue *queue = to_netdev_queue(kobj); memset(kobj, 0, sizeof(*kobj)); - dev_put_track(queue->dev, &queue->dev_tracker); + netdev_put(queue->dev, &queue->dev_tracker); } static const void *netdev_queue_namespace(struct kobject *kobj) @@ -1659,7 +1659,7 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index) /* Kobject_put later will trigger netdev_queue_release call * which decreases dev refcount: Take that reference here */ - dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL); + netdev_hold(queue->dev, &queue->dev_tracker, GFP_KERNEL); kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, diff --git a/net/core/netpoll.c b/net/core/netpoll.c index db724463e7cd..5d27067b72d5 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -853,7 +853,7 @@ void netpoll_cleanup(struct netpoll *np) if (!np->dev) goto out; __netpoll_cleanup(np); - dev_put_track(np->dev, &np->dev_tracker); + netdev_put(np->dev, &np->dev_tracker); np->dev = NULL; out: rtnl_unlock(); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 84b62cd7bc57..88906ba6d9a7 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2100,7 +2100,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn, /* Clean old setups */ if (pkt_dev->odev) { - dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); + netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker); pkt_dev->odev = NULL; } @@ -3807,7 +3807,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) return add_dev_to_thread(t, pkt_dev); out2: - dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); + netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker); out1: #ifdef CONFIG_XFRM free_SAs(pkt_dev); @@ -3901,7 +3901,7 @@ static int pktgen_remove_device(struct pktgen_thread *t, /* Dis-associate from the interface */ if (pkt_dev->odev) { - dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker); + netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker); pkt_dev->odev = NULL; } diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 326e14ee05db..d05ff6a17a1f 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -2010,7 +2010,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) * removal of the device. */ busy = true; - dev_hold_track(dev, &dev_tracker, GFP_KERNEL); + netdev_hold(dev, &dev_tracker, GFP_KERNEL); rtnl_unlock(); if (rc == 0) { @@ -2034,7 +2034,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) } rtnl_lock(); - dev_put_track(dev, &dev_tracker); + netdev_put(dev, &dev_tracker); busy = false; (void) ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE); diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 5fe8f4ae2ceb..e26079e11835 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -402,7 +402,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info) ops->cleanup_data(reply_data); genlmsg_end(rskb, reply_payload); - dev_put_track(req_info->dev, &req_info->dev_tracker); + netdev_put(req_info->dev, &req_info->dev_tracker); kfree(reply_data); kfree(req_info); return genlmsg_reply(rskb, info); @@ -414,7 +414,7 @@ err_cleanup: if (ops->cleanup_data) ops->cleanup_data(reply_data); err_dev: - dev_put_track(req_info->dev, &req_info->dev_tracker); + netdev_put(req_info->dev, &req_info->dev_tracker); kfree(reply_data); kfree(req_info); return ret; @@ -550,7 +550,7 @@ static int ethnl_default_start(struct netlink_callback *cb) * same parser as for non-dump (doit) requests is used, it * would take reference to the device if it finds one */ - dev_put_track(req_info->dev, &req_info->dev_tracker); + netdev_put(req_info->dev, &req_info->dev_tracker); req_info->dev = NULL; } if (ret < 0) diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index 7919ddb2371c..c0d587611854 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -237,7 +237,7 @@ struct ethnl_req_info { static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info) { - dev_put_track(req_info->dev, &req_info->dev_tracker); + netdev_put(req_info->dev, &req_info->dev_tracker); } /** diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index b2366ad540e6..92b778e423df 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -244,7 +244,7 @@ void in_dev_finish_destroy(struct in_device *idev) #ifdef NET_REFCNT_DEBUG pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL"); #endif - dev_put_track(dev, &idev->dev_tracker); + netdev_put(dev, &idev->dev_tracker); if (!idev->dead) pr_err("Freeing alive in_device %p\n", idev); else @@ -272,7 +272,7 @@ static struct in_device *inetdev_init(struct net_device *dev) if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) dev_disable_lro(dev); /* Reference in_dev->dev */ - dev_hold_track(dev, &in_dev->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &in_dev->dev_tracker, GFP_KERNEL); /* Account for reference dev->ip_ptr (below) */ refcount_set(&in_dev->refcnt, 1); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index a57ba23571c9..a5439a8414d4 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -211,7 +211,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp) void fib_nh_common_release(struct fib_nh_common *nhc) { - dev_put_track(nhc->nhc_dev, &nhc->nhc_dev_tracker); + netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker); lwtstate_put(nhc->nhc_lwtstate); rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output); rt_fibinfo_free(&nhc->nhc_rth_input); @@ -1057,7 +1057,8 @@ static int fib_check_nh_v6_gw(struct net *net, struct fib_nh *nh, err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack); if (!err) { nh->fib_nh_dev = fib6_nh.fib_nh_dev; - dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_KERNEL); + netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, + GFP_KERNEL); nh->fib_nh_oif = nh->fib_nh_dev->ifindex; nh->fib_nh_scope = RT_SCOPE_LINK; @@ -1141,7 +1142,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table, if (!netif_carrier_ok(dev)) nh->fib_nh_flags |= RTNH_F_LINKDOWN; nh->fib_nh_dev = dev; - dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); nh->fib_nh_scope = RT_SCOPE_LINK; return 0; } @@ -1195,7 +1196,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table, "No egress device for nexthop gateway"); goto out; } - dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); if (!netif_carrier_ok(dev)) nh->fib_nh_flags |= RTNH_F_LINKDOWN; err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; @@ -1229,7 +1230,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh, } nh->fib_nh_dev = in_dev->dev; - dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); + netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC); nh->fib_nh_scope = RT_SCOPE_HOST; if (!netif_carrier_ok(nh->fib_nh_dev)) nh->fib_nh_flags |= RTNH_F_LINKDOWN; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 13e6329784fb..8324e541d193 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -691,7 +691,7 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify, if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER) && !notify) unregister_netdevice_queue(dev, head); - dev_put_track(dev, &v->dev_tracker); + netdev_put(dev, &v->dev_tracker); return 0; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 356f535f3443..2d16bcc7d346 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1550,9 +1550,8 @@ void rt_flush_dev(struct net_device *dev) if (rt->dst.dev != dev) continue; rt->dst.dev = blackhole_netdev; - dev_replace_track(dev, blackhole_netdev, - &rt->dst.dev_tracker, - GFP_ATOMIC); + netdev_ref_replace(dev, blackhole_netdev, + &rt->dst.dev_tracker, GFP_ATOMIC); list_move(&rt->rt_uncached, &ul->quarantine); } spin_unlock_bh(&ul->lock); @@ -2851,7 +2850,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or new->output = dst_discard_out; new->dev = net->loopback_dev; - dev_hold_track(new->dev, &new->dev_tracker, GFP_ATOMIC); + netdev_hold(new->dev, &new->dev_tracker, GFP_ATOMIC); rt->rt_is_input = ort->rt_is_input; rt->rt_iif = ort->rt_iif; diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 6fde0b184791..3d0dfa6cf9f9 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -75,7 +75,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, xdst->u.rt.rt_iif = fl4->flowi4_iif; xdst->u.dst.dev = dev; - dev_hold_track(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); /* Sheit... I remember I did this right. Apparently, * it was magically lost, so this code needs audit */ diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1b1932502e9e..3497ad1362c0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -398,13 +398,13 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) if (ndev->cnf.forwarding) dev_disable_lro(dev); /* We refer to the device */ - dev_hold_track(dev, &ndev->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &ndev->dev_tracker, GFP_KERNEL); if (snmp6_alloc_dev(ndev) < 0) { netdev_dbg(dev, "%s: cannot allocate memory for statistics\n", __func__); neigh_parms_release(&nd_tbl, ndev->nd_parms); - dev_put_track(dev, &ndev->dev_tracker); + netdev_put(dev, &ndev->dev_tracker); kfree(ndev); return ERR_PTR(err); } diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index 881d1477d24a..507a8353a6bd 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c @@ -263,7 +263,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) #ifdef NET_REFCNT_DEBUG pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL"); #endif - dev_put_track(dev, &idev->dev_tracker); + netdev_put(dev, &idev->dev_tracker); if (!idev->dead) { pr_warn("Freeing alive inet6 device %p\n", idev); return; diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 4e37f7c29900..3e22cbe5966a 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -398,7 +398,7 @@ static void ip6erspan_tunnel_uninit(struct net_device *dev) ip6erspan_tunnel_unlink_md(ign, t); ip6gre_tunnel_unlink(ign, t); dst_cache_reset(&t->dst_cache); - dev_put_track(dev, &t->dev_tracker); + netdev_put(dev, &t->dev_tracker); } static void ip6gre_tunnel_uninit(struct net_device *dev) @@ -411,7 +411,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev) if (ign->fb_tunnel_dev == dev) WRITE_ONCE(ign->fb_tunnel_dev, NULL); dst_cache_reset(&t->dst_cache); - dev_put_track(dev, &t->dev_tracker); + netdev_put(dev, &t->dev_tracker); } @@ -1495,7 +1495,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev) } ip6gre_tnl_init_features(dev); - dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); return 0; cleanup_dst_cache_init: @@ -1887,7 +1887,7 @@ static int ip6erspan_tap_init(struct net_device *dev) dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; ip6erspan_tnl_link_config(tunnel, 1); - dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); return 0; cleanup_dst_cache_init: diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 19325b7600bb..689de5eb604e 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -381,7 +381,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) else ip6_tnl_unlink(ip6n, t); dst_cache_reset(&t->dst_cache); - dev_put_track(dev, &t->dev_tracker); + netdev_put(dev, &t->dev_tracker); } /** @@ -1889,7 +1889,7 @@ ip6_tnl_dev_init_gen(struct net_device *dev) dev->min_mtu = ETH_MIN_MTU; dev->max_mtu = IP6_MAX_MTU - dev->hard_header_len; - dev_hold_track(dev, &t->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &t->dev_tracker, GFP_KERNEL); return 0; destroy_dst: diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 3a434d75925c..8fe59a79e800 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -293,7 +293,7 @@ static void vti6_dev_uninit(struct net_device *dev) RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); else vti6_tnl_unlink(ip6n, t); - dev_put_track(dev, &t->dev_tracker); + netdev_put(dev, &t->dev_tracker); } static int vti6_input_proto(struct sk_buff *skb, int nexthdr, __be32 spi, @@ -936,7 +936,7 @@ static inline int vti6_dev_init_gen(struct net_device *dev) dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!dev->tstats) return -ENOMEM; - dev_hold_track(dev, &t->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &t->dev_tracker, GFP_KERNEL); return 0; } diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 4e74bc61a3db..d4aad41c9849 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -741,7 +741,7 @@ static int mif6_delete(struct mr_table *mrt, int vifi, int notify, if ((v->flags & MIFF_REGISTER) && !notify) unregister_netdevice_queue(dev, head); - dev_put_track(dev, &v->dev_tracker); + netdev_put(dev, &v->dev_tracker); return 0; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d25dc83bac62..0be01a4d48c1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -182,9 +182,9 @@ static void rt6_uncached_list_flush_dev(struct net_device *dev) if (rt_dev == dev) { rt->dst.dev = blackhole_netdev; - dev_replace_track(rt_dev, blackhole_netdev, - &rt->dst.dev_tracker, - GFP_ATOMIC); + netdev_ref_replace(rt_dev, blackhole_netdev, + &rt->dst.dev_tracker, + GFP_ATOMIC); handled = true; } if (handled) @@ -607,7 +607,7 @@ static void rt6_probe_deferred(struct work_struct *w) addrconf_addr_solict_mult(&work->target, &mcaddr); ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0); - dev_put_track(work->dev, &work->dev_tracker); + netdev_put(work->dev, &work->dev_tracker); kfree(work); } @@ -661,7 +661,7 @@ static void rt6_probe(struct fib6_nh *fib6_nh) } else { INIT_WORK(&work->work, rt6_probe_deferred); work->target = *nh_gw; - dev_hold_track(dev, &work->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &work->dev_tracker, GFP_ATOMIC); work->dev = dev; schedule_work(&work->work); } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index c0b138c20992..4f1721865fda 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -521,7 +521,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) ipip6_tunnel_del_prl(tunnel, NULL); } dst_cache_reset(&tunnel->dst_cache); - dev_put_track(dev, &tunnel->dev_tracker); + netdev_put(dev, &tunnel->dev_tracker); } static int ipip6_err(struct sk_buff *skb, u32 info) @@ -1463,7 +1463,7 @@ static int ipip6_tunnel_init(struct net_device *dev) dev->tstats = NULL; return err; } - dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL); return 0; } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index e64e427a51cf..4a4b0e49ec92 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -73,11 +73,11 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, struct rt6_info *rt = (struct rt6_info *)xdst->route; xdst->u.dst.dev = dev; - dev_hold_track(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); xdst->u.rt6.rt6i_idev = in6_dev_get(dev); if (!xdst->u.rt6.rt6i_idev) { - dev_put_track(dev, &xdst->u.dst.dev_tracker); + netdev_put(dev, &xdst->u.dst.dev_tracker); return -ENODEV; } diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 7f555d2e5357..da7fe94bea2e 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -224,7 +224,7 @@ static int llc_ui_release(struct socket *sock) } else { release_sock(sk); } - dev_put_track(llc->dev, &llc->dev_tracker); + netdev_put(llc->dev, &llc->dev_tracker); sock_put(sk); llc_sk_free(sk); out: diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index b498dac4e1e0..2f61d5bdce1a 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -115,7 +115,7 @@ error_master_upper_dev_unlink: error_unlock: rtnl_unlock(); error_put: - dev_put_track(vport->dev, &vport->dev_tracker); + netdev_put(vport->dev, &vport->dev_tracker); error_free_vport: ovs_vport_free(vport); return ERR_PTR(err); @@ -137,7 +137,7 @@ static void vport_netdev_free(struct rcu_head *rcu) { struct vport *vport = container_of(rcu, struct vport, rcu); - dev_put_track(vport->dev, &vport->dev_tracker); + netdev_put(vport->dev, &vport->dev_tracker); ovs_vport_free(vport); } @@ -173,7 +173,7 @@ void ovs_netdev_tunnel_destroy(struct vport *vport) */ if (vport->dev->reg_state == NETREG_REGISTERED) rtnl_delete_link(vport->dev); - dev_put_track(vport->dev, &vport->dev_tracker); + netdev_put(vport->dev, &vport->dev_tracker); vport->dev = NULL; rtnl_unlock(); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ca6e92a22923..d08c4728523b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3134,7 +3134,7 @@ static int packet_release(struct socket *sock) packet_cached_dev_reset(po); if (po->prot_hook.dev) { - dev_put_track(po->prot_hook.dev, &po->prot_hook.dev_tracker); + netdev_put(po->prot_hook.dev, &po->prot_hook.dev_tracker); po->prot_hook.dev = NULL; } spin_unlock(&po->bind_lock); @@ -3235,15 +3235,15 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex, WRITE_ONCE(po->num, proto); po->prot_hook.type = proto; - dev_put_track(po->prot_hook.dev, &po->prot_hook.dev_tracker); + netdev_put(po->prot_hook.dev, &po->prot_hook.dev_tracker); if (unlikely(unlisted)) { po->prot_hook.dev = NULL; WRITE_ONCE(po->ifindex, -1); packet_cached_dev_reset(po); } else { - dev_hold_track(dev, &po->prot_hook.dev_tracker, - GFP_ATOMIC); + netdev_hold(dev, &po->prot_hook.dev_tracker, + GFP_ATOMIC); po->prot_hook.dev = dev; WRITE_ONCE(po->ifindex, dev ? dev->ifindex : 0); packet_cached_dev_assign(po, dev); @@ -4167,8 +4167,8 @@ static int packet_notifier(struct notifier_block *this, if (msg == NETDEV_UNREGISTER) { packet_cached_dev_reset(po); WRITE_ONCE(po->ifindex, -1); - dev_put_track(po->prot_hook.dev, - &po->prot_hook.dev_tracker); + netdev_put(po->prot_hook.dev, + &po->prot_hook.dev_tracker); po->prot_hook.dev = NULL; } spin_unlock(&po->bind_lock); diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index ebb92fb072ab..a1d70cf86843 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -79,7 +79,7 @@ static void tcf_mirred_release(struct tc_action *a) /* last reference to action, no need to lock */ dev = rcu_dereference_protected(m->tcfm_dev, 1); - dev_put_track(dev, &m->tcfm_dev_tracker); + netdev_put(dev, &m->tcfm_dev_tracker); } static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { @@ -181,7 +181,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, mac_header_xmit = dev_is_mac_header_xmit(ndev); odev = rcu_replace_pointer(m->tcfm_dev, ndev, lockdep_is_held(&m->tcf_lock)); - dev_put_track(odev, &m->tcfm_dev_tracker); + netdev_put(odev, &m->tcfm_dev_tracker); netdev_tracker_alloc(ndev, &m->tcfm_dev_tracker, GFP_ATOMIC); m->tcfm_mac_header_xmit = mac_header_xmit; } @@ -402,7 +402,7 @@ static int mirred_device_event(struct notifier_block *unused, list_for_each_entry(m, &mirred_list, tcfm_list) { spin_lock_bh(&m->tcf_lock); if (tcf_mirred_dev_dereference(m) == dev) { - dev_put_track(dev, &m->tcfm_dev_tracker); + netdev_put(dev, &m->tcfm_dev_tracker); /* Note : no rcu grace period necessary, as * net_device are already rcu protected. */ diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index e3c0e8ea2dbb..bf87b50837a8 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1292,7 +1292,7 @@ err_out5: if (ops->destroy) ops->destroy(sch); err_out3: - dev_put_track(dev, &sch->dev_tracker); + netdev_put(dev, &sch->dev_tracker); qdisc_free(sch); err_out2: module_put(ops->owner); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index dba0b3e24af5..cc6eabee2830 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -541,7 +541,7 @@ static void dev_watchdog(struct timer_list *t) spin_unlock(&dev->tx_global_lock); if (release) - dev_put_track(dev, &dev->watchdog_dev_tracker); + netdev_put(dev, &dev->watchdog_dev_tracker); } void __netdev_watchdog_up(struct net_device *dev) @@ -551,7 +551,8 @@ void __netdev_watchdog_up(struct net_device *dev) dev->watchdog_timeo = 5*HZ; if (!mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + dev->watchdog_timeo))) - dev_hold_track(dev, &dev->watchdog_dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &dev->watchdog_dev_tracker, + GFP_ATOMIC); } } EXPORT_SYMBOL_GPL(__netdev_watchdog_up); @@ -565,7 +566,7 @@ static void dev_watchdog_down(struct net_device *dev) { netif_tx_lock_bh(dev); if (del_timer(&dev->watchdog_timer)) - dev_put_track(dev, &dev->watchdog_dev_tracker); + netdev_put(dev, &dev->watchdog_dev_tracker); netif_tx_unlock_bh(dev); } @@ -975,7 +976,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, sch->enqueue = ops->enqueue; sch->dequeue = ops->dequeue; sch->dev_queue = dev_queue; - dev_hold_track(dev, &sch->dev_tracker, GFP_KERNEL); + netdev_hold(dev, &sch->dev_tracker, GFP_KERNEL); refcount_set(&sch->refcnt, 1); return sch; @@ -1067,7 +1068,7 @@ static void qdisc_destroy(struct Qdisc *qdisc) ops->destroy(qdisc); module_put(ops->owner); - dev_put_track(qdisc_dev(qdisc), &qdisc->dev_tracker); + netdev_put(qdisc_dev(qdisc), &qdisc->dev_tracker); trace_qdisc_destroy(qdisc); diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 7055ed10e316..4c3bf6db7038 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c @@ -120,7 +120,8 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name) smc_pnet_match(pnetelem->pnet_name, pnet_name)) { list_del(&pnetelem->list); if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev) { - dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker); + netdev_put(pnetelem->ndev, + &pnetelem->dev_tracker); pr_warn_ratelimited("smc: net device %s " "erased user defined " "pnetid %.16s\n", @@ -196,7 +197,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev) list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) { if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev && !strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) { - dev_hold_track(ndev, &pnetelem->dev_tracker, GFP_ATOMIC); + netdev_hold(ndev, &pnetelem->dev_tracker, GFP_ATOMIC); pnetelem->ndev = ndev; rc = 0; pr_warn_ratelimited("smc: adding net device %s with " @@ -227,7 +228,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev) mutex_lock(&pnettable->lock); list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) { if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) { - dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker); + netdev_put(pnetelem->ndev, &pnetelem->dev_tracker); pnetelem->ndev = NULL; rc = 0; pr_warn_ratelimited("smc: removing net device %s with " diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 474f76383033..8cc42aea19c7 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -64,7 +64,7 @@ void switchdev_deferred_process(void) while ((dfitem = switchdev_deferred_dequeue())) { dfitem->func(dfitem->dev, dfitem->data); - dev_put_track(dfitem->dev, &dfitem->dev_tracker); + netdev_put(dfitem->dev, &dfitem->dev_tracker); kfree(dfitem); } } @@ -91,7 +91,7 @@ static int switchdev_deferred_enqueue(struct net_device *dev, dfitem->dev = dev; dfitem->func = func; memcpy(dfitem->data, data, data_len); - dev_hold_track(dev, &dfitem->dev_tracker, GFP_ATOMIC); + netdev_hold(dev, &dfitem->dev_tracker, GFP_ATOMIC); spin_lock_bh(&deferred_lock); list_add_tail(&dfitem->list, &deferred); spin_unlock_bh(&deferred_lock); diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 932c87b98eca..35cac7733fd3 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -788,7 +788,7 @@ int tipc_attach_loopback(struct net *net) if (!dev) return -ENODEV; - dev_hold_track(dev, &tn->loopback_pt.dev_tracker, GFP_KERNEL); + netdev_hold(dev, &tn->loopback_pt.dev_tracker, GFP_KERNEL); tn->loopback_pt.dev = dev; tn->loopback_pt.type = htons(ETH_P_TIPC); tn->loopback_pt.func = tipc_loopback_rcv_pkt; @@ -801,7 +801,7 @@ void tipc_detach_loopback(struct net *net) struct tipc_net *tn = tipc_net(net); dev_remove_pack(&tn->loopback_pt); - dev_put_track(net->loopback_dev, &tn->loopback_pt.dev_tracker); + netdev_put(net->loopback_dev, &tn->loopback_pt.dev_tracker); } /* Caller should hold rtnl_lock to protect the bearer */ diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 35c7e89b2e7d..637ca8838436 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -275,7 +275,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, xso->dev = NULL; xso->dir = 0; xso->real_dev = NULL; - dev_put_track(dev, &xso->dev_tracker); + netdev_put(dev, &xso->dev_tracker); if (err != -EOPNOTSUPP) return err; -- cgit v1.2.3 From 09cca53c1656960c38c04bb12da30f61952ca660 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 08:46:32 -0700 Subject: vlan: adopt u64_stats_t As explained in commit 316580b69d0a ("u64_stats: provide u64_stats_t type") we should use u64_stats_t and related accessors to avoid load/store tearing. Add READ_ONCE() when reading rx_errors & tx_dropped. Signed-off-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- drivers/net/macvlan.c | 18 +++++++++--------- include/linux/if_macvlan.h | 6 +++--- include/linux/if_vlan.h | 10 +++++----- net/8021q/vlan_core.c | 6 +++--- net/8021q/vlan_dev.c | 18 +++++++++--------- 5 files changed, 29 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 5b46a6526fc6..1080d6ebff63 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -575,8 +575,8 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, pcpu_stats = this_cpu_ptr(vlan->pcpu_stats); u64_stats_update_begin(&pcpu_stats->syncp); - pcpu_stats->tx_packets++; - pcpu_stats->tx_bytes += len; + u64_stats_inc(&pcpu_stats->tx_packets); + u64_stats_add(&pcpu_stats->tx_bytes, len); u64_stats_update_end(&pcpu_stats->syncp); } else { this_cpu_inc(vlan->pcpu_stats->tx_dropped); @@ -949,11 +949,11 @@ static void macvlan_dev_get_stats64(struct net_device *dev, p = per_cpu_ptr(vlan->pcpu_stats, i); do { start = u64_stats_fetch_begin_irq(&p->syncp); - rx_packets = p->rx_packets; - rx_bytes = p->rx_bytes; - rx_multicast = p->rx_multicast; - tx_packets = p->tx_packets; - tx_bytes = p->tx_bytes; + rx_packets = u64_stats_read(&p->rx_packets); + rx_bytes = u64_stats_read(&p->rx_bytes); + rx_multicast = u64_stats_read(&p->rx_multicast); + tx_packets = u64_stats_read(&p->tx_packets); + tx_bytes = u64_stats_read(&p->tx_bytes); } while (u64_stats_fetch_retry_irq(&p->syncp, start)); stats->rx_packets += rx_packets; @@ -964,8 +964,8 @@ static void macvlan_dev_get_stats64(struct net_device *dev, /* rx_errors & tx_dropped are u32, updated * without syncp protection. */ - rx_errors += p->rx_errors; - tx_dropped += p->tx_dropped; + rx_errors += READ_ONCE(p->rx_errors); + tx_dropped += READ_ONCE(p->tx_dropped); } stats->rx_errors = rx_errors; stats->rx_dropped = rx_errors; diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index b42294739063..523025106a64 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h @@ -46,10 +46,10 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan, pcpu_stats = get_cpu_ptr(vlan->pcpu_stats); u64_stats_update_begin(&pcpu_stats->syncp); - pcpu_stats->rx_packets++; - pcpu_stats->rx_bytes += len; + u64_stats_inc(&pcpu_stats->rx_packets); + u64_stats_add(&pcpu_stats->rx_bytes, len); if (multicast) - pcpu_stats->rx_multicast++; + u64_stats_inc(&pcpu_stats->rx_multicast); u64_stats_update_end(&pcpu_stats->syncp); put_cpu_ptr(vlan->pcpu_stats); } else { diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 2be4dd7e90a9..e00c4ee81ff7 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -118,11 +118,11 @@ static inline void vlan_drop_rx_stag_filter_info(struct net_device *dev) * @tx_dropped: number of tx drops */ struct vlan_pcpu_stats { - u64 rx_packets; - u64 rx_bytes; - u64 rx_multicast; - u64 tx_packets; - u64 tx_bytes; + u64_stats_t rx_packets; + u64_stats_t rx_bytes; + u64_stats_t rx_multicast; + u64_stats_t tx_packets; + u64_stats_t tx_bytes; struct u64_stats_sync syncp; u32 rx_errors; u32 tx_dropped; diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index acf8c791f320..5aa8144101dc 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -63,10 +63,10 @@ bool vlan_do_receive(struct sk_buff **skbp) rx_stats = this_cpu_ptr(vlan_dev_priv(vlan_dev)->vlan_pcpu_stats); u64_stats_update_begin(&rx_stats->syncp); - rx_stats->rx_packets++; - rx_stats->rx_bytes += skb->len; + u64_stats_inc(&rx_stats->rx_packets); + u64_stats_add(&rx_stats->rx_bytes, skb->len); if (skb->pkt_type == PACKET_MULTICAST) - rx_stats->rx_multicast++; + u64_stats_inc(&rx_stats->rx_multicast); u64_stats_update_end(&rx_stats->syncp); return true; diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index e3dff2df6f54..035812b0461c 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -128,8 +128,8 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, stats = this_cpu_ptr(vlan->vlan_pcpu_stats); u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += len; + u64_stats_inc(&stats->tx_packets); + u64_stats_add(&stats->tx_bytes, len); u64_stats_update_end(&stats->syncp); } else { this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped); @@ -713,11 +713,11 @@ static void vlan_dev_get_stats64(struct net_device *dev, p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i); do { start = u64_stats_fetch_begin_irq(&p->syncp); - rxpackets = p->rx_packets; - rxbytes = p->rx_bytes; - rxmulticast = p->rx_multicast; - txpackets = p->tx_packets; - txbytes = p->tx_bytes; + rxpackets = u64_stats_read(&p->rx_packets); + rxbytes = u64_stats_read(&p->rx_bytes); + rxmulticast = u64_stats_read(&p->rx_multicast); + txpackets = u64_stats_read(&p->tx_packets); + txbytes = u64_stats_read(&p->tx_bytes); } while (u64_stats_fetch_retry_irq(&p->syncp, start)); stats->rx_packets += rxpackets; @@ -726,8 +726,8 @@ static void vlan_dev_get_stats64(struct net_device *dev, stats->tx_packets += txpackets; stats->tx_bytes += txbytes; /* rx_errors & tx_dropped are u32 */ - rx_errors += p->rx_errors; - tx_dropped += p->tx_dropped; + rx_errors += READ_ONCE(p->rx_errors); + tx_dropped += READ_ONCE(p->tx_dropped); } stats->rx_errors = rx_errors; stats->tx_dropped = tx_dropped; -- cgit v1.2.3 From 9962acefbcb92736c268aafe5f52200948f60f3e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 08:46:37 -0700 Subject: net: adopt u64_stats_t in struct pcpu_sw_netstats As explained in commit 316580b69d0a ("u64_stats: provide u64_stats_t type") we should use u64_stats_t and related accessors to avoid load/store tearing. Signed-off-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- drivers/net/macsec.c | 8 ++++---- drivers/net/usb/usbnet.c | 8 ++++---- drivers/net/vxlan/vxlan_core.c | 8 ++++---- include/linux/netdevice.h | 16 ++++++++-------- include/net/ip_tunnels.h | 4 ++-- net/bridge/br_netlink.c | 8 ++++---- net/bridge/br_vlan.c | 36 ++++++++++++++++++++---------------- net/core/dev.c | 18 +++++++++--------- net/dsa/slave.c | 8 ++++---- 9 files changed, 59 insertions(+), 55 deletions(-) (limited to 'include') diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 815738c0e067..c881e1bf6f6e 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -523,8 +523,8 @@ static void count_tx(struct net_device *dev, int ret, int len) struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats); u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += len; + u64_stats_inc(&stats->tx_packets); + u64_stats_add(&stats->tx_bytes, len); u64_stats_update_end(&stats->syncp); } } @@ -825,8 +825,8 @@ static void count_rx(struct net_device *dev, int len) struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats); u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += len; + u64_stats_inc(&stats->rx_packets); + u64_stats_add(&stats->rx_bytes, len); u64_stats_update_end(&stats->syncp); } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 1cb6dab3e2d0..dc79811535c2 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -337,8 +337,8 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) skb->protocol = eth_type_trans (skb, dev->net); flags = u64_stats_update_begin_irqsave(&stats64->syncp); - stats64->rx_packets++; - stats64->rx_bytes += skb->len; + u64_stats_inc(&stats64->rx_packets); + u64_stats_add(&stats64->rx_bytes, skb->len); u64_stats_update_end_irqrestore(&stats64->syncp, flags); netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", @@ -1258,8 +1258,8 @@ static void tx_complete (struct urb *urb) unsigned long flags; flags = u64_stats_update_begin_irqsave(&stats64->syncp); - stats64->tx_packets += entry->packets; - stats64->tx_bytes += entry->length; + u64_stats_add(&stats64->tx_packets, entry->packets); + u64_stats_add(&stats64->tx_bytes, entry->length); u64_stats_update_end_irqrestore(&stats64->syncp, flags); } else { dev->net->stats.tx_errors++; diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 265d4a0245e7..8b0710b576c2 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2385,15 +2385,15 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni); u64_stats_update_begin(&tx_stats->syncp); - tx_stats->tx_packets++; - tx_stats->tx_bytes += len; + u64_stats_inc(&tx_stats->tx_packets); + u64_stats_add(&tx_stats->tx_bytes, len); u64_stats_update_end(&tx_stats->syncp); vxlan_vnifilter_count(src_vxlan, vni, NULL, VXLAN_VNI_STATS_TX, len); if (__netif_rx(skb) == NET_RX_SUCCESS) { u64_stats_update_begin(&rx_stats->syncp); - rx_stats->rx_packets++; - rx_stats->rx_bytes += len; + u64_stats_inc(&rx_stats->rx_packets); + u64_stats_add(&rx_stats->rx_bytes, len); u64_stats_update_end(&rx_stats->syncp); vxlan_vnifilter_count(dst_vxlan, vni, NULL, VXLAN_VNI_STATS_RX, len); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e2e5088888b1..89afa4f7747d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2636,10 +2636,10 @@ struct packet_offload { /* often modified stats are per-CPU, other are shared (netdev->stats) */ struct pcpu_sw_netstats { - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; + u64_stats_t rx_packets; + u64_stats_t rx_bytes; + u64_stats_t tx_packets; + u64_stats_t tx_bytes; struct u64_stats_sync syncp; } __aligned(4 * sizeof(u64)); @@ -2656,8 +2656,8 @@ static inline void dev_sw_netstats_rx_add(struct net_device *dev, unsigned int l struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); u64_stats_update_begin(&tstats->syncp); - tstats->rx_bytes += len; - tstats->rx_packets++; + u64_stats_add(&tstats->rx_bytes, len); + u64_stats_inc(&tstats->rx_packets); u64_stats_update_end(&tstats->syncp); } @@ -2668,8 +2668,8 @@ static inline void dev_sw_netstats_tx_add(struct net_device *dev, struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); u64_stats_update_begin(&tstats->syncp); - tstats->tx_bytes += len; - tstats->tx_packets += packets; + u64_stats_add(&tstats->tx_bytes, len); + u64_stats_add(&tstats->tx_packets, packets); u64_stats_update_end(&tstats->syncp); } diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index c24fa934221d..70cbc4a72669 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -456,8 +456,8 @@ static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len) struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats); u64_stats_update_begin(&tstats->syncp); - tstats->tx_bytes += pkt_len; - tstats->tx_packets++; + u64_stats_add(&tstats->tx_bytes, pkt_len); + u64_stats_inc(&tstats->tx_packets); u64_stats_update_end(&tstats->syncp); put_cpu_ptr(tstats); } else { diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index bb01776d2d88..1ef14a099c6b 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -1770,10 +1770,10 @@ static int br_fill_linkxstats(struct sk_buff *skb, if (v->vid == pvid) vxi.flags |= BRIDGE_VLAN_INFO_PVID; br_vlan_get_stats(v, &stats); - vxi.rx_bytes = stats.rx_bytes; - vxi.rx_packets = stats.rx_packets; - vxi.tx_bytes = stats.tx_bytes; - vxi.tx_packets = stats.tx_packets; + vxi.rx_bytes = u64_stats_read(&stats.rx_bytes); + vxi.rx_packets = u64_stats_read(&stats.rx_packets); + vxi.tx_bytes = u64_stats_read(&stats.tx_bytes); + vxi.tx_packets = u64_stats_read(&stats.tx_packets); if (nla_put(skb, BRIDGE_XSTATS_VLAN, sizeof(vxi), &vxi)) goto nla_put_failure; diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 0f5e75ccac79..6e53dc991409 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -505,8 +505,8 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br, if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { stats = this_cpu_ptr(v->stats); u64_stats_update_begin(&stats->syncp); - stats->tx_bytes += skb->len; - stats->tx_packets++; + u64_stats_add(&stats->tx_bytes, skb->len); + u64_stats_inc(&stats->tx_packets); u64_stats_update_end(&stats->syncp); } @@ -624,8 +624,8 @@ static bool __allowed_ingress(const struct net_bridge *br, if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) { stats = this_cpu_ptr(v->stats); u64_stats_update_begin(&stats->syncp); - stats->rx_bytes += skb->len; - stats->rx_packets++; + u64_stats_add(&stats->rx_bytes, skb->len); + u64_stats_inc(&stats->rx_packets); u64_stats_update_end(&stats->syncp); } @@ -1379,16 +1379,16 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v, cpu_stats = per_cpu_ptr(v->stats, i); do { start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); - rxpackets = cpu_stats->rx_packets; - rxbytes = cpu_stats->rx_bytes; - txbytes = cpu_stats->tx_bytes; - txpackets = cpu_stats->tx_packets; + rxpackets = u64_stats_read(&cpu_stats->rx_packets); + rxbytes = u64_stats_read(&cpu_stats->rx_bytes); + txbytes = u64_stats_read(&cpu_stats->tx_bytes); + txpackets = u64_stats_read(&cpu_stats->tx_packets); } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); - stats->rx_packets += rxpackets; - stats->rx_bytes += rxbytes; - stats->tx_bytes += txbytes; - stats->tx_packets += txpackets; + u64_stats_add(&stats->rx_packets, rxpackets); + u64_stats_add(&stats->rx_bytes, rxbytes); + u64_stats_add(&stats->tx_bytes, txbytes); + u64_stats_add(&stats->tx_packets, txpackets); } } @@ -1779,14 +1779,18 @@ static bool br_vlan_stats_fill(struct sk_buff *skb, return false; br_vlan_get_stats(v, &stats); - if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES, stats.rx_bytes, + if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES, + u64_stats_read(&stats.rx_bytes), BRIDGE_VLANDB_STATS_PAD) || nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_PACKETS, - stats.rx_packets, BRIDGE_VLANDB_STATS_PAD) || - nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES, stats.tx_bytes, + u64_stats_read(&stats.rx_packets), + BRIDGE_VLANDB_STATS_PAD) || + nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES, + u64_stats_read(&stats.tx_bytes), BRIDGE_VLANDB_STATS_PAD) || nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_PACKETS, - stats.tx_packets, BRIDGE_VLANDB_STATS_PAD)) + u64_stats_read(&stats.tx_packets), + BRIDGE_VLANDB_STATS_PAD)) goto out_err; nla_nest_end(skb, nest); diff --git a/net/core/dev.c b/net/core/dev.c index c9d96b85a825..511cf5d3aade 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10459,23 +10459,23 @@ void dev_fetch_sw_netstats(struct rtnl_link_stats64 *s, int cpu; for_each_possible_cpu(cpu) { + u64 rx_packets, rx_bytes, tx_packets, tx_bytes; const struct pcpu_sw_netstats *stats; - struct pcpu_sw_netstats tmp; unsigned int start; stats = per_cpu_ptr(netstats, cpu); do { start = u64_stats_fetch_begin_irq(&stats->syncp); - tmp.rx_packets = stats->rx_packets; - tmp.rx_bytes = stats->rx_bytes; - tmp.tx_packets = stats->tx_packets; - tmp.tx_bytes = stats->tx_bytes; + rx_packets = u64_stats_read(&stats->rx_packets); + rx_bytes = u64_stats_read(&stats->rx_bytes); + tx_packets = u64_stats_read(&stats->tx_packets); + tx_bytes = u64_stats_read(&stats->tx_bytes); } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); - s->rx_packets += tmp.rx_packets; - s->rx_bytes += tmp.rx_bytes; - s->tx_packets += tmp.tx_packets; - s->tx_bytes += tmp.tx_bytes; + s->rx_packets += rx_packets; + s->rx_bytes += rx_bytes; + s->tx_packets += tx_packets; + s->tx_bytes += tx_bytes; } } EXPORT_SYMBOL_GPL(dev_fetch_sw_netstats); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 801a5d445833..2e1ac638d135 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -935,10 +935,10 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev, s = per_cpu_ptr(dev->tstats, i); do { start = u64_stats_fetch_begin_irq(&s->syncp); - tx_packets = s->tx_packets; - tx_bytes = s->tx_bytes; - rx_packets = s->rx_packets; - rx_bytes = s->rx_bytes; + tx_packets = u64_stats_read(&s->tx_packets); + tx_bytes = u64_stats_read(&s->tx_bytes); + rx_packets = u64_stats_read(&s->rx_packets); + rx_bytes = u64_stats_read(&s->rx_bytes); } while (u64_stats_fetch_retry_irq(&s->syncp, start)); data[0] += tx_packets; data[1] += tx_bytes; -- cgit v1.2.3 From 9ec321aba2eaca109139a2a67c65ede7f07bd8ec Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 08:46:40 -0700 Subject: team: adopt u64_stats_t As explained in commit 316580b69d0a ("u64_stats: provide u64_stats_t type") we should use u64_stats_t and related accessors to avoid load/store tearing. Signed-off-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- drivers/net/team/team.c | 26 +++++++++++++------------- include/linux/if_team.h | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index b07dde6f0abf..aac133a1e27a 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -749,10 +749,10 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) pcpu_stats = this_cpu_ptr(team->pcpu_stats); u64_stats_update_begin(&pcpu_stats->syncp); - pcpu_stats->rx_packets++; - pcpu_stats->rx_bytes += skb->len; + u64_stats_inc(&pcpu_stats->rx_packets); + u64_stats_add(&pcpu_stats->rx_bytes, skb->len); if (skb->pkt_type == PACKET_MULTICAST) - pcpu_stats->rx_multicast++; + u64_stats_inc(&pcpu_stats->rx_multicast); u64_stats_update_end(&pcpu_stats->syncp); skb->dev = team->dev; @@ -1720,8 +1720,8 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev) pcpu_stats = this_cpu_ptr(team->pcpu_stats); u64_stats_update_begin(&pcpu_stats->syncp); - pcpu_stats->tx_packets++; - pcpu_stats->tx_bytes += len; + u64_stats_inc(&pcpu_stats->tx_packets); + u64_stats_add(&pcpu_stats->tx_bytes, len); u64_stats_update_end(&pcpu_stats->syncp); } else { this_cpu_inc(team->pcpu_stats->tx_dropped); @@ -1854,11 +1854,11 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) p = per_cpu_ptr(team->pcpu_stats, i); do { start = u64_stats_fetch_begin_irq(&p->syncp); - rx_packets = p->rx_packets; - rx_bytes = p->rx_bytes; - rx_multicast = p->rx_multicast; - tx_packets = p->tx_packets; - tx_bytes = p->tx_bytes; + rx_packets = u64_stats_read(&p->rx_packets); + rx_bytes = u64_stats_read(&p->rx_bytes); + rx_multicast = u64_stats_read(&p->rx_multicast); + tx_packets = u64_stats_read(&p->tx_packets); + tx_bytes = u64_stats_read(&p->tx_bytes); } while (u64_stats_fetch_retry_irq(&p->syncp, start)); stats->rx_packets += rx_packets; @@ -1870,9 +1870,9 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) * rx_dropped, tx_dropped & rx_nohandler are u32, * updated without syncp protection. */ - rx_dropped += p->rx_dropped; - tx_dropped += p->tx_dropped; - rx_nohandler += p->rx_nohandler; + rx_dropped += READ_ONCE(p->rx_dropped); + tx_dropped += READ_ONCE(p->tx_dropped); + rx_nohandler += READ_ONCE(p->rx_nohandler); } stats->rx_dropped = rx_dropped; stats->tx_dropped = tx_dropped; diff --git a/include/linux/if_team.h b/include/linux/if_team.h index add607943c95..fc985e5c739d 100644 --- a/include/linux/if_team.h +++ b/include/linux/if_team.h @@ -12,11 +12,11 @@ #include struct team_pcpu_stats { - u64 rx_packets; - u64 rx_bytes; - u64 rx_multicast; - u64 tx_packets; - u64 tx_bytes; + u64_stats_t rx_packets; + u64_stats_t rx_bytes; + u64_stats_t rx_multicast; + u64_stats_t tx_packets; + u64_stats_t tx_bytes; struct u64_stats_sync syncp; u32 rx_dropped; u32 tx_dropped; -- cgit v1.2.3 From 2bff369b23542ea22d0111aaa8e0b8208bf0dc96 Mon Sep 17 00:00:00 2001 From: Jonathan Toppins Date: Wed, 8 Jun 2022 14:14:56 -0400 Subject: bonding: netlink error message support for options Add support for reporting errors via extack in both bond_newlink and bond_changelink. Instead of having to look in the kernel log for why an option was not correct just report the error to the user via the extack variable. What is currently reported today: ip link add bond0 type bond ip link set bond0 up ip link set bond0 type bond mode 4 RTNETLINK answers: Device or resource busy After this change: ip link add bond0 type bond ip link set bond0 up ip link set bond0 type bond mode 4 Error: unable to set option because the bond is up. Signed-off-by: Jonathan Toppins Acked-by: Jay Vosburgh Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_netlink.c | 101 +++++++++++++++++++++++++------------ drivers/net/bonding/bond_options.c | 32 +++++++++--- include/net/bond_options.h | 3 +- 3 files changed, 95 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 6f404f9c34e3..5a6f44455b95 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -151,7 +151,8 @@ static int bond_slave_changelink(struct net_device *bond_dev, snprintf(queue_id_str, sizeof(queue_id_str), "%s:%u\n", slave_dev->name, queue_id); bond_opt_initstr(&newval, queue_id_str); - err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval); + err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval, + data[IFLA_BOND_SLAVE_QUEUE_ID], extack); if (err) return err; } @@ -175,7 +176,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int mode = nla_get_u8(data[IFLA_BOND_MODE]); bond_opt_initval(&newval, mode); - err = __bond_opt_set(bond, BOND_OPT_MODE, &newval); + err = __bond_opt_set(bond, BOND_OPT_MODE, &newval, + data[IFLA_BOND_MODE], extack); if (err) return err; } @@ -192,7 +194,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], active_slave = slave_dev->name; } bond_opt_initstr(&newval, active_slave); - err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval); + err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval, + data[IFLA_BOND_ACTIVE_SLAVE], extack); if (err) return err; } @@ -200,7 +203,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], miimon = nla_get_u32(data[IFLA_BOND_MIIMON]); bond_opt_initval(&newval, miimon); - err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval); + err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval, + data[IFLA_BOND_MIIMON], extack); if (err) return err; } @@ -208,7 +212,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]); bond_opt_initval(&newval, updelay); - err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval); + err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval, + data[IFLA_BOND_UPDELAY], extack); if (err) return err; } @@ -216,7 +221,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]); bond_opt_initval(&newval, downdelay); - err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval); + err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval, + data[IFLA_BOND_DOWNDELAY], extack); if (err) return err; } @@ -224,7 +230,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int delay = nla_get_u32(data[IFLA_BOND_PEER_NOTIF_DELAY]); bond_opt_initval(&newval, delay); - err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval); + err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval, + data[IFLA_BOND_PEER_NOTIF_DELAY], extack); if (err) return err; } @@ -232,7 +239,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]); bond_opt_initval(&newval, use_carrier); - err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval); + err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval, + data[IFLA_BOND_USE_CARRIER], extack); if (err) return err; } @@ -240,12 +248,14 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]); if (arp_interval && miimon) { - netdev_err(bond->dev, "ARP monitoring cannot be used with MII monitoring\n"); + NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL], + "ARP monitoring cannot be used with MII monitoring"); return -EINVAL; } bond_opt_initval(&newval, arp_interval); - err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval); + err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval, + data[IFLA_BOND_ARP_INTERVAL], extack); if (err) return err; } @@ -264,7 +274,9 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], bond_opt_initval(&newval, (__force u64)target); err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS, - &newval); + &newval, + data[IFLA_BOND_ARP_IP_TARGET], + extack); if (err) break; i++; @@ -292,7 +304,9 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], bond_opt_initextra(&newval, &addr6, sizeof(addr6)); err = __bond_opt_set(bond, BOND_OPT_NS_TARGETS, - &newval); + &newval, + data[IFLA_BOND_NS_IP6_TARGET], + extack); if (err) break; i++; @@ -307,12 +321,14 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]); if (arp_validate && miimon) { - netdev_err(bond->dev, "ARP validating cannot be used with MII monitoring\n"); + NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL], + "ARP validating cannot be used with MII monitoring"); return -EINVAL; } bond_opt_initval(&newval, arp_validate); - err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval); + err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval, + data[IFLA_BOND_ARP_VALIDATE], extack); if (err) return err; } @@ -321,7 +337,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]); bond_opt_initval(&newval, arp_all_targets); - err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval); + err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval, + data[IFLA_BOND_ARP_ALL_TARGETS], extack); if (err) return err; } @@ -335,7 +352,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], primary = dev->name; bond_opt_initstr(&newval, primary); - err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval); + err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval, + data[IFLA_BOND_PRIMARY], extack); if (err) return err; } @@ -344,7 +362,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_PRIMARY_RESELECT]); bond_opt_initval(&newval, primary_reselect); - err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval); + err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval, + data[IFLA_BOND_PRIMARY_RESELECT], extack); if (err) return err; } @@ -353,7 +372,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_FAIL_OVER_MAC]); bond_opt_initval(&newval, fail_over_mac); - err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval); + err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval, + data[IFLA_BOND_FAIL_OVER_MAC], extack); if (err) return err; } @@ -362,7 +382,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_XMIT_HASH_POLICY]); bond_opt_initval(&newval, xmit_hash_policy); - err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval); + err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval, + data[IFLA_BOND_XMIT_HASH_POLICY], extack); if (err) return err; } @@ -371,7 +392,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_RESEND_IGMP]); bond_opt_initval(&newval, resend_igmp); - err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval); + err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval, + data[IFLA_BOND_RESEND_IGMP], extack); if (err) return err; } @@ -380,7 +402,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_NUM_PEER_NOTIF]); bond_opt_initval(&newval, num_peer_notif); - err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval); + err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval, + data[IFLA_BOND_NUM_PEER_NOTIF], extack); if (err) return err; } @@ -389,7 +412,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]); bond_opt_initval(&newval, all_slaves_active); - err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval); + err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval, + data[IFLA_BOND_ALL_SLAVES_ACTIVE], extack); if (err) return err; } @@ -398,7 +422,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_MIN_LINKS]); bond_opt_initval(&newval, min_links); - err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval); + err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval, + data[IFLA_BOND_MIN_LINKS], extack); if (err) return err; } @@ -407,7 +432,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_LP_INTERVAL]); bond_opt_initval(&newval, lp_interval); - err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval); + err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval, + data[IFLA_BOND_LP_INTERVAL], extack); if (err) return err; } @@ -416,7 +442,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]); bond_opt_initval(&newval, packets_per_slave); - err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval); + err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval, + data[IFLA_BOND_PACKETS_PER_SLAVE], extack); if (err) return err; } @@ -425,7 +452,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int lacp_active = nla_get_u8(data[IFLA_BOND_AD_LACP_ACTIVE]); bond_opt_initval(&newval, lacp_active); - err = __bond_opt_set(bond, BOND_OPT_LACP_ACTIVE, &newval); + err = __bond_opt_set(bond, BOND_OPT_LACP_ACTIVE, &newval, + data[IFLA_BOND_AD_LACP_ACTIVE], extack); if (err) return err; } @@ -435,7 +463,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_AD_LACP_RATE]); bond_opt_initval(&newval, lacp_rate); - err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval); + err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval, + data[IFLA_BOND_AD_LACP_RATE], extack); if (err) return err; } @@ -444,7 +473,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u8(data[IFLA_BOND_AD_SELECT]); bond_opt_initval(&newval, ad_select); - err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval); + err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval, + data[IFLA_BOND_AD_SELECT], extack); if (err) return err; } @@ -453,7 +483,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u16(data[IFLA_BOND_AD_ACTOR_SYS_PRIO]); bond_opt_initval(&newval, actor_sys_prio); - err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval); + err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval, + data[IFLA_BOND_AD_ACTOR_SYS_PRIO], extack); if (err) return err; } @@ -462,7 +493,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]); bond_opt_initval(&newval, port_key); - err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval); + err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval, + data[IFLA_BOND_AD_USER_PORT_KEY], extack); if (err) return err; } @@ -472,7 +504,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], bond_opt_initval(&newval, nla_get_u64(data[IFLA_BOND_AD_ACTOR_SYSTEM])); - err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval); + err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval, + data[IFLA_BOND_AD_ACTOR_SYSTEM], extack); if (err) return err; } @@ -480,7 +513,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int dynamic_lb = nla_get_u8(data[IFLA_BOND_TLB_DYNAMIC_LB]); bond_opt_initval(&newval, dynamic_lb); - err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval); + err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval, + data[IFLA_BOND_TLB_DYNAMIC_LB], extack); if (err) return err; } @@ -489,7 +523,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], int missed_max = nla_get_u8(data[IFLA_BOND_MISSED_MAX]); bond_opt_initval(&newval, missed_max); - err = __bond_opt_set(bond, BOND_OPT_MISSED_MAX, &newval); + err = __bond_opt_set(bond, BOND_OPT_MISSED_MAX, &newval, + data[IFLA_BOND_MISSED_MAX], extack); if (err) return err; } diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 1f8323ad5282..96eef19cffc4 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -632,27 +632,35 @@ static int bond_opt_check_deps(struct bonding *bond, } static void bond_opt_dep_print(struct bonding *bond, - const struct bond_option *opt) + const struct bond_option *opt, + struct nlattr *bad_attr, + struct netlink_ext_ack *extack) { const struct bond_opt_value *modeval; struct bond_params *params; params = &bond->params; modeval = bond_opt_get_val(BOND_OPT_MODE, params->mode); - if (test_bit(params->mode, &opt->unsuppmodes)) + if (test_bit(params->mode, &opt->unsuppmodes)) { netdev_err(bond->dev, "option %s: mode dependency failed, not supported in mode %s(%llu)\n", opt->name, modeval->string, modeval->value); + NL_SET_ERR_MSG_ATTR(extack, bad_attr, + "option not supported in mode"); + } } static void bond_opt_error_interpret(struct bonding *bond, const struct bond_option *opt, - int error, const struct bond_opt_value *val) + int error, const struct bond_opt_value *val, + struct nlattr *bad_attr, + struct netlink_ext_ack *extack) { const struct bond_opt_value *minval, *maxval; char *p; switch (error) { case -EINVAL: + NL_SET_ERR_MSG_ATTR(extack, bad_attr, "invalid option value"); if (val) { if (val->string) { /* sometimes RAWVAL opts may have new lines */ @@ -674,13 +682,17 @@ static void bond_opt_error_interpret(struct bonding *bond, opt->name, minval ? minval->value : 0, maxval->value); break; case -EACCES: - bond_opt_dep_print(bond, opt); + bond_opt_dep_print(bond, opt, bad_attr, extack); break; case -ENOTEMPTY: + NL_SET_ERR_MSG_ATTR(extack, bad_attr, + "unable to set option because the bond device has slaves"); netdev_err(bond->dev, "option %s: unable to set because the bond device has slaves\n", opt->name); break; case -EBUSY: + NL_SET_ERR_MSG_ATTR(extack, bad_attr, + "unable to set option because the bond is up"); netdev_err(bond->dev, "option %s: unable to set because the bond device is up\n", opt->name); break; @@ -691,6 +703,8 @@ static void bond_opt_error_interpret(struct bonding *bond, *p = '\0'; netdev_err(bond->dev, "option %s: interface %s does not exist!\n", opt->name, val->string); + NL_SET_ERR_MSG_ATTR(extack, bad_attr, + "interface does not exist"); } break; default: @@ -703,13 +717,17 @@ static void bond_opt_error_interpret(struct bonding *bond, * @bond: target bond device * @option: option to set * @val: value to set it to + * @bad_attr: netlink attribue that caused the error + * @extack: extended netlink error structure, used when an error message + * needs to be returned to the caller via netlink * * This function is used to change the bond's option value, it can be * used for both enabling/changing an option and for disabling it. RTNL lock * must be obtained before calling this function. */ int __bond_opt_set(struct bonding *bond, - unsigned int option, struct bond_opt_value *val) + unsigned int option, struct bond_opt_value *val, + struct nlattr *bad_attr, struct netlink_ext_ack *extack) { const struct bond_opt_value *retval = NULL; const struct bond_option *opt; @@ -731,7 +749,7 @@ int __bond_opt_set(struct bonding *bond, ret = opt->set(bond, retval); out: if (ret) - bond_opt_error_interpret(bond, opt, ret, val); + bond_opt_error_interpret(bond, opt, ret, val, bad_attr, extack); return ret; } @@ -753,7 +771,7 @@ int __bond_opt_set_notify(struct bonding *bond, ASSERT_RTNL(); - ret = __bond_opt_set(bond, option, val); + ret = __bond_opt_set(bond, option, val, NULL, NULL); if (!ret && (bond->dev->reg_state == NETREG_REGISTERED)) call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev); diff --git a/include/net/bond_options.h b/include/net/bond_options.h index 61b49063791c..1618b76f4903 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -107,7 +107,8 @@ struct bond_option { }; int __bond_opt_set(struct bonding *bond, unsigned int option, - struct bond_opt_value *val); + struct bond_opt_value *val, + struct nlattr *bad_attr, struct netlink_ext_ack *extack); int __bond_opt_set_notify(struct bonding *bond, unsigned int option, struct bond_opt_value *val); int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf); -- cgit v1.2.3 From 21ab562c1f65e583b5d89081acaf096805522482 Mon Sep 17 00:00:00 2001 From: Po Hao Huang Date: Wed, 8 Jun 2022 19:32:22 +0800 Subject: ieee80211: add trigger frame definition Define trigger stype of control frame, and its checking function, struct and trigger type within common_info of trigger. Signed-off-by: Po Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20220608113224.11193-2-pkshih@realtek.com --- include/linux/ieee80211.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'include') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 75d40acb60c1..5c65ae6b8154 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -76,6 +76,7 @@ #define IEEE80211_STYPE_ACTION 0x00D0 /* control */ +#define IEEE80211_STYPE_TRIGGER 0x0020 #define IEEE80211_STYPE_CTL_EXT 0x0060 #define IEEE80211_STYPE_BACK_REQ 0x0080 #define IEEE80211_STYPE_BACK 0x0090 @@ -295,6 +296,17 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) #define IEEE80211_HT_CTL_LEN 4 +/* trigger type within common_info of trigger frame */ +#define IEEE80211_TRIGGER_TYPE_MASK 0xf +#define IEEE80211_TRIGGER_TYPE_BASIC 0x0 +#define IEEE80211_TRIGGER_TYPE_BFRP 0x1 +#define IEEE80211_TRIGGER_TYPE_MU_BAR 0x2 +#define IEEE80211_TRIGGER_TYPE_MU_RTS 0x3 +#define IEEE80211_TRIGGER_TYPE_BSRP 0x4 +#define IEEE80211_TRIGGER_TYPE_GCR_MU_BAR 0x5 +#define IEEE80211_TRIGGER_TYPE_BQRP 0x6 +#define IEEE80211_TRIGGER_TYPE_NFRP 0x7 + struct ieee80211_hdr { __le16 frame_control; __le16 duration_id; @@ -324,6 +336,15 @@ struct ieee80211_qos_hdr { __le16 qos_ctrl; } __packed __aligned(2); +struct ieee80211_trigger { + __le16 frame_control; + __le16 duration; + u8 ra[ETH_ALEN]; + u8 ta[ETH_ALEN]; + __le64 common_info; + u8 variable[]; +} __packed __aligned(2); + /** * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set * @fc: frame control bytes in little-endian byteorder @@ -729,6 +750,16 @@ static inline bool ieee80211_is_qos_nullfunc(__le16 fc) cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC); } +/** + * ieee80211_is_trigger - check if frame is trigger frame + * @fc: frame control field in little-endian byteorder + */ +static inline bool ieee80211_is_trigger(__le16 fc) +{ + return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_TRIGGER); +} + /** * ieee80211_is_any_nullfunc - check if frame is regular or QoS nullfunc frame * @fc: frame control bytes in little-endian byteorder -- cgit v1.2.3 From f3c923a09c4c4f5861b1ed53cf75673992a6ba68 Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Fri, 20 May 2022 18:14:54 +0000 Subject: crypto: polyval - Add POLYVAL support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for POLYVAL, an ε-Δ-universal hash function similar to GHASH. This patch only uses POLYVAL as a component to implement HCTR2 mode. It should be noted that POLYVAL was originally specified for use in AES-GCM-SIV (RFC 8452), but the kernel does not currently support this mode. POLYVAL is implemented as an shash algorithm. The implementation is modified from ghash-generic.c. For more information on POLYVAL see: Length-preserving encryption with HCTR2: https://eprint.iacr.org/2021/1441.pdf AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption: https://datatracker.ietf.org/doc/html/rfc8452 Signed-off-by: Nathan Huckleberry Reviewed-by: Eric Biggers Reviewed-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/Kconfig | 8 ++ crypto/Makefile | 1 + crypto/polyval-generic.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++ crypto/tcrypt.c | 4 + crypto/testmgr.c | 6 ++ crypto/testmgr.h | 171 +++++++++++++++++++++++++++++++++++++++ include/crypto/polyval.h | 17 ++++ 7 files changed, 412 insertions(+) create mode 100644 crypto/polyval-generic.c create mode 100644 include/crypto/polyval.h (limited to 'include') diff --git a/crypto/Kconfig b/crypto/Kconfig index b9e4d511bf5a..d59e70dca197 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -773,6 +773,14 @@ config CRYPTO_GHASH GHASH is the hash function used in GCM (Galois/Counter Mode). It is not a general-purpose cryptographic hash function. +config CRYPTO_POLYVAL + tristate + select CRYPTO_GF128MUL + select CRYPTO_HASH + help + POLYVAL is the hash function used in HCTR2. It is not a general-purpose + cryptographic hash function. + config CRYPTO_POLY1305 tristate "Poly1305 authenticator algorithm" select CRYPTO_HASH diff --git a/crypto/Makefile b/crypto/Makefile index 93d0afeb3a77..7694ed0a44d5 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -172,6 +172,7 @@ UBSAN_SANITIZE_jitterentropy.o = n jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o +obj-$(CONFIG_CRYPTO_POLYVAL) += polyval-generic.o obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o diff --git a/crypto/polyval-generic.c b/crypto/polyval-generic.c new file mode 100644 index 000000000000..bf2b03b7bfc0 --- /dev/null +++ b/crypto/polyval-generic.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * POLYVAL: hash function for HCTR2. + * + * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen + * Copyright (c) 2009 Intel Corp. + * Author: Huang Ying + * Copyright 2021 Google LLC + */ + +/* + * Code based on crypto/ghash-generic.c + * + * POLYVAL is a keyed hash function similar to GHASH. POLYVAL uses a different + * modulus for finite field multiplication which makes hardware accelerated + * implementations on little-endian machines faster. POLYVAL is used in the + * kernel to implement HCTR2, but was originally specified for AES-GCM-SIV + * (RFC 8452). + * + * For more information see: + * Length-preserving encryption with HCTR2: + * https://eprint.iacr.org/2021/1441.pdf + * AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption: + * https://datatracker.ietf.org/doc/html/rfc8452 + * + * Like GHASH, POLYVAL is not a cryptographic hash function and should + * not be used outside of crypto modes explicitly designed to use POLYVAL. + * + * This implementation uses a convenient trick involving the GHASH and POLYVAL + * fields. This trick allows multiplication in the POLYVAL field to be + * implemented by using multiplication in the GHASH field as a subroutine. An + * element of the POLYVAL field can be converted to an element of the GHASH + * field by computing x*REVERSE(a), where REVERSE reverses the byte-ordering of + * a. Similarly, an element of the GHASH field can be converted back to the + * POLYVAL field by computing REVERSE(x^{-1}*a). For more information, see: + * https://datatracker.ietf.org/doc/html/rfc8452#appendix-A + * + * By using this trick, we do not need to implement the POLYVAL field for the + * generic implementation. + * + * Warning: this generic implementation is not intended to be used in practice + * and is not constant time. For practical use, a hardware accelerated + * implementation of POLYVAL should be used instead. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct polyval_tfm_ctx { + struct gf128mul_4k *gf128; +}; + +struct polyval_desc_ctx { + union { + u8 buffer[POLYVAL_BLOCK_SIZE]; + be128 buffer128; + }; + u32 bytes; +}; + +static void copy_and_reverse(u8 dst[POLYVAL_BLOCK_SIZE], + const u8 src[POLYVAL_BLOCK_SIZE]) +{ + u64 a = get_unaligned((const u64 *)&src[0]); + u64 b = get_unaligned((const u64 *)&src[8]); + + put_unaligned(swab64(a), (u64 *)&dst[8]); + put_unaligned(swab64(b), (u64 *)&dst[0]); +} + +static int polyval_setkey(struct crypto_shash *tfm, + const u8 *key, unsigned int keylen) +{ + struct polyval_tfm_ctx *ctx = crypto_shash_ctx(tfm); + be128 k; + + if (keylen != POLYVAL_BLOCK_SIZE) + return -EINVAL; + + gf128mul_free_4k(ctx->gf128); + + BUILD_BUG_ON(sizeof(k) != POLYVAL_BLOCK_SIZE); + copy_and_reverse((u8 *)&k, key); + gf128mul_x_lle(&k, &k); + + ctx->gf128 = gf128mul_init_4k_lle(&k); + memzero_explicit(&k, POLYVAL_BLOCK_SIZE); + + if (!ctx->gf128) + return -ENOMEM; + + return 0; +} + +static int polyval_init(struct shash_desc *desc) +{ + struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); + + memset(dctx, 0, sizeof(*dctx)); + + return 0; +} + +static int polyval_update(struct shash_desc *desc, + const u8 *src, unsigned int srclen) +{ + struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); + const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm); + u8 *pos; + u8 tmp[POLYVAL_BLOCK_SIZE]; + int n; + + if (dctx->bytes) { + n = min(srclen, dctx->bytes); + pos = dctx->buffer + dctx->bytes - 1; + + dctx->bytes -= n; + srclen -= n; + + while (n--) + *pos-- ^= *src++; + + if (!dctx->bytes) + gf128mul_4k_lle(&dctx->buffer128, ctx->gf128); + } + + while (srclen >= POLYVAL_BLOCK_SIZE) { + copy_and_reverse(tmp, src); + crypto_xor(dctx->buffer, tmp, POLYVAL_BLOCK_SIZE); + gf128mul_4k_lle(&dctx->buffer128, ctx->gf128); + src += POLYVAL_BLOCK_SIZE; + srclen -= POLYVAL_BLOCK_SIZE; + } + + if (srclen) { + dctx->bytes = POLYVAL_BLOCK_SIZE - srclen; + pos = dctx->buffer + POLYVAL_BLOCK_SIZE - 1; + while (srclen--) + *pos-- ^= *src++; + } + + return 0; +} + +static int polyval_final(struct shash_desc *desc, u8 *dst) +{ + struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); + const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm); + + if (dctx->bytes) + gf128mul_4k_lle(&dctx->buffer128, ctx->gf128); + copy_and_reverse(dst, dctx->buffer); + return 0; +} + +static void polyval_exit_tfm(struct crypto_tfm *tfm) +{ + struct polyval_tfm_ctx *ctx = crypto_tfm_ctx(tfm); + + gf128mul_free_4k(ctx->gf128); +} + +static struct shash_alg polyval_alg = { + .digestsize = POLYVAL_DIGEST_SIZE, + .init = polyval_init, + .update = polyval_update, + .final = polyval_final, + .setkey = polyval_setkey, + .descsize = sizeof(struct polyval_desc_ctx), + .base = { + .cra_name = "polyval", + .cra_driver_name = "polyval-generic", + .cra_priority = 100, + .cra_blocksize = POLYVAL_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct polyval_tfm_ctx), + .cra_module = THIS_MODULE, + .cra_exit = polyval_exit_tfm, + }, +}; + +static int __init polyval_mod_init(void) +{ + return crypto_register_shash(&polyval_alg); +} + +static void __exit polyval_mod_exit(void) +{ + crypto_unregister_shash(&polyval_alg); +} + +subsys_initcall(polyval_mod_init); +module_exit(polyval_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("POLYVAL hash function"); +MODULE_ALIAS_CRYPTO("polyval"); +MODULE_ALIAS_CRYPTO("polyval-generic"); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index fd671d0e2012..dd9cf216029b 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1730,6 +1730,10 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) ret += tcrypt_test("ccm(sm4)"); break; + case 57: + ret += tcrypt_test("polyval"); + break; + case 100: ret += tcrypt_test("hmac(md5)"); break; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 0ea77dcdc6c0..0f40e260b5a9 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -5342,6 +5342,12 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(poly1305_tv_template) } + }, { + .alg = "polyval", + .test = alg_test_hash, + .suite = { + .hash = __VECS(polyval_tv_template) + } }, { .alg = "rfc3686(ctr(aes))", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 7179df0a39b6..b58e13930307 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -34944,4 +34944,175 @@ static const struct cipher_testvec aes_xctr_tv_template[] = { }; +/* + * Test vectors generated using https://github.com/google/hctr2 + * + * To ensure compatibility with RFC 8452, some tests were sourced from + * https://datatracker.ietf.org/doc/html/rfc8452 + */ +static const struct hash_testvec polyval_tv_template[] = { + { // From RFC 8452 + .key = "\x31\x07\x28\xd9\x91\x1f\x1f\x38" + "\x37\xb2\x43\x16\xc3\xfa\xb9\xa0", + .plaintext = "\x65\x78\x61\x6d\x70\x6c\x65\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x48\x65\x6c\x6c\x6f\x20\x77\x6f" + "\x72\x6c\x64\x00\x00\x00\x00\x00" + "\x38\x00\x00\x00\x00\x00\x00\x00" + "\x58\x00\x00\x00\x00\x00\x00\x00", + .digest = "\xad\x7f\xcf\x0b\x51\x69\x85\x16" + "\x62\x67\x2f\x3c\x5f\x95\x13\x8f", + .psize = 48, + .ksize = 16, + }, + { // From RFC 8452 + .key = "\xd9\xb3\x60\x27\x96\x94\x94\x1a" + "\xc5\xdb\xc6\x98\x7a\xda\x73\x77", + .plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .digest = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .psize = 16, + .ksize = 16, + }, + { // From RFC 8452 + .key = "\xd9\xb3\x60\x27\x96\x94\x94\x1a" + "\xc5\xdb\xc6\x98\x7a\xda\x73\x77", + .plaintext = "\x01\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x40\x00\x00\x00\x00\x00\x00\x00", + .digest = "\xeb\x93\xb7\x74\x09\x62\xc5\xe4" + "\x9d\x2a\x90\xa7\xdc\x5c\xec\x74", + .psize = 32, + .ksize = 16, + }, + { // From RFC 8452 + .key = "\xd9\xb3\x60\x27\x96\x94\x94\x1a" + "\xc5\xdb\xc6\x98\x7a\xda\x73\x77", + .plaintext = "\x01\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x02\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x03\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x01\x00\x00\x00\x00\x00\x00", + .digest = "\x81\x38\x87\x46\xbc\x22\xd2\x6b" + "\x2a\xbc\x3d\xcb\x15\x75\x42\x22", + .psize = 64, + .ksize = 16, + }, + { // From RFC 8452 + .key = "\xd9\xb3\x60\x27\x96\x94\x94\x1a" + "\xc5\xdb\xc6\x98\x7a\xda\x73\x77", + .plaintext = "\x01\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x02\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x03\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x04\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x02\x00\x00\x00\x00\x00\x00", + .digest = "\x1e\x39\xb6\xd3\x34\x4d\x34\x8f" + "\x60\x44\xf8\x99\x35\xd1\xcf\x78", + .psize = 80, + .ksize = 16, + }, + { // From RFC 8452 + .key = "\xd9\xb3\x60\x27\x96\x94\x94\x1a" + "\xc5\xdb\xc6\x98\x7a\xda\x73\x77", + .plaintext = "\x01\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x02\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x03\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x04\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x05\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x08\x00\x00\x00\x00\x00\x00\x00" + "\x00\x02\x00\x00\x00\x00\x00\x00", + .digest = "\xff\xcd\x05\xd5\x77\x0f\x34\xad" + "\x92\x67\xf0\xa5\x99\x94\xb1\x5a", + .psize = 96, + .ksize = 16, + }, + { // Random ( 1) + .key = "\x90\xcc\xac\xee\xba\xd7\xd4\x68" + "\x98\xa6\x79\x70\xdf\x66\x15\x6c", + .plaintext = "", + .digest = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .psize = 0, + .ksize = 16, + }, + { // Random ( 1) + .key = "\xc1\x45\x71\xf0\x30\x07\x94\xe7" + "\x3a\xdd\xe4\xc6\x19\x2d\x02\xa2", + .plaintext = "\xc1\x5d\x47\xc7\x4c\x7c\x5e\x07" + "\x85\x14\x8f\x79\xcc\x73\x83\xf7" + "\x35\xb8\xcb\x73\x61\xf0\x53\x31" + "\xbf\x84\xde\xb6\xde\xaf\xb0\xb8" + "\xb7\xd9\x11\x91\x89\xfd\x1e\x4c" + "\x84\x4a\x1f\x2a\x87\xa4\xaf\x62" + "\x8d\x7d\x58\xf6\x43\x35\xfc\x53" + "\x8f\x1a\xf6\x12\xe1\x13\x3f\x66" + "\x91\x4b\x13\xd6\x45\xfb\xb0\x7a" + "\xe0\x8b\x8e\x99\xf7\x86\x46\x37" + "\xd1\x22\x9e\x52\xf3\x3f\xd9\x75" + "\x2c\x2c\xc6\xbb\x0e\x08\x14\x29" + "\xe8\x50\x2f\xd8\xbe\xf4\xe9\x69" + "\x4a\xee\xf7\xae\x15\x65\x35\x1e", + .digest = "\x00\x4f\x5d\xe9\x3b\xc0\xd6\x50" + "\x3e\x38\x73\x86\xc6\xda\xca\x7f", + .psize = 112, + .ksize = 16, + }, + { // Random ( 1) + .key = "\x37\xbe\x68\x16\x50\xb9\x4e\xb0" + "\x47\xde\xe2\xbd\xde\xe4\x48\x09", + .plaintext = "\x87\xfc\x68\x9f\xff\xf2\x4a\x1e" + "\x82\x3b\x73\x8f\xc1\xb2\x1b\x7a" + "\x6c\x4f\x81\xbc\x88\x9b\x6c\xa3" + "\x9c\xc2\xa5\xbc\x14\x70\x4c\x9b" + "\x0c\x9f\x59\x92\x16\x4b\x91\x3d" + "\x18\x55\x22\x68\x12\x8c\x63\xb2" + "\x51\xcb\x85\x4b\xd2\xae\x0b\x1c" + "\x5d\x28\x9d\x1d\xb1\xc8\xf0\x77" + "\xe9\xb5\x07\x4e\x06\xc8\xee\xf8" + "\x1b\xed\x72\x2a\x55\x7d\x16\xc9" + "\xf2\x54\xe7\xe9\xe0\x44\x5b\x33" + "\xb1\x49\xee\xff\x43\xfb\x82\xcd" + "\x4a\x70\x78\x81\xa4\x34\x36\xe8" + "\x4c\x28\x54\xa6\x6c\xc3\x6b\x78" + "\xe7\xc0\x5d\xc6\x5d\x81\xab\x70" + "\x08\x86\xa1\xfd\xf4\x77\x55\xfd" + "\xa3\xe9\xe2\x1b\xdf\x99\xb7\x80" + "\xf9\x0a\x4f\x72\x4a\xd3\xaf\xbb" + "\xb3\x3b\xeb\x08\x58\x0f\x79\xce" + "\xa5\x99\x05\x12\x34\xd4\xf4\x86" + "\x37\x23\x1d\xc8\x49\xc0\x92\xae" + "\xa6\xac\x9b\x31\x55\xed\x15\xc6" + "\x05\x17\x37\x8d\x90\x42\xe4\x87" + "\x89\x62\x88\x69\x1c\x6a\xfd\xe3" + "\x00\x2b\x47\x1a\x73\xc1\x51\xc2" + "\xc0\x62\x74\x6a\x9e\xb2\xe5\x21" + "\xbe\x90\xb5\xb0\x50\xca\x88\x68" + "\xe1\x9d\x7a\xdf\x6c\xb7\xb9\x98" + "\xee\x28\x62\x61\x8b\xd1\x47\xf9" + "\x04\x7a\x0b\x5d\xcd\x2b\x65\xf5" + "\x12\xa3\xfe\x1a\xaa\x2c\x78\x42" + "\xb8\xbe\x7d\x74\xeb\x59\xba\xba", + .digest = "\xae\x11\xd4\x60\x2a\x5f\x9e\x42" + "\x89\x04\xc2\x34\x8d\x55\x94\x0a", + .psize = 256, + .ksize = 16, + }, + +}; + #endif /* _CRYPTO_TESTMGR_H */ diff --git a/include/crypto/polyval.h b/include/crypto/polyval.h new file mode 100644 index 000000000000..b14c38aa9166 --- /dev/null +++ b/include/crypto/polyval.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Common values for the Polyval hash algorithm + * + * Copyright 2021 Google LLC + */ + +#ifndef _CRYPTO_POLYVAL_H +#define _CRYPTO_POLYVAL_H + +#include +#include + +#define POLYVAL_BLOCK_SIZE 16 +#define POLYVAL_DIGEST_SIZE 16 + +#endif -- cgit v1.2.3 From 34f7f6c3011276313383099156be287ac745bcea Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Fri, 20 May 2022 18:14:59 +0000 Subject: crypto: x86/polyval - Add PCLMULQDQ accelerated implementation of POLYVAL Add hardware accelerated version of POLYVAL for x86-64 CPUs with PCLMULQDQ support. This implementation is accelerated using PCLMULQDQ instructions to perform the finite field computations. For added efficiency, 8 blocks of the message are processed simultaneously by precomputing the first 8 powers of the key. Schoolbook multiplication is used instead of Karatsuba multiplication because it was found to be slightly faster on x86-64 machines. Montgomery reduction must be used instead of Barrett reduction due to the difference in modulus between POLYVAL's field and other finite fields. More information on POLYVAL can be found in the HCTR2 paper: "Length-preserving encryption with HCTR2": https://eprint.iacr.org/2021/1441.pdf Signed-off-by: Nathan Huckleberry Reviewed-by: Ard Biesheuvel Reviewed-by: Eric Biggers Signed-off-by: Herbert Xu --- arch/x86/crypto/Makefile | 3 + arch/x86/crypto/polyval-clmulni_asm.S | 321 +++++++++++++++++++++++++++++++++ arch/x86/crypto/polyval-clmulni_glue.c | 203 +++++++++++++++++++++ crypto/Kconfig | 9 + crypto/polyval-generic.c | 40 ++++ include/crypto/polyval.h | 5 + 6 files changed, 581 insertions(+) create mode 100644 arch/x86/crypto/polyval-clmulni_asm.S create mode 100644 arch/x86/crypto/polyval-clmulni_glue.c (limited to 'include') diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 2831685adf6f..b9847152acd8 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -69,6 +69,9 @@ libblake2s-x86_64-y := blake2s-core.o blake2s-glue.o obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o +obj-$(CONFIG_CRYPTO_POLYVAL_CLMUL_NI) += polyval-clmulni.o +polyval-clmulni-y := polyval-clmulni_asm.o polyval-clmulni_glue.o + obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o crc32c-intel-y := crc32c-intel_glue.o crc32c-intel-$(CONFIG_64BIT) += crc32c-pcl-intel-asm_64.o diff --git a/arch/x86/crypto/polyval-clmulni_asm.S b/arch/x86/crypto/polyval-clmulni_asm.S new file mode 100644 index 000000000000..a6ebe4e7dd2b --- /dev/null +++ b/arch/x86/crypto/polyval-clmulni_asm.S @@ -0,0 +1,321 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2021 Google LLC + */ +/* + * This is an efficient implementation of POLYVAL using intel PCLMULQDQ-NI + * instructions. It works on 8 blocks at a time, by precomputing the first 8 + * keys powers h^8, ..., h^1 in the POLYVAL finite field. This precomputation + * allows us to split finite field multiplication into two steps. + * + * In the first step, we consider h^i, m_i as normal polynomials of degree less + * than 128. We then compute p(x) = h^8m_0 + ... + h^1m_7 where multiplication + * is simply polynomial multiplication. + * + * In the second step, we compute the reduction of p(x) modulo the finite field + * modulus g(x) = x^128 + x^127 + x^126 + x^121 + 1. + * + * This two step process is equivalent to computing h^8m_0 + ... + h^1m_7 where + * multiplication is finite field multiplication. The advantage is that the + * two-step process only requires 1 finite field reduction for every 8 + * polynomial multiplications. Further parallelism is gained by interleaving the + * multiplications and polynomial reductions. + */ + +#include +#include + +#define STRIDE_BLOCKS 8 + +#define GSTAR %xmm7 +#define PL %xmm8 +#define PH %xmm9 +#define TMP_XMM %xmm11 +#define LO %xmm12 +#define HI %xmm13 +#define MI %xmm14 +#define SUM %xmm15 + +#define KEY_POWERS %rdi +#define MSG %rsi +#define BLOCKS_LEFT %rdx +#define ACCUMULATOR %rcx +#define TMP %rax + +.section .rodata.cst16.gstar, "aM", @progbits, 16 +.align 16 + +.Lgstar: + .quad 0xc200000000000000, 0xc200000000000000 + +.text + +/* + * Performs schoolbook1_iteration on two lists of 128-bit polynomials of length + * count pointed to by MSG and KEY_POWERS. + */ +.macro schoolbook1 count + .set i, 0 + .rept (\count) + schoolbook1_iteration i 0 + .set i, (i +1) + .endr +.endm + +/* + * Computes the product of two 128-bit polynomials at the memory locations + * specified by (MSG + 16*i) and (KEY_POWERS + 16*i) and XORs the components of + * the 256-bit product into LO, MI, HI. + * + * Given: + * X = [X_1 : X_0] + * Y = [Y_1 : Y_0] + * + * We compute: + * LO += X_0 * Y_0 + * MI += X_0 * Y_1 + X_1 * Y_0 + * HI += X_1 * Y_1 + * + * Later, the 256-bit result can be extracted as: + * [HI_1 : HI_0 + MI_1 : LO_1 + MI_0 : LO_0] + * This step is done when computing the polynomial reduction for efficiency + * reasons. + * + * If xor_sum == 1, then also XOR the value of SUM into m_0. This avoids an + * extra multiplication of SUM and h^8. + */ +.macro schoolbook1_iteration i xor_sum + movups (16*\i)(MSG), %xmm0 + .if (\i == 0 && \xor_sum == 1) + pxor SUM, %xmm0 + .endif + vpclmulqdq $0x01, (16*\i)(KEY_POWERS), %xmm0, %xmm2 + vpclmulqdq $0x00, (16*\i)(KEY_POWERS), %xmm0, %xmm1 + vpclmulqdq $0x10, (16*\i)(KEY_POWERS), %xmm0, %xmm3 + vpclmulqdq $0x11, (16*\i)(KEY_POWERS), %xmm0, %xmm4 + vpxor %xmm2, MI, MI + vpxor %xmm1, LO, LO + vpxor %xmm4, HI, HI + vpxor %xmm3, MI, MI +.endm + +/* + * Performs the same computation as schoolbook1_iteration, except we expect the + * arguments to already be loaded into xmm0 and xmm1 and we set the result + * registers LO, MI, and HI directly rather than XOR'ing into them. + */ +.macro schoolbook1_noload + vpclmulqdq $0x01, %xmm0, %xmm1, MI + vpclmulqdq $0x10, %xmm0, %xmm1, %xmm2 + vpclmulqdq $0x00, %xmm0, %xmm1, LO + vpclmulqdq $0x11, %xmm0, %xmm1, HI + vpxor %xmm2, MI, MI +.endm + +/* + * Computes the 256-bit polynomial represented by LO, HI, MI. Stores + * the result in PL, PH. + * [PH : PL] = [HI_1 : HI_0 + MI_1 : LO_1 + MI_0 : LO_0] + */ +.macro schoolbook2 + vpslldq $8, MI, PL + vpsrldq $8, MI, PH + pxor LO, PL + pxor HI, PH +.endm + +/* + * Computes the 128-bit reduction of PH : PL. Stores the result in dest. + * + * This macro computes p(x) mod g(x) where p(x) is in montgomery form and g(x) = + * x^128 + x^127 + x^126 + x^121 + 1. + * + * We have a 256-bit polynomial PH : PL = P_3 : P_2 : P_1 : P_0 that is the + * product of two 128-bit polynomials in Montgomery form. We need to reduce it + * mod g(x). Also, since polynomials in Montgomery form have an "extra" factor + * of x^128, this product has two extra factors of x^128. To get it back into + * Montgomery form, we need to remove one of these factors by dividing by x^128. + * + * To accomplish both of these goals, we add multiples of g(x) that cancel out + * the low 128 bits P_1 : P_0, leaving just the high 128 bits. Since the low + * bits are zero, the polynomial division by x^128 can be done by right shifting. + * + * Since the only nonzero term in the low 64 bits of g(x) is the constant term, + * the multiple of g(x) needed to cancel out P_0 is P_0 * g(x). The CPU can + * only do 64x64 bit multiplications, so split P_0 * g(x) into x^128 * P_0 + + * x^64 * g*(x) * P_0 + P_0, where g*(x) is bits 64-127 of g(x). Adding this to + * the original polynomial gives P_3 : P_2 + P_0 + T_1 : P_1 + T_0 : 0, where T + * = T_1 : T_0 = g*(x) * P_0. Thus, bits 0-63 got "folded" into bits 64-191. + * + * Repeating this same process on the next 64 bits "folds" bits 64-127 into bits + * 128-255, giving the answer in bits 128-255. This time, we need to cancel P_1 + * + T_0 in bits 64-127. The multiple of g(x) required is (P_1 + T_0) * g(x) * + * x^64. Adding this to our previous computation gives P_3 + P_1 + T_0 + V_1 : + * P_2 + P_0 + T_1 + V_0 : 0 : 0, where V = V_1 : V_0 = g*(x) * (P_1 + T_0). + * + * So our final computation is: + * T = T_1 : T_0 = g*(x) * P_0 + * V = V_1 : V_0 = g*(x) * (P_1 + T_0) + * p(x) / x^{128} mod g(x) = P_3 + P_1 + T_0 + V_1 : P_2 + P_0 + T_1 + V_0 + * + * The implementation below saves a XOR instruction by computing P_1 + T_0 : P_0 + * + T_1 and XORing into dest, rather than separately XORing P_1 : P_0 and T_0 : + * T_1 into dest. This allows us to reuse P_1 + T_0 when computing V. + */ +.macro montgomery_reduction dest + vpclmulqdq $0x00, PL, GSTAR, TMP_XMM # TMP_XMM = T_1 : T_0 = P_0 * g*(x) + pshufd $0b01001110, TMP_XMM, TMP_XMM # TMP_XMM = T_0 : T_1 + pxor PL, TMP_XMM # TMP_XMM = P_1 + T_0 : P_0 + T_1 + pxor TMP_XMM, PH # PH = P_3 + P_1 + T_0 : P_2 + P_0 + T_1 + pclmulqdq $0x11, GSTAR, TMP_XMM # TMP_XMM = V_1 : V_0 = V = [(P_1 + T_0) * g*(x)] + vpxor TMP_XMM, PH, \dest +.endm + +/* + * Compute schoolbook multiplication for 8 blocks + * m_0h^8 + ... + m_7h^1 + * + * If reduce is set, also computes the montgomery reduction of the + * previous full_stride call and XORs with the first message block. + * (m_0 + REDUCE(PL, PH))h^8 + ... + m_7h^1. + * I.e., the first multiplication uses m_0 + REDUCE(PL, PH) instead of m_0. + */ +.macro full_stride reduce + pxor LO, LO + pxor HI, HI + pxor MI, MI + + schoolbook1_iteration 7 0 + .if \reduce + vpclmulqdq $0x00, PL, GSTAR, TMP_XMM + .endif + + schoolbook1_iteration 6 0 + .if \reduce + pshufd $0b01001110, TMP_XMM, TMP_XMM + .endif + + schoolbook1_iteration 5 0 + .if \reduce + pxor PL, TMP_XMM + .endif + + schoolbook1_iteration 4 0 + .if \reduce + pxor TMP_XMM, PH + .endif + + schoolbook1_iteration 3 0 + .if \reduce + pclmulqdq $0x11, GSTAR, TMP_XMM + .endif + + schoolbook1_iteration 2 0 + .if \reduce + vpxor TMP_XMM, PH, SUM + .endif + + schoolbook1_iteration 1 0 + + schoolbook1_iteration 0 1 + + addq $(8*16), MSG + schoolbook2 +.endm + +/* + * Process BLOCKS_LEFT blocks, where 0 < BLOCKS_LEFT < STRIDE_BLOCKS + */ +.macro partial_stride + mov BLOCKS_LEFT, TMP + shlq $4, TMP + addq $(16*STRIDE_BLOCKS), KEY_POWERS + subq TMP, KEY_POWERS + + movups (MSG), %xmm0 + pxor SUM, %xmm0 + movaps (KEY_POWERS), %xmm1 + schoolbook1_noload + dec BLOCKS_LEFT + addq $16, MSG + addq $16, KEY_POWERS + + test $4, BLOCKS_LEFT + jz .Lpartial4BlocksDone + schoolbook1 4 + addq $(4*16), MSG + addq $(4*16), KEY_POWERS +.Lpartial4BlocksDone: + test $2, BLOCKS_LEFT + jz .Lpartial2BlocksDone + schoolbook1 2 + addq $(2*16), MSG + addq $(2*16), KEY_POWERS +.Lpartial2BlocksDone: + test $1, BLOCKS_LEFT + jz .LpartialDone + schoolbook1 1 +.LpartialDone: + schoolbook2 + montgomery_reduction SUM +.endm + +/* + * Perform montgomery multiplication in GF(2^128) and store result in op1. + * + * Computes op1*op2*x^{-128} mod x^128 + x^127 + x^126 + x^121 + 1 + * If op1, op2 are in montgomery form, this computes the montgomery + * form of op1*op2. + * + * void clmul_polyval_mul(u8 *op1, const u8 *op2); + */ +SYM_FUNC_START(clmul_polyval_mul) + FRAME_BEGIN + vmovdqa .Lgstar(%rip), GSTAR + movups (%rdi), %xmm0 + movups (%rsi), %xmm1 + schoolbook1_noload + schoolbook2 + montgomery_reduction SUM + movups SUM, (%rdi) + FRAME_END + RET +SYM_FUNC_END(clmul_polyval_mul) + +/* + * Perform polynomial evaluation as specified by POLYVAL. This computes: + * h^n * accumulator + h^n * m_0 + ... + h^1 * m_{n-1} + * where n=nblocks, h is the hash key, and m_i are the message blocks. + * + * rdi - pointer to precomputed key powers h^8 ... h^1 + * rsi - pointer to message blocks + * rdx - number of blocks to hash + * rcx - pointer to the accumulator + * + * void clmul_polyval_update(const struct polyval_tfm_ctx *keys, + * const u8 *in, size_t nblocks, u8 *accumulator); + */ +SYM_FUNC_START(clmul_polyval_update) + FRAME_BEGIN + vmovdqa .Lgstar(%rip), GSTAR + movups (ACCUMULATOR), SUM + subq $STRIDE_BLOCKS, BLOCKS_LEFT + js .LstrideLoopExit + full_stride 0 + subq $STRIDE_BLOCKS, BLOCKS_LEFT + js .LstrideLoopExitReduce +.LstrideLoop: + full_stride 1 + subq $STRIDE_BLOCKS, BLOCKS_LEFT + jns .LstrideLoop +.LstrideLoopExitReduce: + montgomery_reduction SUM +.LstrideLoopExit: + add $STRIDE_BLOCKS, BLOCKS_LEFT + jz .LskipPartial + partial_stride +.LskipPartial: + movups SUM, (ACCUMULATOR) + FRAME_END + RET +SYM_FUNC_END(clmul_polyval_update) diff --git a/arch/x86/crypto/polyval-clmulni_glue.c b/arch/x86/crypto/polyval-clmulni_glue.c new file mode 100644 index 000000000000..b7664d018851 --- /dev/null +++ b/arch/x86/crypto/polyval-clmulni_glue.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Glue code for POLYVAL using PCMULQDQ-NI + * + * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen + * Copyright (c) 2009 Intel Corp. + * Author: Huang Ying + * Copyright 2021 Google LLC + */ + +/* + * Glue code based on ghash-clmulni-intel_glue.c. + * + * This implementation of POLYVAL uses montgomery multiplication + * accelerated by PCLMULQDQ-NI to implement the finite field + * operations. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NUM_KEY_POWERS 8 + +struct polyval_tfm_ctx { + /* + * These powers must be in the order h^8, ..., h^1. + */ + u8 key_powers[NUM_KEY_POWERS][POLYVAL_BLOCK_SIZE]; +}; + +struct polyval_desc_ctx { + u8 buffer[POLYVAL_BLOCK_SIZE]; + u32 bytes; +}; + +asmlinkage void clmul_polyval_update(const struct polyval_tfm_ctx *keys, + const u8 *in, size_t nblocks, u8 *accumulator); +asmlinkage void clmul_polyval_mul(u8 *op1, const u8 *op2); + +static void internal_polyval_update(const struct polyval_tfm_ctx *keys, + const u8 *in, size_t nblocks, u8 *accumulator) +{ + if (likely(crypto_simd_usable())) { + kernel_fpu_begin(); + clmul_polyval_update(keys, in, nblocks, accumulator); + kernel_fpu_end(); + } else { + polyval_update_non4k(keys->key_powers[NUM_KEY_POWERS-1], in, + nblocks, accumulator); + } +} + +static void internal_polyval_mul(u8 *op1, const u8 *op2) +{ + if (likely(crypto_simd_usable())) { + kernel_fpu_begin(); + clmul_polyval_mul(op1, op2); + kernel_fpu_end(); + } else { + polyval_mul_non4k(op1, op2); + } +} + +static int polyval_x86_setkey(struct crypto_shash *tfm, + const u8 *key, unsigned int keylen) +{ + struct polyval_tfm_ctx *tctx = crypto_shash_ctx(tfm); + int i; + + if (keylen != POLYVAL_BLOCK_SIZE) + return -EINVAL; + + memcpy(tctx->key_powers[NUM_KEY_POWERS-1], key, POLYVAL_BLOCK_SIZE); + + for (i = NUM_KEY_POWERS-2; i >= 0; i--) { + memcpy(tctx->key_powers[i], key, POLYVAL_BLOCK_SIZE); + internal_polyval_mul(tctx->key_powers[i], + tctx->key_powers[i+1]); + } + + return 0; +} + +static int polyval_x86_init(struct shash_desc *desc) +{ + struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); + + memset(dctx, 0, sizeof(*dctx)); + + return 0; +} + +static int polyval_x86_update(struct shash_desc *desc, + const u8 *src, unsigned int srclen) +{ + struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); + const struct polyval_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + u8 *pos; + unsigned int nblocks; + unsigned int n; + + if (dctx->bytes) { + n = min(srclen, dctx->bytes); + pos = dctx->buffer + POLYVAL_BLOCK_SIZE - dctx->bytes; + + dctx->bytes -= n; + srclen -= n; + + while (n--) + *pos++ ^= *src++; + + if (!dctx->bytes) + internal_polyval_mul(dctx->buffer, + tctx->key_powers[NUM_KEY_POWERS-1]); + } + + while (srclen >= POLYVAL_BLOCK_SIZE) { + /* Allow rescheduling every 4K bytes. */ + nblocks = min(srclen, 4096U) / POLYVAL_BLOCK_SIZE; + internal_polyval_update(tctx, src, nblocks, dctx->buffer); + srclen -= nblocks * POLYVAL_BLOCK_SIZE; + src += nblocks * POLYVAL_BLOCK_SIZE; + } + + if (srclen) { + dctx->bytes = POLYVAL_BLOCK_SIZE - srclen; + pos = dctx->buffer; + while (srclen--) + *pos++ ^= *src++; + } + + return 0; +} + +static int polyval_x86_final(struct shash_desc *desc, u8 *dst) +{ + struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); + const struct polyval_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + + if (dctx->bytes) { + internal_polyval_mul(dctx->buffer, + tctx->key_powers[NUM_KEY_POWERS-1]); + } + + memcpy(dst, dctx->buffer, POLYVAL_BLOCK_SIZE); + + return 0; +} + +static struct shash_alg polyval_alg = { + .digestsize = POLYVAL_DIGEST_SIZE, + .init = polyval_x86_init, + .update = polyval_x86_update, + .final = polyval_x86_final, + .setkey = polyval_x86_setkey, + .descsize = sizeof(struct polyval_desc_ctx), + .base = { + .cra_name = "polyval", + .cra_driver_name = "polyval-clmulni", + .cra_priority = 200, + .cra_blocksize = POLYVAL_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct polyval_tfm_ctx), + .cra_module = THIS_MODULE, + }, +}; + +__maybe_unused static const struct x86_cpu_id pcmul_cpu_id[] = { + X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL), + {} +}; +MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id); + +static int __init polyval_clmulni_mod_init(void) +{ + if (!x86_match_cpu(pcmul_cpu_id)) + return -ENODEV; + + if (!boot_cpu_has(X86_FEATURE_AVX)) + return -ENODEV; + + return crypto_register_shash(&polyval_alg); +} + +static void __exit polyval_clmulni_mod_exit(void) +{ + crypto_unregister_shash(&polyval_alg); +} + +module_init(polyval_clmulni_mod_init); +module_exit(polyval_clmulni_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("POLYVAL hash function accelerated by PCLMULQDQ-NI"); +MODULE_ALIAS_CRYPTO("polyval"); +MODULE_ALIAS_CRYPTO("polyval-clmulni"); diff --git a/crypto/Kconfig b/crypto/Kconfig index dfcc3235e918..9b654984de79 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -792,6 +792,15 @@ config CRYPTO_POLYVAL POLYVAL is the hash function used in HCTR2. It is not a general-purpose cryptographic hash function. +config CRYPTO_POLYVAL_CLMUL_NI + tristate "POLYVAL hash function (CLMUL-NI accelerated)" + depends on X86 && 64BIT + select CRYPTO_POLYVAL + help + This is the x86_64 CLMUL-NI accelerated implementation of POLYVAL. It is + used to efficiently implement HCTR2 on x86-64 processors that support + carry-less multiplication instructions. + config CRYPTO_POLY1305 tristate "Poly1305 authenticator algorithm" select CRYPTO_HASH diff --git a/crypto/polyval-generic.c b/crypto/polyval-generic.c index bf2b03b7bfc0..16bfa6925b31 100644 --- a/crypto/polyval-generic.c +++ b/crypto/polyval-generic.c @@ -76,6 +76,46 @@ static void copy_and_reverse(u8 dst[POLYVAL_BLOCK_SIZE], put_unaligned(swab64(b), (u64 *)&dst[0]); } +/* + * Performs multiplication in the POLYVAL field using the GHASH field as a + * subroutine. This function is used as a fallback for hardware accelerated + * implementations when simd registers are unavailable. + * + * Note: This function is not used for polyval-generic, instead we use the 4k + * lookup table implementation for finite field multiplication. + */ +void polyval_mul_non4k(u8 *op1, const u8 *op2) +{ + be128 a, b; + + // Assume one argument is in Montgomery form and one is not. + copy_and_reverse((u8 *)&a, op1); + copy_and_reverse((u8 *)&b, op2); + gf128mul_x_lle(&a, &a); + gf128mul_lle(&a, &b); + copy_and_reverse(op1, (u8 *)&a); +} +EXPORT_SYMBOL_GPL(polyval_mul_non4k); + +/* + * Perform a POLYVAL update using non4k multiplication. This function is used + * as a fallback for hardware accelerated implementations when simd registers + * are unavailable. + * + * Note: This function is not used for polyval-generic, instead we use the 4k + * lookup table implementation of finite field multiplication. + */ +void polyval_update_non4k(const u8 *key, const u8 *in, + size_t nblocks, u8 *accumulator) +{ + while (nblocks--) { + crypto_xor(accumulator, in, POLYVAL_BLOCK_SIZE); + polyval_mul_non4k(accumulator, key); + in += POLYVAL_BLOCK_SIZE; + } +} +EXPORT_SYMBOL_GPL(polyval_update_non4k); + static int polyval_setkey(struct crypto_shash *tfm, const u8 *key, unsigned int keylen) { diff --git a/include/crypto/polyval.h b/include/crypto/polyval.h index b14c38aa9166..1d630f371f77 100644 --- a/include/crypto/polyval.h +++ b/include/crypto/polyval.h @@ -14,4 +14,9 @@ #define POLYVAL_BLOCK_SIZE 16 #define POLYVAL_DIGEST_SIZE 16 +void polyval_mul_non4k(u8 *op1, const u8 *op2); + +void polyval_update_non4k(const u8 *key, const u8 *in, + size_t nblocks, u8 *accumulator); + #endif -- cgit v1.2.3 From 6b2a51ff03bf0c54cbc699ee85a9a49eb203ebfc Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Fri, 20 May 2022 18:15:01 +0000 Subject: fscrypt: Add HCTR2 support for filename encryption HCTR2 is a tweakable, length-preserving encryption mode that is intended for use on CPUs with dedicated crypto instructions. HCTR2 has the property that a bitflip in the plaintext changes the entire ciphertext. This property fixes a known weakness with filename encryption: when two filenames in the same directory share a prefix of >= 16 bytes, with AES-CTS-CBC their encrypted filenames share a common substring, leaking information. HCTR2 does not have this problem. More information on HCTR2 can be found here: "Length-preserving encryption with HCTR2": https://eprint.iacr.org/2021/1441.pdf Signed-off-by: Nathan Huckleberry Reviewed-by: Ard Biesheuvel Acked-by: Eric Biggers Signed-off-by: Herbert Xu --- Documentation/filesystems/fscrypt.rst | 22 +++++++++++++++++----- fs/crypto/fscrypt_private.h | 2 +- fs/crypto/keysetup.c | 7 +++++++ fs/crypto/policy.c | 14 +++++++++++--- include/uapi/linux/fscrypt.h | 3 ++- 5 files changed, 38 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 2e9aaa295125..5ba5817c17c2 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -337,6 +337,7 @@ Currently, the following pairs of encryption modes are supported: - AES-256-XTS for contents and AES-256-CTS-CBC for filenames - AES-128-CBC for contents and AES-128-CTS-CBC for filenames - Adiantum for both contents and filenames +- AES-256-XTS for contents and AES-256-HCTR2 for filenames (v2 policies only) If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair. @@ -357,6 +358,17 @@ To use Adiantum, CONFIG_CRYPTO_ADIANTUM must be enabled. Also, fast implementations of ChaCha and NHPoly1305 should be enabled, e.g. CONFIG_CRYPTO_CHACHA20_NEON and CONFIG_CRYPTO_NHPOLY1305_NEON for ARM. +AES-256-HCTR2 is another true wide-block encryption mode that is intended for +use on CPUs with dedicated crypto instructions. AES-256-HCTR2 has the property +that a bitflip in the plaintext changes the entire ciphertext. This property +makes it desirable for filename encryption since initialization vectors are +reused within a directory. For more details on AES-256-HCTR2, see the paper +"Length-preserving encryption with HCTR2" +(https://eprint.iacr.org/2021/1441.pdf). To use AES-256-HCTR2, +CONFIG_CRYPTO_HCTR2 must be enabled. Also, fast implementations of XCTR and +POLYVAL should be enabled, e.g. CRYPTO_POLYVAL_ARM64_CE and +CRYPTO_AES_ARM64_CE_BLK for ARM64. + New encryption modes can be added relatively easily, without changes to individual filesystems. However, authenticated encryption (AE) modes are not currently supported because of the difficulty of dealing @@ -404,11 +416,11 @@ alternatively has the file's nonce (for `DIRECT_KEY policies`_) or inode number (for `IV_INO_LBLK_64 policies`_) included in the IVs. Thus, IV reuse is limited to within a single directory. -With CTS-CBC, the IV reuse means that when the plaintext filenames -share a common prefix at least as long as the cipher block size (16 -bytes for AES), the corresponding encrypted filenames will also share -a common prefix. This is undesirable. Adiantum does not have this -weakness, as it is a wide-block encryption mode. +With CTS-CBC, the IV reuse means that when the plaintext filenames share a +common prefix at least as long as the cipher block size (16 bytes for AES), the +corresponding encrypted filenames will also share a common prefix. This is +undesirable. Adiantum and HCTR2 do not have this weakness, as they are +wide-block encryption modes. All supported filenames encryption modes accept any plaintext length >= 16 bytes; cipher block alignment is not required. However, diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 6b4c8094cc7b..f5be777d8279 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -31,7 +31,7 @@ #define FSCRYPT_CONTEXT_V2 2 /* Keep this in sync with include/uapi/linux/fscrypt.h */ -#define FSCRYPT_MODE_MAX FSCRYPT_MODE_ADIANTUM +#define FSCRYPT_MODE_MAX FSCRYPT_MODE_AES_256_HCTR2 struct fscrypt_context_v1 { u8 version; /* FSCRYPT_CONTEXT_V1 */ diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index c35711896bd4..fbc71abdabe3 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -53,6 +53,13 @@ struct fscrypt_mode fscrypt_modes[] = { .ivsize = 32, .blk_crypto_mode = BLK_ENCRYPTION_MODE_ADIANTUM, }, + [FSCRYPT_MODE_AES_256_HCTR2] = { + .friendly_name = "AES-256-HCTR2", + .cipher_str = "hctr2(aes)", + .keysize = 32, + .security_strength = 32, + .ivsize = 32, + }, }; static DEFINE_MUTEX(fscrypt_mode_key_setup_mutex); diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 5f858cee1e3b..8a054e6d1e68 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -61,7 +61,7 @@ fscrypt_get_dummy_policy(struct super_block *sb) return sb->s_cop->get_dummy_policy(sb); } -static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode) +static bool fscrypt_valid_enc_modes_v1(u32 contents_mode, u32 filenames_mode) { if (contents_mode == FSCRYPT_MODE_AES_256_XTS && filenames_mode == FSCRYPT_MODE_AES_256_CTS) @@ -78,6 +78,14 @@ static bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode) return false; } +static bool fscrypt_valid_enc_modes_v2(u32 contents_mode, u32 filenames_mode) +{ + if (contents_mode == FSCRYPT_MODE_AES_256_XTS && + filenames_mode == FSCRYPT_MODE_AES_256_HCTR2) + return true; + return fscrypt_valid_enc_modes_v1(contents_mode, filenames_mode); +} + static bool supported_direct_key_modes(const struct inode *inode, u32 contents_mode, u32 filenames_mode) { @@ -151,7 +159,7 @@ static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy, static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy, const struct inode *inode) { - if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, + if (!fscrypt_valid_enc_modes_v1(policy->contents_encryption_mode, policy->filenames_encryption_mode)) { fscrypt_warn(inode, "Unsupported encryption modes (contents %d, filenames %d)", @@ -187,7 +195,7 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, { int count = 0; - if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, + if (!fscrypt_valid_enc_modes_v2(policy->contents_encryption_mode, policy->filenames_encryption_mode)) { fscrypt_warn(inode, "Unsupported encryption modes (contents %d, filenames %d)", diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h index 9f4428be3e36..a756b29afcc2 100644 --- a/include/uapi/linux/fscrypt.h +++ b/include/uapi/linux/fscrypt.h @@ -27,7 +27,8 @@ #define FSCRYPT_MODE_AES_128_CBC 5 #define FSCRYPT_MODE_AES_128_CTS 6 #define FSCRYPT_MODE_ADIANTUM 9 -/* If adding a mode number > 9, update FSCRYPT_MODE_MAX in fscrypt_private.h */ +#define FSCRYPT_MODE_AES_256_HCTR2 10 +/* If adding a mode number > 10, update FSCRYPT_MODE_MAX in fscrypt_private.h */ /* * Legacy policy version; ad-hoc KDF and no key verification. -- cgit v1.2.3 From 2d16803c562ecc644803d42ba98a8e0aef9c014e Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sat, 28 May 2022 21:44:07 +0200 Subject: crypto: blake2s - remove shash module BLAKE2s has no currently known use as an shash. Just remove all of this unnecessary plumbing. Removing this shash was something we talked about back when we were making BLAKE2s a built-in, but I simply never got around to doing it. So this completes that project. Importantly, this fixs a bug in which the lib code depends on crypto_simd_disabled_for_test, causing linker errors. Also add more alignment tests to the selftests and compare SIMD and non-SIMD compression functions, to make up for what we lose from testmgr.c. Reported-by: gaochao Cc: Eric Biggers Cc: Ard Biesheuvel Cc: stable@vger.kernel.org Fixes: 6048fdcc5f26 ("lib/crypto: blake2s: include as built-in") Signed-off-by: Jason A. Donenfeld Signed-off-by: Herbert Xu --- arch/arm/crypto/Kconfig | 2 +- arch/arm/crypto/Makefile | 4 +- arch/arm/crypto/blake2s-shash.c | 75 ------------- arch/x86/crypto/Makefile | 4 +- arch/x86/crypto/blake2s-glue.c | 3 +- arch/x86/crypto/blake2s-shash.c | 77 -------------- crypto/Kconfig | 20 +--- crypto/Makefile | 1 - crypto/blake2s_generic.c | 75 ------------- crypto/tcrypt.c | 12 --- crypto/testmgr.c | 24 ----- crypto/testmgr.h | 217 -------------------------------------- include/crypto/internal/blake2s.h | 108 ------------------- lib/crypto/blake2s-selftest.c | 41 +++++++ lib/crypto/blake2s.c | 37 +++++-- 15 files changed, 76 insertions(+), 624 deletions(-) delete mode 100644 arch/arm/crypto/blake2s-shash.c delete mode 100644 arch/x86/crypto/blake2s-shash.c delete mode 100644 crypto/blake2s_generic.c (limited to 'include') diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index e4dba5461cb3..149a5bd6b88c 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig @@ -63,7 +63,7 @@ config CRYPTO_SHA512_ARM using optimized ARM assembler and NEON, when available. config CRYPTO_BLAKE2S_ARM - tristate "BLAKE2s digest algorithm (ARM)" + bool "BLAKE2s digest algorithm (ARM)" select CRYPTO_ARCH_HAVE_LIB_BLAKE2S help BLAKE2s digest algorithm optimized with ARM scalar instructions. This diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index 0274f81cc8ea..971e74546fb1 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -9,8 +9,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o -obj-$(CONFIG_CRYPTO_BLAKE2S_ARM) += blake2s-arm.o -obj-$(if $(CONFIG_CRYPTO_BLAKE2S_ARM),y) += libblake2s-arm.o +obj-$(CONFIG_CRYPTO_BLAKE2S_ARM) += libblake2s-arm.o obj-$(CONFIG_CRYPTO_BLAKE2B_NEON) += blake2b-neon.o obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o obj-$(CONFIG_CRYPTO_POLY1305_ARM) += poly1305-arm.o @@ -32,7 +31,6 @@ sha256-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha256_neon_glue.o sha256-arm-y := sha256-core.o sha256_glue.o $(sha256-arm-neon-y) sha512-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha512-neon-glue.o sha512-arm-y := sha512-core.o sha512-glue.o $(sha512-arm-neon-y) -blake2s-arm-y := blake2s-shash.o libblake2s-arm-y:= blake2s-core.o blake2s-glue.o blake2b-neon-y := blake2b-neon-core.o blake2b-neon-glue.o sha1-arm-ce-y := sha1-ce-core.o sha1-ce-glue.o diff --git a/arch/arm/crypto/blake2s-shash.c b/arch/arm/crypto/blake2s-shash.c deleted file mode 100644 index 763c73beea2d..000000000000 --- a/arch/arm/crypto/blake2s-shash.c +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * BLAKE2s digest algorithm, ARM scalar implementation - * - * Copyright 2020 Google LLC - */ - -#include -#include - -#include - -static int crypto_blake2s_update_arm(struct shash_desc *desc, - const u8 *in, unsigned int inlen) -{ - return crypto_blake2s_update(desc, in, inlen, false); -} - -static int crypto_blake2s_final_arm(struct shash_desc *desc, u8 *out) -{ - return crypto_blake2s_final(desc, out, false); -} - -#define BLAKE2S_ALG(name, driver_name, digest_size) \ - { \ - .base.cra_name = name, \ - .base.cra_driver_name = driver_name, \ - .base.cra_priority = 200, \ - .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, \ - .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, \ - .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), \ - .base.cra_module = THIS_MODULE, \ - .digestsize = digest_size, \ - .setkey = crypto_blake2s_setkey, \ - .init = crypto_blake2s_init, \ - .update = crypto_blake2s_update_arm, \ - .final = crypto_blake2s_final_arm, \ - .descsize = sizeof(struct blake2s_state), \ - } - -static struct shash_alg blake2s_arm_algs[] = { - BLAKE2S_ALG("blake2s-128", "blake2s-128-arm", BLAKE2S_128_HASH_SIZE), - BLAKE2S_ALG("blake2s-160", "blake2s-160-arm", BLAKE2S_160_HASH_SIZE), - BLAKE2S_ALG("blake2s-224", "blake2s-224-arm", BLAKE2S_224_HASH_SIZE), - BLAKE2S_ALG("blake2s-256", "blake2s-256-arm", BLAKE2S_256_HASH_SIZE), -}; - -static int __init blake2s_arm_mod_init(void) -{ - return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? - crypto_register_shashes(blake2s_arm_algs, - ARRAY_SIZE(blake2s_arm_algs)) : 0; -} - -static void __exit blake2s_arm_mod_exit(void) -{ - if (IS_REACHABLE(CONFIG_CRYPTO_HASH)) - crypto_unregister_shashes(blake2s_arm_algs, - ARRAY_SIZE(blake2s_arm_algs)); -} - -module_init(blake2s_arm_mod_init); -module_exit(blake2s_arm_mod_exit); - -MODULE_DESCRIPTION("BLAKE2s digest algorithm, ARM scalar implementation"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Eric Biggers "); -MODULE_ALIAS_CRYPTO("blake2s-128"); -MODULE_ALIAS_CRYPTO("blake2s-128-arm"); -MODULE_ALIAS_CRYPTO("blake2s-160"); -MODULE_ALIAS_CRYPTO("blake2s-160-arm"); -MODULE_ALIAS_CRYPTO("blake2s-224"); -MODULE_ALIAS_CRYPTO("blake2s-224-arm"); -MODULE_ALIAS_CRYPTO("blake2s-256"); -MODULE_ALIAS_CRYPTO("blake2s-256-arm"); diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index b9847152acd8..04d07ab744b2 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -61,9 +61,7 @@ sha256-ssse3-$(CONFIG_AS_SHA256_NI) += sha256_ni_asm.o obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o -obj-$(CONFIG_CRYPTO_BLAKE2S_X86) += blake2s-x86_64.o -blake2s-x86_64-y := blake2s-shash.o -obj-$(if $(CONFIG_CRYPTO_BLAKE2S_X86),y) += libblake2s-x86_64.o +obj-$(CONFIG_CRYPTO_BLAKE2S_X86) += libblake2s-x86_64.o libblake2s-x86_64-y := blake2s-core.o blake2s-glue.o obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o diff --git a/arch/x86/crypto/blake2s-glue.c b/arch/x86/crypto/blake2s-glue.c index 69853c13e8fb..aaba21230528 100644 --- a/arch/x86/crypto/blake2s-glue.c +++ b/arch/x86/crypto/blake2s-glue.c @@ -4,7 +4,6 @@ */ #include -#include #include #include @@ -33,7 +32,7 @@ void blake2s_compress(struct blake2s_state *state, const u8 *block, /* SIMD disables preemption, so relax after processing each page. */ BUILD_BUG_ON(SZ_4K / BLAKE2S_BLOCK_SIZE < 8); - if (!static_branch_likely(&blake2s_use_ssse3) || !crypto_simd_usable()) { + if (!static_branch_likely(&blake2s_use_ssse3) || !may_use_simd()) { blake2s_compress_generic(state, block, nblocks, inc); return; } diff --git a/arch/x86/crypto/blake2s-shash.c b/arch/x86/crypto/blake2s-shash.c deleted file mode 100644 index 59ae28abe35c..000000000000 --- a/arch/x86/crypto/blake2s-shash.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* - * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -static int crypto_blake2s_update_x86(struct shash_desc *desc, - const u8 *in, unsigned int inlen) -{ - return crypto_blake2s_update(desc, in, inlen, false); -} - -static int crypto_blake2s_final_x86(struct shash_desc *desc, u8 *out) -{ - return crypto_blake2s_final(desc, out, false); -} - -#define BLAKE2S_ALG(name, driver_name, digest_size) \ - { \ - .base.cra_name = name, \ - .base.cra_driver_name = driver_name, \ - .base.cra_priority = 200, \ - .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, \ - .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, \ - .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), \ - .base.cra_module = THIS_MODULE, \ - .digestsize = digest_size, \ - .setkey = crypto_blake2s_setkey, \ - .init = crypto_blake2s_init, \ - .update = crypto_blake2s_update_x86, \ - .final = crypto_blake2s_final_x86, \ - .descsize = sizeof(struct blake2s_state), \ - } - -static struct shash_alg blake2s_algs[] = { - BLAKE2S_ALG("blake2s-128", "blake2s-128-x86", BLAKE2S_128_HASH_SIZE), - BLAKE2S_ALG("blake2s-160", "blake2s-160-x86", BLAKE2S_160_HASH_SIZE), - BLAKE2S_ALG("blake2s-224", "blake2s-224-x86", BLAKE2S_224_HASH_SIZE), - BLAKE2S_ALG("blake2s-256", "blake2s-256-x86", BLAKE2S_256_HASH_SIZE), -}; - -static int __init blake2s_mod_init(void) -{ - if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && boot_cpu_has(X86_FEATURE_SSSE3)) - return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); - return 0; -} - -static void __exit blake2s_mod_exit(void) -{ - if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && boot_cpu_has(X86_FEATURE_SSSE3)) - crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); -} - -module_init(blake2s_mod_init); -module_exit(blake2s_mod_exit); - -MODULE_ALIAS_CRYPTO("blake2s-128"); -MODULE_ALIAS_CRYPTO("blake2s-128-x86"); -MODULE_ALIAS_CRYPTO("blake2s-160"); -MODULE_ALIAS_CRYPTO("blake2s-160-x86"); -MODULE_ALIAS_CRYPTO("blake2s-224"); -MODULE_ALIAS_CRYPTO("blake2s-224-x86"); -MODULE_ALIAS_CRYPTO("blake2s-256"); -MODULE_ALIAS_CRYPTO("blake2s-256-x86"); -MODULE_LICENSE("GPL v2"); diff --git a/crypto/Kconfig b/crypto/Kconfig index 6e30e8138057..59489a300cd1 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -712,26 +712,8 @@ config CRYPTO_BLAKE2B See https://blake2.net for further information. -config CRYPTO_BLAKE2S - tristate "BLAKE2s digest algorithm" - select CRYPTO_LIB_BLAKE2S_GENERIC - select CRYPTO_HASH - help - Implementation of cryptographic hash function BLAKE2s - optimized for 8-32bit platforms and can produce digests of any size - between 1 to 32. The keyed hash is also implemented. - - This module provides the following algorithms: - - - blake2s-128 - - blake2s-160 - - blake2s-224 - - blake2s-256 - - See https://blake2.net for further information. - config CRYPTO_BLAKE2S_X86 - tristate "BLAKE2s digest algorithm (x86 accelerated version)" + bool "BLAKE2s digest algorithm (x86 accelerated version)" depends on X86 && 64BIT select CRYPTO_LIB_BLAKE2S_GENERIC select CRYPTO_ARCH_HAVE_LIB_BLAKE2S diff --git a/crypto/Makefile b/crypto/Makefile index 1f529704fe80..a4a84860fe43 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -84,7 +84,6 @@ obj-$(CONFIG_CRYPTO_STREEBOG) += streebog_generic.o obj-$(CONFIG_CRYPTO_WP512) += wp512.o CFLAGS_wp512.o := $(call cc-option,-fno-schedule-insns) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149 obj-$(CONFIG_CRYPTO_BLAKE2B) += blake2b_generic.o -obj-$(CONFIG_CRYPTO_BLAKE2S) += blake2s_generic.o obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o obj-$(CONFIG_CRYPTO_ECB) += ecb.o obj-$(CONFIG_CRYPTO_CBC) += cbc.o diff --git a/crypto/blake2s_generic.c b/crypto/blake2s_generic.c deleted file mode 100644 index 5f96a21f8788..000000000000 --- a/crypto/blake2s_generic.c +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* - * shash interface to the generic implementation of BLAKE2s - * - * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. - */ - -#include -#include - -#include -#include -#include - -static int crypto_blake2s_update_generic(struct shash_desc *desc, - const u8 *in, unsigned int inlen) -{ - return crypto_blake2s_update(desc, in, inlen, true); -} - -static int crypto_blake2s_final_generic(struct shash_desc *desc, u8 *out) -{ - return crypto_blake2s_final(desc, out, true); -} - -#define BLAKE2S_ALG(name, driver_name, digest_size) \ - { \ - .base.cra_name = name, \ - .base.cra_driver_name = driver_name, \ - .base.cra_priority = 100, \ - .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, \ - .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, \ - .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), \ - .base.cra_module = THIS_MODULE, \ - .digestsize = digest_size, \ - .setkey = crypto_blake2s_setkey, \ - .init = crypto_blake2s_init, \ - .update = crypto_blake2s_update_generic, \ - .final = crypto_blake2s_final_generic, \ - .descsize = sizeof(struct blake2s_state), \ - } - -static struct shash_alg blake2s_algs[] = { - BLAKE2S_ALG("blake2s-128", "blake2s-128-generic", - BLAKE2S_128_HASH_SIZE), - BLAKE2S_ALG("blake2s-160", "blake2s-160-generic", - BLAKE2S_160_HASH_SIZE), - BLAKE2S_ALG("blake2s-224", "blake2s-224-generic", - BLAKE2S_224_HASH_SIZE), - BLAKE2S_ALG("blake2s-256", "blake2s-256-generic", - BLAKE2S_256_HASH_SIZE), -}; - -static int __init blake2s_mod_init(void) -{ - return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); -} - -static void __exit blake2s_mod_exit(void) -{ - crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); -} - -subsys_initcall(blake2s_mod_init); -module_exit(blake2s_mod_exit); - -MODULE_ALIAS_CRYPTO("blake2s-128"); -MODULE_ALIAS_CRYPTO("blake2s-128-generic"); -MODULE_ALIAS_CRYPTO("blake2s-160"); -MODULE_ALIAS_CRYPTO("blake2s-160-generic"); -MODULE_ALIAS_CRYPTO("blake2s-224"); -MODULE_ALIAS_CRYPTO("blake2s-224-generic"); -MODULE_ALIAS_CRYPTO("blake2s-256"); -MODULE_ALIAS_CRYPTO("blake2s-256-generic"); -MODULE_LICENSE("GPL v2"); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 336598da8eac..a8831060c4ce 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1670,10 +1670,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) ret += tcrypt_test("rmd160"); break; - case 41: - ret += tcrypt_test("blake2s-256"); - break; - case 42: ret += tcrypt_test("blake2b-512"); break; @@ -2250,10 +2246,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) test_hash_speed("rmd160", sec, generic_hash_speed_template); if (mode > 300 && mode < 400) break; fallthrough; - case 316: - test_hash_speed("blake2s-256", sec, generic_hash_speed_template); - if (mode > 300 && mode < 400) break; - fallthrough; case 317: test_hash_speed("blake2b-512", sec, generic_hash_speed_template); if (mode > 300 && mode < 400) break; @@ -2362,10 +2354,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) test_ahash_speed("rmd160", sec, generic_hash_speed_template); if (mode > 400 && mode < 500) break; fallthrough; - case 416: - test_ahash_speed("blake2s-256", sec, generic_hash_speed_template); - if (mode > 400 && mode < 500) break; - fallthrough; case 417: test_ahash_speed("blake2b-512", sec, generic_hash_speed_template); if (mode > 400 && mode < 500) break; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 485097461068..7a8a56749960 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4375,30 +4375,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(blake2b_512_tv_template) } - }, { - .alg = "blake2s-128", - .test = alg_test_hash, - .suite = { - .hash = __VECS(blakes2s_128_tv_template) - } - }, { - .alg = "blake2s-160", - .test = alg_test_hash, - .suite = { - .hash = __VECS(blakes2s_160_tv_template) - } - }, { - .alg = "blake2s-224", - .test = alg_test_hash, - .suite = { - .hash = __VECS(blakes2s_224_tv_template) - } - }, { - .alg = "blake2s-256", - .test = alg_test_hash, - .suite = { - .hash = __VECS(blakes2s_256_tv_template) - } }, { .alg = "cbc(aes)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 808ba07baa04..4f3955ea40bf 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -34034,223 +34034,6 @@ static const struct hash_testvec blake2b_512_tv_template[] = {{ 0xae, 0x15, 0x81, 0x15, 0xd0, 0x88, 0xa0, 0x3c, }, }}; -static const struct hash_testvec blakes2s_128_tv_template[] = {{ - .digest = (u8[]){ 0x64, 0x55, 0x0d, 0x6f, 0xfe, 0x2c, 0x0a, 0x01, - 0xa1, 0x4a, 0xba, 0x1e, 0xad, 0xe0, 0x20, 0x0c, }, -}, { - .plaintext = blake2_ordered_sequence, - .psize = 64, - .digest = (u8[]){ 0xdc, 0x66, 0xca, 0x8f, 0x03, 0x86, 0x58, 0x01, - 0xb0, 0xff, 0xe0, 0x6e, 0xd8, 0xa1, 0xa9, 0x0e, }, -}, { - .ksize = 16, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 1, - .digest = (u8[]){ 0x88, 0x1e, 0x42, 0xe7, 0xbb, 0x35, 0x80, 0x82, - 0x63, 0x7c, 0x0a, 0x0f, 0xd7, 0xec, 0x6c, 0x2f, }, -}, { - .ksize = 32, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 7, - .digest = (u8[]){ 0xcf, 0x9e, 0x07, 0x2a, 0xd5, 0x22, 0xf2, 0xcd, - 0xa2, 0xd8, 0x25, 0x21, 0x80, 0x86, 0x73, 0x1c, }, -}, { - .ksize = 1, - .key = "B", - .plaintext = blake2_ordered_sequence, - .psize = 15, - .digest = (u8[]){ 0xf6, 0x33, 0x5a, 0x2c, 0x22, 0xa0, 0x64, 0xb2, - 0xb6, 0x3f, 0xeb, 0xbc, 0xd1, 0xc3, 0xe5, 0xb2, }, -}, { - .ksize = 16, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 247, - .digest = (u8[]){ 0x72, 0x66, 0x49, 0x60, 0xf9, 0x4a, 0xea, 0xbe, - 0x1f, 0xf4, 0x60, 0xce, 0xb7, 0x81, 0xcb, 0x09, }, -}, { - .ksize = 32, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 256, - .digest = (u8[]){ 0xd5, 0xa4, 0x0e, 0xc3, 0x16, 0xc7, 0x51, 0xa6, - 0x3c, 0xd0, 0xd9, 0x11, 0x57, 0xfa, 0x1e, 0xbb, }, -}}; - -static const struct hash_testvec blakes2s_160_tv_template[] = {{ - .plaintext = blake2_ordered_sequence, - .psize = 7, - .digest = (u8[]){ 0xb4, 0xf2, 0x03, 0x49, 0x37, 0xed, 0xb1, 0x3e, - 0x5b, 0x2a, 0xca, 0x64, 0x82, 0x74, 0xf6, 0x62, - 0xe3, 0xf2, 0x84, 0xff, }, -}, { - .plaintext = blake2_ordered_sequence, - .psize = 256, - .digest = (u8[]){ 0xaa, 0x56, 0x9b, 0xdc, 0x98, 0x17, 0x75, 0xf2, - 0xb3, 0x68, 0x83, 0xb7, 0x9b, 0x8d, 0x48, 0xb1, - 0x9b, 0x2d, 0x35, 0x05, }, -}, { - .ksize = 1, - .key = "B", - .digest = (u8[]){ 0x50, 0x16, 0xe7, 0x0c, 0x01, 0xd0, 0xd3, 0xc3, - 0xf4, 0x3e, 0xb1, 0x6e, 0x97, 0xa9, 0x4e, 0xd1, - 0x79, 0x65, 0x32, 0x93, }, -}, { - .ksize = 32, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 1, - .digest = (u8[]){ 0x1c, 0x2b, 0xcd, 0x9a, 0x68, 0xca, 0x8c, 0x71, - 0x90, 0x29, 0x6c, 0x54, 0xfa, 0x56, 0x4a, 0xef, - 0xa2, 0x3a, 0x56, 0x9c, }, -}, { - .ksize = 16, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 15, - .digest = (u8[]){ 0x36, 0xc3, 0x5f, 0x9a, 0xdc, 0x7e, 0xbf, 0x19, - 0x68, 0xaa, 0xca, 0xd8, 0x81, 0xbf, 0x09, 0x34, - 0x83, 0x39, 0x0f, 0x30, }, -}, { - .ksize = 1, - .key = "B", - .plaintext = blake2_ordered_sequence, - .psize = 64, - .digest = (u8[]){ 0x86, 0x80, 0x78, 0xa4, 0x14, 0xec, 0x03, 0xe5, - 0xb6, 0x9a, 0x52, 0x0e, 0x42, 0xee, 0x39, 0x9d, - 0xac, 0xa6, 0x81, 0x63, }, -}, { - .ksize = 32, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 247, - .digest = (u8[]){ 0x2d, 0xd8, 0xd2, 0x53, 0x66, 0xfa, 0xa9, 0x01, - 0x1c, 0x9c, 0xaf, 0xa3, 0xe2, 0x9d, 0x9b, 0x10, - 0x0a, 0xf6, 0x73, 0xe8, }, -}}; - -static const struct hash_testvec blakes2s_224_tv_template[] = {{ - .plaintext = blake2_ordered_sequence, - .psize = 1, - .digest = (u8[]){ 0x61, 0xb9, 0x4e, 0xc9, 0x46, 0x22, 0xa3, 0x91, - 0xd2, 0xae, 0x42, 0xe6, 0x45, 0x6c, 0x90, 0x12, - 0xd5, 0x80, 0x07, 0x97, 0xb8, 0x86, 0x5a, 0xfc, - 0x48, 0x21, 0x97, 0xbb, }, -}, { - .plaintext = blake2_ordered_sequence, - .psize = 247, - .digest = (u8[]){ 0x9e, 0xda, 0xc7, 0x20, 0x2c, 0xd8, 0x48, 0x2e, - 0x31, 0x94, 0xab, 0x46, 0x6d, 0x94, 0xd8, 0xb4, - 0x69, 0xcd, 0xae, 0x19, 0x6d, 0x9e, 0x41, 0xcc, - 0x2b, 0xa4, 0xd5, 0xf6, }, -}, { - .ksize = 16, - .key = blake2_ordered_sequence, - .digest = (u8[]){ 0x32, 0xc0, 0xac, 0xf4, 0x3b, 0xd3, 0x07, 0x9f, - 0xbe, 0xfb, 0xfa, 0x4d, 0x6b, 0x4e, 0x56, 0xb3, - 0xaa, 0xd3, 0x27, 0xf6, 0x14, 0xbf, 0xb9, 0x32, - 0xa7, 0x19, 0xfc, 0xb8, }, -}, { - .ksize = 1, - .key = "B", - .plaintext = blake2_ordered_sequence, - .psize = 7, - .digest = (u8[]){ 0x73, 0xad, 0x5e, 0x6d, 0xb9, 0x02, 0x8e, 0x76, - 0xf2, 0x66, 0x42, 0x4b, 0x4c, 0xfa, 0x1f, 0xe6, - 0x2e, 0x56, 0x40, 0xe5, 0xa2, 0xb0, 0x3c, 0xe8, - 0x7b, 0x45, 0xfe, 0x05, }, -}, { - .ksize = 32, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 15, - .digest = (u8[]){ 0x16, 0x60, 0xfb, 0x92, 0x54, 0xb3, 0x6e, 0x36, - 0x81, 0xf4, 0x16, 0x41, 0xc3, 0x3d, 0xd3, 0x43, - 0x84, 0xed, 0x10, 0x6f, 0x65, 0x80, 0x7a, 0x3e, - 0x25, 0xab, 0xc5, 0x02, }, -}, { - .ksize = 16, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 64, - .digest = (u8[]){ 0xca, 0xaa, 0x39, 0x67, 0x9c, 0xf7, 0x6b, 0xc7, - 0xb6, 0x82, 0xca, 0x0e, 0x65, 0x36, 0x5b, 0x7c, - 0x24, 0x00, 0xfa, 0x5f, 0xda, 0x06, 0x91, 0x93, - 0x6a, 0x31, 0x83, 0xb5, }, -}, { - .ksize = 1, - .key = "B", - .plaintext = blake2_ordered_sequence, - .psize = 256, - .digest = (u8[]){ 0x90, 0x02, 0x26, 0xb5, 0x06, 0x9c, 0x36, 0x86, - 0x94, 0x91, 0x90, 0x1e, 0x7d, 0x2a, 0x71, 0xb2, - 0x48, 0xb5, 0xe8, 0x16, 0xfd, 0x64, 0x33, 0x45, - 0xb3, 0xd7, 0xec, 0xcc, }, -}}; - -static const struct hash_testvec blakes2s_256_tv_template[] = {{ - .plaintext = blake2_ordered_sequence, - .psize = 15, - .digest = (u8[]){ 0xd9, 0x7c, 0x82, 0x8d, 0x81, 0x82, 0xa7, 0x21, - 0x80, 0xa0, 0x6a, 0x78, 0x26, 0x83, 0x30, 0x67, - 0x3f, 0x7c, 0x4e, 0x06, 0x35, 0x94, 0x7c, 0x04, - 0xc0, 0x23, 0x23, 0xfd, 0x45, 0xc0, 0xa5, 0x2d, }, -}, { - .ksize = 32, - .key = blake2_ordered_sequence, - .digest = (u8[]){ 0x48, 0xa8, 0x99, 0x7d, 0xa4, 0x07, 0x87, 0x6b, - 0x3d, 0x79, 0xc0, 0xd9, 0x23, 0x25, 0xad, 0x3b, - 0x89, 0xcb, 0xb7, 0x54, 0xd8, 0x6a, 0xb7, 0x1a, - 0xee, 0x04, 0x7a, 0xd3, 0x45, 0xfd, 0x2c, 0x49, }, -}, { - .ksize = 1, - .key = "B", - .plaintext = blake2_ordered_sequence, - .psize = 1, - .digest = (u8[]){ 0x22, 0x27, 0xae, 0xaa, 0x6e, 0x81, 0x56, 0x03, - 0xa7, 0xe3, 0xa1, 0x18, 0xa5, 0x9a, 0x2c, 0x18, - 0xf4, 0x63, 0xbc, 0x16, 0x70, 0xf1, 0xe7, 0x4b, - 0x00, 0x6d, 0x66, 0x16, 0xae, 0x9e, 0x74, 0x4e, }, -}, { - .ksize = 16, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 7, - .digest = (u8[]){ 0x58, 0x5d, 0xa8, 0x60, 0x1c, 0xa4, 0xd8, 0x03, - 0x86, 0x86, 0x84, 0x64, 0xd7, 0xa0, 0x8e, 0x15, - 0x2f, 0x05, 0xa2, 0x1b, 0xbc, 0xef, 0x7a, 0x34, - 0xb3, 0xc5, 0xbc, 0x4b, 0xf0, 0x32, 0xeb, 0x12, }, -}, { - .ksize = 32, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 64, - .digest = (u8[]){ 0x89, 0x75, 0xb0, 0x57, 0x7f, 0xd3, 0x55, 0x66, - 0xd7, 0x50, 0xb3, 0x62, 0xb0, 0x89, 0x7a, 0x26, - 0xc3, 0x99, 0x13, 0x6d, 0xf0, 0x7b, 0xab, 0xab, - 0xbd, 0xe6, 0x20, 0x3f, 0xf2, 0x95, 0x4e, 0xd4, }, -}, { - .ksize = 1, - .key = "B", - .plaintext = blake2_ordered_sequence, - .psize = 247, - .digest = (u8[]){ 0x2e, 0x74, 0x1c, 0x1d, 0x03, 0xf4, 0x9d, 0x84, - 0x6f, 0xfc, 0x86, 0x32, 0x92, 0x49, 0x7e, 0x66, - 0xd7, 0xc3, 0x10, 0x88, 0xfe, 0x28, 0xb3, 0xe0, - 0xbf, 0x50, 0x75, 0xad, 0x8e, 0xa4, 0xe6, 0xb2, }, -}, { - .ksize = 16, - .key = blake2_ordered_sequence, - .plaintext = blake2_ordered_sequence, - .psize = 256, - .digest = (u8[]){ 0xb9, 0xd2, 0x81, 0x0e, 0x3a, 0xb1, 0x62, 0x9b, - 0xad, 0x44, 0x05, 0xf4, 0x92, 0x2e, 0x99, 0xc1, - 0x4a, 0x47, 0xbb, 0x5b, 0x6f, 0xb2, 0x96, 0xed, - 0xd5, 0x06, 0xb5, 0x3a, 0x7c, 0x7a, 0x65, 0x1d, }, -}}; - /* * Test vectors generated using https://github.com/google/hctr2 */ diff --git a/include/crypto/internal/blake2s.h b/include/crypto/internal/blake2s.h index 52363eee2b20..506d56530ca9 100644 --- a/include/crypto/internal/blake2s.h +++ b/include/crypto/internal/blake2s.h @@ -8,7 +8,6 @@ #define _CRYPTO_INTERNAL_BLAKE2S_H #include -#include #include void blake2s_compress_generic(struct blake2s_state *state, const u8 *block, @@ -19,111 +18,4 @@ void blake2s_compress(struct blake2s_state *state, const u8 *block, bool blake2s_selftest(void); -static inline void blake2s_set_lastblock(struct blake2s_state *state) -{ - state->f[0] = -1; -} - -/* Helper functions for BLAKE2s shared by the library and shash APIs */ - -static __always_inline void -__blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen, - bool force_generic) -{ - const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen; - - if (unlikely(!inlen)) - return; - if (inlen > fill) { - memcpy(state->buf + state->buflen, in, fill); - if (force_generic) - blake2s_compress_generic(state, state->buf, 1, - BLAKE2S_BLOCK_SIZE); - else - blake2s_compress(state, state->buf, 1, - BLAKE2S_BLOCK_SIZE); - state->buflen = 0; - in += fill; - inlen -= fill; - } - if (inlen > BLAKE2S_BLOCK_SIZE) { - const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE); - /* Hash one less (full) block than strictly possible */ - if (force_generic) - blake2s_compress_generic(state, in, nblocks - 1, - BLAKE2S_BLOCK_SIZE); - else - blake2s_compress(state, in, nblocks - 1, - BLAKE2S_BLOCK_SIZE); - in += BLAKE2S_BLOCK_SIZE * (nblocks - 1); - inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1); - } - memcpy(state->buf + state->buflen, in, inlen); - state->buflen += inlen; -} - -static __always_inline void -__blake2s_final(struct blake2s_state *state, u8 *out, bool force_generic) -{ - blake2s_set_lastblock(state); - memset(state->buf + state->buflen, 0, - BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */ - if (force_generic) - blake2s_compress_generic(state, state->buf, 1, state->buflen); - else - blake2s_compress(state, state->buf, 1, state->buflen); - cpu_to_le32_array(state->h, ARRAY_SIZE(state->h)); - memcpy(out, state->h, state->outlen); -} - -/* Helper functions for shash implementations of BLAKE2s */ - -struct blake2s_tfm_ctx { - u8 key[BLAKE2S_KEY_SIZE]; - unsigned int keylen; -}; - -static inline int crypto_blake2s_setkey(struct crypto_shash *tfm, - const u8 *key, unsigned int keylen) -{ - struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(tfm); - - if (keylen == 0 || keylen > BLAKE2S_KEY_SIZE) - return -EINVAL; - - memcpy(tctx->key, key, keylen); - tctx->keylen = keylen; - - return 0; -} - -static inline int crypto_blake2s_init(struct shash_desc *desc) -{ - const struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); - struct blake2s_state *state = shash_desc_ctx(desc); - unsigned int outlen = crypto_shash_digestsize(desc->tfm); - - __blake2s_init(state, outlen, tctx->key, tctx->keylen); - return 0; -} - -static inline int crypto_blake2s_update(struct shash_desc *desc, - const u8 *in, unsigned int inlen, - bool force_generic) -{ - struct blake2s_state *state = shash_desc_ctx(desc); - - __blake2s_update(state, in, inlen, force_generic); - return 0; -} - -static inline int crypto_blake2s_final(struct shash_desc *desc, u8 *out, - bool force_generic) -{ - struct blake2s_state *state = shash_desc_ctx(desc); - - __blake2s_final(state, out, force_generic); - return 0; -} - #endif /* _CRYPTO_INTERNAL_BLAKE2S_H */ diff --git a/lib/crypto/blake2s-selftest.c b/lib/crypto/blake2s-selftest.c index 409e4b728770..66f505220f43 100644 --- a/lib/crypto/blake2s-selftest.c +++ b/lib/crypto/blake2s-selftest.c @@ -4,6 +4,8 @@ */ #include +#include +#include #include /* @@ -587,5 +589,44 @@ bool __init blake2s_selftest(void) } } + for (i = 0; i < 32; ++i) { + enum { TEST_ALIGNMENT = 16 }; + u8 unaligned_block[BLAKE2S_BLOCK_SIZE + TEST_ALIGNMENT - 1] + __aligned(TEST_ALIGNMENT); + u8 blocks[BLAKE2S_BLOCK_SIZE * 3]; + struct blake2s_state state1, state2; + + get_random_bytes(blocks, sizeof(blocks)); + get_random_bytes(&state, sizeof(state)); + +#if defined(CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC) && \ + defined(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S) + memcpy(&state1, &state, sizeof(state1)); + memcpy(&state2, &state, sizeof(state2)); + blake2s_compress(&state1, blocks, 3, BLAKE2S_BLOCK_SIZE); + blake2s_compress_generic(&state2, blocks, 3, BLAKE2S_BLOCK_SIZE); + if (memcmp(&state1, &state2, sizeof(state1))) { + pr_err("blake2s random compress self-test %d: FAIL\n", + i + 1); + success = false; + } +#endif + + memcpy(&state1, &state, sizeof(state1)); + blake2s_compress(&state1, blocks, 1, BLAKE2S_BLOCK_SIZE); + for (l = 1; l < TEST_ALIGNMENT; ++l) { + memcpy(unaligned_block + l, blocks, + BLAKE2S_BLOCK_SIZE); + memcpy(&state2, &state, sizeof(state2)); + blake2s_compress(&state2, unaligned_block + l, 1, + BLAKE2S_BLOCK_SIZE); + if (memcmp(&state1, &state2, sizeof(state1))) { + pr_err("blake2s random compress align %d self-test %d: FAIL\n", + l, i + 1); + success = false; + } + } + } + return success; } diff --git a/lib/crypto/blake2s.c b/lib/crypto/blake2s.c index c71c09621c09..98e688c6d891 100644 --- a/lib/crypto/blake2s.c +++ b/lib/crypto/blake2s.c @@ -16,16 +16,44 @@ #include #include +static inline void blake2s_set_lastblock(struct blake2s_state *state) +{ + state->f[0] = -1; +} + void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen) { - __blake2s_update(state, in, inlen, false); + const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen; + + if (unlikely(!inlen)) + return; + if (inlen > fill) { + memcpy(state->buf + state->buflen, in, fill); + blake2s_compress(state, state->buf, 1, BLAKE2S_BLOCK_SIZE); + state->buflen = 0; + in += fill; + inlen -= fill; + } + if (inlen > BLAKE2S_BLOCK_SIZE) { + const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE); + blake2s_compress(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE); + in += BLAKE2S_BLOCK_SIZE * (nblocks - 1); + inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1); + } + memcpy(state->buf + state->buflen, in, inlen); + state->buflen += inlen; } EXPORT_SYMBOL(blake2s_update); void blake2s_final(struct blake2s_state *state, u8 *out) { WARN_ON(IS_ENABLED(DEBUG) && !out); - __blake2s_final(state, out, false); + blake2s_set_lastblock(state); + memset(state->buf + state->buflen, 0, + BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */ + blake2s_compress(state, state->buf, 1, state->buflen); + cpu_to_le32_array(state->h, ARRAY_SIZE(state->h)); + memcpy(out, state->h, state->outlen); memzero_explicit(state, sizeof(*state)); } EXPORT_SYMBOL(blake2s_final); @@ -38,12 +66,7 @@ static int __init blake2s_mod_init(void) return 0; } -static void __exit blake2s_mod_exit(void) -{ -} - module_init(blake2s_mod_init); -module_exit(blake2s_mod_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BLAKE2s hash function"); MODULE_AUTHOR("Jason A. Donenfeld "); -- cgit v1.2.3 From b5c8b3fe8946c1927155599dfb79045477901009 Mon Sep 17 00:00:00 2001 From: Eyal Birger Date: Fri, 20 May 2022 13:48:45 +0300 Subject: xfrm: no need to set DST_NOPOLICY in IPv4 This is a cleanup patch following commit e6175a2ed1f1 ("xfrm: fix "disable_policy" flag use when arriving from different devices") which made DST_NOPOLICY no longer be used for inbound policy checks. On outbound the flag was set, but never used. As such, avoid setting it altogether and remove the nopolicy argument from rt_dst_alloc(). Signed-off-by: Eyal Birger Reviewed-by: Nicolas Dichtel Signed-off-by: Steffen Klassert --- drivers/net/vrf.c | 2 +- include/net/route.h | 3 +-- net/ipv4/route.c | 24 ++++++++---------------- 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 40445a12c682..5df7a0abc39d 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1077,7 +1077,7 @@ static int vrf_rtable_create(struct net_device *dev) return -ENOMEM; /* create a dst for routing packets out through a VRF device */ - rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1, 1); + rth = rt_dst_alloc(dev, 0, RTN_UNICAST, 1); if (!rth) return -ENOMEM; diff --git a/include/net/route.h b/include/net/route.h index 991a3985712d..b6743ff88e30 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -244,8 +244,7 @@ void ip_rt_multicast_event(struct in_device *); int ip_rt_ioctl(struct net *, unsigned int cmd, struct rtentry *rt); void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt); struct rtable *rt_dst_alloc(struct net_device *dev, - unsigned int flags, u16 type, - bool nopolicy, bool noxfrm); + unsigned int flags, u16 type, bool noxfrm); struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt); struct in_ifaddr; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2d16bcc7d346..bd351fab46e6 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1626,12 +1626,11 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr, struct rtable *rt_dst_alloc(struct net_device *dev, unsigned int flags, u16 type, - bool nopolicy, bool noxfrm) + bool noxfrm) { struct rtable *rt; rt = dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK, - (nopolicy ? DST_NOPOLICY : 0) | (noxfrm ? DST_NOXFRM : 0)); if (rt) { @@ -1726,7 +1725,6 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, struct in_device *in_dev = __in_dev_get_rcu(dev); unsigned int flags = RTCF_MULTICAST; struct rtable *rth; - bool no_policy; u32 itag = 0; int err; @@ -1737,12 +1735,11 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, if (our) flags |= RTCF_LOCAL; - no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY); - if (no_policy) + if (IN_DEV_ORCONF(in_dev, NOPOLICY)) IPCB(skb)->flags |= IPSKB_NOPOLICY; rth = rt_dst_alloc(dev_net(dev)->loopback_dev, flags, RTN_MULTICAST, - no_policy, false); + false); if (!rth) return -ENOBUFS; @@ -1801,7 +1798,7 @@ static int __mkroute_input(struct sk_buff *skb, struct rtable *rth; int err; struct in_device *out_dev; - bool do_cache, no_policy; + bool do_cache; u32 itag = 0; /* get a working reference to the output device */ @@ -1846,8 +1843,7 @@ static int __mkroute_input(struct sk_buff *skb, } } - no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY); - if (no_policy) + if (IN_DEV_ORCONF(in_dev, NOPOLICY)) IPCB(skb)->flags |= IPSKB_NOPOLICY; fnhe = find_exception(nhc, daddr); @@ -1862,7 +1858,7 @@ static int __mkroute_input(struct sk_buff *skb, } } - rth = rt_dst_alloc(out_dev->dev, 0, res->type, no_policy, + rth = rt_dst_alloc(out_dev->dev, 0, res->type, IN_DEV_ORCONF(out_dev, NOXFRM)); if (!rth) { err = -ENOBUFS; @@ -2237,7 +2233,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, struct rtable *rth; struct flowi4 fl4; bool do_cache = true; - bool no_policy; /* IP on this device is disabled. */ @@ -2356,8 +2351,7 @@ brd_input: RT_CACHE_STAT_INC(in_brd); local_input: - no_policy = IN_DEV_ORCONF(in_dev, NOPOLICY); - if (no_policy) + if (IN_DEV_ORCONF(in_dev, NOPOLICY)) IPCB(skb)->flags |= IPSKB_NOPOLICY; do_cache &= res->fi && !itag; @@ -2373,8 +2367,7 @@ local_input: } rth = rt_dst_alloc(ip_rt_get_dev(net, res), - flags | RTCF_LOCAL, res->type, - no_policy, false); + flags | RTCF_LOCAL, res->type, false); if (!rth) goto e_nobufs; @@ -2597,7 +2590,6 @@ static struct rtable *__mkroute_output(const struct fib_result *res, add: rth = rt_dst_alloc(dev_out, flags, type, - IN_DEV_ORCONF(in_dev, NOPOLICY), IN_DEV_ORCONF(in_dev, NOXFRM)); if (!rth) return ERR_PTR(-ENOBUFS); -- cgit v1.2.3 From e3fa404a261bb8b7795b62be1b9af7b7dc1030f6 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 28 May 2022 16:59:17 +0200 Subject: USB: Follow-up to SPDX identifiers addition - remove now useless comments All these files have been updated in the commit given in the Fixes: tag below. When the SPDX-License-Identifier: has been added, the corresponding text at the beginning of the files has not been deleted. All these texts are about GPL-2.0, with different variation in the wording. Remove these now useless lines to save some LoC. Fixes: 5fd54ace4721 ("USB: add SPDX identifiers to all remaining files in drivers/usb/") Signed-off-by: Christophe JAILLET Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/audio-v2.h | 3 --- include/linux/usb/audio.h | 3 --- include/linux/usb/cdc-wdm.h | 4 ---- include/linux/usb/cdc.h | 4 ---- include/linux/usb/gadget.h | 2 -- include/linux/usb/input.h | 4 ---- include/linux/usb/isp1301.h | 10 ---------- include/linux/usb/m66592.h | 14 -------------- include/linux/usb/of.h | 2 -- include/linux/usb/r8a66597.h | 14 -------------- include/linux/usb/serial.h | 5 ----- include/linux/usb/storage.h | 2 -- include/linux/usb/tegra_usb_phy.h | 10 ---------- include/linux/usb/ulpi.h | 4 ---- include/linux/usb/xhci-dbgp.h | 4 ---- 15 files changed, 85 deletions(-) (limited to 'include') diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 8fc2abd7aecb..ca796dc1a984 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -2,9 +2,6 @@ /* * Copyright (c) 2010 Daniel Mack * - * This software is distributed under the terms of the GNU General Public - * License ("GPL") version 2, as published by the Free Software Foundation. - * * This file holds USB constants and structures defined * by the USB Device Class Definition for Audio Devices in version 2.0. * Comments below reference relevant sections of the documents contained diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index 170acd500ea1..0747b24a1a7c 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h @@ -6,9 +6,6 @@ * Developed for Thumtronics by Grey Innovation * Ben Williamson * - * This software is distributed under the terms of the GNU General Public - * License ("GPL") version 2, as published by the Free Software Foundation. - * * This file holds USB constants and structures defined * by the USB Device Class Definition for Audio Devices. * Comments below reference relevant sections of that document: diff --git a/include/linux/usb/cdc-wdm.h b/include/linux/usb/cdc-wdm.h index 9f5a51f79ba5..85417f00a89a 100644 --- a/include/linux/usb/cdc-wdm.h +++ b/include/linux/usb/cdc-wdm.h @@ -3,10 +3,6 @@ * USB CDC Device Management subdriver * * Copyright (c) 2012 Bjørn Mork - * - * 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 __LINUX_USB_CDC_WDM_H diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h index 35d784cf32a4..0af0db51bc89 100644 --- a/include/linux/usb/cdc.h +++ b/include/linux/usb/cdc.h @@ -3,10 +3,6 @@ * USB CDC common helpers * * Copyright (c) 2015 Oliver Neukum - * - * 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 __LINUX_USB_CDC_H #define __LINUX_USB_CDC_H diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3ad58b7a0824..dc3092cea99e 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -10,8 +10,6 @@ * * (C) Copyright 2002-2004 by David Brownell * All Rights Reserved. - * - * This software is licensed under the GNU GPL version 2. */ #ifndef __LINUX_USB_GADGET_H diff --git a/include/linux/usb/input.h b/include/linux/usb/input.h index 974befa72ac0..5e759b2cf551 100644 --- a/include/linux/usb/input.h +++ b/include/linux/usb/input.h @@ -1,10 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2005 Dmitry Torokhov - * - * 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 __LINUX_USB_INPUT_H diff --git a/include/linux/usb/isp1301.h b/include/linux/usb/isp1301.h index dedb3b2473e8..fa986b926a12 100644 --- a/include/linux/usb/isp1301.h +++ b/include/linux/usb/isp1301.h @@ -3,16 +3,6 @@ * NXP ISP1301 USB transceiver driver * * Copyright (C) 2012 Roland Stigge - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 __LINUX_USB_ISP1301_H diff --git a/include/linux/usb/m66592.h b/include/linux/usb/m66592.h index 2dfe68183495..5f04de2b47fd 100644 --- a/include/linux/usb/m66592.h +++ b/include/linux/usb/m66592.h @@ -3,20 +3,6 @@ * M66592 driver platform data * * Copyright (C) 2009 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef __LINUX_USB_M66592_H diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index dba55ccb9b53..98487fd7ab11 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* * OF helpers for usb devices. - * - * This file is released under the GPLv2 */ #ifndef __LINUX_USB_OF_H diff --git a/include/linux/usb/r8a66597.h b/include/linux/usb/r8a66597.h index c0753d026bbf..f0fa7ddadbaa 100644 --- a/include/linux/usb/r8a66597.h +++ b/include/linux/usb/r8a66597.h @@ -5,20 +5,6 @@ * Copyright (C) 2009 Renesas Solutions Corp. * * Author : Yoshihiro Shimoda - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef __LINUX_USB_R8A66597_H diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 16ea5a4cc586..8ea319f89e1f 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -4,11 +4,6 @@ * * Copyright (C) 1999 - 2012 * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * */ #ifndef __LINUX_USB_SERIAL_H diff --git a/include/linux/usb/storage.h b/include/linux/usb/storage.h index e0240f864548..2827ce72e502 100644 --- a/include/linux/usb/storage.h +++ b/include/linux/usb/storage.h @@ -9,8 +9,6 @@ * * This file contains definitions taken from the * USB Mass Storage Class Specification Overview - * - * Distributed under the terms of the GNU GPL, version two. */ /* Storage subclass codes */ diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d3e65eb9e16f..46e73584b6e6 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -1,16 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __TEGRA_USB_PHY_H diff --git a/include/linux/usb/ulpi.h b/include/linux/usb/ulpi.h index 36c2982780ad..5050f502c1ed 100644 --- a/include/linux/usb/ulpi.h +++ b/include/linux/usb/ulpi.h @@ -3,10 +3,6 @@ * ulpi.h -- ULPI defines and function prorotypes * * Copyright (C) 2010 Nokia Corporation - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * version 2 of that License. */ #ifndef __LINUX_USB_ULPI_H diff --git a/include/linux/usb/xhci-dbgp.h b/include/linux/usb/xhci-dbgp.h index 01fe768873f9..171fd74b1cfc 100644 --- a/include/linux/usb/xhci-dbgp.h +++ b/include/linux/usb/xhci-dbgp.h @@ -5,10 +5,6 @@ * Copyright (C) 2016 Intel Corporation * * Author: Lu Baolu - * - * 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 __LINUX_XHCI_DBGP_H -- cgit v1.2.3 From 3e00a22fdc9a9457f1c64d885532710e174babd8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 28 May 2022 17:13:56 +0200 Subject: USB: Follow-up to SPDX GPL-2.0+ identifiers addition - remove now useless comments All these files have been updated in the commit given in the Fixes: tag below. When the SPDX-License-Identifier: has been added, the corresponding text at the beginning of the files has not been deleted. All these texts are about GPL-2.0+, with different variation in the wording. Remove these now useless lines to save some LoC. Fixes: 5fd54ace4721 ("USB: add SPDX identifiers to all remaining files in drivers/usb/") Signed-off-by: Christophe JAILLET Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/c67x00.h | 15 --------------- include/linux/usb/composite.h | 14 -------------- include/linux/usb/ehci_def.h | 14 -------------- include/linux/usb/ehci_pdriver.h | 14 -------------- include/linux/usb/g_hid.h | 14 -------------- include/linux/usb/hcd.h | 14 -------------- include/linux/usb/musb-ux500.h | 10 ---------- include/linux/usb/net2280.h | 14 -------------- include/linux/usb/ohci_pdriver.h | 14 -------------- include/linux/usb/otg-fsm.h | 17 ++--------------- include/linux/usb/phy_companion.h | 10 ---------- include/linux/usb/rndis_host.h | 14 -------------- include/linux/usb/usb338x.h | 11 ----------- include/linux/usb/usbnet.h | 14 -------------- 14 files changed, 2 insertions(+), 187 deletions(-) (limited to 'include') diff --git a/include/linux/usb/c67x00.h b/include/linux/usb/c67x00.h index 2fc39e3b7281..45e0757e58f3 100644 --- a/include/linux/usb/c67x00.h +++ b/include/linux/usb/c67x00.h @@ -3,21 +3,6 @@ * usb_c67x00.h: platform definitions for the Cypress C67X00 USB chip * * Copyright (C) 2006-2008 Barco N.V. - * - * 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. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. */ #ifndef _LINUX_USB_C67X00_H diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 9d2762279286..43ac3fa760db 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -3,20 +3,6 @@ * composite.h -- framework for usb gadgets which are composite devices * * Copyright (C) 2006-2008 David Brownell - * - * 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. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __LINUX_USB_COMPOSITE_H diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h index c892c5bc6638..fbabadd3b372 100644 --- a/include/linux/usb/ehci_def.h +++ b/include/linux/usb/ehci_def.h @@ -1,20 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2001-2002 by David Brownell - * - * 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. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __LINUX_USB_EHCI_DEF_H diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h index 89fc901e778f..0f1b166f5aa0 100644 --- a/include/linux/usb/ehci_pdriver.h +++ b/include/linux/usb/ehci_pdriver.h @@ -1,20 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2012 Hauke Mehrtens - * - * 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. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __USB_CORE_EHCI_PDRIVER_H diff --git a/include/linux/usb/g_hid.h b/include/linux/usb/g_hid.h index 7581e488c237..d56bfedeb079 100644 --- a/include/linux/usb/g_hid.h +++ b/include/linux/usb/g_hid.h @@ -3,20 +3,6 @@ * g_hid.h -- Header file for USB HID gadget driver * * Copyright (C) 2010 Fabien Chouteau - * - * 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. - * - * 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 */ #ifndef __LINUX_USB_G_HID_H diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 2c1fc9212cf2..37ccb31b1d40 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -1,20 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2001-2002 by David Brownell - * - * 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. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __USB_CORE_HCD_H diff --git a/include/linux/usb/musb-ux500.h b/include/linux/usb/musb-ux500.h index c4b7ad9850ca..d60dcfc56b5a 100644 --- a/include/linux/usb/musb-ux500.h +++ b/include/linux/usb/musb-ux500.h @@ -1,16 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2013 ST-Ericsson AB - * - * 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 __MUSB_UX500_H__ diff --git a/include/linux/usb/net2280.h b/include/linux/usb/net2280.h index 08b85caecfaf..f29fe6a1f415 100644 --- a/include/linux/usb/net2280.h +++ b/include/linux/usb/net2280.h @@ -5,20 +5,6 @@ * * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) * Copyright (C) 2003 David Brownell - * - * 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. - * - * 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 */ #ifndef __LINUX_USB_NET2280_H diff --git a/include/linux/usb/ohci_pdriver.h b/include/linux/usb/ohci_pdriver.h index 7eb16cf587ee..2447c78b1766 100644 --- a/include/linux/usb/ohci_pdriver.h +++ b/include/linux/usb/ohci_pdriver.h @@ -1,20 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2012 Hauke Mehrtens - * - * 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. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __USB_CORE_OHCI_PDRIVER_H diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h index 784659d4dc99..6135d076c53d 100644 --- a/include/linux/usb/otg-fsm.h +++ b/include/linux/usb/otg-fsm.h @@ -1,19 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ -/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * 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, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. +/* + * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. */ #ifndef __LINUX_USB_OTG_FSM_H diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h index 263196f05015..862aaeca2319 100644 --- a/include/linux/usb/phy_companion.h +++ b/include/linux/usb/phy_companion.h @@ -3,18 +3,8 @@ * phy-companion.h -- phy companion to indicate the comparator part of PHY * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com - * 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. * * Author: Kishon Vijay Abraham I - * - * 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 __DRIVERS_PHY_COMPANION_H diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h index cc42db51bbba..489cfb1d00f6 100644 --- a/include/linux/usb/rndis_host.h +++ b/include/linux/usb/rndis_host.h @@ -2,20 +2,6 @@ /* * Host Side support for RNDIS Networking Links * Copyright (C) 2005 by David Brownell - * - * 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. - * - * 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 */ #ifndef __LINUX_USB_RNDIS_HOST_H diff --git a/include/linux/usb/usb338x.h b/include/linux/usb/usb338x.h index 20020c1336d5..70a7e3cdb3c9 100644 --- a/include/linux/usb/usb338x.h +++ b/include/linux/usb/usb338x.h @@ -6,17 +6,6 @@ * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) * Copyright (C) 2003 David Brownell * Copyright (C) 2014 Ricardo Ribalda - Qtechnology/AS - * - * 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 __LINUX_USB_USB338X_H diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 1b4d72d5e891..4f5608cbd9ab 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -4,20 +4,6 @@ * * Copyright (C) 2000-2005 by David Brownell * Copyright (C) 2003-2005 David Hollis - * - * 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. - * - * 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 */ #ifndef __LINUX_USB_USBNET_H -- cgit v1.2.3 From 924b290655c0f17ac84e752addfc9bc3ec361069 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 24 May 2022 13:47:40 -0700 Subject: xfrm: convert alg_key to flexible array member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Iproute2 build generates a warning when built with gcc-12. This is because the alg_key in xfrm.h API has zero size array element instead of flexible array. CC xfrm_state.o In function ‘xfrm_algo_parse’, inlined from ‘xfrm_state_modify.constprop’ at xfrm_state.c:573:5: xfrm_state.c:162:32: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=] 162 | buf[j] = val; | ~~~~~~~^~~~~ This patch convert the alg_key into flexible array member. There are other zero size arrays here that should be converted as well. This patch is RFC only since it is only compile tested and passes trivial iproute2 tests. Signed-off-by: Stephen Hemminger Acked-by: Herbert Xu Signed-off-by: Steffen Klassert --- include/uapi/linux/xfrm.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index 65e13a099b1a..3ed61df9cc91 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h @@ -102,21 +102,21 @@ struct xfrm_replay_state_esn { struct xfrm_algo { char alg_name[64]; unsigned int alg_key_len; /* in bits */ - char alg_key[0]; + char alg_key[]; }; struct xfrm_algo_auth { char alg_name[64]; unsigned int alg_key_len; /* in bits */ unsigned int alg_trunc_len; /* in bits */ - char alg_key[0]; + char alg_key[]; }; struct xfrm_algo_aead { char alg_name[64]; unsigned int alg_key_len; /* in bits */ unsigned int alg_icv_len; /* in bits */ - char alg_key[0]; + char alg_key[]; }; struct xfrm_stats { -- cgit v1.2.3 From 4173f018aae16b6496d292c234b858241f85254f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:12 +0200 Subject: tty/vt: consolemap: rename and document struct uni_pagedir struct uni_pagedir contains 32 unicode page directories, so the name of the structure is a bit misleading. Rename the structure to uni_pagedict, so it looks like this: struct uni_pagedict -> 32 page dirs -> 32 rows -> 64 glyphs Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 47 +++++++++++++++++++++++++----------------- drivers/video/console/vgacon.c | 4 ++-- include/linux/console_struct.h | 6 +++--- 3 files changed, 33 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 839d75d1a6c0..5acafeea9afc 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -186,17 +186,26 @@ static unsigned short translations[][256] = { static int inv_translate[MAX_NR_CONSOLES]; -struct uni_pagedir { - u16 **uni_pgdir[32]; +/** + * struct uni_pagedict -- unicode directory + * + * @uni_pgdir: 32*32*64 table with glyphs + * @refcount: reference count of this structure + * @sum: checksum + * @inverse_translations: best-effort inverse mapping + * @inverse_trans_unicode: best-effort inverse mapping to unicode + */ +struct uni_pagedict { + u16 **uni_pgdir[32]; unsigned long refcount; unsigned long sum; unsigned char *inverse_translations[4]; u16 *inverse_trans_unicode; }; -static struct uni_pagedir *dflt; +static struct uni_pagedict *dflt; -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i) +static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, int i) { int j, glyph; unsigned short *t = translations[i]; @@ -221,7 +230,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int } static void set_inverse_trans_unicode(struct vc_data *conp, - struct uni_pagedir *p) + struct uni_pagedict *p) { int i, j, k, glyph; u16 **p1, *p2; @@ -270,7 +279,7 @@ unsigned short *set_translate(int m, struct vc_data *vc) */ u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode) { - struct uni_pagedir *p; + struct uni_pagedict *p; int m; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; @@ -297,7 +306,7 @@ EXPORT_SYMBOL_GPL(inverse_translate); static void update_user_maps(void) { int i; - struct uni_pagedir *p, *q = NULL; + struct uni_pagedict *p, *q = NULL; for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) @@ -393,7 +402,7 @@ int con_get_trans_new(ushort __user * arg) extern u8 dfont_unicount[]; /* Defined in console_defmap.c */ extern u16 dfont_unitable[]; -static void con_release_unimap(struct uni_pagedir *p) +static void con_release_unimap(struct uni_pagedict *p) { u16 **p1; int i, j; @@ -419,7 +428,7 @@ static void con_release_unimap(struct uni_pagedir *p) /* Caller must hold the console lock */ void con_free_unimap(struct vc_data *vc) { - struct uni_pagedir *p; + struct uni_pagedict *p; p = *vc->vc_uni_pagedir_loc; if (!p) @@ -431,10 +440,10 @@ void con_free_unimap(struct vc_data *vc) kfree(p); } -static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) +static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *p) { int i, j, k; - struct uni_pagedir *q; + struct uni_pagedict *q; for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) @@ -472,7 +481,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p) } static int -con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) +con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos) { int i, n; u16 **p1, *p2; @@ -503,7 +512,7 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) /* Caller must hold the lock */ static int con_do_clear_unimap(struct vc_data *vc) { - struct uni_pagedir *p, *q; + struct uni_pagedict *p, *q; p = *vc->vc_uni_pagedir_loc; if (!p || --p->refcount) { @@ -536,7 +545,7 @@ int con_clear_unimap(struct vc_data *vc) int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) { int err = 0, err1, i; - struct uni_pagedir *p, *q; + struct uni_pagedict *p, *q; struct unipair *unilist, *plist; if (!ct) @@ -569,7 +578,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* * Since refcount was > 1, con_clear_unimap() allocated a - * a new uni_pagedir for this vc. Re: p != q + * a new uni_pagedict for this vc. Re: p != q */ q = *vc->vc_uni_pagedir_loc; @@ -660,7 +669,7 @@ int con_set_default_unimap(struct vc_data *vc) { int i, j, err = 0, err1; u16 *q; - struct uni_pagedir *p; + struct uni_pagedict *p; if (dflt) { p = *vc->vc_uni_pagedir_loc; @@ -714,7 +723,7 @@ EXPORT_SYMBOL(con_set_default_unimap); */ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) { - struct uni_pagedir *q; + struct uni_pagedict *q; if (!*src_vc->vc_uni_pagedir_loc) return -EINVAL; @@ -739,7 +748,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni int i, j, k, ret = 0; ushort ect; u16 **p1, *p2; - struct uni_pagedir *p; + struct uni_pagedict *p; struct unipair *unilist; unilist = kvmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL); @@ -810,7 +819,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs) { int h; u16 **p1, *p2; - struct uni_pagedir *p; + struct uni_pagedict *p; /* Only 16-bit codes supported at this time */ if (ucs > 0xffff) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 576612f18d59..058a78b8dbcf 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -75,7 +75,7 @@ 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 void vgacon_invert_region(struct vc_data *c, u16 * p, int count); -static struct uni_pagedir *vgacon_uni_pagedir; +static struct uni_pagedict *vgacon_uni_pagedir; static int vgacon_refcount; /* Description of the hardware situation */ @@ -342,7 +342,7 @@ static const char *vgacon_startup(void) static void vgacon_init(struct vc_data *c, int init) { - struct uni_pagedir *p; + struct uni_pagedict *p; /* * We cannot be loaded as a module, therefore init will be 1 diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index d5b9c8d40c18..f75033f0277f 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -17,7 +17,7 @@ #include #include -struct uni_pagedir; +struct uni_pagedict; struct uni_screen; #define NPAR 16 @@ -157,8 +157,8 @@ struct vc_data { unsigned int vc_bell_duration; /* Console bell duration */ unsigned short vc_cur_blink_ms; /* Cursor blink duration */ struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ - struct uni_pagedir *vc_uni_pagedir; - struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ + struct uni_pagedict *vc_uni_pagedir; + struct uni_pagedict **vc_uni_pagedir_loc; /* [!] Location of uni_pagedict variable for this console */ struct uni_screen *vc_uni_screen; /* unicode screen content */ /* additional information is in vt_kern.h */ }; -- cgit v1.2.3 From 0b75f7968d61566d150747512344cabaa59e54c6 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:15 +0200 Subject: tty/vt: consolemap: remove extern from function decls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extern keyword is not needed for function declarations. Remove it, so that the consolemap header conforms to other tty headers. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-5-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- include/linux/consolemap.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index bcfce748c9d8..abc28e4450bf 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -17,12 +17,11 @@ #ifdef CONFIG_CONSOLE_TRANSLATIONS struct vc_data; -extern u16 inverse_translate(const struct vc_data *conp, int glyph, - int use_unicode); -extern unsigned short *set_translate(int m, struct vc_data *vc); -extern int conv_uni_to_pc(struct vc_data *conp, long ucs); -extern u32 conv_8bit_to_uni(unsigned char c); -extern int conv_uni_to_8bit(u32 uni); +u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode); +unsigned short *set_translate(int m, struct vc_data *vc); +int conv_uni_to_pc(struct vc_data *conp, long ucs); +u32 conv_8bit_to_uni(unsigned char c); +int conv_uni_to_8bit(u32 uni); void console_map_init(void); #else #define inverse_translate(conp, glyph, uni) ((uint16_t)glyph) -- cgit v1.2.3 From f827c754f9b6247f4d4f9cbb508b22bff2cf8e6d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:16 +0200 Subject: tty/vt: consolemap: convert macros to static inlines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit changes !CONFIG_CONSOLE_TRANSLATIONS definitions to real (inline) functions. So the commit: * makes type checking much stronger, * removes the need of many parentheses and casts, and * makes the code more readable. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-6-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- include/linux/consolemap.h | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index abc28e4450bf..98171dbed51f 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -14,9 +14,9 @@ #include -#ifdef CONFIG_CONSOLE_TRANSLATIONS struct vc_data; +#ifdef CONFIG_CONSOLE_TRANSLATIONS u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode); unsigned short *set_translate(int m, struct vc_data *vc); int conv_uni_to_pc(struct vc_data *conp, long ucs); @@ -24,12 +24,33 @@ u32 conv_8bit_to_uni(unsigned char c); int conv_uni_to_8bit(u32 uni); void console_map_init(void); #else -#define inverse_translate(conp, glyph, uni) ((uint16_t)glyph) -#define set_translate(m, vc) ((unsigned short *)NULL) -#define conv_uni_to_pc(conp, ucs) ((int) (ucs > 0xff ? -1: ucs)) -#define conv_8bit_to_uni(c) ((uint32_t)(c)) -#define conv_uni_to_8bit(c) ((int) ((c) & 0xff)) -#define console_map_init(c) do { ; } while (0) +static inline u16 inverse_translate(const struct vc_data *conp, int glyph, + int use_unicode) +{ + return glyph; +} + +static inline unsigned short *set_translate(int m, struct vc_data *vc) +{ + return NULL; +} + +static inline int conv_uni_to_pc(struct vc_data *conp, long ucs) +{ + return ucs > 0xff ? -1 : ucs; +} + +static inline u32 conv_8bit_to_uni(unsigned char c) +{ + return c; +} + +static inline int conv_uni_to_8bit(u32 uni) +{ + return uni & 0xff; +} + +static inline void console_map_init(void) { } #endif /* CONFIG_CONSOLE_TRANSLATIONS */ #endif /* __LINUX_CONSOLEMAP_H__ */ -- cgit v1.2.3 From d9ebb906a45adc71a62aceb1e3608c847cafa660 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:17 +0200 Subject: tty/vt: consolemap: make parameters of inverse_translate() saner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - int use_unicode -> bool: it's used as bool at some places already, so make it explicit. - int glyph -> u16: every caller passes a u16 in. So make it explicit too. And remove a negative check from inverse_translate() as it never could be negative. Reviewed-by: Ilpo Järvinen Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-7-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/accessibility/braille/braille_console.c | 2 +- drivers/accessibility/speakup/main.c | 2 +- drivers/tty/vt/consolemap.c | 4 ++-- drivers/tty/vt/selection.c | 3 ++- drivers/tty/vt/vt.c | 2 +- include/linux/consolemap.h | 6 +++--- 6 files changed, 10 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index fdc6b593f500..c4d54a5326b1 100644 --- a/drivers/accessibility/braille/braille_console.c +++ b/drivers/accessibility/braille/braille_console.c @@ -131,7 +131,7 @@ static void vc_refresh(struct vc_data *vc) for (i = 0; i < WIDTH; i++) { u16 glyph = screen_glyph(vc, 2 * (vc_x + i) + vc_y * vc->vc_size_row); - buf[i] = inverse_translate(vc, glyph, 1); + buf[i] = inverse_translate(vc, glyph, true); } braille_write(buf); } diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c index d726537fa16c..f52265293482 100644 --- a/drivers/accessibility/speakup/main.c +++ b/drivers/accessibility/speakup/main.c @@ -470,7 +470,7 @@ static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs) c |= 0x100; } - ch = inverse_translate(vc, c, 1); + ch = inverse_translate(vc, c, true); *attribs = (w & 0xff00) >> 8; } return ch; diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index fb61158f4dc6..157c7f936294 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -281,12 +281,12 @@ unsigned short *set_translate(int m, struct vc_data *vc) * was active. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode) +u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode) { struct uni_pagedict *p; int m; - if (glyph < 0 || glyph >= MAX_GLYPH) + if (glyph >= MAX_GLYPH) return 0; p = *conp->vc_uni_pagedir_loc; diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index f7755e73696e..6ef22f01cc51 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -68,7 +68,8 @@ sel_pos(int n, bool unicode) { if (unicode) return screen_glyph_unicode(vc_sel.cons, n / 2); - return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), 0); + return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), + false); } /** diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index f8c87c4d7399..1ea1c11c42fd 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4741,7 +4741,7 @@ u32 screen_glyph_unicode(const struct vc_data *vc, int n) if (uniscr) return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols]; - return inverse_translate(vc, screen_glyph(vc, n * 2), 1); + return inverse_translate(vc, screen_glyph(vc, n * 2), true); } EXPORT_SYMBOL_GPL(screen_glyph_unicode); diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index 98171dbed51f..1ff2bf55eb85 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -17,15 +17,15 @@ struct vc_data; #ifdef CONFIG_CONSOLE_TRANSLATIONS -u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode); +u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode); unsigned short *set_translate(int m, struct vc_data *vc); int conv_uni_to_pc(struct vc_data *conp, long ucs); u32 conv_8bit_to_uni(unsigned char c); int conv_uni_to_8bit(u32 uni); void console_map_init(void); #else -static inline u16 inverse_translate(const struct vc_data *conp, int glyph, - int use_unicode) +static inline u16 inverse_translate(const struct vc_data *conp, u16 glyph, + bool use_unicode) { return glyph; } -- cgit v1.2.3 From 5a904a936b407624cd1ff5ee3f1675ca3d2366a5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Jun 2022 12:49:27 +0200 Subject: tty/vt: consolemap: introduce enum translation_map and use it Again, instead of magic constants in the code, declare an enum and be a little bit more explicit. Both in the translations definition and in the loops etc. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220607104946.18710-17-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/consolemap.c | 39 ++++++++++++++++++++------------------- include/linux/consolemap.h | 18 ++++++++++++------ 2 files changed, 32 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 92b5dddb00d9..80536687acef 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -38,7 +38,7 @@ static unsigned short translations[][256] = { /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ - { + [LAT1_MAP] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, @@ -71,9 +71,9 @@ static unsigned short translations[][256] = { 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff - }, + }, /* VT100 graphics mapped to Unicode */ - { + [GRAF_MAP] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, @@ -108,8 +108,8 @@ static unsigned short translations[][256] = { 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff }, /* IBM Codepage 437 mapped to Unicode */ - { - 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + [IBMPC_MAP] = { + 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc, @@ -141,9 +141,9 @@ static unsigned short translations[][256] = { 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 - }, + }, /* User mapping -- default to codes for direct font mapping */ - { + [USER_MAP] = { 0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007, 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f, 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017, @@ -184,7 +184,7 @@ static unsigned short translations[][256] = { #define MAX_GLYPH 512 /* Max possible glyph value */ -static int inv_translate[MAX_NR_CONSOLES]; +static enum translation_map inv_translate[MAX_NR_CONSOLES]; #define UNI_DIRS 32U #define UNI_DIR_ROWS 32U @@ -208,24 +208,25 @@ struct uni_pagedict { u16 **uni_pgdir[UNI_DIRS]; unsigned long refcount; unsigned long sum; - unsigned char *inverse_translations[4]; + unsigned char *inverse_translations[LAST_MAP + 1]; u16 *inverse_trans_unicode; }; static struct uni_pagedict *dflt; -static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, int i) +static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *p, + enum translation_map m) { int j, glyph; - unsigned short *t = translations[i]; + unsigned short *t = translations[m]; unsigned char *q; if (!p) return; - q = p->inverse_translations[i]; + q = p->inverse_translations[m]; if (!q) { - q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL); + q = p->inverse_translations[m] = kmalloc(MAX_GLYPH, GFP_KERNEL); if (!q) return; } @@ -276,7 +277,7 @@ static void set_inverse_trans_unicode(struct vc_data *conp, } } -unsigned short *set_translate(int m, struct vc_data *vc) +unsigned short *set_translate(enum translation_map m, struct vc_data *vc) { inv_translate[vc->vc_num] = m; return translations[m]; @@ -292,7 +293,7 @@ unsigned short *set_translate(int m, struct vc_data *vc) u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode) { struct uni_pagedict *p; - int m; + enum translation_map m; if (glyph >= MAX_GLYPH) return 0; @@ -669,8 +670,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) if (con_unify_unimap(vc, p)) goto out_unlock; - for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update inverse translations */ + for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) + set_inverse_transl(vc, p, m); /* Update inverse translations */ set_inverse_trans_unicode(vc, p); out_unlock: @@ -731,8 +732,8 @@ int con_set_default_unimap(struct vc_data *vc) return err; } - for (i = 0; i <= 3; i++) - set_inverse_transl(vc, p, i); /* Update all inverse translations */ + for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++) + set_inverse_transl(vc, p, m); /* Update all inverse translations */ set_inverse_trans_unicode(vc, p); dflt = p; return err; diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h index 1ff2bf55eb85..c35db4896c37 100644 --- a/include/linux/consolemap.h +++ b/include/linux/consolemap.h @@ -7,10 +7,15 @@ #ifndef __LINUX_CONSOLEMAP_H__ #define __LINUX_CONSOLEMAP_H__ -#define LAT1_MAP 0 -#define GRAF_MAP 1 -#define IBMPC_MAP 2 -#define USER_MAP 3 +enum translation_map { + LAT1_MAP, + GRAF_MAP, + IBMPC_MAP, + USER_MAP, + + FIRST_MAP = LAT1_MAP, + LAST_MAP = USER_MAP, +}; #include @@ -18,7 +23,7 @@ struct vc_data; #ifdef CONFIG_CONSOLE_TRANSLATIONS u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode); -unsigned short *set_translate(int m, struct vc_data *vc); +unsigned short *set_translate(enum translation_map m, struct vc_data *vc); int conv_uni_to_pc(struct vc_data *conp, long ucs); u32 conv_8bit_to_uni(unsigned char c); int conv_uni_to_8bit(u32 uni); @@ -30,7 +35,8 @@ static inline u16 inverse_translate(const struct vc_data *conp, u16 glyph, return glyph; } -static inline unsigned short *set_translate(int m, struct vc_data *vc) +static inline unsigned short *set_translate(enum translation_map m, + struct vc_data *vc) { return NULL; } -- cgit v1.2.3 From 8322b1f527159de578aab277629296575a11eb3c Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:03:58 +0300 Subject: serial: Add uart_rs485_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few serial drivers make a call to rs485_config() themselves (all these seem to relate to init). Convert them all to use a common helper which makes it easy to make adjustments on tasks related to it as serial_rs485 struct sanitization is going to be added. In pci_fintek_setup() (in 8250_pci.c), the rs485_config() call was made with NULL, however, it can be changed to pass uart_port's rs485 struct. No other callers should pass NULL into rs485_config() so the NULL check can now be eliminated. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 6 ++---- drivers/tty/serial/8250/8250_port.c | 2 +- drivers/tty/serial/fsl_lpuart.c | 2 +- drivers/tty/serial/imx.c | 2 +- drivers/tty/serial/serial_core.c | 6 ++++++ include/linux/serial_core.h | 1 + 6 files changed, 12 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index a17619db7939..fb0a49e39072 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1562,9 +1562,7 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting); - if (!rs485) - rs485 = &port->rs485; - else if (rs485->flags & SER_RS485_ENABLED) + if (rs485->flags & SER_RS485_ENABLED) memset(rs485->padding, 0, sizeof(rs485->padding)); else memset(rs485, 0, sizeof(*rs485)); @@ -1689,7 +1687,7 @@ static int pci_fintek_init(struct pci_dev *dev) * pciserial_resume_ports() */ port = serial8250_get_port(priv->line[i]); - pci_fintek_rs485_config(&port->port, NULL); + uart_rs485_config(&port->port); } else { /* First init without port data * force init to RS232 Mode diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 30e0aaf52adc..af550a4a27f8 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -3191,7 +3191,7 @@ static void serial8250_config_port(struct uart_port *port, int flags) autoconfig(up); if (port->rs485.flags & SER_RS485_ENABLED) - port->rs485_config(port, &port->rs485); + uart_rs485_config(port); /* if access method is AU, it is a 16550 with a quirk */ if (port->type == PORT_16550A && port->iotype == UPIO_AU) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 0d6e62f6bb07..509a7912fa9d 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2724,7 +2724,7 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.rs485.delay_rts_after_send) dev_err(&pdev->dev, "driver doesn't support RTS delays\n"); - sport->port.rs485_config(&sport->port, &sport->port.rs485); + uart_rs485_config(&sport->port); ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0, DRIVER_NAME, sport); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 30edb35a6a15..17fb9a57078b 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2338,7 +2338,7 @@ static int imx_uart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "low-active RTS not possible when receiver is off, enabling receiver\n"); - imx_uart_rs485_config(&sport->port, &sport->port.rs485); + uart_rs485_config(&sport->port); /* Disable interrupts before requesting them */ ucr1 = imx_uart_readl(sport, UCR1); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9a85b41caa0a..8466181db4e9 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1276,6 +1276,12 @@ static int uart_get_icount(struct tty_struct *tty, return 0; } +int uart_rs485_config(struct uart_port *port) +{ + return port->rs485_config(port, &port->rs485); +} +EXPORT_SYMBOL_GPL(uart_rs485_config); + static int uart_get_rs485_config(struct uart_port *port, struct serial_rs485 __user *rs485) { diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index cbd5070bc87f..d3ebb4db2d80 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -592,4 +592,5 @@ static inline int uart_handle_break(struct uart_port *port) !((cflag) & CLOCAL)) int uart_get_rs485_mode(struct uart_port *port); +int uart_rs485_config(struct uart_port *port); #endif /* LINUX_SERIAL_CORE_H */ -- cgit v1.2.3 From 8925c31c1ac2f1e05da988581f2a70a2a8c4d638 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 13:04:00 +0300 Subject: serial: Add rs485_supported to uart_port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparing to move serial_rs485 struct sanitization into serial core, each driver has to provide what fields/flags it supports. This information is pointed into by rs485_supported. Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606100433.13793-4-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 1 + include/linux/serial_core.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index b0320de3379c..90ddc8924811 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1003,6 +1003,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up) uart->port.throttle = up->port.throttle; uart->port.unthrottle = up->port.unthrottle; uart->port.rs485_config = up->port.rs485_config; + uart->port.rs485_supported = up->port.rs485_supported; uart->port.rs485 = up->port.rs485; uart->rs485_start_tx = up->rs485_start_tx; uart->rs485_stop_tx = up->rs485_stop_tx; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index d3ebb4db2d80..5518b70177b3 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -254,6 +254,7 @@ struct uart_port { struct attribute_group *attr_group; /* port specific attributes */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ struct serial_rs485 rs485; + const struct serial_rs485 *rs485_supported; /* Supported mask for serial_rs485 */ struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */ struct serial_iso7816 iso7816; void *private_data; /* generic platform data pointer */ -- cgit v1.2.3 From 6bb6fa6908ebd3cb4e14cd4f0ce272ec885d2eb0 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Mon, 6 Jun 2022 18:36:51 +0300 Subject: tty: Implement lookahead to process XON/XOFF timely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When tty is not read from, XON/XOFF may get stuck into an intermediate buffer. As those characters are there to do software flow-control, it is not very useful. In the case where neither end reads from ttys, the receiving ends might not be able receive the XOFF characters and just keep sending more data to the opposite direction. This problem is almost guaranteed to occur with DMA which sends data in large chunks. If TTY is slow to process characters, that is, eats less than given amount in receive_buf, invoke lookahead for the rest of the chars to process potential XON/XOFF characters. We need to keep track of how many characters have been processed by the lookahead to avoid processing the flow control char again on the normal path. Bookkeeping occurs parallel on two layers (tty_buffer and n_tty) to avoid passing the lookahead_count through the whole call chain. When a flow-control char is processed, two things must occur: a) it must not be treated as normal char b) if not yet processed, flow-control actions need to be taken The return value of n_tty_receive_char_flow_ctrl() tells caller a), and b) is kept internal to n_tty_receive_char_flow_ctrl(). If characters were previous looked ahead, __receive_buf() makes two calls to the appropriate n_tty_receive_buf_* function. First call is made with lookahead_done=true for the characters that were subject to lookahead earlier and then with lookahead=false for the new characters. Either of the calls might be skipped when it has no characters to handle. Reported-by: Gilles Buloz Reviewed-by: Andy Shevchenko Signed-off-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20220606153652.63554-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 91 ++++++++++++++++++++++++++++++++++++++-------- drivers/tty/tty_buffer.c | 59 +++++++++++++++++++++++++----- drivers/tty/tty_port.c | 21 +++++++++++ include/linux/tty_buffer.h | 1 + include/linux/tty_ldisc.h | 14 +++++++ include/linux/tty_port.h | 2 + 6 files changed, 163 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 640c9e871044..8d80384df874 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -118,6 +118,9 @@ struct n_tty_data { size_t read_tail; size_t line_start; + /* # of chars looked ahead (to find software flow control chars) */ + size_t lookahead_count; + /* protected by output lock */ unsigned int column; unsigned int canon_column; @@ -333,6 +336,8 @@ static void reset_buffer_flags(struct n_tty_data *ldata) ldata->erasing = 0; bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); ldata->push = 0; + + ldata->lookahead_count = 0; } static void n_tty_packet_mode_flush(struct tty_struct *tty) @@ -1225,12 +1230,30 @@ static bool n_tty_is_char_flow_ctrl(struct tty_struct *tty, unsigned char c) return c == START_CHAR(tty) || c == STOP_CHAR(tty); } -/* Returns true if c is consumed as flow-control character */ -static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c) +/** + * n_tty_receive_char_flow_ctrl - receive flow control chars + * @tty: terminal device + * @c: character + * @lookahead_done: lookahead has processed this character already + * + * Receive and process flow control character actions. + * + * In case lookahead for flow control chars already handled the character in + * advance to the normal receive, the actions are skipped during normal + * receive. + * + * Returns true if @c is consumed as flow-control character, the character + * must not be treated as normal character. + */ +static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c, + bool lookahead_done) { if (!n_tty_is_char_flow_ctrl(tty, c)) return false; + if (lookahead_done) + return true; + if (c == START_CHAR(tty)) { start_tty(tty); process_echoes(tty); @@ -1242,11 +1265,12 @@ static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c return true; } -static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) +static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c, + bool lookahead_done) { struct n_tty_data *ldata = tty->disc_data; - if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c)) + if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c, lookahead_done)) return; if (L_ISIG(tty)) { @@ -1401,7 +1425,8 @@ static void n_tty_receive_char(struct tty_struct *tty, unsigned char c) put_tty_queue(c, ldata); } -static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) +static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c, + bool lookahead_done) { if (I_ISTRIP(tty)) c &= 0x7f; @@ -1409,9 +1434,12 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) c = tolower(c); if (I_IXON(tty)) { - if (c == STOP_CHAR(tty)) - stop_tty(tty); - else if (c == START_CHAR(tty) || + if (c == STOP_CHAR(tty)) { + if (!lookahead_done) + stop_tty(tty); + } else if (c == START_CHAR(tty) && lookahead_done) { + return; + } else if (c == START_CHAR(tty) || (tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) && c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty))) { @@ -1457,6 +1485,27 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag) n_tty_receive_char_flagged(tty, c, flag); } +/* Caller must ensure count > 0 */ +static void n_tty_lookahead_flow_ctrl(struct tty_struct *tty, const unsigned char *cp, + const unsigned char *fp, unsigned int count) +{ + struct n_tty_data *ldata = tty->disc_data; + unsigned char flag = TTY_NORMAL; + + ldata->lookahead_count += count; + + if (!I_IXON(tty)) + return; + + while (count--) { + if (fp) + flag = *fp++; + if (likely(flag == TTY_NORMAL)) + n_tty_receive_char_flow_ctrl(tty, *cp, false); + cp++; + } +} + static void n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, const char *fp, int count) @@ -1496,7 +1545,7 @@ n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp, static void n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, - const char *fp, int count) + const char *fp, int count, bool lookahead_done) { char flag = TTY_NORMAL; @@ -1504,12 +1553,12 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, if (fp) flag = *fp++; if (likely(flag == TTY_NORMAL)) - n_tty_receive_char_closing(tty, *cp++); + n_tty_receive_char_closing(tty, *cp++, lookahead_done); } } static void n_tty_receive_buf_standard(struct tty_struct *tty, - const unsigned char *cp, const char *fp, int count) + const unsigned char *cp, const char *fp, int count, bool lookahead_done) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; @@ -1540,7 +1589,7 @@ static void n_tty_receive_buf_standard(struct tty_struct *tty, } if (test_bit(c, ldata->char_map)) - n_tty_receive_char_special(tty, c); + n_tty_receive_char_special(tty, c, lookahead_done); else n_tty_receive_char(tty, c); } @@ -1551,21 +1600,30 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, { struct n_tty_data *ldata = tty->disc_data; bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty)); + size_t la_count = min_t(size_t, ldata->lookahead_count, count); if (ldata->real_raw) n_tty_receive_buf_real_raw(tty, cp, fp, count); else if (ldata->raw || (L_EXTPROC(tty) && !preops)) n_tty_receive_buf_raw(tty, cp, fp, count); - else if (tty->closing && !L_EXTPROC(tty)) - n_tty_receive_buf_closing(tty, cp, fp, count); - else { - n_tty_receive_buf_standard(tty, cp, fp, count); + else if (tty->closing && !L_EXTPROC(tty)) { + if (la_count > 0) + n_tty_receive_buf_closing(tty, cp, fp, la_count, true); + if (count > la_count) + n_tty_receive_buf_closing(tty, cp, fp, count - la_count, false); + } else { + if (la_count > 0) + n_tty_receive_buf_standard(tty, cp, fp, la_count, true); + if (count > la_count) + n_tty_receive_buf_standard(tty, cp, fp, count - la_count, false); flush_echoes(tty); if (tty->ops->flush_chars) tty->ops->flush_chars(tty); } + ldata->lookahead_count -= la_count; + if (ldata->icanon && !L_EXTPROC(tty)) return; @@ -2446,6 +2504,7 @@ static struct tty_ldisc_ops n_tty_ops = { .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup, .receive_buf2 = n_tty_receive_buf2, + .lookahead_buf = n_tty_lookahead_flow_ctrl, }; /** diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index bfa431a8e690..754fa43670cc 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -104,6 +105,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size) p->size = size; p->next = NULL; p->commit = 0; + p->lookahead = 0; p->read = 0; p->flags = 0; } @@ -234,6 +236,7 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) buf->head = next; } buf->head->read = buf->head->commit; + buf->head->lookahead = buf->head->read; if (ld && ld->ops->flush_buffer) ld->ops->flush_buffer(tty); @@ -276,13 +279,15 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size, if (n != NULL) { n->flags = flags; buf->tail = n; - /* paired w/ acquire in flush_to_ldisc(); ensures - * flush_to_ldisc() sees buffer data. + /* + * Paired w/ acquire in flush_to_ldisc() and lookahead_bufs() + * ensures they see all buffer data. */ smp_store_release(&b->commit, b->used); - /* paired w/ acquire in flush_to_ldisc(); ensures the - * latest commit value can be read before the head is - * advanced to the next buffer + /* + * Paired w/ acquire in flush_to_ldisc() and lookahead_bufs() + * ensures the latest commit value can be read before the head + * is advanced to the next buffer. */ smp_store_release(&b->next, n); } else if (change) @@ -459,6 +464,40 @@ int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, } EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf); +static void lookahead_bufs(struct tty_port *port, struct tty_buffer *head) +{ + head->lookahead = max(head->lookahead, head->read); + + while (head) { + struct tty_buffer *next; + unsigned char *p, *f = NULL; + unsigned int count; + + /* + * Paired w/ release in __tty_buffer_request_room(); + * ensures commit value read is not stale if the head + * is advancing to the next buffer. + */ + next = smp_load_acquire(&head->next); + /* + * Paired w/ release in __tty_buffer_request_room() or in + * tty_buffer_flush(); ensures we see the committed buffer data. + */ + count = smp_load_acquire(&head->commit) - head->lookahead; + if (!count) { + head = next; + continue; + } + + p = char_buf_ptr(head, head->lookahead); + if (~head->flags & TTYB_NORMAL) + f = flag_buf_ptr(head, head->lookahead); + + port->client_ops->lookahead_buf(port, p, f, count); + head->lookahead += count; + } +} + static int receive_buf(struct tty_port *port, struct tty_buffer *head, int count) { @@ -496,7 +535,7 @@ static void flush_to_ldisc(struct work_struct *work) while (1) { struct tty_buffer *head = buf->head; struct tty_buffer *next; - int count; + int count, rcvd; /* Ldisc or user is trying to gain exclusive access */ if (atomic_read(&buf->priority)) @@ -519,10 +558,12 @@ static void flush_to_ldisc(struct work_struct *work) continue; } - count = receive_buf(port, head, count); - if (!count) + rcvd = receive_buf(port, head, count); + head->read += rcvd; + if (rcvd < count) + lookahead_bufs(port, head); + if (!rcvd) break; - head->read += count; if (need_resched()) cond_resched(); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 880608a65773..dce08a6d7b5e 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -43,6 +43,26 @@ static int tty_port_default_receive_buf(struct tty_port *port, return ret; } +static void tty_port_default_lookahead_buf(struct tty_port *port, const unsigned char *p, + const unsigned char *f, unsigned int count) +{ + struct tty_struct *tty; + struct tty_ldisc *disc; + + tty = READ_ONCE(port->itty); + if (!tty) + return; + + disc = tty_ldisc_ref(tty); + if (!disc) + return; + + if (disc->ops->lookahead_buf) + disc->ops->lookahead_buf(disc->tty, p, f, count); + + tty_ldisc_deref(disc); +} + static void tty_port_default_wakeup(struct tty_port *port) { struct tty_struct *tty = tty_port_tty_get(port); @@ -55,6 +75,7 @@ static void tty_port_default_wakeup(struct tty_port *port) const struct tty_port_client_operations tty_port_default_client_ops = { .receive_buf = tty_port_default_receive_buf, + .lookahead_buf = tty_port_default_lookahead_buf, .write_wakeup = tty_port_default_wakeup, }; EXPORT_SYMBOL_GPL(tty_port_default_client_ops); diff --git a/include/linux/tty_buffer.h b/include/linux/tty_buffer.h index 3b9d77604291..1796648c2907 100644 --- a/include/linux/tty_buffer.h +++ b/include/linux/tty_buffer.h @@ -15,6 +15,7 @@ struct tty_buffer { int used; int size; int commit; + int lookahead; /* Lazy update on recv, can become less than "read" */ int read; int flags; /* Data points here */ diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index e85002b56752..33678e1936f6 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -186,6 +186,18 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, * indicate all data received is %TTY_NORMAL. If assigned, prefer this * function for automatic flow control. * + * @lookahead_buf: [DRV] ``void ()(struct tty_struct *tty, + * const unsigned char *cp, const char *fp, int count) + * + * This function is called by the low-level tty driver for characters + * not eaten by ->receive_buf() or ->receive_buf2(). It is useful for + * processing high-priority characters such as software flow-control + * characters that could otherwise get stuck into the intermediate + * buffer until tty has room to receive them. Ldisc must be able to + * handle later a ->receive_buf() or ->receive_buf2() call for the + * same characters (e.g. by skipping the actions for high-priority + * characters already handled by ->lookahead_buf()). + * * @owner: module containting this ldisc (for reference counting) * * This structure defines the interface between the tty line discipline @@ -229,6 +241,8 @@ struct tty_ldisc_ops { void (*dcd_change)(struct tty_struct *tty, unsigned int status); int (*receive_buf2)(struct tty_struct *tty, const unsigned char *cp, const char *fp, int count); + void (*lookahead_buf)(struct tty_struct *tty, const unsigned char *cp, + const unsigned char *fp, unsigned int count); struct module *owner; }; diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index 58e9619116b7..fa3c3bdaa234 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -40,6 +40,8 @@ struct tty_port_operations { struct tty_port_client_operations { int (*receive_buf)(struct tty_port *port, const unsigned char *, const unsigned char *, size_t); + void (*lookahead_buf)(struct tty_port *port, const unsigned char *cp, + const unsigned char *fp, unsigned int count); void (*write_wakeup)(struct tty_port *port); }; -- cgit v1.2.3 From bd3df9ff25b32b66630c283bb2e065e8bb822e72 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 10 Jun 2022 11:35:47 +0300 Subject: ASoC: SOF: ipc4: Add set_core_state pm_ops implementation IPC4 uses the SET_DX message to enable/disable cores managed by the DSP. The dx_state.core_mask indicates which core is going to change state, the dx_state.dx_mask is to power on (1) or off (0) the core. In the dx_mask only those bits (cores) checked which bit is set in the core_mask, other bits (cores) ignored. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220610083549.16773-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/ipc4/header.h | 8 ++++++++ sound/soc/sof/ipc4.c | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'include') diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index b8b8e5b5e3e1..a795deacc2ea 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -385,6 +385,14 @@ struct sof_ipc4_fw_version { uint16_t build; } __packed; +/* Payload data for SOF_IPC4_MOD_SET_DX */ +struct sof_ipc4_dx_state_info { + /* core(s) to apply the change */ + uint32_t core_mask; + /* core state: 0: put core_id to D3; 1: put core_id to D0 */ + uint32_t dx_mask; +} __packed __aligned(4); + /* Reply messages */ /* diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 658802c86685..b2cb92745ec6 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -597,10 +597,36 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev) } } +static int sof_ipc4_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on) +{ + struct sof_ipc4_dx_state_info dx_state; + struct sof_ipc4_msg msg; + + dx_state.core_mask = BIT(core_idx); + if (on) + dx_state.dx_mask = BIT(core_idx); + else + dx_state.dx_mask = 0; + + msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_DX); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.extension = 0; + msg.data_ptr = &dx_state; + msg.data_size = sizeof(dx_state); + + return sof_ipc4_tx_msg(sdev, &msg, msg.data_size, NULL, 0, false); +} + +static const struct sof_ipc_pm_ops ipc4_pm_ops = { + .set_core_state = sof_ipc4_set_core_state, +}; + const struct sof_ipc_ops ipc4_ops = { .tx_msg = sof_ipc4_tx_msg, .rx_msg = sof_ipc4_rx_msg, .set_get_data = sof_ipc4_set_get_data, .get_reply = sof_ipc4_get_reply, + .pm = &ipc4_pm_ops, .fw_loader = &ipc4_loader_ops, }; -- cgit v1.2.3 From bd10cd5ec54616a488d0bda695f78694ad79f779 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 8 Jun 2022 20:26:21 -0700 Subject: ASoC: SOF: Add topology tokens for IPC4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the required tokens for parsing the topology for IPC4. Co-developed-by: Rander Wang Signed-off-by: Rander Wang Co-developed-by: Bard Liao Signed-off-by: Bard Liao Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220609032643.916882-2-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index b72fa385bebf..f7b2019065ad 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -52,11 +52,17 @@ #define SOF_TKN_SCHED_FRAMES 204 #define SOF_TKN_SCHED_TIME_DOMAIN 205 #define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206 +#define SOF_TKN_SCHED_LP_MODE 207 +#define SOF_TKN_SCHED_MEM_USAGE 208 /* volume */ #define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 #define SOF_TKN_VOLUME_RAMP_STEP_MS 251 +#define SOF_TKN_GAIN_RAMP_TYPE 260 +#define SOF_TKN_GAIN_RAMP_DURATION 261 +#define SOF_TKN_GAIN_VAL 262 + /* SRC */ #define SOF_TKN_SRC_RATE_IN 300 #define SOF_TKN_SRC_RATE_OUT 301 @@ -79,6 +85,9 @@ */ #define SOF_TKN_COMP_CORE_ID 404 #define SOF_TKN_COMP_UUID 405 +#define SOF_TKN_COMP_CPC 406 +#define SOF_TKN_COMP_IS_PAGES 409 +#define SOF_TKN_COMP_NUM_AUDIO_FORMATS 410 /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 @@ -145,4 +154,35 @@ #define SOF_TKN_MEDIATEK_AFE_CH 1601 #define SOF_TKN_MEDIATEK_AFE_FORMAT 1602 +/* MIXER */ +#define SOF_TKN_MIXER_TYPE 1700 + +/* CAVS AUDIO FORMAT */ +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE 1900 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH 1901 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT 1902 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CHANNELS 1903 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP 1904 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG 1905 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE 1906 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG 1907 +#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_SAMPLE_TYPE 1908 +/* intentional token numbering discontinuity, reserved for future use */ +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE 1930 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH 1931 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT 1932 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CHANNELS 1933 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP 1934 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG 1935 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE 1936 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG 1937 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_SAMPLE_TYPE 1938 +/* intentional token numbering discontinuity, reserved for future use */ +#define SOF_TKN_CAVS_AUDIO_FORMAT_IBS 1970 +#define SOF_TKN_CAVS_AUDIO_FORMAT_OBS 1971 +#define SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE 1972 + +/* COPIER */ +#define SOF_TKN_INTEL_COPIER_NODE_TYPE 1980 + #endif -- cgit v1.2.3 From bc433fd76faefb8484f5bc653d846043822a2d35 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 8 Jun 2022 20:26:37 -0700 Subject: ASoC: SOF: Add ops_free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the ops_free callback in struct sof_dev_desc. Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220609032643.916882-18-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 1 + sound/soc/sof/core.c | 7 ++++++- sound/soc/sof/ops.h | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/sof.h b/include/sound/sof.h index 1a82a0db5e7f..367dccfea7ad 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -138,6 +138,7 @@ struct sof_dev_desc { struct snd_sof_dsp_ops *ops; int (*ops_init)(struct snd_sof_dev *sdev); + void (*ops_free)(struct snd_sof_dev *sdev); }; int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd); diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 53719c04658f..c99b5e6c026c 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -189,7 +189,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ret = snd_sof_probe(sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret); - return ret; + goto probe_err; } sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); @@ -317,6 +317,8 @@ dbg_err: snd_sof_free_debug(sdev); dsp_err: snd_sof_remove(sdev); +probe_err: + sof_ops_free(sdev); /* all resources freed, update state to match */ sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); @@ -374,6 +376,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data) { + sof_ops_free(sdev); dev_err(dev, "error: missing mandatory ops\n"); return -EINVAL; } @@ -457,6 +460,8 @@ int snd_sof_device_remove(struct device *dev) snd_sof_remove(sdev); } + sof_ops_free(sdev); + /* release firmware */ snd_sof_fw_unload(sdev); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b79ae4f66eba..55d43adb6a29 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -29,6 +29,12 @@ static inline int sof_ops_init(struct snd_sof_dev *sdev) return 0; } +static inline void sof_ops_free(struct snd_sof_dev *sdev) +{ + if (sdev->pdata->desc->ops_free) + sdev->pdata->desc->ops_free(sdev); +} + /* Mandatory operations are verified during probing */ /* init */ -- cgit v1.2.3 From 4453d24d10fdd9e40c84673e3eda7701055081ea Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 8 Jun 2022 20:26:39 -0700 Subject: ASoC: SOF: Add two new structures for topology manifest data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a couple of structures for parsing and saving the topology manifest data. Co-developed-by: Jaska Uimonen Signed-off-by: Jaska Uimonen Signed-off-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Péter Ujfalusi Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20220609032643.916882-20-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/abi.h | 2 ++ include/uapi/sound/sof/header.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 0e7dccdc25fd..c88f467374ae 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -24,6 +24,8 @@ #ifndef __INCLUDE_UAPI_SOUND_SOF_ABI_H__ #define __INCLUDE_UAPI_SOUND_SOF_ABI_H__ +#include + /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 #define SOF_ABI_MINOR 21 diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h index 5f4518e7a972..f125f7772ee7 100644 --- a/include/uapi/sound/sof/header.h +++ b/include/uapi/sound/sof/header.h @@ -26,4 +26,34 @@ struct sof_abi_hdr { __u32 data[0]; /**< Component data - opaque to core */ } __packed; +#define SOF_MANIFEST_DATA_TYPE_NHLT 1 + +/** + * struct sof_manifest_tlv - SOF manifest TLV data + * @type: type of data + * @size: data size (not including the size of this struct) + * @data: payload data + */ +struct sof_manifest_tlv { + __le32 type; + __le32 size; + __u8 data[]; +}; + +/** + * struct sof_manifest - SOF topology manifest + * @abi_major: Major ABI version + * @abi_minor: Minor ABI version + * @abi_patch: ABI patch + * @count: count of tlv items + * @items: consecutive variable size tlv items + */ +struct sof_manifest { + __le16 abi_major; + __le16 abi_minor; + __le16 abi_patch; + __le16 count; + struct sof_manifest_tlv items[]; +}; + #endif -- cgit v1.2.3 From df4d27b19b892f464685ea45fa6132dd1a2b6864 Mon Sep 17 00:00:00 2001 From: Martin Povišer Date: Mon, 6 Jun 2022 21:19:09 +0200 Subject: ASoC: Introduce 'fixup_controls' card method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new method is called just before the card is registered, providing an opportune time for machine-level drivers to do some final controls amending: deactivating individual controls or obtaining control references for later use. Some controls can be created by DAPM after 'late_probe' has been called, hence the need for this new method. Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20220606191910.16580-5-povik+lin@cutebit.org Signed-off-by: Mark Brown --- include/sound/soc-card.h | 1 + include/sound/soc.h | 1 + sound/soc/soc-card.c | 6 ++++++ sound/soc/soc-core.c | 1 + 4 files changed, 9 insertions(+) (limited to 'include') diff --git a/include/sound/soc-card.h b/include/sound/soc-card.h index df08573bd80c..9d31a5c0db33 100644 --- a/include/sound/soc-card.h +++ b/include/sound/soc-card.h @@ -29,6 +29,7 @@ int snd_soc_card_resume_post(struct snd_soc_card *card); int snd_soc_card_probe(struct snd_soc_card *card); int snd_soc_card_late_probe(struct snd_soc_card *card); +void snd_soc_card_fixup_controls(struct snd_soc_card *card); int snd_soc_card_remove(struct snd_soc_card *card); int snd_soc_card_set_bias_level(struct snd_soc_card *card, diff --git a/include/sound/soc.h b/include/sound/soc.h index f20f5f890794..faef85e37e32 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -916,6 +916,7 @@ struct snd_soc_card { int (*probe)(struct snd_soc_card *card); int (*late_probe)(struct snd_soc_card *card); + void (*fixup_controls)(struct snd_soc_card *card); int (*remove)(struct snd_soc_card *card); /* the pre and post PM functions are used to do any PM work before and diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c index 4158f5aacfd3..285ab4c9c716 100644 --- a/sound/soc/soc-card.c +++ b/sound/soc/soc-card.c @@ -197,6 +197,12 @@ int snd_soc_card_late_probe(struct snd_soc_card *card) return 0; } +void snd_soc_card_fixup_controls(struct snd_soc_card *card) +{ + if (card->fixup_controls) + card->fixup_controls(card); +} + int snd_soc_card_remove(struct snd_soc_card *card) { int ret = 0; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 227540851ded..57f7105c12b7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2066,6 +2066,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) goto probe_end; snd_soc_dapm_new_widgets(card); + snd_soc_card_fixup_controls(card); ret = snd_card_register(card->snd_card); if (ret < 0) { -- cgit v1.2.3 From 67b9d64139e13621d3ab8bb0daad7602e5fe0778 Mon Sep 17 00:00:00 2001 From: David Jander Date: Thu, 9 Jun 2022 14:13:34 +0200 Subject: spi: Fix per-cpu stats access on 32 bit systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 32 bit systems, the following kernel BUG is hit: BUG: using smp_processor_id() in preemptible [00000000] code: swapper/0/1 caller is debug_smp_processor_id+0x18/0x24 CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.19.0-rc1-00001-g6ae0aec8a366 #181 Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) Backtrace: dump_backtrace from show_stack+0x20/0x24 r7:81024ffd r6:00000000 r5:81024ffd r4:60000013 show_stack from dump_stack_lvl+0x60/0x78 dump_stack_lvl from dump_stack+0x14/0x1c r7:81024ffd r6:80f652de r5:80bec180 r4:819a2500 dump_stack from check_preemption_disabled+0xc8/0xf0 check_preemption_disabled from debug_smp_processor_id+0x18/0x24 r8:8119b7e0 r7:81205534 r6:819f5c00 r5:819f4c00 r4:c083d724 debug_smp_processor_id from __spi_sync+0x78/0x220 __spi_sync from spi_sync+0x34/0x4c r10:bb7bf4e0 r9:c083d724 r8:00000007 r7:81a068c0 r6:822a83c0 r5:c083d724 r4:819f4c00 spi_sync from spi_mem_exec_op+0x338/0x370 r5:000000b4 r4:c083d910 spi_mem_exec_op from spi_nor_read_id+0x98/0xdc r10:bb7bf4e0 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:82358040 r4:819f7c40 spi_nor_read_id from spi_nor_detect+0x38/0x114 r7:82358040 r6:00000000 r5:819f7c40 r4:819f7c40 spi_nor_detect from spi_nor_scan+0x11c/0xbec r10:bb7bf4e0 r9:00000000 r8:00000000 r7:c083da4c r6:00000000 r5:00010101 r4:819f7c40 spi_nor_scan from spi_nor_probe+0x10c/0x2d0 r10:bb7bf4e0 r9:bb7bf4d0 r8:00000000 r7:819f4c00 r6:00000000 r5:00000000 r4:819f7c40 per-cpu access needs to be guarded against preemption. Fixes: 6598b91b5ac3 ("spi: spi.c: Convert statistics to per-cpu u64_stats_t") Reported-by: Marc Kleine-Budde Signed-off-by: David Jander Tested-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20220609121334.2984808-1-david@protonic.nl Signed-off-by: Mark Brown --- drivers/spi/spi.c | 5 ++++- include/linux/spi/spi.h | 10 ++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d94822bf3cec..ac61824b87b5 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -314,11 +314,13 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics *pcpu_stats, struct spi_controller *ctlr) { int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1; - struct spi_statistics *stats = this_cpu_ptr(pcpu_stats); + struct spi_statistics *stats; if (l2len < 0) l2len = 0; + get_cpu(); + stats = this_cpu_ptr(pcpu_stats); u64_stats_update_begin(&stats->syncp); u64_stats_inc(&stats->transfers); @@ -333,6 +335,7 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics *pcpu_stats, u64_stats_add(&stats->bytes_rx, xfer->len); u64_stats_update_end(&stats->syncp); + put_cpu(); } /* diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 2e63b4935deb..c96f526d9a20 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -84,18 +84,24 @@ struct spi_statistics { #define SPI_STATISTICS_ADD_TO_FIELD(pcpu_stats, field, count) \ do { \ - struct spi_statistics *__lstats = this_cpu_ptr(pcpu_stats); \ + struct spi_statistics *__lstats; \ + get_cpu(); \ + __lstats = this_cpu_ptr(pcpu_stats); \ u64_stats_update_begin(&__lstats->syncp); \ u64_stats_add(&__lstats->field, count); \ u64_stats_update_end(&__lstats->syncp); \ + put_cpu(); \ } while (0) #define SPI_STATISTICS_INCREMENT_FIELD(pcpu_stats, field) \ do { \ - struct spi_statistics *__lstats = this_cpu_ptr(pcpu_stats); \ + struct spi_statistics *__lstats; \ + get_cpu(); \ + __lstats = this_cpu_ptr(pcpu_stats); \ u64_stats_update_begin(&__lstats->syncp); \ u64_stats_inc(&__lstats->field); \ u64_stats_update_end(&__lstats->syncp); \ + put_cpu(); \ } while (0) /** -- cgit v1.2.3 From 20646f5b1e798bcc20044ae90ac3702f177bf254 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 Jun 2022 17:23:45 +0200 Subject: netfilter: xtables: Bring SPDX identifier back Commit e2be04c7f995 ("License cleanup: add SPDX license identifier to uapi header files with a license") added the correct SPDX identifier to include/uapi/linux/netfilter/xt_IDLETIMER.h. A subsequent commit removed it for no reason and reintroduced the UAPI license incorrectness as the file is now missing the UAPI exception again. Add it back and remove the GPLv2 boilerplate while at it. Fixes: 68983a354a65 ("netfilter: xtables: Add snapshot of hardidletimer target") Cc: Manoj Basapathi Cc: Subash Abhinov Kasiviswanathan Cc: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/netfilter/xt_IDLETIMER.h | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/netfilter/xt_IDLETIMER.h b/include/uapi/linux/netfilter/xt_IDLETIMER.h index 49ddcdc61c09..7bfb31a66fc9 100644 --- a/include/uapi/linux/netfilter/xt_IDLETIMER.h +++ b/include/uapi/linux/netfilter/xt_IDLETIMER.h @@ -1,6 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * linux/include/linux/netfilter/xt_IDLETIMER.h - * * Header file for Xtables timer target module. * * Copyright (C) 2004, 2010 Nokia Corporation @@ -10,20 +9,6 @@ * by Luciano Coelho * * Contact: Luciano Coelho - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef _XT_IDLETIMER_H -- cgit v1.2.3 From a6546f89eac9bfad4b50a7f8ccfbefe0ae01e7df Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:10 +0200 Subject: treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_8.RULE Based on the normalized pattern: 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/vfio-mediated-device.rst | 4 +--- arch/arm/boot/bootp/bootp.lds | 5 +---- include/linux/input/elan-i2c-ids.h | 5 +---- 3 files changed, 3 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/vfio-mediated-device.rst b/Documentation/driver-api/vfio-mediated-device.rst index eded8719180f..66bd00d7aecf 100644 --- a/Documentation/driver-api/vfio-mediated-device.rst +++ b/Documentation/driver-api/vfio-mediated-device.rst @@ -1,3 +1,4 @@ +.. SPDX-License-Identifier: GPL-2.0-only .. include:: ===================== @@ -8,9 +9,6 @@ VFIO Mediated devices :Author: Neo Jia :Author: Kirti Wankhede -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. Virtual Function I/O (VFIO) Mediated devices[1] diff --git a/arch/arm/boot/bootp/bootp.lds b/arch/arm/boot/bootp/bootp.lds index fc54394f4340..160128186bf8 100644 --- a/arch/arm/boot/bootp/bootp.lds +++ b/arch/arm/boot/bootp/bootp.lds @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/arch/arm/boot/bootp/bootp.lds * * Copyright (C) 2000-2002 Russell King - * - * 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. */ OUTPUT_ARCH(arm) ENTRY(_start) diff --git a/include/linux/input/elan-i2c-ids.h b/include/linux/input/elan-i2c-ids.h index 520858d12680..51cca17ee94c 100644 --- a/include/linux/input/elan-i2c-ids.h +++ b/include/linux/input/elan-i2c-ids.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Elan I2C/SMBus Touchpad device whitelist * @@ -11,10 +12,6 @@ * copyright (c) 2011-2012 Cypress Semiconductor, Inc. * copyright (c) 2011-2012 Google, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ -- cgit v1.2.3 From 2aec85b26f39fa9e036c5872950c0ef9b479a1ec Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:13 +0200 Subject: treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_30.RULE (part 2) Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license as published by the free software foundation version 2 this program is distributed as is without any warranty of any kind whether express or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/dma/bcm-sba-raid.c | 14 ++------------ drivers/dma/ti/edma.c | 10 +--------- drivers/gpio/gpio-bcm-kona.c | 10 +--------- drivers/gpio/gpio-brcmstb.c | 14 ++------------ drivers/i2c/busses/i2c-bcm-iproc.c | 14 ++------------ drivers/i2c/busses/i2c-bcm-kona.c | 14 ++------------ drivers/i2c/busses/i2c-brcmstb.c | 14 ++------------ drivers/input/keyboard/bcm-keypad.c | 14 ++------------ drivers/input/misc/gpio_decoder.c | 10 +--------- drivers/input/touchscreen/bcm_iproc_tsc.c | 9 +-------- drivers/irqchip/irq-keystone.c | 10 +--------- drivers/mailbox/bcm-flexrm-mailbox.c | 14 ++------------ drivers/media/i2c/adv7343_regs.h | 10 +--------- drivers/media/i2c/adv7393_regs.h | 10 +--------- drivers/media/platform/ti/davinci/vpif.h | 11 +---------- drivers/media/platform/ti/davinci/vpif_display.h | 10 +--------- drivers/memory/ti-emif-sram-pm.S | 10 +--------- drivers/mfd/lp873x.c | 10 +--------- drivers/mfd/tps65217.c | 10 +--------- drivers/mmc/host/sdhci-bcm-kona.c | 14 ++------------ drivers/mmc/host/sdhci-iproc.c | 14 ++------------ drivers/net/can/ti_hecc.c | 11 +---------- drivers/nvmem/bcm-ocotp.c | 14 ++------------ drivers/phy/broadcom/phy-bcm-cygnus-pcie.c | 14 ++------------ drivers/phy/broadcom/phy-bcm-ns2-pcie.c | 14 ++------------ drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c | 14 ++------------ drivers/phy/motorola/phy-cpcap-usb.c | 10 +--------- drivers/phy/ti/phy-dm816x-usb.c | 11 +---------- drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 14 ++------------ drivers/pinctrl/bcm/pinctrl-cygnus-mux.c | 14 ++------------ drivers/pinctrl/bcm/pinctrl-ns2-mux.c | 10 +--------- drivers/pinctrl/bcm/pinctrl-nsp-gpio.c | 14 ++------------ drivers/pinctrl/bcm/pinctrl-nsp-mux.c | 10 +--------- drivers/power/reset/brcm-kona-reset.c | 14 ++------------ drivers/power/reset/brcmstb-reboot.c | 14 ++------------ drivers/ptp/ptp_dte.c | 14 ++------------ drivers/pwm/pwm-bcm-iproc.c | 14 ++------------ drivers/pwm/pwm-bcm-kona.c | 14 ++------------ drivers/regulator/cpcap-regulator.c | 10 +--------- drivers/regulator/isl6271a-regulator.c | 10 +--------- drivers/regulator/tps65023-regulator.c | 10 +--------- drivers/regulator/tps6507x-regulator.c | 10 +--------- drivers/regulator/tps65217-regulator.c | 10 +--------- drivers/soc/ti/knav_dma.c | 10 +--------- drivers/uio/uio_pruss.c | 10 +--------- drivers/video/backlight/tps65217_bl.c | 10 +--------- include/dt-bindings/clock/bcm21664.h | 10 +--------- include/dt-bindings/clock/bcm281xx.h | 10 +--------- include/linux/mfd/lp873x.h | 10 +--------- include/linux/mfd/tps65217.h | 10 +--------- include/linux/platform_data/davinci_asp.h | 10 +--------- include/linux/platform_data/gpio-davinci.h | 10 +--------- include/linux/platform_data/uio_dmem_genirq.h | 10 +--------- include/linux/platform_data/uio_pruss.h | 10 +--------- include/linux/reset/bcm63xx_pmb.h | 10 +--------- include/linux/soc/ti/knav_dma.h | 10 +--------- include/linux/soc/ti/knav_qmss.h | 10 +--------- include/linux/sram.h | 14 ++------------ include/linux/ti-emif-sram.h | 10 +--------- include/linux/wkup_m3_ipc.h | 10 +--------- include/media/i2c/adv7343.h | 10 +--------- include/media/i2c/adv7393.h | 10 +--------- net/hsr/hsr_debugfs.c | 10 +--------- sound/soc/bcm/cygnus-pcm.c | 14 ++------------ sound/soc/bcm/cygnus-ssp.c | 14 ++------------ sound/soc/bcm/cygnus-ssp.h | 14 ++------------ 66 files changed, 91 insertions(+), 671 deletions(-) (limited to 'include') diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index 64239da02e74..064761289a73 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2017 Broadcom /* * Broadcom SBA RAID Driver diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 3ea8ef7f57df..4cbca80ee16e 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI EDMA DMA engine driver * * Copyright 2012 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index e84474494429..70770429ba48 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom Kona GPIO Driver * * Author: Broadcom Corporation * Copyright (C) 2012-2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 6b7439b44690..85429dd6b3b6 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2015-2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2015-2017 Broadcom #include #include diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 6304d1dd2dd6..85d8a6b04885 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index 8e350f20cde0..16bf41f1f086 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation #include #include diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index b00f35c0b066..ff63ed5ec961 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c index 166d6023a538..56a919ec23b5 100644 --- a/drivers/input/keyboard/bcm-keypad.c +++ b/drivers/input/keyboard/bcm-keypad.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c index 145826a1a9a1..ee668eba302f 100644 --- a/drivers/input/misc/gpio_decoder.c +++ b/drivers/input/misc/gpio_decoder.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * A generic driver to read multiple gpio lines and translate the * encoded numeric value into an input event. */ diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c index 7de1fd24ce36..35e2fe9911a4 100644 --- a/drivers/input/touchscreen/bcm_iproc_tsc.c +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom Corporation * -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation version 2. -* -* This program is distributed "as is" WITHOUT ANY WARRANTY of any -* kind, whether express or implied; without even the implied warranty -* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. */ #include #include diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index d47c8041e5bc..ba9792e60329 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instruments Keystone IRQ controller IP driver * * Copyright (C) 2014 Texas Instruments, Inc. * Author: Sajesh Kumar Saran * Grygorii Strashko - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c index 22acb51531cb..fda16f76401e 100644 --- a/drivers/mailbox/bcm-flexrm-mailbox.c +++ b/drivers/mailbox/bcm-flexrm-mailbox.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2017 Broadcom /* * Broadcom FlexRM Mailbox Driver diff --git a/drivers/media/i2c/adv7343_regs.h b/drivers/media/i2c/adv7343_regs.h index 2f04ce4b9118..e0357e6272e3 100644 --- a/drivers/media/i2c/adv7343_regs.h +++ b/drivers/media/i2c/adv7343_regs.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ADV7343 encoder related structure and register definitions * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ADV7343_REGS_H diff --git a/drivers/media/i2c/adv7393_regs.h b/drivers/media/i2c/adv7393_regs.h index 78968330f0be..6eb8732b5324 100644 --- a/drivers/media/i2c/adv7393_regs.h +++ b/drivers/media/i2c/adv7393_regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ADV7393 encoder related structure and register definitions * @@ -7,15 +8,6 @@ * Based on ADV7343 driver, * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ADV7393_REGS_H diff --git a/drivers/media/platform/ti/davinci/vpif.h b/drivers/media/platform/ti/davinci/vpif.h index c6d1d890478a..651943e3e375 100644 --- a/drivers/media/platform/ti/davinci/vpif.h +++ b/drivers/media/platform/ti/davinci/vpif.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * VPIF header file * * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef VPIF_H @@ -685,4 +677,3 @@ struct vpif_params { }; #endif /* End of #ifndef VPIF_H */ - diff --git a/drivers/media/platform/ti/davinci/vpif_display.h b/drivers/media/platform/ti/davinci/vpif_display.h index f98062e79167..f27474e0fc36 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.h +++ b/drivers/media/platform/ti/davinci/vpif_display.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * VPIF display header file * * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef VPIF_DISPLAY_H diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S index d1c83bd5b98e..9bcac35c3304 100644 --- a/drivers/memory/ti-emif-sram-pm.S +++ b/drivers/memory/ti-emif-sram-pm.S @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Low level PM code for TI EMIF * * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ * Dave Gerlach - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c index 858c9e0a49a4..b6166dec492d 100644 --- a/drivers/mfd/lp873x.c +++ b/drivers/mfd/lp873x.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ * * Author: Keerthy - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 8027b0a9e14f..8e8da204a02e 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65217.c * * TPS65217 chip family multi-function driver * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index 4d4aac85cc7a..61a12f2f7f03 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation #include #include diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 032bf852397f..6db35b1b8557 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation /* * iProc SDHCI platform driver diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index debe17bfd0f0..7ce26cdbeb77 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI HECC (CAN) device driver * @@ -6,16 +7,6 @@ * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2019 Jeroen Hofstee - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed as is WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/nvmem/bcm-ocotp.c b/drivers/nvmem/bcm-ocotp.c index dfea96c52463..a128c7f5e351 100644 --- a/drivers/nvmem/bcm-ocotp.c +++ b/drivers/nvmem/bcm-ocotp.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include #include diff --git a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c index 548e46776100..cc29b08e49eb 100644 --- a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2015 Broadcom Corporation #include #include diff --git a/drivers/phy/broadcom/phy-bcm-ns2-pcie.c b/drivers/phy/broadcom/phy-bcm-ns2-pcie.c index 9e7434a0d3e0..2eaa41f8fc70 100644 --- a/drivers/phy/broadcom/phy-bcm-ns2-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-ns2-pcie.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include #include diff --git a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c index 65a399acc845..36ad02c33ac5 100644 --- a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c +++ b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2017 Broadcom #include #include diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 6ee478bc5211..2f8210167b77 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Motorola CPCAP PMIC USB PHY driver * Copyright (C) 2017 Tony Lindgren @@ -5,15 +6,6 @@ * Some parts based on earlier Motorola Linux kernel tree code in * board-mapphone-usb.c and cpcap-usb-det.c: * Copyright (C) 2007 - 2011 Motorola, 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 version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c index 9fe6ea6fdae5..fb619908f912 100644 --- a/drivers/phy/ti/phy-dm816x-usb.c +++ b/drivers/phy/ti/phy-dm816x-usb.c @@ -1,13 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only #include #include diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c index 9ab1f427286a..fd52a83387ef 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013-2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013-2017 Broadcom #include #include diff --git a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c index 4344c5732400..5251460f6327 100644 --- a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c +++ b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2017 Broadcom /* * Broadcom Cygnus IOMUX driver diff --git a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c index 0fe4a1fcdf00..960e253f0be4 100644 --- a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c +++ b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c @@ -1,13 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2016 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. * * This file contains the Northstar2 IOMUX driver that supports group * based PINMUX configuration. The PWM is functional only when the diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c index 643dbd315033..3c792bf03bda 100644 --- a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c +++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2017 Broadcom /* * This file contains the Broadcom Northstar Plus (NSP) GPIO driver that diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c index f1d60a708815..db8f79920ff0 100644 --- a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c +++ b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c @@ -1,13 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. * * This file contains the Northstar plus (NSP) IOMUX driver that supports * group based PINMUX configuration. The Northstar plus IOMUX controller diff --git a/drivers/power/reset/brcm-kona-reset.c b/drivers/power/reset/brcm-kona-reset.c index 8eaa959d8be6..3de024e3ceb7 100644 --- a/drivers/power/reset/brcm-kona-reset.c +++ b/drivers/power/reset/brcm-kona-reset.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include #include diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c index 884b53c483c0..0f2944dc9355 100644 --- a/drivers/power/reset/brcmstb-reboot.c +++ b/drivers/power/reset/brcmstb-reboot.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation #include #include diff --git a/drivers/ptp/ptp_dte.c b/drivers/ptp/ptp_dte.c index 82d31ba32690..8641fd060491 100644 --- a/drivers/ptp/ptp_dte.c +++ b/drivers/ptp/ptp_dte.c @@ -1,15 +1,5 @@ -/* - * Copyright 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2017 Broadcom #include #include diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index 0226bf697f09..7251037d4dd5 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include #include diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index f171169c1c1f..4fa6e249e4cf 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index 79b3eb3222c6..b0c225d98631 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Motorola CPCAP PMIC regulator driver * @@ -6,15 +7,6 @@ * * Rewritten for mainline kernel to use device tree and regmap * Copyright (C) 2017 Tony Lindgren - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 6f28bba81d13..591a64e1ca61 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * isl6271a-regulator.c * * Support for Intersil ISL6271A voltage regulator * * Copyright (C) 2010 Marek Vasut - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #include diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index f25806531c7e..d24333344f93 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65023-regulator.c * * Supports TPS65023 Regulator * * Copyright (C) 2009 Texas Instrument Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #include diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index eafbc2bb4b57..b83816ee6867 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps6507x-regulator.c * * Regulator driver for TPS65073 PMIC * * Copyright (C) 2009 Texas Instrument Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #include diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index e88ed96f4744..6bb5b02e19e2 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65217-regulator.c * * Regulator driver for TPS65217 PMIC * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index d756591de973..84afebd355be 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments Incorporated * Authors: Santosh Shilimkar * Sandeep Nair * Cyril Chemparathy - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index e9096f53b4cc..83966dbd3bbf 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Programmable Real-Time Unit Sub System (PRUSS) UIO driver (uio_pruss) * @@ -5,15 +6,6 @@ * and DDR RAM to user space for applications interacting with PRUSS firmware * * Copyright (C) 2010-11 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 8457166f357f..d96d713fe7db 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65217_bl.c * @@ -5,15 +6,6 @@ * * Copyright (C) 2012 Matthias Kaehlcke * Author: Matthias Kaehlcke - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/include/dt-bindings/clock/bcm21664.h b/include/dt-bindings/clock/bcm21664.h index 5a7f0e4750a8..7c7492742f3d 100644 --- a/include/dt-bindings/clock/bcm21664.h +++ b/include/dt-bindings/clock/bcm21664.h @@ -1,15 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Broadcom Corporation * Copyright 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _CLOCK_BCM21664_H diff --git a/include/dt-bindings/clock/bcm281xx.h b/include/dt-bindings/clock/bcm281xx.h index a763460cf1af..d74ca42112e7 100644 --- a/include/dt-bindings/clock/bcm281xx.h +++ b/include/dt-bindings/clock/bcm281xx.h @@ -1,15 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Broadcom Corporation * Copyright 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _CLOCK_BCM281XX_H diff --git a/include/linux/mfd/lp873x.h b/include/linux/mfd/lp873x.h index 5546688c7da7..fe8174cc8637 100644 --- a/include/linux/mfd/lp873x.h +++ b/include/linux/mfd/lp873x.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Functions to access LP873X power management chip. * * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_MFD_LP873X_H diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index db7091824ed0..877d9c41c53d 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/mfd/tps65217.h * * Functions to access TPS65217 power management chip. * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_MFD_TPS65217_H diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 76b13ef67562..c8645b2ed3c0 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI DaVinci Audio Serial Port support * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DAVINCI_ASP_H diff --git a/include/linux/platform_data/gpio-davinci.h b/include/linux/platform_data/gpio-davinci.h index e182a46e609f..b82e44662efe 100644 --- a/include/linux/platform_data/gpio-davinci.h +++ b/include/linux/platform_data/gpio-davinci.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * DaVinci GPIO Platform Related Defines * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DAVINCI_GPIO_PLATFORM_H diff --git a/include/linux/platform_data/uio_dmem_genirq.h b/include/linux/platform_data/uio_dmem_genirq.h index 973c1bb32168..c8f6de685306 100644 --- a/include/linux/platform_data/uio_dmem_genirq.h +++ b/include/linux/platform_data/uio_dmem_genirq.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * include/linux/platform_data/uio_dmem_genirq.h * * Copyright (C) 2012 Damian Hobson-Garcia - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _UIO_DMEM_GENIRQ_H diff --git a/include/linux/platform_data/uio_pruss.h b/include/linux/platform_data/uio_pruss.h index 31f2e22661bc..f76fa393b802 100644 --- a/include/linux/platform_data/uio_pruss.h +++ b/include/linux/platform_data/uio_pruss.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * include/linux/platform_data/uio_pruss.h * * Platform data for uio_pruss driver * * Copyright (C) 2010-11 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _UIO_PRUSS_H_ diff --git a/include/linux/reset/bcm63xx_pmb.h b/include/linux/reset/bcm63xx_pmb.h index bb4af7b5eb36..c77b6999518a 100644 --- a/include/linux/reset/bcm63xx_pmb.h +++ b/include/linux/reset/bcm63xx_pmb.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Broadcom BCM63xx Processor Monitor Bus shared routines (SMP and reset) * * Copyright (C) 2015, Broadcom Corporation * Author: Florian Fainelli - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __BCM63XX_PMB_H #define __BCM63XX_PMB_H diff --git a/include/linux/soc/ti/knav_dma.h b/include/linux/soc/ti/knav_dma.h index 7127ec301537..18d806a8e52c 100644 --- a/include/linux/soc/ti/knav_dma.h +++ b/include/linux/soc/ti/knav_dma.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2014 Texas Instruments Incorporated * Authors: Sandeep Nair - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __SOC_TI_KEYSTONE_NAVIGATOR_DMA_H__ diff --git a/include/linux/soc/ti/knav_qmss.h b/include/linux/soc/ti/knav_qmss.h index c75ef99c99ca..175f466ebcc3 100644 --- a/include/linux/soc/ti/knav_qmss.h +++ b/include/linux/soc/ti/knav_qmss.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Keystone Navigator Queue Management Sub-System header * @@ -5,15 +6,6 @@ * Author: Sandeep Nair * Cyril Chemparathy * Santosh Shilimkar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __SOC_TI_KNAV_QMSS_H__ diff --git a/include/linux/sram.h b/include/linux/sram.h index 4fb405fb0480..d7dee19505c6 100644 --- a/include/linux/sram.h +++ b/include/linux/sram.h @@ -1,15 +1,5 @@ -/* - * Generic SRAM Driver Interface - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Generic SRAM Driver Interface */ #ifndef __LINUX_SRAM_H__ #define __LINUX_SRAM_H__ diff --git a/include/linux/ti-emif-sram.h b/include/linux/ti-emif-sram.h index 2fc854155c27..441b2988e66a 100644 --- a/include/linux/ti-emif-sram.h +++ b/include/linux/ti-emif-sram.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI AM33XX EMIF Routines * * Copyright (C) 2016-2017 Texas Instruments Inc. * Dave Gerlach - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_TI_EMIF_H #define __LINUX_TI_EMIF_H diff --git a/include/linux/wkup_m3_ipc.h b/include/linux/wkup_m3_ipc.h index 26d1eb058fa3..5e1b26f988e2 100644 --- a/include/linux/wkup_m3_ipc.h +++ b/include/linux/wkup_m3_ipc.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI Wakeup M3 for AMx3 SoCs Power Management Routines * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Dave Gerlach - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _LINUX_WKUP_M3_IPC_H diff --git a/include/media/i2c/adv7343.h b/include/media/i2c/adv7343.h index b8937035c5d3..d35d3e925795 100644 --- a/include/media/i2c/adv7343.h +++ b/include/media/i2c/adv7343.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ADV7343 header file * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ADV7343_H diff --git a/include/media/i2c/adv7393.h b/include/media/i2c/adv7393.h index b28edf351842..c73b36321d06 100644 --- a/include/media/i2c/adv7393.h +++ b/include/media/i2c/adv7393.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ADV7393 header file * @@ -7,15 +8,6 @@ * Based on ADV7343 driver, * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ADV7393_H diff --git a/net/hsr/hsr_debugfs.c b/net/hsr/hsr_debugfs.c index fe6094e9a2db..de476a417631 100644 --- a/net/hsr/hsr_debugfs.c +++ b/net/hsr/hsr_debugfs.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * debugfs code for HSR & PRP * Copyright (C) 2019 Texas Instruments Incorporated * * Author(s): * Murali Karicheri - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c index 3abeaf0f1b1c..8f488f92936b 100644 --- a/sound/soc/bcm/cygnus-pcm.c +++ b/sound/soc/bcm/cygnus-pcm.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2015 Broadcom Corporation #include #include #include diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 9698f4531c90..b0254e724ec9 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2015 Broadcom Corporation #include #include #include diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h index 33dd34305928..74152b2d770d 100644 --- a/sound/soc/bcm/cygnus-ssp.h +++ b/sound/soc/bcm/cygnus-ssp.h @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2014-2015 Broadcom Corporation */ #ifndef __CYGNUS_SSP_H__ #define __CYGNUS_SSP_H__ -- cgit v1.2.3 From 94c0ded75c85201bfb8fce95dab44cc53addfcb5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:18 +0200 Subject: treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_133.RULE Based on the normalized pattern: 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 merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/mediatek/mt6755.dtsi | 9 +-------- arch/arm64/boot/dts/mediatek/mt6795.dtsi | 9 +-------- arch/arm64/boot/dts/mediatek/mt8173.dtsi | 9 +-------- include/dt-bindings/power/mt6797-power.h | 9 +-------- 4 files changed, 4 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/arch/arm64/boot/dts/mediatek/mt6755.dtsi b/arch/arm64/boot/dts/mediatek/mt6755.dtsi index 01ba77669717..b55d3fac9bd4 100644 --- a/arch/arm64/boot/dts/mediatek/mt6755.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt6755.dtsi @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016 MediaTek Inc. * Author: Mars.C - * - * 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, - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi index c85659d0ff5d..1413f32c70af 100644 --- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015 MediaTek Inc. * Author: Mars.C - * - * 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, - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi index 40d7b47fc52e..e14b6e68c4df 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 MediaTek Inc. * Author: Eddie Huang - * - * 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, - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/include/dt-bindings/power/mt6797-power.h b/include/dt-bindings/power/mt6797-power.h index a60c1d81cf75..bd451d860e6a 100644 --- a/include/dt-bindings/power/mt6797-power.h +++ b/include/dt-bindings/power/mt6797-power.h @@ -1,14 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017 MediaTek Inc. * Author: Mars.C - * - * 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, - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DT_BINDINGS_POWER_MT6797_POWER_H -- cgit v1.2.3 From 1accad5e74635d7f9d994e692649fbe736afe150 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:20 +0200 Subject: treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_149.RULE Based on the normalized pattern: netapp provides this source code under the gpl v2 license the gpl v2 license is available at https://opensource org/licenses/gpl-license php this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall the copyright owner or contributors be liable for any direct indirect incidental special exemplary or consequential damages (including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption) however caused and on any theory of liability whether in contract strict liability or tort (including negligence or otherwise) arising in any way out of the use of this software even if advised of the possibility of such damage extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- include/linux/sunrpc/bc_xprt.h | 17 +---------------- net/sunrpc/backchannel_rqst.c | 16 +--------------- net/sunrpc/sunrpc.h | 16 +--------------- 3 files changed, 3 insertions(+), 46 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h index f07c334c599f..db30a159f9d5 100644 --- a/include/linux/sunrpc/bc_xprt.h +++ b/include/linux/sunrpc/bc_xprt.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /****************************************************************************** (c) 2008 NetApp. All Rights Reserved. -NetApp provides this source code under the GPL v2 License. -The GPL v2 license is available at -https://opensource.org/licenses/gpl-license.php. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ @@ -83,4 +69,3 @@ static inline void xprt_free_bc_request(struct rpc_rqst *req) } #endif /* CONFIG_SUNRPC_BACKCHANNEL */ #endif /* _LINUX_SUNRPC_BC_XPRT_H */ - diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 5a6b61dcdf2d..253a54c2fcfe 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -1,23 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** (c) 2007 Network Appliance, Inc. All Rights Reserved. (c) 2009 NetApp. All Rights Reserved. -NetApp provides this source code under the GPL v2 License. -The GPL v2 license is available at -https://opensource.org/licenses/gpl-license.php. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index 2f59464e6524..d4a362c9e4b3 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /****************************************************************************** (c) 2008 NetApp. All Rights Reserved. -NetApp provides this source code under the GPL v2 License. -The GPL v2 license is available at -https://opensource.org/licenses/gpl-license.php. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -- cgit v1.2.3 From 298b95f111be85f2d5a18dc0177eb9a64130f9b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:21 +0200 Subject: treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_152.RULE Based on the normalized pattern: this software is distributed under the terms of the gnu general public license ( gpl ) version 2 as published by the free software foundation this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall the copyright owner or contributors be liable for any direct indirect incidental special exemplary or consequential damages (including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption) however caused and on any theory of liability whether in contract strict liability or tort (including negligence or otherwise) arising in any way out of the use of this software even if advised of the possibility of such damage extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- include/linux/platform_data/usb-omap.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'include') diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h index 5e70d667031c..580978e468f8 100644 --- a/include/linux/platform_data/usb-omap.h +++ b/include/linux/platform_data/usb-omap.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * usb-omap.h - Platform data for the various OMAP USB IPs * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com - * - * This software is distributed under the terms of the GNU General Public - * License ("GPL") version 2, as published by the Free Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. */ #define OMAP3_HS_USB_PORTS 3 -- cgit v1.2.3 From dfb99b050e4bc5bfb74973761752395d82644e48 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:25 +0200 Subject: treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_168.RULE (part 2) Based on the normalized pattern: 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/snic/snic_attrs.c | 18 ++---------------- drivers/scsi/snic/snic_ctl.c | 18 ++---------------- drivers/scsi/snic/snic_debugfs.c | 18 ++---------------- drivers/scsi/snic/snic_disc.c | 18 ++---------------- drivers/scsi/snic/snic_disc.h | 18 ++---------------- drivers/scsi/snic/snic_fwint.h | 18 ++---------------- drivers/scsi/snic/snic_io.c | 18 ++---------------- drivers/scsi/snic/snic_io.h | 18 ++---------------- drivers/scsi/snic/snic_isr.c | 18 ++---------------- drivers/scsi/snic/snic_main.c | 18 ++---------------- drivers/scsi/snic/snic_res.c | 18 ++---------------- drivers/scsi/snic/snic_res.h | 18 ++---------------- drivers/scsi/snic/snic_scsi.c | 18 ++---------------- drivers/scsi/snic/snic_stats.h | 18 ++---------------- drivers/scsi/snic/snic_trc.c | 18 ++---------------- drivers/scsi/snic/snic_trc.h | 18 ++---------------- drivers/scsi/snic/vnic_cq.c | 18 ++---------------- drivers/scsi/snic/vnic_cq.h | 18 ++---------------- drivers/scsi/snic/vnic_cq_fw.h | 18 ++---------------- drivers/scsi/snic/vnic_dev.c | 18 ++---------------- drivers/scsi/snic/vnic_dev.h | 18 ++---------------- drivers/scsi/snic/vnic_devcmd.h | 18 ++---------------- drivers/scsi/snic/vnic_intr.c | 18 ++---------------- drivers/scsi/snic/vnic_intr.h | 18 ++---------------- drivers/scsi/snic/vnic_resource.h | 18 ++---------------- drivers/scsi/snic/vnic_snic.h | 18 ++---------------- drivers/scsi/snic/vnic_stats.h | 18 ++---------------- drivers/scsi/snic/vnic_wq.c | 18 ++---------------- drivers/scsi/snic/vnic_wq.h | 18 ++---------------- drivers/scsi/snic/wq_enet_desc.h | 18 ++---------------- include/media/i2c/ov2659.h | 14 +------------- samples/v4l/v4l2-pci-skeleton.c | 14 +------------- 32 files changed, 62 insertions(+), 506 deletions(-) (limited to 'include') diff --git a/drivers/scsi/snic/snic_attrs.c b/drivers/scsi/snic/snic_attrs.c index dc03ce1ec909..3ddbdbc3ded1 100644 --- a/drivers/scsi/snic/snic_attrs.c +++ b/drivers/scsi/snic/snic_attrs.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_ctl.c b/drivers/scsi/snic/snic_ctl.c index 703f229862fc..5f4fca96b192 100644 --- a/drivers/scsi/snic/snic_ctl.c +++ b/drivers/scsi/snic/snic_ctl.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_debugfs.c b/drivers/scsi/snic/snic_debugfs.c index 5e0faeba516e..57bdc3ba49d9 100644 --- a/drivers/scsi/snic/snic_debugfs.c +++ b/drivers/scsi/snic/snic_debugfs.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c index 27e98df83b31..9b2b5f8c23b9 100644 --- a/drivers/scsi/snic/snic_disc.c +++ b/drivers/scsi/snic/snic_disc.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_disc.h b/drivers/scsi/snic/snic_disc.h index 97fa3f5c5bb4..9ad7f84a3484 100644 --- a/drivers/scsi/snic/snic_disc.h +++ b/drivers/scsi/snic/snic_disc.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_DISC_H #define __SNIC_DISC_H diff --git a/drivers/scsi/snic/snic_fwint.h b/drivers/scsi/snic/snic_fwint.h index 2a045a57e365..e6b3e8b431c0 100644 --- a/drivers/scsi/snic/snic_fwint.h +++ b/drivers/scsi/snic/snic_fwint.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_FWINT_H #define __SNIC_FWINT_H diff --git a/drivers/scsi/snic/snic_io.c b/drivers/scsi/snic/snic_io.c index 159ee94d2a55..32a77bee41d5 100644 --- a/drivers/scsi/snic/snic_io.c +++ b/drivers/scsi/snic/snic_io.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_io.h b/drivers/scsi/snic/snic_io.h index 093d6524cd42..de6694a24c5f 100644 --- a/drivers/scsi/snic/snic_io.h +++ b/drivers/scsi/snic/snic_io.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _SNIC_IO_H #define _SNIC_IO_H diff --git a/drivers/scsi/snic/snic_isr.c b/drivers/scsi/snic/snic_isr.c index c4da3673f2ae..471a37422da9 100644 --- a/drivers/scsi/snic/snic_isr.c +++ b/drivers/scsi/snic/snic_isr.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c index 29d56396058c..174f7811fe50 100644 --- a/drivers/scsi/snic/snic_main.c +++ b/drivers/scsi/snic/snic_main.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_res.c b/drivers/scsi/snic/snic_res.c index b54912c8ca0c..43f1a2823514 100644 --- a/drivers/scsi/snic/snic_res.c +++ b/drivers/scsi/snic/snic_res.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_res.h b/drivers/scsi/snic/snic_res.h index 273f72f2a023..53cf6b19ab28 100644 --- a/drivers/scsi/snic/snic_res.h +++ b/drivers/scsi/snic/snic_res.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_RES_H #define __SNIC_RES_H diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c index 5f17666f3e1d..961af6fc21bc 100644 --- a/drivers/scsi/snic/snic_scsi.c +++ b/drivers/scsi/snic/snic_scsi.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_stats.h b/drivers/scsi/snic/snic_stats.h index faf0cb601954..f0285c5a35f8 100644 --- a/drivers/scsi/snic/snic_stats.h +++ b/drivers/scsi/snic/snic_stats.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_STATS_H #define __SNIC_STATS_H diff --git a/drivers/scsi/snic/snic_trc.c b/drivers/scsi/snic/snic_trc.c index f23fe2f88438..c2e5ab7e976c 100644 --- a/drivers/scsi/snic/snic_trc.c +++ b/drivers/scsi/snic/snic_trc.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_trc.h b/drivers/scsi/snic/snic_trc.h index ce305b4b8fa2..c38e0dadc958 100644 --- a/drivers/scsi/snic/snic_trc.h +++ b/drivers/scsi/snic/snic_trc.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_TRC_H #define __SNIC_TRC_H diff --git a/drivers/scsi/snic/vnic_cq.c b/drivers/scsi/snic/vnic_cq.c index 3455dd7e73f4..0d5d3bd4be1c 100644 --- a/drivers/scsi/snic/vnic_cq.c +++ b/drivers/scsi/snic/vnic_cq.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/vnic_cq.h b/drivers/scsi/snic/vnic_cq.h index 6e651c3e16f7..6cee911eec5f 100644 --- a/drivers/scsi/snic/vnic_cq.h +++ b/drivers/scsi/snic/vnic_cq.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_CQ_H_ #define _VNIC_CQ_H_ diff --git a/drivers/scsi/snic/vnic_cq_fw.h b/drivers/scsi/snic/vnic_cq_fw.h index c2d1bbd44bd1..d74954bc70e3 100644 --- a/drivers/scsi/snic/vnic_cq_fw.h +++ b/drivers/scsi/snic/vnic_cq_fw.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_CQ_FW_H_ #define _VNIC_CQ_FW_H_ diff --git a/drivers/scsi/snic/vnic_dev.c b/drivers/scsi/snic/vnic_dev.c index 05e374f80946..760f3f22095c 100644 --- a/drivers/scsi/snic/vnic_dev.c +++ b/drivers/scsi/snic/vnic_dev.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/vnic_dev.h b/drivers/scsi/snic/vnic_dev.h index e65726da6504..d2f9b6f7b313 100644 --- a/drivers/scsi/snic/vnic_dev.h +++ b/drivers/scsi/snic/vnic_dev.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_DEV_H_ #define _VNIC_DEV_H_ diff --git a/drivers/scsi/snic/vnic_devcmd.h b/drivers/scsi/snic/vnic_devcmd.h index 0e0fa38f8d90..9d82fcb7414b 100644 --- a/drivers/scsi/snic/vnic_devcmd.h +++ b/drivers/scsi/snic/vnic_devcmd.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_DEVCMD_H_ #define _VNIC_DEVCMD_H_ diff --git a/drivers/scsi/snic/vnic_intr.c b/drivers/scsi/snic/vnic_intr.c index a7d54806787d..23627f9591f2 100644 --- a/drivers/scsi/snic/vnic_intr.c +++ b/drivers/scsi/snic/vnic_intr.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/vnic_intr.h b/drivers/scsi/snic/vnic_intr.h index 4547f603fe5e..7bff60fafb07 100644 --- a/drivers/scsi/snic/vnic_intr.h +++ b/drivers/scsi/snic/vnic_intr.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_INTR_H_ #define _VNIC_INTR_H_ diff --git a/drivers/scsi/snic/vnic_resource.h b/drivers/scsi/snic/vnic_resource.h index 9713d6835db3..372596b0915f 100644 --- a/drivers/scsi/snic/vnic_resource.h +++ b/drivers/scsi/snic/vnic_resource.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_RESOURCE_H_ #define _VNIC_RESOURCE_H_ diff --git a/drivers/scsi/snic/vnic_snic.h b/drivers/scsi/snic/vnic_snic.h index 514d39f5cf00..ffc8a0fee577 100644 --- a/drivers/scsi/snic/vnic_snic.h +++ b/drivers/scsi/snic/vnic_snic.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_SNIC_H_ #define _VNIC_SNIC_H_ diff --git a/drivers/scsi/snic/vnic_stats.h b/drivers/scsi/snic/vnic_stats.h index 370a37c97748..38155aae7a52 100644 --- a/drivers/scsi/snic/vnic_stats.h +++ b/drivers/scsi/snic/vnic_stats.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_STATS_H_ #define _VNIC_STATS_H_ diff --git a/drivers/scsi/snic/vnic_wq.c b/drivers/scsi/snic/vnic_wq.c index 1e91d432089e..48be9a3f4c3d 100644 --- a/drivers/scsi/snic/vnic_wq.c +++ b/drivers/scsi/snic/vnic_wq.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/vnic_wq.h b/drivers/scsi/snic/vnic_wq.h index 7cc031c7ceba..1415da4b68dc 100644 --- a/drivers/scsi/snic/vnic_wq.h +++ b/drivers/scsi/snic/vnic_wq.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_WQ_H_ #define _VNIC_WQ_H_ diff --git a/drivers/scsi/snic/wq_enet_desc.h b/drivers/scsi/snic/wq_enet_desc.h index 68f62b6d105b..e8025331b503 100644 --- a/drivers/scsi/snic/wq_enet_desc.h +++ b/drivers/scsi/snic/wq_enet_desc.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _WQ_ENET_DESC_H_ #define _WQ_ENET_DESC_H_ diff --git a/include/media/i2c/ov2659.h b/include/media/i2c/ov2659.h index 4216adc1ede2..c9ea318a8fc3 100644 --- a/include/media/i2c/ov2659.h +++ b/include/media/i2c/ov2659.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Omnivision OV2659 CMOS Image Sensor driver * @@ -5,19 +6,6 @@ * * Benoit Parrot * Lad, Prabhakar - * - * 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. */ #ifndef OV2659_H diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index 6311b7465220..a61f94db18d9 100644 --- a/samples/v4l/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * This is a V4L2 PCI Skeleton Driver. It gives an initial skeleton source * for use with other PCI drivers. @@ -6,19 +7,6 @@ * input 0 and an HDMI connector as input 1. * * Copyright 2014 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. */ #include -- cgit v1.2.3 From abd462747539bbc630e50e8be59e3aebca63441d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:31 +0200 Subject: treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_319.RULE Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed as is without any warranty of any kind whether expressed or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license version 2 for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-lp873x.c | 10 +--------- drivers/gpio/gpio-lp87565.c | 10 +--------- drivers/gpio/gpio-pisosr.c | 10 +--------- drivers/gpio/gpio-tpic2810.c | 10 +--------- drivers/mfd/tps65086.c | 10 +--------- drivers/mfd/tps65218.c | 10 +--------- drivers/mfd/tps65912-core.c | 10 +--------- drivers/mfd/tps65912-i2c.c | 10 +--------- drivers/mfd/tps65912-spi.c | 10 +--------- drivers/regulator/lp873x-regulator.c | 10 +--------- drivers/regulator/tps65086-regulator.c | 10 +--------- drivers/regulator/tps65218-regulator.c | 10 +--------- drivers/regulator/tps65912-regulator.c | 10 +--------- include/linux/mfd/tps65086.h | 10 +--------- include/linux/mfd/tps65218.h | 10 +--------- include/linux/mfd/tps65912.h | 10 +--------- 16 files changed, 16 insertions(+), 144 deletions(-) (limited to 'include') diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c index 70fad87ff2db..5c79ba1f229c 100644 --- a/drivers/gpio/gpio-lp873x.c +++ b/drivers/gpio/gpio-lp873x.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * Keerthy * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver */ diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c index fcde6708b5df..d3ce027de081 100644 --- a/drivers/gpio/gpio-lp87565.c +++ b/drivers/gpio/gpio-lp87565.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ * Keerthy * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the LP873X driver */ diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c index 81a47ae09ff8..67071bea08c2 100644 --- a/drivers/gpio/gpio-pisosr.c +++ b/drivers/gpio/gpio-pisosr.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c index 99d5a84a9129..a09b1e69b072 100644 --- a/drivers/gpio/gpio-tpic2810.c +++ b/drivers/gpio/gpio-tpic2810.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c index 3bd5728844a0..cbae9777a24e 100644 --- a/drivers/mfd/tps65086.c +++ b/drivers/mfd/tps65086.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65912 driver */ diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index 167e9fc308ef..49bb8fd168f8 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for TPS65218 Integrated power management chipsets * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index c282a05e7146..7d994b8a5965 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Core functions for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index 06eb2784d322..afb7f7d97dc0 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C access driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index bba38fbc781d..9e976f9c6bbe 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI access driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c index c38387e0fbb2..d6e597922cb5 100644 --- a/drivers/regulator/lp873x-regulator.c +++ b/drivers/regulator/lp873x-regulator.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator driver for LP873X PMIC * * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c index 070c956216b0..f1bc54c825dd 100644 --- a/drivers/regulator/tps65086-regulator.c +++ b/drivers/regulator/tps65086-regulator.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * * Author: Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65912 driver */ diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index fa263545a70e..48809c3b3abc 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65218-regulator.c * * Regulator driver for TPS65218 PMIC * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index b52d4f2874b7..76f90202ae09 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ diff --git a/include/linux/mfd/tps65086.h b/include/linux/mfd/tps65086.h index e0a417e53766..16f87cccc003 100644 --- a/include/linux/mfd/tps65086.h +++ b/include/linux/mfd/tps65086.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65912 driver */ diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h index 122e24ddbd4b..2946be2f15f3 100644 --- a/include/linux/mfd/tps65218.h +++ b/include/linux/mfd/tps65218.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/mfd/tps65218.h * * Functions to access TPS65218 power management chip. * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #ifndef __LINUX_MFD_TPS65218_H diff --git a/include/linux/mfd/tps65912.h b/include/linux/mfd/tps65912.h index 8a61386cb8c1..860ec0a16c96 100644 --- a/include/linux/mfd/tps65912.h +++ b/include/linux/mfd/tps65912.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ -- cgit v1.2.3 From 5a729246e57eac410e4a13f5aba66ae2dc552632 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:32 +0200 Subject: treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_320.RULE Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed as is without any warranty of any kind whether express or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap1/timer.c | 10 +--------- arch/arm/mach-omap2/display.c | 10 +--------- arch/arm/mach-omap2/omap_opp_data.h | 10 +--------- arch/arm/mach-omap2/opp3xxx_data.c | 10 +--------- arch/arm/mach-omap2/opp4xxx_data.c | 10 +--------- arch/arm/mach-versatile/spc.c | 10 +--------- drivers/bus/omap_l3_noc.c | 10 +--------- drivers/bus/omap_l3_noc.h | 10 +--------- drivers/clk/keystone/sci-clk.c | 10 +--------- drivers/clk/ti/apll.c | 10 +--------- drivers/clk/ti/autoidle.c | 10 +--------- drivers/clk/ti/clk-dra7-atl.c | 10 +--------- drivers/clk/ti/clk.c | 10 +--------- drivers/clk/ti/clkctrl.c | 10 +--------- drivers/clk/ti/clkt_dflt.c | 10 +--------- drivers/clk/ti/clockdomain.c | 10 +--------- drivers/clk/ti/composite.c | 10 +--------- drivers/clk/ti/divider.c | 10 +--------- drivers/clk/ti/dpll.c | 10 +--------- drivers/clk/ti/fixed-factor.c | 10 +--------- drivers/clk/ti/gate.c | 10 +--------- drivers/clk/ti/interface.c | 10 +--------- drivers/clk/ti/mux.c | 10 +--------- drivers/cpufreq/scpi-cpufreq.c | 10 +--------- drivers/input/misc/palmas-pwrbutton.c | 10 +--------- drivers/input/misc/tps65218-pwrbutton.c | 10 +--------- drivers/misc/sram-exec.c | 10 +--------- drivers/power/supply/cpcap-battery.c | 10 +--------- drivers/regulator/ti-abb-regulator.c | 10 +--------- drivers/reset/reset-ti-sci.c | 10 +--------- drivers/reset/reset-ti-syscon.c | 10 +--------- drivers/thermal/hisi_thermal.c | 10 +--------- include/dt-bindings/clock/ti-dra7-atl.h | 10 +--------- include/dt-bindings/pinctrl/hisi.h | 10 +--------- include/dt-bindings/pinctrl/keystone.h | 10 +--------- include/linux/clk/ti.h | 10 +--------- include/linux/pm_wakeirq.h | 14 ++------------ include/linux/soc/ti/ti-msgmgr.h | 10 +--------- 38 files changed, 39 insertions(+), 345 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c index 9ed64345f06e..f5cd4bbf7566 100644 --- a/arch/arm/mach-omap1/timer.c +++ b/arch/arm/mach-omap1/timer.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP1 Dual-Mode Timers - platform device registration * @@ -9,15 +10,6 @@ * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ * Tarun Kanti DebBarma * Thara Gopinath - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 21413a9b7b6c..47149b278ad5 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP2plus display device setup / initialization. * * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ * Senthilvadivu Guruswamy * Sumit Semwal - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/omap_opp_data.h b/arch/arm/mach-omap2/omap_opp_data.h index 533dd643069a..88375ab38e31 100644 --- a/arch/arm/mach-omap2/omap_opp_data.h +++ b/arch/arm/mach-omap2/omap_opp_data.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * OMAP SoC specific OPP Data helpers * @@ -6,15 +7,6 @@ * Kevin Hilman * Copyright (C) 2010 Nokia Corporation. * Eduardo Valentin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H #define __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c index b610c5fb423b..90257e2fb3d6 100644 --- a/arch/arm/mach-omap2/opp3xxx_data.c +++ b/arch/arm/mach-omap2/opp3xxx_data.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP3 OPP table definitions. * @@ -7,15 +8,6 @@ * Copyright (C) 2010-2011 Nokia Corporation. * Eduardo Valentin * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c index d937c5ef41c6..a9851886017d 100644 --- a/arch/arm/mach-omap2/opp4xxx_data.c +++ b/arch/arm/mach-omap2/opp4xxx_data.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP4 OPP table definitions. * @@ -8,15 +9,6 @@ * Copyright (C) 2010-2011 Nokia Corporation. * Eduardo Valentin * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-versatile/spc.c b/arch/arm/mach-versatile/spc.c index 6e6985e756af..5e44170e1a9a 100644 --- a/arch/arm/mach-versatile/spc.c +++ b/arch/arm/mach-versatile/spc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Versatile Express Serial Power Controller (SPC) support * @@ -6,15 +7,6 @@ * Authors: Sudeep KarkadaNagesha * Achin Gupta * Lorenzo Pieralisi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index dcfb32ee5cb6..eb1ba6319fda 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP L3 Interconnect error handling driver * * Copyright (C) 2011-2015 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar * Sricharan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 73431f81da28..bb3eebd3465d 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * OMAP L3 Interconnect error handling driver header * * Copyright (C) 2011-2015 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar * sricharan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __OMAP_L3_NOC_H #define __OMAP_L3_NOC_H diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index 7e1b136e71ae..d4b4e74e22da 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCI Clock driver for keystone based devices * * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index e4db6b9a55c6..dd0709c9c249 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP APLL clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * J Keerthy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index d6e5f1511ace..27e6b9cb1881 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI clock autoidle support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index aa0950c4f498..f0f5bf68b6d2 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DRA7 ATL (Audio Tracking Logic) clock driver * * Copyright (C) 2013 Texas Instruments, Inc. * * Peter Ujfalusi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 3463579220b5..ef2a445c63a3 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c index 617360e20d86..3b5ebae3740f 100644 --- a/drivers/clk/ti/clkctrl.c +++ b/drivers/clk/ti/clkctrl.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP clkctrl clock support * * Copyright (C) 2017 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clkt_dflt.c b/drivers/clk/ti/clkt_dflt.c index 91751dd26b16..a756ab1a5856 100644 --- a/drivers/clk/ti/clkt_dflt.c +++ b/drivers/clk/ti/clkt_dflt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Default clock type * @@ -8,15 +9,6 @@ * Richard Woodruff * Paul Walmsley * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index 24179c907774..c897ad7e681e 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP clockdomain support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c index 779b9900f636..77b771dd050a 100644 --- a/drivers/clk/ti/composite.c +++ b/drivers/clk/ti/composite.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI composite clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 9fbea0997b43..488d3da60c31 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI Divider Clock * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 7c6dc8449b22..8ed43bc6b7cc 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP DPLL clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c index 8cb00d0af966..c80cee0f5d3d 100644 --- a/drivers/clk/ti/fixed-factor.c +++ b/drivers/clk/ti/fixed-factor.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI Fixed Factor Clock * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c index 0033de9beb4c..307702921431 100644 --- a/drivers/clk/ti/gate.c +++ b/drivers/clk/ti/gate.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP gate clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c index dd2b455183a9..f47beeea211e 100644 --- a/drivers/clk/ti/interface.c +++ b/drivers/clk/ti/interface.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP interface clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index 15de513d2d81..46b45b3e8319 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI Multiplexer Clock * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index bda3e7d42964..fd2c16821d54 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * System Control and Power Interface (SCPI) based CPUFreq Interface driver * * Copyright (C) 2015 ARM Ltd. * Sudeep Holla - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c index 2213e06b611d..465e6693077a 100644 --- a/drivers/input/misc/palmas-pwrbutton.c +++ b/drivers/input/misc/palmas-pwrbutton.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instruments' Palmas Power Button Input Driver * * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/ * Girish S Ghongdemath * Nishanth Menon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c index f011447c44fb..fc450fce0932 100644 --- a/drivers/input/misc/tps65218-pwrbutton.c +++ b/drivers/input/misc/tps65218-pwrbutton.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instruments' TPS65217 and TPS65218 Power Button Input Driver * * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ * Author: Felipe Balbi * Author: Marcin Niestroj - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/misc/sram-exec.c b/drivers/misc/sram-exec.c index 6cc31789b38d..a948e95d4375 100644 --- a/drivers/misc/sram-exec.c +++ b/drivers/misc/sram-exec.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SRAM protect-exec region helper functions * * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ * Dave Gerlach - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index ae284bdd6cc3..d98d9244e394 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery driver for CPCAP PMIC * @@ -7,15 +8,6 @@ * drivers: * * Copyright (C) 2009-2010 Motorola, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index bd7b2f287250..cf18452386ca 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instruments SoC Adaptive Body Bias(ABB) Regulator * @@ -7,15 +8,6 @@ * Copyright (C) 2012-2013 Texas Instruments, Inc. * Andrii Tseglytskyi * Nishanth Menon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/reset/reset-ti-sci.c b/drivers/reset/reset-ti-sci.c index b799aefad547..cc01fa5b0bea 100644 --- a/drivers/reset/reset-ti-sci.c +++ b/drivers/reset/reset-ti-sci.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instrument's System Control Interface (TI-SCI) reset driver * * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c index 2b92775d58f0..f0dd7ffc3b72 100644 --- a/drivers/reset/reset-ti-syscon.c +++ b/drivers/reset/reset-ti-syscon.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI SYSCON regmap reset driver * * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * Suman Anna - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index b29ab09040d5..19a242c69ce6 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HiSilicon thermal sensor driver * @@ -6,15 +7,6 @@ * * Xinwei Kong * Leo Yan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/include/dt-bindings/clock/ti-dra7-atl.h b/include/dt-bindings/clock/ti-dra7-atl.h index 42dd4164f6f4..b0e71e3cce95 100644 --- a/include/dt-bindings/clock/ti-dra7-atl.h +++ b/include/dt-bindings/clock/ti-dra7-atl.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This header provides constants for DRA7 ATL (Audio Tracking Logic) * @@ -6,15 +7,6 @@ * Copyright (C) 2013 Texas Instruments, Inc. * * Peter Ujfalusi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DT_BINDINGS_CLK_DRA7_ATL_H diff --git a/include/dt-bindings/pinctrl/hisi.h b/include/dt-bindings/pinctrl/hisi.h index 93064c750c8c..2175ec89c82f 100644 --- a/include/dt-bindings/pinctrl/hisi.h +++ b/include/dt-bindings/pinctrl/hisi.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This header provides constants for hisilicon pinctrl bindings. * * Copyright (c) 2015 HiSilicon Limited. * Copyright (c) 2015 Linaro Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DT_BINDINGS_PINCTRL_HISI_H diff --git a/include/dt-bindings/pinctrl/keystone.h b/include/dt-bindings/pinctrl/keystone.h index 7f97d776a8ff..66f8aecada53 100644 --- a/include/dt-bindings/pinctrl/keystone.h +++ b/include/dt-bindings/pinctrl/keystone.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This header provides constants for Keystone pinctrl bindings. * * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DT_BINDINGS_PINCTRL_KEYSTONE_H diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 3486f20a3753..cbfcbf186ce3 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI clock drivers support * * Copyright (C) 2013 Texas Instruments, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_CLK_TI_H__ #define __LINUX_CLK_TI_H__ diff --git a/include/linux/pm_wakeirq.h b/include/linux/pm_wakeirq.h index e63a63aa47a3..dd42d16945d0 100644 --- a/include/linux/pm_wakeirq.h +++ b/include/linux/pm_wakeirq.h @@ -1,15 +1,5 @@ -/* - * pm_wakeirq.h - Device wakeirq helper functions - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* pm_wakeirq.h - Device wakeirq helper functions */ #ifndef _LINUX_PM_WAKEIRQ_H #define _LINUX_PM_WAKEIRQ_H diff --git a/include/linux/soc/ti/ti-msgmgr.h b/include/linux/soc/ti/ti-msgmgr.h index 69a8d7682c4b..543da257a5f2 100644 --- a/include/linux/soc/ti/ti-msgmgr.h +++ b/include/linux/soc/ti/ti-msgmgr.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Texas Instruments' Message Manager * * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/ * Nishanth Menon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef TI_MSGMGR_H -- cgit v1.2.3 From 17472bc2c3d00e4ed72c3c7b9af0697edea02fff Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:11:27 +0200 Subject: wifi: nl80211: fix typo in comment Spelling mistake (triple letters) in comment. Detected with the help of Coccinelle. Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20220521111145.81697-77-Julia.Lawall@inria.fr Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index d9490e3062a7..98f905f16411 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5874,7 +5874,7 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up * the connected inactive stations in AP mode. * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested - * to work properly to suppport receiving regulatory hints from + * to work properly to support receiving regulatory hints from * cellular base stations. * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: (no longer available, only * here to reserve the value for API/ABI compatibility) -- cgit v1.2.3 From 23a5f0af6ff43195c6fd15d8ae59d019836a6046 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Feb 2022 13:14:26 +0100 Subject: wifi: mac80211: remove cipher scheme support The only driver using this was iwlwifi, where we just removed the support because it was never really used. Remove the code from mac80211 as well. Change-Id: I1667417a5932315ee9d81f5c233c56a354923f09 Signed-off-by: Johannes Berg --- include/net/mac80211.h | 35 ------------ net/mac80211/cfg.c | 26 +-------- net/mac80211/ieee80211_i.h | 11 +--- net/mac80211/iface.c | 7 +-- net/mac80211/key.c | 22 +------- net/mac80211/key.h | 7 +-- net/mac80211/main.c | 69 ++--------------------- net/mac80211/mesh_hwmp.c | 6 +- net/mac80211/mlme.c | 6 +- net/mac80211/rx.c | 49 ++++------------- net/mac80211/sta_info.h | 4 +- net/mac80211/tx.c | 21 ++----- net/mac80211/util.c | 70 +----------------------- net/mac80211/wpa.c | 133 +-------------------------------------------- net/mac80211/wpa.h | 5 +- 15 files changed, 39 insertions(+), 432 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ebadb2103968..5c9e97eca739 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1958,36 +1958,6 @@ struct ieee80211_key_seq { }; }; -/** - * struct ieee80211_cipher_scheme - cipher scheme - * - * This structure contains a cipher scheme information defining - * the secure packet crypto handling. - * - * @cipher: a cipher suite selector - * @iftype: a cipher iftype bit mask indicating an allowed cipher usage - * @hdr_len: a length of a security header used the cipher - * @pn_len: a length of a packet number in the security header - * @pn_off: an offset of pn from the beginning of the security header - * @key_idx_off: an offset of key index byte in the security header - * @key_idx_mask: a bit mask of key_idx bits - * @key_idx_shift: a bit shift needed to get key_idx - * key_idx value calculation: - * (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift - * @mic_len: a mic length in bytes - */ -struct ieee80211_cipher_scheme { - u32 cipher; - u16 iftype; - u8 hdr_len; - u8 pn_len; - u8 pn_off; - u8 key_idx_off; - u8 key_idx_mask; - u8 key_idx_shift; - u8 mic_len; -}; - /** * enum set_key_cmd - key command * @@ -2664,9 +2634,6 @@ enum ieee80211_hw_flags { * deliver to a WMM STA during any Service Period triggered by the WMM STA. * Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values. * - * @n_cipher_schemes: a size of an array of cipher schemes definitions. - * @cipher_schemes: a pointer to an array of cipher scheme definitions - * supported by HW. * @max_nan_de_entries: maximum number of NAN DE functions supported by the * device. * @@ -2716,8 +2683,6 @@ struct ieee80211_hw { netdev_features_t netdev_features; u8 uapsd_queues; u8 uapsd_max_sp_len; - u8 n_cipher_schemes; - const struct ieee80211_cipher_scheme *cipher_schemes; u8 max_nan_de_entries; u8 tx_sk_pacing_shift; u8 weight_multiplier; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f7896f257e1b..f3b10cee9299 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -5,7 +5,7 @@ * Copyright 2006-2010 Johannes Berg * Copyright 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include @@ -438,7 +438,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; struct sta_info *sta = NULL; - const struct ieee80211_cipher_scheme *cs = NULL; struct ieee80211_key *key; int err; @@ -456,23 +455,12 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, if (WARN_ON_ONCE(fips_enabled)) return -EINVAL; break; - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_CCMP_256: - case WLAN_CIPHER_SUITE_AES_CMAC: - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - break; default: - cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type); break; } key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, - params->key, params->seq_len, params->seq, - cs); + params->key, params->seq_len, params->seq); if (IS_ERR(key)) return PTR_ERR(key); @@ -537,9 +525,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, break; } - if (sta) - sta->cipher_scheme = cs; - err = ieee80211_key_link(key, sdata, sta); out_unlock: @@ -1207,9 +1192,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_over_nl80211; sdata->control_port_no_preauth = params->crypto.control_port_no_preauth; - sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, - ¶ms->crypto, - sdata->vif.type); list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { vlan->control_port_protocol = @@ -1220,10 +1202,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, params->crypto.control_port_over_nl80211; vlan->control_port_no_preauth = params->crypto.control_port_no_preauth; - vlan->encrypt_headroom = - ieee80211_cs_headroom(sdata->local, - ¶ms->crypto, - vlan->vif.type); } sdata->vif.bss_conf.dtim_period = params->dtim_period; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 86ef0a46a68c..1cf331572de1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007-2010 Johannes Berg * Copyright 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #ifndef IEEE80211_I_H @@ -944,7 +944,6 @@ struct ieee80211_sub_if_data { bool control_port_no_encrypt; bool control_port_no_preauth; bool control_port_over_nl80211; - int encrypt_headroom; atomic_t num_tx_queued; struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; @@ -2483,14 +2482,6 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work); int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, struct cfg80211_csa_settings *csa_settings); -bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs); -bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n); -const struct ieee80211_cipher_scheme * -ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, - enum nl80211_iftype iftype); -int ieee80211_cs_headroom(struct ieee80211_local *local, - struct cfg80211_crypto_settings *crypto, - enum nl80211_iftype iftype); void ieee80211_recalc_dtim(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 41531478437c..fb8d102fca48 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -8,7 +8,7 @@ * Copyright 2008, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -1036,8 +1036,6 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) wiphy_name(local->hw.wiphy)); sdata->wdev.iftype = NL80211_IFTYPE_MONITOR; - sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; - ieee80211_set_default_queues(sdata); ret = drv_add_interface(local, sdata); @@ -1644,7 +1642,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, sdata->control_port_no_encrypt = false; sdata->control_port_over_nl80211 = false; sdata->control_port_no_preauth = false; - sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; sdata->vif.bss_conf.idle = true; sdata->vif.bss_conf.txpower = INT_MIN; /* unset */ @@ -2116,8 +2113,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; sdata->user_power_level = local->user_power_level; - sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; - /* setup type-dependent data */ ieee80211_setup_sdata(sdata, type); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 0fcf8aebedc4..c3476de4b14d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -6,7 +6,7 @@ * Copyright 2007-2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright 2018-2020 Intel Corporation + * Copyright 2018-2020, 2022 Intel Corporation */ #include @@ -531,8 +531,7 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, struct ieee80211_key * ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, const u8 *key_data, - size_t seq_len, const u8 *seq, - const struct ieee80211_cipher_scheme *cs) + size_t seq_len, const u8 *seq) { struct ieee80211_key *key; int i, j, err; @@ -675,21 +674,6 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, return ERR_PTR(err); } break; - default: - if (cs) { - if (seq_len && seq_len != cs->pn_len) { - kfree(key); - return ERR_PTR(-EINVAL); - } - - key->conf.iv_len = cs->hdr_len; - key->conf.icv_len = cs->mic_len; - for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) - for (j = 0; j < seq_len; j++) - key->u.gen.rx_pn[i][j] = - seq[seq_len - j - 1]; - key->flags |= KEY_FLAG_CIPHER_SCHEME; - } } memcpy(key->conf.key, key_data, key_len); INIT_LIST_HEAD(&key->list); @@ -1294,7 +1278,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, keyconf->keylen, keyconf->key, - 0, NULL, NULL); + 0, NULL); if (IS_ERR(key)) return ERR_CAST(key); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 1e326c89d721..b3fb41c0c77f 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -2,7 +2,7 @@ /* * Copyright 2002-2004, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. - * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2019, 2022 Intel Corporation */ #ifndef IEEE80211_KEY_H @@ -30,12 +30,10 @@ struct sta_info; * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present * in the hardware for TX crypto hardware acceleration. * @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped. - * @KEY_FLAG_CIPHER_SCHEME: This key is for a hardware cipher scheme */ enum ieee80211_internal_key_flags { KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), KEY_FLAG_TAINTED = BIT(1), - KEY_FLAG_CIPHER_SCHEME = BIT(2), }; enum ieee80211_internal_tkip_state { @@ -140,8 +138,7 @@ struct ieee80211_key { struct ieee80211_key * ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, const u8 *key_data, - size_t seq_len, const u8 *seq, - const struct ieee80211_cipher_scheme *cs); + size_t seq_len, const u8 *seq); /* * Insert a key into data structures (sdata, sta if necessary) * to make it used, free old key. On failure, also free the new key. diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5a385d4146b9..4f3e93c0819b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include @@ -778,7 +778,7 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) { bool have_wep = !fips_enabled; /* FIPS does not permit the use of RC4 */ bool have_mfp = ieee80211_hw_check(&local->hw, MFP_CAPABLE); - int n_suites = 0, r = 0, w = 0; + int r = 0, w = 0; u32 *suites; static const u32 cipher_suites[] = { /* keep WEP first, it may be removed below */ @@ -824,10 +824,9 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) continue; suites[w++] = suite; } - } else if (!local->hw.cipher_schemes) { - /* If the driver doesn't have cipher schemes, there's nothing - * else to do other than assign the (software supported and - * perhaps offloaded) cipher suites. + } else { + /* assign the (software supported and perhaps offloaded) + * cipher suites */ local->hw.wiphy->cipher_suites = cipher_suites; local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); @@ -842,58 +841,6 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local) /* not dynamically allocated, so just return */ return 0; - } else { - const struct ieee80211_cipher_scheme *cs; - - cs = local->hw.cipher_schemes; - - /* Driver specifies cipher schemes only (but not cipher suites - * including the schemes) - * - * We start counting ciphers defined by schemes, TKIP, CCMP, - * CCMP-256, GCMP, and GCMP-256 - */ - n_suites = local->hw.n_cipher_schemes + 5; - - /* check if we have WEP40 and WEP104 */ - if (have_wep) - n_suites += 2; - - /* check if we have AES_CMAC, BIP-CMAC-256, BIP-GMAC-128, - * BIP-GMAC-256 - */ - if (have_mfp) - n_suites += 4; - - suites = kmalloc_array(n_suites, sizeof(u32), GFP_KERNEL); - if (!suites) - return -ENOMEM; - - suites[w++] = WLAN_CIPHER_SUITE_CCMP; - suites[w++] = WLAN_CIPHER_SUITE_CCMP_256; - suites[w++] = WLAN_CIPHER_SUITE_TKIP; - suites[w++] = WLAN_CIPHER_SUITE_GCMP; - suites[w++] = WLAN_CIPHER_SUITE_GCMP_256; - - if (have_wep) { - suites[w++] = WLAN_CIPHER_SUITE_WEP40; - suites[w++] = WLAN_CIPHER_SUITE_WEP104; - } - - if (have_mfp) { - suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; - suites[w++] = WLAN_CIPHER_SUITE_BIP_CMAC_256; - suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_128; - suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_256; - } - - for (r = 0; r < local->hw.n_cipher_schemes; r++) { - suites[w++] = cs[r].cipher; - if (WARN_ON(cs[r].pn_len > IEEE80211_MAX_PN_LEN)) { - kfree(suites); - return -EINVAL; - } - } } local->hw.wiphy->cipher_suites = suites; @@ -1168,12 +1115,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (local->hw.wiphy->max_scan_ie_len) local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; - if (WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes, - local->hw.n_cipher_schemes))) { - result = -EINVAL; - goto fail_workqueue; - } - result = ieee80211_init_cipher_suites(local); if (result < 0) goto fail_workqueue; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 58ebdcd69d05..45e7c1b307bc 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2019, 2021 Intel Corporation + * Copyright (C) 2019, 2021-2022 Intel Corporation * Author: Luis Carlos Cobo */ @@ -247,13 +247,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, return -EAGAIN; skb = dev_alloc_skb(local->tx_headroom + - sdata->encrypt_headroom + + IEEE80211_ENCRYPT_HEADROOM + IEEE80211_ENCRYPT_TAILROOM + hdr_len + 2 + 15 /* PERR IE */); if (!skb) return -1; - skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom); + skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); mgmt = skb_put_zero(skb, hdr_len); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 58d48dcae030..6d5ad71ef02c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -8,7 +8,7 @@ * Copyright 2007, Michael Wu * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2022 Intel Corporation */ #include @@ -2496,8 +2496,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec)); cancel_delayed_work_sync(&ifmgd->tx_tspec_wk); - sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; - bss_conf->pwr_reduction = 0; bss_conf->tx_pwr_env_num = 0; memset(bss_conf->tx_pwr_env, 0, sizeof(bss_conf->tx_pwr_env)); @@ -6071,8 +6069,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, sdata->control_port_over_nl80211 = req->crypto.control_port_over_nl80211; sdata->control_port_no_preauth = req->crypto.control_port_no_preauth; - sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto, - sdata->vif.type); /* kick off associate process */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3c08ae04ddbc..a9f4e90ad893 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -6,7 +6,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include @@ -1009,43 +1009,20 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) return -1; } -static int ieee80211_get_keyid(struct sk_buff *skb, - const struct ieee80211_cipher_scheme *cs) +static int ieee80211_get_keyid(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc; - int hdrlen; - int minlen; - u8 key_idx_off; - u8 key_idx_shift; + __le16 fc = hdr->frame_control; + int hdrlen = ieee80211_hdrlen(fc); u8 keyid; - fc = hdr->frame_control; - hdrlen = ieee80211_hdrlen(fc); - - if (cs) { - minlen = hdrlen + cs->hdr_len; - key_idx_off = hdrlen + cs->key_idx_off; - key_idx_shift = cs->key_idx_shift; - } else { - /* WEP, TKIP, CCMP and GCMP */ - minlen = hdrlen + IEEE80211_WEP_IV_LEN; - key_idx_off = hdrlen + 3; - key_idx_shift = 6; - } - - if (unlikely(skb->len < minlen)) + /* WEP, TKIP, CCMP and GCMP */ + if (unlikely(skb->len < hdrlen + IEEE80211_WEP_IV_LEN)) return -EINVAL; - skb_copy_bits(skb, key_idx_off, &keyid, 1); + skb_copy_bits(skb, hdrlen + 3, &keyid, 1); - if (cs) - keyid &= cs->key_idx_mask; - keyid >>= key_idx_shift; - - /* cs could use more than the usual two bits for the keyid */ - if (unlikely(keyid >= NUM_DEFAULT_KEYS)) - return -EINVAL; + keyid >>= 6; return keyid; } @@ -1916,7 +1893,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) struct ieee80211_key *ptk_idx = NULL; int mmie_keyidx = -1; __le16 fc; - const struct ieee80211_cipher_scheme *cs = NULL; if (ieee80211_is_ext(hdr->frame_control)) return RX_CONTINUE; @@ -1959,8 +1935,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (ieee80211_has_protected(fc) && !(status->flag & RX_FLAG_IV_STRIPPED)) { - cs = rx->sta->cipher_scheme; - keyid = ieee80211_get_keyid(rx->skb, cs); + keyid = ieee80211_get_keyid(rx->skb); if (unlikely(keyid < 0)) return RX_DROP_UNUSABLE; @@ -2065,7 +2040,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) (status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; - keyidx = ieee80211_get_keyid(rx->skb, cs); + keyidx = ieee80211_get_keyid(rx->skb); if (unlikely(keyidx < 0)) return RX_DROP_UNUSABLE; @@ -2131,7 +2106,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) result = ieee80211_crypto_gcmp_decrypt(rx); break; default: - result = ieee80211_crypto_hw_decrypt(rx); + result = RX_DROP_UNUSABLE; } /* the hdr variable is invalid after the decrypt handlers */ @@ -2945,7 +2920,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) tailroom = IEEE80211_ENCRYPT_TAILROOM; fwd_skb = skb_copy_expand(skb, local->tx_headroom + - sdata->encrypt_headroom, + IEEE80211_ENCRYPT_HEADROOM, tailroom, GFP_ATOMIC); if (!fwd_skb) goto out; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 35c390bedfba..aa6950aa49a9 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -3,7 +3,7 @@ * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015-2017 Intel Deutschland GmbH - * Copyright(c) 2020-2021 Intel Corporation + * Copyright(c) 2020-2022 Intel Corporation */ #ifndef STA_INFO_H @@ -616,7 +616,6 @@ struct link_sta_info { * taken from HT/VHT capabilities or VHT operating mode notification * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for * AP only. - * @cipher_scheme: optional cipher scheme for this station * @cparams: CoDel parameters for this station. * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) * @fast_tx: TX fastpath information @@ -700,7 +699,6 @@ struct sta_info { #endif enum ieee80211_smps_mode known_smps_mode; - const struct ieee80211_cipher_scheme *cipher_scheme; struct codel_params cparams; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0e4efc08c762..37fe72bb5ab0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation * * Transmit and frame generation functions. */ @@ -882,7 +882,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, rem -= fraglen; tmp = dev_alloc_skb(local->tx_headroom + frag_threshold + - tx->sdata->encrypt_headroom + + IEEE80211_ENCRYPT_HEADROOM + IEEE80211_ENCRYPT_TAILROOM); if (!tmp) return -ENOMEM; @@ -890,7 +890,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, __skb_queue_tail(&tx->skbs, tmp); skb_reserve(tmp, - local->tx_headroom + tx->sdata->encrypt_headroom); + local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); /* copy control information */ memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); @@ -1040,8 +1040,6 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: return ieee80211_crypto_gcmp_encrypt(tx); - default: - return ieee80211_crypto_hw_encrypt(tx); } return TX_DROP; @@ -2013,7 +2011,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, headroom = local->tx_headroom; if (encrypt != ENCRYPT_NO) - headroom += sdata->encrypt_headroom; + headroom += IEEE80211_ENCRYPT_HEADROOM; headroom -= skb_headroom(skb); headroom = max_t(int, 0, headroom); @@ -2867,7 +2865,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, */ if (head_need > 0 || skb_cloned(skb)) { - head_need += sdata->encrypt_headroom; + head_need += IEEE80211_ENCRYPT_HEADROOM; head_need += local->tx_headroom; head_need = max_t(int, 0, head_need); if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) { @@ -3128,15 +3126,6 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) /* we don't know how to generate IVs for this at all */ if (WARN_ON(gen_iv)) goto out; - /* pure hardware keys are OK, of course */ - if (!(build.key->flags & KEY_FLAG_CIPHER_SCHEME)) - break; - /* cipher scheme might require space allocation */ - if (iv_spc && - build.key->conf.iv_len > IEEE80211_FAST_XMIT_MAX_IV) - goto out; - if (iv_spc) - build.hdr_len += build.key->conf.iv_len; } fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1e26b5235add..9e6c4dcef280 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -6,7 +6,7 @@ * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation * * utilities for mac80211 */ @@ -4212,74 +4212,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, return 0; } -bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs) -{ - return !(cs == NULL || cs->cipher == 0 || - cs->hdr_len < cs->pn_len + cs->pn_off || - cs->hdr_len <= cs->key_idx_off || - cs->key_idx_shift > 7 || - cs->key_idx_mask == 0); -} - -bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n) -{ - int i; - - /* Ensure we have enough iftype bitmap space for all iftype values */ - WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype)); - - for (i = 0; i < n; i++) - if (!ieee80211_cs_valid(&cs[i])) - return false; - - return true; -} - -const struct ieee80211_cipher_scheme * -ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, - enum nl80211_iftype iftype) -{ - const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes; - int n = local->hw.n_cipher_schemes; - int i; - const struct ieee80211_cipher_scheme *cs = NULL; - - for (i = 0; i < n; i++) { - if (l[i].cipher == cipher) { - cs = &l[i]; - break; - } - } - - if (!cs || !(cs->iftype & BIT(iftype))) - return NULL; - - return cs; -} - -int ieee80211_cs_headroom(struct ieee80211_local *local, - struct cfg80211_crypto_settings *crypto, - enum nl80211_iftype iftype) -{ - const struct ieee80211_cipher_scheme *cs; - int headroom = IEEE80211_ENCRYPT_HEADROOM; - int i; - - for (i = 0; i < crypto->n_ciphers_pairwise; i++) { - cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i], - iftype); - - if (cs && headroom < cs->hdr_len) - headroom = cs->hdr_len; - } - - cs = ieee80211_cs_get(local, crypto->cipher_group, iftype); - if (cs && headroom < cs->hdr_len) - headroom = cs->hdr_len; - - return headroom; -} - static bool ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i) { diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 5fd8a3e8b5b4..93ec2f349748 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -3,7 +3,7 @@ * Copyright 2002-2004, Instant802 Networks, Inc. * Copyright 2008, Jouni Malinen * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2022 Intel Corporation */ #include @@ -778,102 +778,6 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; } -static ieee80211_tx_result -ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, - struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_key *key = tx->key; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int hdrlen; - u8 *pos, iv_len = key->conf.iv_len; - - if (info->control.hw_key && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { - /* hwaccel has no need for preallocated head room */ - return TX_CONTINUE; - } - - if (unlikely(skb_headroom(skb) < iv_len && - pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC))) - return TX_DROP; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - - pos = skb_push(skb, iv_len); - memmove(pos, pos + iv_len, hdrlen); - - return TX_CONTINUE; -} - -static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) -{ - int i; - - /* pn is little endian */ - for (i = len - 1; i >= 0; i--) { - if (pn1[i] < pn2[i]) - return -1; - else if (pn1[i] > pn2[i]) - return 1; - } - - return 0; -} - -static ieee80211_rx_result -ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) -{ - struct ieee80211_key *key = rx->key; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; - const struct ieee80211_cipher_scheme *cs = NULL; - int hdrlen = ieee80211_hdrlen(hdr->frame_control); - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - int data_len; - u8 *rx_pn; - u8 *skb_pn; - u8 qos_tid; - - if (!rx->sta || !rx->sta->cipher_scheme || - !(status->flag & RX_FLAG_DECRYPTED)) - return RX_DROP_UNUSABLE; - - if (!ieee80211_is_data(hdr->frame_control)) - return RX_CONTINUE; - - cs = rx->sta->cipher_scheme; - - data_len = rx->skb->len - hdrlen - cs->hdr_len; - - if (data_len < 0) - return RX_DROP_UNUSABLE; - - if (ieee80211_is_data_qos(hdr->frame_control)) - qos_tid = ieee80211_get_tid(hdr); - else - qos_tid = 0; - - if (skb_linearize(rx->skb)) - return RX_DROP_UNUSABLE; - - rx_pn = key->u.gen.rx_pn[qos_tid]; - skb_pn = rx->skb->data + hdrlen + cs->pn_off; - - if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) - return RX_DROP_UNUSABLE; - - memcpy(rx_pn, skb_pn, cs->pn_len); - - /* remove security header and MIC */ - if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) - return RX_DROP_UNUSABLE; - - memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); - skb_pull(rx->skb, cs->hdr_len); - - return RX_CONTINUE; -} - static void bip_aad(struct sk_buff *skb, u8 *aad) { __le16 mask_fc; @@ -1212,38 +1116,3 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx) return RX_CONTINUE; } - -ieee80211_tx_result -ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) -{ - struct sk_buff *skb; - struct ieee80211_tx_info *info = NULL; - ieee80211_tx_result res; - - skb_queue_walk(&tx->skbs, skb) { - info = IEEE80211_SKB_CB(skb); - - /* handle hw-only algorithm */ - if (!info->control.hw_key) - return TX_DROP; - - if (tx->key->flags & KEY_FLAG_CIPHER_SCHEME) { - res = ieee80211_crypto_cs_encrypt(tx, skb); - if (res != TX_CONTINUE) - return res; - } - } - - ieee80211_tx_set_protected(tx); - - return TX_CONTINUE; -} - -ieee80211_rx_result -ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) -{ - if (rx->sta && rx->sta->cipher_scheme) - return ieee80211_crypto_cs_decrypt(rx); - - return RX_DROP_UNUSABLE; -} diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index af3272284e85..a9a81abb5479 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2002-2004, Instant802 Networks, Inc. + * Copyright (C) 2022 Intel Corporation */ #ifndef WPA_H @@ -39,10 +40,6 @@ ieee80211_tx_result ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx); ieee80211_rx_result ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx); -ieee80211_tx_result -ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); -ieee80211_rx_result -ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); ieee80211_tx_result ieee80211_crypto_gcmp_encrypt(struct ieee80211_tx_data *tx); -- cgit v1.2.3 From 35ba63b8f6d07d353159505423cfca5a4378a11c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 6 Jun 2022 10:41:05 +0200 Subject: vme: move back to staging The VME subsystem graduated from staging into a top-level subsystem in 2012, with commit db3b9e990e75 ("Staging: VME: move VME drivers out of staging") stating: The VME device drivers have not moved out yet due to some API questions they are still working through, that should happen soon, hopefully. However, this never happened: maintenance of drivers/vme effectively stopped in 2017, with all subsequent changes being treewide cleanups. No hardware driver remains in staging, only the limited user-level access, and I just removed one of the two bridge drivers and the only remaining board. drivers/staging/vme/devices/ was recently moved to drivers/staging/vme_user/, but as the vme_user driver is the only one remaining for this subsystem, it is easier to just move the remaining three source files into this directory rather than keeping the original hierarchy. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20220606084109.4108188-3-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/vme.rst | 4 +- MAINTAINERS | 4 +- drivers/Kconfig | 2 - drivers/Makefile | 1 - drivers/staging/vme_user/Kconfig | 27 + drivers/staging/vme_user/Makefile | 3 + drivers/staging/vme_user/vme.c | 2015 +++++++++++++++++++++++++ drivers/staging/vme_user/vme.h | 190 +++ drivers/staging/vme_user/vme_bridge.h | 190 +++ drivers/staging/vme_user/vme_fake.c | 1305 ++++++++++++++++ drivers/staging/vme_user/vme_tsi148.c | 2661 +++++++++++++++++++++++++++++++++ drivers/staging/vme_user/vme_tsi148.h | 1407 +++++++++++++++++ drivers/staging/vme_user/vme_user.c | 2 +- drivers/vme/Kconfig | 16 - drivers/vme/Makefile | 7 - drivers/vme/bridges/Kconfig | 17 - drivers/vme/bridges/Makefile | 3 - drivers/vme/bridges/vme_fake.c | 1305 ---------------- drivers/vme/bridges/vme_tsi148.c | 2661 --------------------------------- drivers/vme/bridges/vme_tsi148.h | 1407 ----------------- drivers/vme/vme.c | 2015 ------------------------- drivers/vme/vme_bridge.h | 190 --- include/linux/vme.h | 190 --- 23 files changed, 7802 insertions(+), 7820 deletions(-) create mode 100644 drivers/staging/vme_user/vme.c create mode 100644 drivers/staging/vme_user/vme.h create mode 100644 drivers/staging/vme_user/vme_bridge.h create mode 100644 drivers/staging/vme_user/vme_fake.c create mode 100644 drivers/staging/vme_user/vme_tsi148.c create mode 100644 drivers/staging/vme_user/vme_tsi148.h delete mode 100644 drivers/vme/Kconfig delete mode 100644 drivers/vme/Makefile delete mode 100644 drivers/vme/bridges/Kconfig delete mode 100644 drivers/vme/bridges/Makefile delete mode 100644 drivers/vme/bridges/vme_fake.c delete mode 100644 drivers/vme/bridges/vme_tsi148.c delete mode 100644 drivers/vme/bridges/vme_tsi148.h delete mode 100644 drivers/vme/vme.c delete mode 100644 drivers/vme/vme_bridge.h delete mode 100644 include/linux/vme.h (limited to 'include') diff --git a/Documentation/driver-api/vme.rst b/Documentation/driver-api/vme.rst index def139c13410..c0b475369de0 100644 --- a/Documentation/driver-api/vme.rst +++ b/Documentation/driver-api/vme.rst @@ -290,8 +290,8 @@ The function :c:func:`vme_bus_num` returns the bus ID of the provided bridge. VME API ------- -.. kernel-doc:: include/linux/vme.h +.. kernel-doc:: drivers/staging/vme_user/vme.h :internal: -.. kernel-doc:: drivers/vme/vme.c +.. kernel-doc:: drivers/staging/vme_user/vme.c :export: diff --git a/MAINTAINERS b/MAINTAINERS index 60e5e4007844..7097b824ba18 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21230,12 +21230,10 @@ M: Martyn Welch M: Manohar Vanga M: Greg Kroah-Hartman L: linux-kernel@vger.kernel.org -S: Maintained +S: Odd fixes T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git F: Documentation/driver-api/vme.rst F: drivers/staging/vme_user/ -F: drivers/vme/ -F: include/linux/vme* VM SOCKETS (AF_VSOCK) M: Stefano Garzarella diff --git a/drivers/Kconfig b/drivers/Kconfig index b6a172d32a7d..19ee995bd0ae 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -183,8 +183,6 @@ source "drivers/iio/Kconfig" source "drivers/ntb/Kconfig" -source "drivers/vme/Kconfig" - source "drivers/pwm/Kconfig" source "drivers/irqchip/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 9a30842b22c5..dadf2678277f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -165,7 +165,6 @@ obj-$(CONFIG_PM_DEVFREQ) += devfreq/ obj-$(CONFIG_EXTCON) += extcon/ obj-$(CONFIG_MEMORY) += memory/ obj-$(CONFIG_IIO) += iio/ -obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_IPACK_BUS) += ipack/ obj-$(CONFIG_NTB) += ntb/ obj-$(CONFIG_POWERCAP) += powercap/ diff --git a/drivers/staging/vme_user/Kconfig b/drivers/staging/vme_user/Kconfig index e8b4461bf27f..c8eabf8f40f1 100644 --- a/drivers/staging/vme_user/Kconfig +++ b/drivers/staging/vme_user/Kconfig @@ -1,4 +1,29 @@ # SPDX-License-Identifier: GPL-2.0 +menuconfig VME_BUS + bool "VME bridge support" + depends on STAGING && PCI + help + If you say Y here you get support for the VME bridge Framework. + +if VME_BUS + +comment "VME Bridge Drivers" + +config VME_TSI148 + tristate "Tempe" + depends on HAS_DMA + help + If you say Y here you get support for the Tundra TSI148 VME bridge + chip. + +config VME_FAKE + tristate "Fake" + help + If you say Y here you get support for the fake VME bridge. This + provides a virtualised VME Bus for devices with no VME bridge. This + is mainly useful for VME development (in the absence of VME + hardware). + comment "VME Device Drivers" config VME_USER @@ -11,3 +36,5 @@ config VME_USER To compile this driver as a module, choose M here. The module will be called vme_user. If unsure, say N. + +endif diff --git a/drivers/staging/vme_user/Makefile b/drivers/staging/vme_user/Makefile index 5380115139b0..8dcc6938ce5c 100644 --- a/drivers/staging/vme_user/Makefile +++ b/drivers/staging/vme_user/Makefile @@ -3,4 +3,7 @@ # Makefile for the VME device drivers. # +obj-$(CONFIG_VME_BUS) += vme.o obj-$(CONFIG_VME_USER) += vme_user.o +obj-$(CONFIG_VME_TSI148) += vme_tsi148.o +obj-$(CONFIG_VME_FAKE) += vme_fake.o diff --git a/drivers/staging/vme_user/vme.c b/drivers/staging/vme_user/vme.c new file mode 100644 index 000000000000..b5555683a069 --- /dev/null +++ b/drivers/staging/vme_user/vme.c @@ -0,0 +1,2015 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * VME Bridge Framework + * + * Author: Martyn Welch + * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. + * + * Based on work by Tom Armistead and Ajit Prem + * Copyright 2004 Motorola Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vme.h" +#include "vme_bridge.h" + +/* Bitmask and list of registered buses both protected by common mutex */ +static unsigned int vme_bus_numbers; +static LIST_HEAD(vme_bus_list); +static DEFINE_MUTEX(vme_buses_lock); + +static int __init vme_init(void); + +static struct vme_dev *dev_to_vme_dev(struct device *dev) +{ + return container_of(dev, struct vme_dev, dev); +} + +/* + * Find the bridge that the resource is associated with. + */ +static struct vme_bridge *find_bridge(struct vme_resource *resource) +{ + /* Get list to search */ + switch (resource->type) { + case VME_MASTER: + return list_entry(resource->entry, struct vme_master_resource, + list)->parent; + case VME_SLAVE: + return list_entry(resource->entry, struct vme_slave_resource, + list)->parent; + case VME_DMA: + return list_entry(resource->entry, struct vme_dma_resource, + list)->parent; + case VME_LM: + return list_entry(resource->entry, struct vme_lm_resource, + list)->parent; + default: + printk(KERN_ERR "Unknown resource type\n"); + return NULL; + } +} + +/** + * vme_alloc_consistent - Allocate contiguous memory. + * @resource: Pointer to VME resource. + * @size: Size of allocation required. + * @dma: Pointer to variable to store physical address of allocation. + * + * Allocate a contiguous block of memory for use by the driver. This is used to + * create the buffers for the slave windows. + * + * Return: Virtual address of allocation on success, NULL on failure. + */ +void *vme_alloc_consistent(struct vme_resource *resource, size_t size, + dma_addr_t *dma) +{ + struct vme_bridge *bridge; + + if (!resource) { + printk(KERN_ERR "No resource\n"); + return NULL; + } + + bridge = find_bridge(resource); + if (!bridge) { + printk(KERN_ERR "Can't find bridge\n"); + return NULL; + } + + if (!bridge->parent) { + printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); + return NULL; + } + + if (!bridge->alloc_consistent) { + printk(KERN_ERR "alloc_consistent not supported by bridge %s\n", + bridge->name); + return NULL; + } + + return bridge->alloc_consistent(bridge->parent, size, dma); +} +EXPORT_SYMBOL(vme_alloc_consistent); + +/** + * vme_free_consistent - Free previously allocated memory. + * @resource: Pointer to VME resource. + * @size: Size of allocation to free. + * @vaddr: Virtual address of allocation. + * @dma: Physical address of allocation. + * + * Free previously allocated block of contiguous memory. + */ +void vme_free_consistent(struct vme_resource *resource, size_t size, + void *vaddr, dma_addr_t dma) +{ + struct vme_bridge *bridge; + + if (!resource) { + printk(KERN_ERR "No resource\n"); + return; + } + + bridge = find_bridge(resource); + if (!bridge) { + printk(KERN_ERR "Can't find bridge\n"); + return; + } + + if (!bridge->parent) { + printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); + return; + } + + if (!bridge->free_consistent) { + printk(KERN_ERR "free_consistent not supported by bridge %s\n", + bridge->name); + return; + } + + bridge->free_consistent(bridge->parent, size, vaddr, dma); +} +EXPORT_SYMBOL(vme_free_consistent); + +/** + * vme_get_size - Helper function returning size of a VME window + * @resource: Pointer to VME slave or master resource. + * + * Determine the size of the VME window provided. This is a helper + * function, wrappering the call to vme_master_get or vme_slave_get + * depending on the type of window resource handed to it. + * + * Return: Size of the window on success, zero on failure. + */ +size_t vme_get_size(struct vme_resource *resource) +{ + int enabled, retval; + unsigned long long base, size; + dma_addr_t buf_base; + u32 aspace, cycle, dwidth; + + switch (resource->type) { + case VME_MASTER: + retval = vme_master_get(resource, &enabled, &base, &size, + &aspace, &cycle, &dwidth); + if (retval) + return 0; + + return size; + case VME_SLAVE: + retval = vme_slave_get(resource, &enabled, &base, &size, + &buf_base, &aspace, &cycle); + if (retval) + return 0; + + return size; + case VME_DMA: + return 0; + default: + printk(KERN_ERR "Unknown resource type\n"); + return 0; + } +} +EXPORT_SYMBOL(vme_get_size); + +int vme_check_window(u32 aspace, unsigned long long vme_base, + unsigned long long size) +{ + int retval = 0; + + if (vme_base + size < size) + return -EINVAL; + + switch (aspace) { + case VME_A16: + if (vme_base + size > VME_A16_MAX) + retval = -EFAULT; + break; + case VME_A24: + if (vme_base + size > VME_A24_MAX) + retval = -EFAULT; + break; + case VME_A32: + if (vme_base + size > VME_A32_MAX) + retval = -EFAULT; + break; + case VME_A64: + /* The VME_A64_MAX limit is actually U64_MAX + 1 */ + break; + case VME_CRCSR: + if (vme_base + size > VME_CRCSR_MAX) + retval = -EFAULT; + break; + case VME_USER1: + case VME_USER2: + case VME_USER3: + case VME_USER4: + /* User Defined */ + break; + default: + printk(KERN_ERR "Invalid address space\n"); + retval = -EINVAL; + break; + } + + return retval; +} +EXPORT_SYMBOL(vme_check_window); + +static u32 vme_get_aspace(int am) +{ + switch (am) { + case 0x29: + case 0x2D: + return VME_A16; + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + return VME_A24; + case 0x8: + case 0x9: + case 0xA: + case 0xB: + case 0xC: + case 0xD: + case 0xE: + case 0xF: + return VME_A32; + case 0x0: + case 0x1: + case 0x3: + return VME_A64; + } + + return 0; +} + +/** + * vme_slave_request - Request a VME slave window resource. + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * @address: Required VME address space. + * @cycle: Required VME data transfer cycle type. + * + * Request use of a VME window resource capable of being set for the requested + * address space and data transfer cycle. + * + * Return: Pointer to VME resource on success, NULL on failure. + */ +struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, + u32 cycle) +{ + struct vme_bridge *bridge; + struct list_head *slave_pos = NULL; + struct vme_slave_resource *allocated_image = NULL; + struct vme_slave_resource *slave_image = NULL; + struct vme_resource *resource = NULL; + + bridge = vdev->bridge; + if (!bridge) { + printk(KERN_ERR "Can't find VME bus\n"); + goto err_bus; + } + + /* Loop through slave resources */ + list_for_each(slave_pos, &bridge->slave_resources) { + slave_image = list_entry(slave_pos, + struct vme_slave_resource, list); + + if (!slave_image) { + printk(KERN_ERR "Registered NULL Slave resource\n"); + continue; + } + + /* Find an unlocked and compatible image */ + mutex_lock(&slave_image->mtx); + if (((slave_image->address_attr & address) == address) && + ((slave_image->cycle_attr & cycle) == cycle) && + (slave_image->locked == 0)) { + + slave_image->locked = 1; + mutex_unlock(&slave_image->mtx); + allocated_image = slave_image; + break; + } + mutex_unlock(&slave_image->mtx); + } + + /* No free image */ + if (!allocated_image) + goto err_image; + + resource = kmalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) + goto err_alloc; + + resource->type = VME_SLAVE; + resource->entry = &allocated_image->list; + + return resource; + +err_alloc: + /* Unlock image */ + mutex_lock(&slave_image->mtx); + slave_image->locked = 0; + mutex_unlock(&slave_image->mtx); +err_image: +err_bus: + return NULL; +} +EXPORT_SYMBOL(vme_slave_request); + +/** + * vme_slave_set - Set VME slave window configuration. + * @resource: Pointer to VME slave resource. + * @enabled: State to which the window should be configured. + * @vme_base: Base address for the window. + * @size: Size of the VME window. + * @buf_base: Based address of buffer used to provide VME slave window storage. + * @aspace: VME address space for the VME window. + * @cycle: VME data transfer cycle type for the VME window. + * + * Set configuration for provided VME slave window. + * + * Return: Zero on success, -EINVAL if operation is not supported on this + * device, if an invalid resource has been provided or invalid + * attributes are provided. Hardware specific errors may also be + * returned. + */ +int vme_slave_set(struct vme_resource *resource, int enabled, + unsigned long long vme_base, unsigned long long size, + dma_addr_t buf_base, u32 aspace, u32 cycle) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_slave_resource *image; + int retval; + + if (resource->type != VME_SLAVE) { + printk(KERN_ERR "Not a slave resource\n"); + return -EINVAL; + } + + image = list_entry(resource->entry, struct vme_slave_resource, list); + + if (!bridge->slave_set) { + printk(KERN_ERR "Function not supported\n"); + return -ENOSYS; + } + + if (!(((image->address_attr & aspace) == aspace) && + ((image->cycle_attr & cycle) == cycle))) { + printk(KERN_ERR "Invalid attributes\n"); + return -EINVAL; + } + + retval = vme_check_window(aspace, vme_base, size); + if (retval) + return retval; + + return bridge->slave_set(image, enabled, vme_base, size, buf_base, + aspace, cycle); +} +EXPORT_SYMBOL(vme_slave_set); + +/** + * vme_slave_get - Retrieve VME slave window configuration. + * @resource: Pointer to VME slave resource. + * @enabled: Pointer to variable for storing state. + * @vme_base: Pointer to variable for storing window base address. + * @size: Pointer to variable for storing window size. + * @buf_base: Pointer to variable for storing slave buffer base address. + * @aspace: Pointer to variable for storing VME address space. + * @cycle: Pointer to variable for storing VME data transfer cycle type. + * + * Return configuration for provided VME slave window. + * + * Return: Zero on success, -EINVAL if operation is not supported on this + * device or if an invalid resource has been provided. + */ +int vme_slave_get(struct vme_resource *resource, int *enabled, + unsigned long long *vme_base, unsigned long long *size, + dma_addr_t *buf_base, u32 *aspace, u32 *cycle) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_slave_resource *image; + + if (resource->type != VME_SLAVE) { + printk(KERN_ERR "Not a slave resource\n"); + return -EINVAL; + } + + image = list_entry(resource->entry, struct vme_slave_resource, list); + + if (!bridge->slave_get) { + printk(KERN_ERR "vme_slave_get not supported\n"); + return -EINVAL; + } + + return bridge->slave_get(image, enabled, vme_base, size, buf_base, + aspace, cycle); +} +EXPORT_SYMBOL(vme_slave_get); + +/** + * vme_slave_free - Free VME slave window + * @resource: Pointer to VME slave resource. + * + * Free the provided slave resource so that it may be reallocated. + */ +void vme_slave_free(struct vme_resource *resource) +{ + struct vme_slave_resource *slave_image; + + if (resource->type != VME_SLAVE) { + printk(KERN_ERR "Not a slave resource\n"); + return; + } + + slave_image = list_entry(resource->entry, struct vme_slave_resource, + list); + if (!slave_image) { + printk(KERN_ERR "Can't find slave resource\n"); + return; + } + + /* Unlock image */ + mutex_lock(&slave_image->mtx); + if (slave_image->locked == 0) + printk(KERN_ERR "Image is already free\n"); + + slave_image->locked = 0; + mutex_unlock(&slave_image->mtx); + + /* Free up resource memory */ + kfree(resource); +} +EXPORT_SYMBOL(vme_slave_free); + +/** + * vme_master_request - Request a VME master window resource. + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * @address: Required VME address space. + * @cycle: Required VME data transfer cycle type. + * @dwidth: Required VME data transfer width. + * + * Request use of a VME window resource capable of being set for the requested + * address space, data transfer cycle and width. + * + * Return: Pointer to VME resource on success, NULL on failure. + */ +struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, + u32 cycle, u32 dwidth) +{ + struct vme_bridge *bridge; + struct list_head *master_pos = NULL; + struct vme_master_resource *allocated_image = NULL; + struct vme_master_resource *master_image = NULL; + struct vme_resource *resource = NULL; + + bridge = vdev->bridge; + if (!bridge) { + printk(KERN_ERR "Can't find VME bus\n"); + goto err_bus; + } + + /* Loop through master resources */ + list_for_each(master_pos, &bridge->master_resources) { + master_image = list_entry(master_pos, + struct vme_master_resource, list); + + if (!master_image) { + printk(KERN_WARNING "Registered NULL master resource\n"); + continue; + } + + /* Find an unlocked and compatible image */ + spin_lock(&master_image->lock); + if (((master_image->address_attr & address) == address) && + ((master_image->cycle_attr & cycle) == cycle) && + ((master_image->width_attr & dwidth) == dwidth) && + (master_image->locked == 0)) { + + master_image->locked = 1; + spin_unlock(&master_image->lock); + allocated_image = master_image; + break; + } + spin_unlock(&master_image->lock); + } + + /* Check to see if we found a resource */ + if (!allocated_image) { + printk(KERN_ERR "Can't find a suitable resource\n"); + goto err_image; + } + + resource = kmalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) + goto err_alloc; + + resource->type = VME_MASTER; + resource->entry = &allocated_image->list; + + return resource; + +err_alloc: + /* Unlock image */ + spin_lock(&master_image->lock); + master_image->locked = 0; + spin_unlock(&master_image->lock); +err_image: +err_bus: + return NULL; +} +EXPORT_SYMBOL(vme_master_request); + +/** + * vme_master_set - Set VME master window configuration. + * @resource: Pointer to VME master resource. + * @enabled: State to which the window should be configured. + * @vme_base: Base address for the window. + * @size: Size of the VME window. + * @aspace: VME address space for the VME window. + * @cycle: VME data transfer cycle type for the VME window. + * @dwidth: VME data transfer width for the VME window. + * + * Set configuration for provided VME master window. + * + * Return: Zero on success, -EINVAL if operation is not supported on this + * device, if an invalid resource has been provided or invalid + * attributes are provided. Hardware specific errors may also be + * returned. + */ +int vme_master_set(struct vme_resource *resource, int enabled, + unsigned long long vme_base, unsigned long long size, u32 aspace, + u32 cycle, u32 dwidth) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_master_resource *image; + int retval; + + if (resource->type != VME_MASTER) { + printk(KERN_ERR "Not a master resource\n"); + return -EINVAL; + } + + image = list_entry(resource->entry, struct vme_master_resource, list); + + if (!bridge->master_set) { + printk(KERN_WARNING "vme_master_set not supported\n"); + return -EINVAL; + } + + if (!(((image->address_attr & aspace) == aspace) && + ((image->cycle_attr & cycle) == cycle) && + ((image->width_attr & dwidth) == dwidth))) { + printk(KERN_WARNING "Invalid attributes\n"); + return -EINVAL; + } + + retval = vme_check_window(aspace, vme_base, size); + if (retval) + return retval; + + return bridge->master_set(image, enabled, vme_base, size, aspace, + cycle, dwidth); +} +EXPORT_SYMBOL(vme_master_set); + +/** + * vme_master_get - Retrieve VME master window configuration. + * @resource: Pointer to VME master resource. + * @enabled: Pointer to variable for storing state. + * @vme_base: Pointer to variable for storing window base address. + * @size: Pointer to variable for storing window size. + * @aspace: Pointer to variable for storing VME address space. + * @cycle: Pointer to variable for storing VME data transfer cycle type. + * @dwidth: Pointer to variable for storing VME data transfer width. + * + * Return configuration for provided VME master window. + * + * Return: Zero on success, -EINVAL if operation is not supported on this + * device or if an invalid resource has been provided. + */ +int vme_master_get(struct vme_resource *resource, int *enabled, + unsigned long long *vme_base, unsigned long long *size, u32 *aspace, + u32 *cycle, u32 *dwidth) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_master_resource *image; + + if (resource->type != VME_MASTER) { + printk(KERN_ERR "Not a master resource\n"); + return -EINVAL; + } + + image = list_entry(resource->entry, struct vme_master_resource, list); + + if (!bridge->master_get) { + printk(KERN_WARNING "%s not supported\n", __func__); + return -EINVAL; + } + + return bridge->master_get(image, enabled, vme_base, size, aspace, + cycle, dwidth); +} +EXPORT_SYMBOL(vme_master_get); + +/** + * vme_master_read - Read data from VME space into a buffer. + * @resource: Pointer to VME master resource. + * @buf: Pointer to buffer where data should be transferred. + * @count: Number of bytes to transfer. + * @offset: Offset into VME master window at which to start transfer. + * + * Perform read of count bytes of data from location on VME bus which maps into + * the VME master window at offset to buf. + * + * Return: Number of bytes read, -EINVAL if resource is not a VME master + * resource or read operation is not supported. -EFAULT returned if + * invalid offset is provided. Hardware specific errors may also be + * returned. + */ +ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, + loff_t offset) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_master_resource *image; + size_t length; + + if (!bridge->master_read) { + printk(KERN_WARNING "Reading from resource not supported\n"); + return -EINVAL; + } + + if (resource->type != VME_MASTER) { + printk(KERN_ERR "Not a master resource\n"); + return -EINVAL; + } + + image = list_entry(resource->entry, struct vme_master_resource, list); + + length = vme_get_size(resource); + + if (offset > length) { + printk(KERN_WARNING "Invalid Offset\n"); + return -EFAULT; + } + + if ((offset + count) > length) + count = length - offset; + + return bridge->master_read(image, buf, count, offset); + +} +EXPORT_SYMBOL(vme_master_read); + +/** + * vme_master_write - Write data out to VME space from a buffer. + * @resource: Pointer to VME master resource. + * @buf: Pointer to buffer holding data to transfer. + * @count: Number of bytes to transfer. + * @offset: Offset into VME master window at which to start transfer. + * + * Perform write of count bytes of data from buf to location on VME bus which + * maps into the VME master window at offset. + * + * Return: Number of bytes written, -EINVAL if resource is not a VME master + * resource or write operation is not supported. -EFAULT returned if + * invalid offset is provided. Hardware specific errors may also be + * returned. + */ +ssize_t vme_master_write(struct vme_resource *resource, void *buf, + size_t count, loff_t offset) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_master_resource *image; + size_t length; + + if (!bridge->master_write) { + printk(KERN_WARNING "Writing to resource not supported\n"); + return -EINVAL; + } + + if (resource->type != VME_MASTER) { + printk(KERN_ERR "Not a master resource\n"); + return -EINVAL; + } + + image = list_entry(resource->entry, struct vme_master_resource, list); + + length = vme_get_size(resource); + + if (offset > length) { + printk(KERN_WARNING "Invalid Offset\n"); + return -EFAULT; + } + + if ((offset + count) > length) + count = length - offset; + + return bridge->master_write(image, buf, count, offset); +} +EXPORT_SYMBOL(vme_master_write); + +/** + * vme_master_rmw - Perform read-modify-write cycle. + * @resource: Pointer to VME master resource. + * @mask: Bits to be compared and swapped in operation. + * @compare: Bits to be compared with data read from offset. + * @swap: Bits to be swapped in data read from offset. + * @offset: Offset into VME master window at which to perform operation. + * + * Perform read-modify-write cycle on provided location: + * - Location on VME bus is read. + * - Bits selected by mask are compared with compare. + * - Where a selected bit matches that in compare and are selected in swap, + * the bit is swapped. + * - Result written back to location on VME bus. + * + * Return: Bytes written on success, -EINVAL if resource is not a VME master + * resource or RMW operation is not supported. Hardware specific + * errors may also be returned. + */ +unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, + unsigned int compare, unsigned int swap, loff_t offset) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_master_resource *image; + + if (!bridge->master_rmw) { + printk(KERN_WARNING "Writing to resource not supported\n"); + return -EINVAL; + } + + if (resource->type != VME_MASTER) { + printk(KERN_ERR "Not a master resource\n"); + return -EINVAL; + } + + image = list_entry(resource->entry, struct vme_master_resource, list); + + return bridge->master_rmw(image, mask, compare, swap, offset); +} +EXPORT_SYMBOL(vme_master_rmw); + +/** + * vme_master_mmap - Mmap region of VME master window. + * @resource: Pointer to VME master resource. + * @vma: Pointer to definition of user mapping. + * + * Memory map a region of the VME master window into user space. + * + * Return: Zero on success, -EINVAL if resource is not a VME master + * resource or -EFAULT if map exceeds window size. Other generic mmap + * errors may also be returned. + */ +int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) +{ + struct vme_master_resource *image; + phys_addr_t phys_addr; + unsigned long vma_size; + + if (resource->type != VME_MASTER) { + pr_err("Not a master resource\n"); + return -EINVAL; + } + + image = list_entry(resource->entry, struct vme_master_resource, list); + phys_addr = image->bus_resource.start + (vma->vm_pgoff << PAGE_SHIFT); + vma_size = vma->vm_end - vma->vm_start; + + if (phys_addr + vma_size > image->bus_resource.end + 1) { + pr_err("Map size cannot exceed the window size\n"); + return -EFAULT; + } + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + return vm_iomap_memory(vma, phys_addr, vma->vm_end - vma->vm_start); +} +EXPORT_SYMBOL(vme_master_mmap); + +/** + * vme_master_free - Free VME master window + * @resource: Pointer to VME master resource. + * + * Free the provided master resource so that it may be reallocated. + */ +void vme_master_free(struct vme_resource *resource) +{ + struct vme_master_resource *master_image; + + if (resource->type != VME_MASTER) { + printk(KERN_ERR "Not a master resource\n"); + return; + } + + master_image = list_entry(resource->entry, struct vme_master_resource, + list); + if (!master_image) { + printk(KERN_ERR "Can't find master resource\n"); + return; + } + + /* Unlock image */ + spin_lock(&master_image->lock); + if (master_image->locked == 0) + printk(KERN_ERR "Image is already free\n"); + + master_image->locked = 0; + spin_unlock(&master_image->lock); + + /* Free up resource memory */ + kfree(resource); +} +EXPORT_SYMBOL(vme_master_free); + +/** + * vme_dma_request - Request a DMA controller. + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * @route: Required src/destination combination. + * + * Request a VME DMA controller with capability to perform transfers bewteen + * requested source/destination combination. + * + * Return: Pointer to VME DMA resource on success, NULL on failure. + */ +struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) +{ + struct vme_bridge *bridge; + struct list_head *dma_pos = NULL; + struct vme_dma_resource *allocated_ctrlr = NULL; + struct vme_dma_resource *dma_ctrlr = NULL; + struct vme_resource *resource = NULL; + + /* XXX Not checking resource attributes */ + printk(KERN_ERR "No VME resource Attribute tests done\n"); + + bridge = vdev->bridge; + if (!bridge) { + printk(KERN_ERR "Can't find VME bus\n"); + goto err_bus; + } + + /* Loop through DMA resources */ + list_for_each(dma_pos, &bridge->dma_resources) { + dma_ctrlr = list_entry(dma_pos, + struct vme_dma_resource, list); + if (!dma_ctrlr) { + printk(KERN_ERR "Registered NULL DMA resource\n"); + continue; + } + + /* Find an unlocked and compatible controller */ + mutex_lock(&dma_ctrlr->mtx); + if (((dma_ctrlr->route_attr & route) == route) && + (dma_ctrlr->locked == 0)) { + + dma_ctrlr->locked = 1; + mutex_unlock(&dma_ctrlr->mtx); + allocated_ctrlr = dma_ctrlr; + break; + } + mutex_unlock(&dma_ctrlr->mtx); + } + + /* Check to see if we found a resource */ + if (!allocated_ctrlr) + goto err_ctrlr; + + resource = kmalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) + goto err_alloc; + + resource->type = VME_DMA; + resource->entry = &allocated_ctrlr->list; + + return resource; + +err_alloc: + /* Unlock image */ + mutex_lock(&dma_ctrlr->mtx); + dma_ctrlr->locked = 0; + mutex_unlock(&dma_ctrlr->mtx); +err_ctrlr: +err_bus: + return NULL; +} +EXPORT_SYMBOL(vme_dma_request); + +/** + * vme_new_dma_list - Create new VME DMA list. + * @resource: Pointer to VME DMA resource. + * + * Create a new VME DMA list. It is the responsibility of the user to free + * the list once it is no longer required with vme_dma_list_free(). + * + * Return: Pointer to new VME DMA list, NULL on allocation failure or invalid + * VME DMA resource. + */ +struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) +{ + struct vme_dma_list *dma_list; + + if (resource->type != VME_DMA) { + printk(KERN_ERR "Not a DMA resource\n"); + return NULL; + } + + dma_list = kmalloc(sizeof(*dma_list), GFP_KERNEL); + if (!dma_list) + return NULL; + + INIT_LIST_HEAD(&dma_list->entries); + dma_list->parent = list_entry(resource->entry, + struct vme_dma_resource, + list); + mutex_init(&dma_list->mtx); + + return dma_list; +} +EXPORT_SYMBOL(vme_new_dma_list); + +/** + * vme_dma_pattern_attribute - Create "Pattern" type VME DMA list attribute. + * @pattern: Value to use used as pattern + * @type: Type of pattern to be written. + * + * Create VME DMA list attribute for pattern generation. It is the + * responsibility of the user to free used attributes using + * vme_dma_free_attribute(). + * + * Return: Pointer to VME DMA attribute, NULL on failure. + */ +struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) +{ + struct vme_dma_attr *attributes; + struct vme_dma_pattern *pattern_attr; + + attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); + if (!attributes) + goto err_attr; + + pattern_attr = kmalloc(sizeof(*pattern_attr), GFP_KERNEL); + if (!pattern_attr) + goto err_pat; + + attributes->type = VME_DMA_PATTERN; + attributes->private = (void *)pattern_attr; + + pattern_attr->pattern = pattern; + pattern_attr->type = type; + + return attributes; + +err_pat: + kfree(attributes); +err_attr: + return NULL; +} +EXPORT_SYMBOL(vme_dma_pattern_attribute); + +/** + * vme_dma_pci_attribute - Create "PCI" type VME DMA list attribute. + * @address: PCI base address for DMA transfer. + * + * Create VME DMA list attribute pointing to a location on PCI for DMA + * transfers. It is the responsibility of the user to free used attributes + * using vme_dma_free_attribute(). + * + * Return: Pointer to VME DMA attribute, NULL on failure. + */ +struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) +{ + struct vme_dma_attr *attributes; + struct vme_dma_pci *pci_attr; + + /* XXX Run some sanity checks here */ + + attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); + if (!attributes) + goto err_attr; + + pci_attr = kmalloc(sizeof(*pci_attr), GFP_KERNEL); + if (!pci_attr) + goto err_pci; + + attributes->type = VME_DMA_PCI; + attributes->private = (void *)pci_attr; + + pci_attr->address = address; + + return attributes; + +err_pci: + kfree(attributes); +err_attr: + return NULL; +} +EXPORT_SYMBOL(vme_dma_pci_attribute); + +/** + * vme_dma_vme_attribute - Create "VME" type VME DMA list attribute. + * @address: VME base address for DMA transfer. + * @aspace: VME address space to use for DMA transfer. + * @cycle: VME bus cycle to use for DMA transfer. + * @dwidth: VME data width to use for DMA transfer. + * + * Create VME DMA list attribute pointing to a location on the VME bus for DMA + * transfers. It is the responsibility of the user to free used attributes + * using vme_dma_free_attribute(). + * + * Return: Pointer to VME DMA attribute, NULL on failure. + */ +struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, + u32 aspace, u32 cycle, u32 dwidth) +{ + struct vme_dma_attr *attributes; + struct vme_dma_vme *vme_attr; + + attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); + if (!attributes) + goto err_attr; + + vme_attr = kmalloc(sizeof(*vme_attr), GFP_KERNEL); + if (!vme_attr) + goto err_vme; + + attributes->type = VME_DMA_VME; + attributes->private = (void *)vme_attr; + + vme_attr->address = address; + vme_attr->aspace = aspace; + vme_attr->cycle = cycle; + vme_attr->dwidth = dwidth; + + return attributes; + +err_vme: + kfree(attributes); +err_attr: + return NULL; +} +EXPORT_SYMBOL(vme_dma_vme_attribute); + +/** + * vme_dma_free_attribute - Free DMA list attribute. + * @attributes: Pointer to DMA list attribute. + * + * Free VME DMA list attribute. VME DMA list attributes can be safely freed + * once vme_dma_list_add() has returned. + */ +void vme_dma_free_attribute(struct vme_dma_attr *attributes) +{ + kfree(attributes->private); + kfree(attributes); +} +EXPORT_SYMBOL(vme_dma_free_attribute); + +/** + * vme_dma_list_add - Add enty to a VME DMA list. + * @list: Pointer to VME list. + * @src: Pointer to DMA list attribute to use as source. + * @dest: Pointer to DMA list attribute to use as destination. + * @count: Number of bytes to transfer. + * + * Add an entry to the provided VME DMA list. Entry requires pointers to source + * and destination DMA attributes and a count. + * + * Please note, the attributes supported as source and destinations for + * transfers are hardware dependent. + * + * Return: Zero on success, -EINVAL if operation is not supported on this + * device or if the link list has already been submitted for execution. + * Hardware specific errors also possible. + */ +int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, + struct vme_dma_attr *dest, size_t count) +{ + struct vme_bridge *bridge = list->parent->parent; + int retval; + + if (!bridge->dma_list_add) { + printk(KERN_WARNING "Link List DMA generation not supported\n"); + return -EINVAL; + } + + if (!mutex_trylock(&list->mtx)) { + printk(KERN_ERR "Link List already submitted\n"); + return -EINVAL; + } + + retval = bridge->dma_list_add(list, src, dest, count); + + mutex_unlock(&list->mtx); + + return retval; +} +EXPORT_SYMBOL(vme_dma_list_add); + +/** + * vme_dma_list_exec - Queue a VME DMA list for execution. + * @list: Pointer to VME list. + * + * Queue the provided VME DMA list for execution. The call will return once the + * list has been executed. + * + * Return: Zero on success, -EINVAL if operation is not supported on this + * device. Hardware specific errors also possible. + */ +int vme_dma_list_exec(struct vme_dma_list *list) +{ + struct vme_bridge *bridge = list->parent->parent; + int retval; + + if (!bridge->dma_list_exec) { + printk(KERN_ERR "Link List DMA execution not supported\n"); + return -EINVAL; + } + + mutex_lock(&list->mtx); + + retval = bridge->dma_list_exec(list); + + mutex_unlock(&list->mtx); + + return retval; +} +EXPORT_SYMBOL(vme_dma_list_exec); + +/** + * vme_dma_list_free - Free a VME DMA list. + * @list: Pointer to VME list. + * + * Free the provided DMA list and all its entries. + * + * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource + * is still in use. Hardware specific errors also possible. + */ +int vme_dma_list_free(struct vme_dma_list *list) +{ + struct vme_bridge *bridge = list->parent->parent; + int retval; + + if (!bridge->dma_list_empty) { + printk(KERN_WARNING "Emptying of Link Lists not supported\n"); + return -EINVAL; + } + + if (!mutex_trylock(&list->mtx)) { + printk(KERN_ERR "Link List in use\n"); + return -EBUSY; + } + + /* + * Empty out all of the entries from the DMA list. We need to go to the + * low level driver as DMA entries are driver specific. + */ + retval = bridge->dma_list_empty(list); + if (retval) { + printk(KERN_ERR "Unable to empty link-list entries\n"); + mutex_unlock(&list->mtx); + return retval; + } + mutex_unlock(&list->mtx); + kfree(list); + + return retval; +} +EXPORT_SYMBOL(vme_dma_list_free); + +/** + * vme_dma_free - Free a VME DMA resource. + * @resource: Pointer to VME DMA resource. + * + * Free the provided DMA resource so that it may be reallocated. + * + * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource + * is still active. + */ +int vme_dma_free(struct vme_resource *resource) +{ + struct vme_dma_resource *ctrlr; + + if (resource->type != VME_DMA) { + printk(KERN_ERR "Not a DMA resource\n"); + return -EINVAL; + } + + ctrlr = list_entry(resource->entry, struct vme_dma_resource, list); + + if (!mutex_trylock(&ctrlr->mtx)) { + printk(KERN_ERR "Resource busy, can't free\n"); + return -EBUSY; + } + + if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) { + printk(KERN_WARNING "Resource still processing transfers\n"); + mutex_unlock(&ctrlr->mtx); + return -EBUSY; + } + + ctrlr->locked = 0; + + mutex_unlock(&ctrlr->mtx); + + kfree(resource); + + return 0; +} +EXPORT_SYMBOL(vme_dma_free); + +void vme_bus_error_handler(struct vme_bridge *bridge, + unsigned long long address, int am) +{ + struct list_head *handler_pos = NULL; + struct vme_error_handler *handler; + int handler_triggered = 0; + u32 aspace = vme_get_aspace(am); + + list_for_each(handler_pos, &bridge->vme_error_handlers) { + handler = list_entry(handler_pos, struct vme_error_handler, + list); + if ((aspace == handler->aspace) && + (address >= handler->start) && + (address < handler->end)) { + if (!handler->num_errors) + handler->first_error = address; + if (handler->num_errors != UINT_MAX) + handler->num_errors++; + handler_triggered = 1; + } + } + + if (!handler_triggered) + dev_err(bridge->parent, + "Unhandled VME access error at address 0x%llx\n", + address); +} +EXPORT_SYMBOL(vme_bus_error_handler); + +struct vme_error_handler *vme_register_error_handler( + struct vme_bridge *bridge, u32 aspace, + unsigned long long address, size_t len) +{ + struct vme_error_handler *handler; + + handler = kmalloc(sizeof(*handler), GFP_ATOMIC); + if (!handler) + return NULL; + + handler->aspace = aspace; + handler->start = address; + handler->end = address + len; + handler->num_errors = 0; + handler->first_error = 0; + list_add_tail(&handler->list, &bridge->vme_error_handlers); + + return handler; +} +EXPORT_SYMBOL(vme_register_error_handler); + +void vme_unregister_error_handler(struct vme_error_handler *handler) +{ + list_del(&handler->list); + kfree(handler); +} +EXPORT_SYMBOL(vme_unregister_error_handler); + +void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) +{ + void (*call)(int, int, void *); + void *priv_data; + + call = bridge->irq[level - 1].callback[statid].func; + priv_data = bridge->irq[level - 1].callback[statid].priv_data; + if (call) + call(level, statid, priv_data); + else + printk(KERN_WARNING "Spurious VME interrupt, level:%x, vector:%x\n", + level, statid); +} +EXPORT_SYMBOL(vme_irq_handler); + +/** + * vme_irq_request - Request a specific VME interrupt. + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * @level: Interrupt priority being requested. + * @statid: Interrupt vector being requested. + * @callback: Pointer to callback function called when VME interrupt/vector + * received. + * @priv_data: Generic pointer that will be passed to the callback function. + * + * Request callback to be attached as a handler for VME interrupts with provided + * level and statid. + * + * Return: Zero on success, -EINVAL on invalid vme device, level or if the + * function is not supported, -EBUSY if the level/statid combination is + * already in use. Hardware specific errors also possible. + */ +int vme_irq_request(struct vme_dev *vdev, int level, int statid, + void (*callback)(int, int, void *), + void *priv_data) +{ + struct vme_bridge *bridge; + + bridge = vdev->bridge; + if (!bridge) { + printk(KERN_ERR "Can't find VME bus\n"); + return -EINVAL; + } + + if ((level < 1) || (level > 7)) { + printk(KERN_ERR "Invalid interrupt level\n"); + return -EINVAL; + } + + if (!bridge->irq_set) { + printk(KERN_ERR "Configuring interrupts not supported\n"); + return -EINVAL; + } + + mutex_lock(&bridge->irq_mtx); + + if (bridge->irq[level - 1].callback[statid].func) { + mutex_unlock(&bridge->irq_mtx); + printk(KERN_WARNING "VME Interrupt already taken\n"); + return -EBUSY; + } + + bridge->irq[level - 1].count++; + bridge->irq[level - 1].callback[statid].priv_data = priv_data; + bridge->irq[level - 1].callback[statid].func = callback; + + /* Enable IRQ level */ + bridge->irq_set(bridge, level, 1, 1); + + mutex_unlock(&bridge->irq_mtx); + + return 0; +} +EXPORT_SYMBOL(vme_irq_request); + +/** + * vme_irq_free - Free a VME interrupt. + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * @level: Interrupt priority of interrupt being freed. + * @statid: Interrupt vector of interrupt being freed. + * + * Remove previously attached callback from VME interrupt priority/vector. + */ +void vme_irq_free(struct vme_dev *vdev, int level, int statid) +{ + struct vme_bridge *bridge; + + bridge = vdev->bridge; + if (!bridge) { + printk(KERN_ERR "Can't find VME bus\n"); + return; + } + + if ((level < 1) || (level > 7)) { + printk(KERN_ERR "Invalid interrupt level\n"); + return; + } + + if (!bridge->irq_set) { + printk(KERN_ERR "Configuring interrupts not supported\n"); + return; + } + + mutex_lock(&bridge->irq_mtx); + + bridge->irq[level - 1].count--; + + /* Disable IRQ level if no more interrupts attached at this level*/ + if (bridge->irq[level - 1].count == 0) + bridge->irq_set(bridge, level, 0, 1); + + bridge->irq[level - 1].callback[statid].func = NULL; + bridge->irq[level - 1].callback[statid].priv_data = NULL; + + mutex_unlock(&bridge->irq_mtx); +} +EXPORT_SYMBOL(vme_irq_free); + +/** + * vme_irq_generate - Generate VME interrupt. + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * @level: Interrupt priority at which to assert the interrupt. + * @statid: Interrupt vector to associate with the interrupt. + * + * Generate a VME interrupt of the provided level and with the provided + * statid. + * + * Return: Zero on success, -EINVAL on invalid vme device, level or if the + * function is not supported. Hardware specific errors also possible. + */ +int vme_irq_generate(struct vme_dev *vdev, int level, int statid) +{ + struct vme_bridge *bridge; + + bridge = vdev->bridge; + if (!bridge) { + printk(KERN_ERR "Can't find VME bus\n"); + return -EINVAL; + } + + if ((level < 1) || (level > 7)) { + printk(KERN_WARNING "Invalid interrupt level\n"); + return -EINVAL; + } + + if (!bridge->irq_generate) { + printk(KERN_WARNING "Interrupt generation not supported\n"); + return -EINVAL; + } + + return bridge->irq_generate(bridge, level, statid); +} +EXPORT_SYMBOL(vme_irq_generate); + +/** + * vme_lm_request - Request a VME location monitor + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * + * Allocate a location monitor resource to the driver. A location monitor + * allows the driver to monitor accesses to a contiguous number of + * addresses on the VME bus. + * + * Return: Pointer to a VME resource on success or NULL on failure. + */ +struct vme_resource *vme_lm_request(struct vme_dev *vdev) +{ + struct vme_bridge *bridge; + struct list_head *lm_pos = NULL; + struct vme_lm_resource *allocated_lm = NULL; + struct vme_lm_resource *lm = NULL; + struct vme_resource *resource = NULL; + + bridge = vdev->bridge; + if (!bridge) { + printk(KERN_ERR "Can't find VME bus\n"); + goto err_bus; + } + + /* Loop through LM resources */ + list_for_each(lm_pos, &bridge->lm_resources) { + lm = list_entry(lm_pos, + struct vme_lm_resource, list); + if (!lm) { + printk(KERN_ERR "Registered NULL Location Monitor resource\n"); + continue; + } + + /* Find an unlocked controller */ + mutex_lock(&lm->mtx); + if (lm->locked == 0) { + lm->locked = 1; + mutex_unlock(&lm->mtx); + allocated_lm = lm; + break; + } + mutex_unlock(&lm->mtx); + } + + /* Check to see if we found a resource */ + if (!allocated_lm) + goto err_lm; + + resource = kmalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) + goto err_alloc; + + resource->type = VME_LM; + resource->entry = &allocated_lm->list; + + return resource; + +err_alloc: + /* Unlock image */ + mutex_lock(&lm->mtx); + lm->locked = 0; + mutex_unlock(&lm->mtx); +err_lm: +err_bus: + return NULL; +} +EXPORT_SYMBOL(vme_lm_request); + +/** + * vme_lm_count - Determine number of VME Addresses monitored + * @resource: Pointer to VME location monitor resource. + * + * The number of contiguous addresses monitored is hardware dependent. + * Return the number of contiguous addresses monitored by the + * location monitor. + * + * Return: Count of addresses monitored or -EINVAL when provided with an + * invalid location monitor resource. + */ +int vme_lm_count(struct vme_resource *resource) +{ + struct vme_lm_resource *lm; + + if (resource->type != VME_LM) { + printk(KERN_ERR "Not a Location Monitor resource\n"); + return -EINVAL; + } + + lm = list_entry(resource->entry, struct vme_lm_resource, list); + + return lm->monitors; +} +EXPORT_SYMBOL(vme_lm_count); + +/** + * vme_lm_set - Configure location monitor + * @resource: Pointer to VME location monitor resource. + * @lm_base: Base address to monitor. + * @aspace: VME address space to monitor. + * @cycle: VME bus cycle type to monitor. + * + * Set the base address, address space and cycle type of accesses to be + * monitored by the location monitor. + * + * Return: Zero on success, -EINVAL when provided with an invalid location + * monitor resource or function is not supported. Hardware specific + * errors may also be returned. + */ +int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, + u32 aspace, u32 cycle) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_lm_resource *lm; + + if (resource->type != VME_LM) { + printk(KERN_ERR "Not a Location Monitor resource\n"); + return -EINVAL; + } + + lm = list_entry(resource->entry, struct vme_lm_resource, list); + + if (!bridge->lm_set) { + printk(KERN_ERR "vme_lm_set not supported\n"); + return -EINVAL; + } + + return bridge->lm_set(lm, lm_base, aspace, cycle); +} +EXPORT_SYMBOL(vme_lm_set); + +/** + * vme_lm_get - Retrieve location monitor settings + * @resource: Pointer to VME location monitor resource. + * @lm_base: Pointer used to output the base address monitored. + * @aspace: Pointer used to output the address space monitored. + * @cycle: Pointer used to output the VME bus cycle type monitored. + * + * Retrieve the base address, address space and cycle type of accesses to + * be monitored by the location monitor. + * + * Return: Zero on success, -EINVAL when provided with an invalid location + * monitor resource or function is not supported. Hardware specific + * errors may also be returned. + */ +int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, + u32 *aspace, u32 *cycle) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_lm_resource *lm; + + if (resource->type != VME_LM) { + printk(KERN_ERR "Not a Location Monitor resource\n"); + return -EINVAL; + } + + lm = list_entry(resource->entry, struct vme_lm_resource, list); + + if (!bridge->lm_get) { + printk(KERN_ERR "vme_lm_get not supported\n"); + return -EINVAL; + } + + return bridge->lm_get(lm, lm_base, aspace, cycle); +} +EXPORT_SYMBOL(vme_lm_get); + +/** + * vme_lm_attach - Provide callback for location monitor address + * @resource: Pointer to VME location monitor resource. + * @monitor: Offset to which callback should be attached. + * @callback: Pointer to callback function called when triggered. + * @data: Generic pointer that will be passed to the callback function. + * + * Attach a callback to the specificed offset into the location monitors + * monitored addresses. A generic pointer is provided to allow data to be + * passed to the callback when called. + * + * Return: Zero on success, -EINVAL when provided with an invalid location + * monitor resource or function is not supported. Hardware specific + * errors may also be returned. + */ +int vme_lm_attach(struct vme_resource *resource, int monitor, + void (*callback)(void *), void *data) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_lm_resource *lm; + + if (resource->type != VME_LM) { + printk(KERN_ERR "Not a Location Monitor resource\n"); + return -EINVAL; + } + + lm = list_entry(resource->entry, struct vme_lm_resource, list); + + if (!bridge->lm_attach) { + printk(KERN_ERR "vme_lm_attach not supported\n"); + return -EINVAL; + } + + return bridge->lm_attach(lm, monitor, callback, data); +} +EXPORT_SYMBOL(vme_lm_attach); + +/** + * vme_lm_detach - Remove callback for location monitor address + * @resource: Pointer to VME location monitor resource. + * @monitor: Offset to which callback should be removed. + * + * Remove the callback associated with the specificed offset into the + * location monitors monitored addresses. + * + * Return: Zero on success, -EINVAL when provided with an invalid location + * monitor resource or function is not supported. Hardware specific + * errors may also be returned. + */ +int vme_lm_detach(struct vme_resource *resource, int monitor) +{ + struct vme_bridge *bridge = find_bridge(resource); + struct vme_lm_resource *lm; + + if (resource->type != VME_LM) { + printk(KERN_ERR "Not a Location Monitor resource\n"); + return -EINVAL; + } + + lm = list_entry(resource->entry, struct vme_lm_resource, list); + + if (!bridge->lm_detach) { + printk(KERN_ERR "vme_lm_detach not supported\n"); + return -EINVAL; + } + + return bridge->lm_detach(lm, monitor); +} +EXPORT_SYMBOL(vme_lm_detach); + +/** + * vme_lm_free - Free allocated VME location monitor + * @resource: Pointer to VME location monitor resource. + * + * Free allocation of a VME location monitor. + * + * WARNING: This function currently expects that any callbacks that have + * been attached to the location monitor have been removed. + * + * Return: Zero on success, -EINVAL when provided with an invalid location + * monitor resource. + */ +void vme_lm_free(struct vme_resource *resource) +{ + struct vme_lm_resource *lm; + + if (resource->type != VME_LM) { + printk(KERN_ERR "Not a Location Monitor resource\n"); + return; + } + + lm = list_entry(resource->entry, struct vme_lm_resource, list); + + mutex_lock(&lm->mtx); + + /* XXX + * Check to see that there aren't any callbacks still attached, if + * there are we should probably be detaching them! + */ + + lm->locked = 0; + + mutex_unlock(&lm->mtx); + + kfree(resource); +} +EXPORT_SYMBOL(vme_lm_free); + +/** + * vme_slot_num - Retrieve slot ID + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * + * Retrieve the slot ID associated with the provided VME device. + * + * Return: The slot ID on success, -EINVAL if VME bridge cannot be determined + * or the function is not supported. Hardware specific errors may also + * be returned. + */ +int vme_slot_num(struct vme_dev *vdev) +{ + struct vme_bridge *bridge; + + bridge = vdev->bridge; + if (!bridge) { + printk(KERN_ERR "Can't find VME bus\n"); + return -EINVAL; + } + + if (!bridge->slot_get) { + printk(KERN_WARNING "vme_slot_num not supported\n"); + return -EINVAL; + } + + return bridge->slot_get(bridge); +} +EXPORT_SYMBOL(vme_slot_num); + +/** + * vme_bus_num - Retrieve bus number + * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. + * + * Retrieve the bus enumeration associated with the provided VME device. + * + * Return: The bus number on success, -EINVAL if VME bridge cannot be + * determined. + */ +int vme_bus_num(struct vme_dev *vdev) +{ + struct vme_bridge *bridge; + + bridge = vdev->bridge; + if (!bridge) { + pr_err("Can't find VME bus\n"); + return -EINVAL; + } + + return bridge->num; +} +EXPORT_SYMBOL(vme_bus_num); + +/* - Bridge Registration --------------------------------------------------- */ + +static void vme_dev_release(struct device *dev) +{ + kfree(dev_to_vme_dev(dev)); +} + +/* Common bridge initialization */ +struct vme_bridge *vme_init_bridge(struct vme_bridge *bridge) +{ + INIT_LIST_HEAD(&bridge->vme_error_handlers); + INIT_LIST_HEAD(&bridge->master_resources); + INIT_LIST_HEAD(&bridge->slave_resources); + INIT_LIST_HEAD(&bridge->dma_resources); + INIT_LIST_HEAD(&bridge->lm_resources); + mutex_init(&bridge->irq_mtx); + + return bridge; +} +EXPORT_SYMBOL(vme_init_bridge); + +int vme_register_bridge(struct vme_bridge *bridge) +{ + int i; + int ret = -1; + + mutex_lock(&vme_buses_lock); + for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) { + if ((vme_bus_numbers & (1 << i)) == 0) { + vme_bus_numbers |= (1 << i); + bridge->num = i; + INIT_LIST_HEAD(&bridge->devices); + list_add_tail(&bridge->bus_list, &vme_bus_list); + ret = 0; + break; + } + } + mutex_unlock(&vme_buses_lock); + + return ret; +} +EXPORT_SYMBOL(vme_register_bridge); + +void vme_unregister_bridge(struct vme_bridge *bridge) +{ + struct vme_dev *vdev; + struct vme_dev *tmp; + + mutex_lock(&vme_buses_lock); + vme_bus_numbers &= ~(1 << bridge->num); + list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) { + list_del(&vdev->drv_list); + list_del(&vdev->bridge_list); + device_unregister(&vdev->dev); + } + list_del(&bridge->bus_list); + mutex_unlock(&vme_buses_lock); +} +EXPORT_SYMBOL(vme_unregister_bridge); + +/* - Driver Registration --------------------------------------------------- */ + +static int __vme_register_driver_bus(struct vme_driver *drv, + struct vme_bridge *bridge, unsigned int ndevs) +{ + int err; + unsigned int i; + struct vme_dev *vdev; + struct vme_dev *tmp; + + for (i = 0; i < ndevs; i++) { + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + if (!vdev) { + err = -ENOMEM; + goto err_devalloc; + } + vdev->num = i; + vdev->bridge = bridge; + vdev->dev.platform_data = drv; + vdev->dev.release = vme_dev_release; + vdev->dev.parent = bridge->parent; + vdev->dev.bus = &vme_bus_type; + dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num, + vdev->num); + + err = device_register(&vdev->dev); + if (err) + goto err_reg; + + if (vdev->dev.platform_data) { + list_add_tail(&vdev->drv_list, &drv->devices); + list_add_tail(&vdev->bridge_list, &bridge->devices); + } else + device_unregister(&vdev->dev); + } + return 0; + +err_reg: + put_device(&vdev->dev); +err_devalloc: + list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) { + list_del(&vdev->drv_list); + list_del(&vdev->bridge_list); + device_unregister(&vdev->dev); + } + return err; +} + +static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) +{ + struct vme_bridge *bridge; + int err = 0; + + mutex_lock(&vme_buses_lock); + list_for_each_entry(bridge, &vme_bus_list, bus_list) { + /* + * This cannot cause trouble as we already have vme_buses_lock + * and if the bridge is removed, it will have to go through + * vme_unregister_bridge() to do it (which calls remove() on + * the bridge which in turn tries to acquire vme_buses_lock and + * will have to wait). + */ + err = __vme_register_driver_bus(drv, bridge, ndevs); + if (err) + break; + } + mutex_unlock(&vme_buses_lock); + return err; +} + +/** + * vme_register_driver - Register a VME driver + * @drv: Pointer to VME driver structure to register. + * @ndevs: Maximum number of devices to allow to be enumerated. + * + * Register a VME device driver with the VME subsystem. + * + * Return: Zero on success, error value on registration failure. + */ +int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) +{ + int err; + + drv->driver.name = drv->name; + drv->driver.bus = &vme_bus_type; + INIT_LIST_HEAD(&drv->devices); + + err = driver_register(&drv->driver); + if (err) + return err; + + err = __vme_register_driver(drv, ndevs); + if (err) + driver_unregister(&drv->driver); + + return err; +} +EXPORT_SYMBOL(vme_register_driver); + +/** + * vme_unregister_driver - Unregister a VME driver + * @drv: Pointer to VME driver structure to unregister. + * + * Unregister a VME device driver from the VME subsystem. + */ +void vme_unregister_driver(struct vme_driver *drv) +{ + struct vme_dev *dev, *dev_tmp; + + mutex_lock(&vme_buses_lock); + list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) { + list_del(&dev->drv_list); + list_del(&dev->bridge_list); + device_unregister(&dev->dev); + } + mutex_unlock(&vme_buses_lock); + + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(vme_unregister_driver); + +/* - Bus Registration ------------------------------------------------------ */ + +static int vme_bus_match(struct device *dev, struct device_driver *drv) +{ + struct vme_driver *vme_drv; + + vme_drv = container_of(drv, struct vme_driver, driver); + + if (dev->platform_data == vme_drv) { + struct vme_dev *vdev = dev_to_vme_dev(dev); + + if (vme_drv->match && vme_drv->match(vdev)) + return 1; + + dev->platform_data = NULL; + } + return 0; +} + +static int vme_bus_probe(struct device *dev) +{ + struct vme_driver *driver; + struct vme_dev *vdev = dev_to_vme_dev(dev); + + driver = dev->platform_data; + if (driver->probe) + return driver->probe(vdev); + + return -ENODEV; +} + +static void vme_bus_remove(struct device *dev) +{ + struct vme_driver *driver; + struct vme_dev *vdev = dev_to_vme_dev(dev); + + driver = dev->platform_data; + if (driver->remove) + driver->remove(vdev); +} + +struct bus_type vme_bus_type = { + .name = "vme", + .match = vme_bus_match, + .probe = vme_bus_probe, + .remove = vme_bus_remove, +}; +EXPORT_SYMBOL(vme_bus_type); + +static int __init vme_init(void) +{ + return bus_register(&vme_bus_type); +} +subsys_initcall(vme_init); diff --git a/drivers/staging/vme_user/vme.h b/drivers/staging/vme_user/vme.h new file mode 100644 index 000000000000..b204a9b4be1b --- /dev/null +++ b/drivers/staging/vme_user/vme.h @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _VME_H_ +#define _VME_H_ + +/* Resource Type */ +enum vme_resource_type { + VME_MASTER, + VME_SLAVE, + VME_DMA, + VME_LM +}; + +/* VME Address Spaces */ +#define VME_A16 0x1 +#define VME_A24 0x2 +#define VME_A32 0x4 +#define VME_A64 0x8 +#define VME_CRCSR 0x10 +#define VME_USER1 0x20 +#define VME_USER2 0x40 +#define VME_USER3 0x80 +#define VME_USER4 0x100 + +#define VME_A16_MAX 0x10000ULL +#define VME_A24_MAX 0x1000000ULL +#define VME_A32_MAX 0x100000000ULL +#define VME_A64_MAX 0x10000000000000000ULL +#define VME_CRCSR_MAX 0x1000000ULL + + +/* VME Cycle Types */ +#define VME_SCT 0x1 +#define VME_BLT 0x2 +#define VME_MBLT 0x4 +#define VME_2eVME 0x8 +#define VME_2eSST 0x10 +#define VME_2eSSTB 0x20 + +#define VME_2eSST160 0x100 +#define VME_2eSST267 0x200 +#define VME_2eSST320 0x400 + +#define VME_SUPER 0x1000 +#define VME_USER 0x2000 +#define VME_PROG 0x4000 +#define VME_DATA 0x8000 + +/* VME Data Widths */ +#define VME_D8 0x1 +#define VME_D16 0x2 +#define VME_D32 0x4 +#define VME_D64 0x8 + +/* Arbitration Scheduling Modes */ +#define VME_R_ROBIN_MODE 0x1 +#define VME_PRIORITY_MODE 0x2 + +#define VME_DMA_PATTERN (1<<0) +#define VME_DMA_PCI (1<<1) +#define VME_DMA_VME (1<<2) + +#define VME_DMA_PATTERN_BYTE (1<<0) +#define VME_DMA_PATTERN_WORD (1<<1) +#define VME_DMA_PATTERN_INCREMENT (1<<2) + +#define VME_DMA_VME_TO_MEM (1<<0) +#define VME_DMA_MEM_TO_VME (1<<1) +#define VME_DMA_VME_TO_VME (1<<2) +#define VME_DMA_MEM_TO_MEM (1<<3) +#define VME_DMA_PATTERN_TO_VME (1<<4) +#define VME_DMA_PATTERN_TO_MEM (1<<5) + +struct vme_dma_attr { + u32 type; + void *private; +}; + +struct vme_resource { + enum vme_resource_type type; + struct list_head *entry; +}; + +extern struct bus_type vme_bus_type; + +/* Number of VME interrupt vectors */ +#define VME_NUM_STATUSID 256 + +/* VME_MAX_BRIDGES comes from the type of vme_bus_numbers */ +#define VME_MAX_BRIDGES (sizeof(unsigned int)*8) +#define VME_MAX_SLOTS 32 + +#define VME_SLOT_CURRENT -1 +#define VME_SLOT_ALL -2 + +/** + * struct vme_dev - Structure representing a VME device + * @num: The device number + * @bridge: Pointer to the bridge device this device is on + * @dev: Internal device structure + * @drv_list: List of devices (per driver) + * @bridge_list: List of devices (per bridge) + */ +struct vme_dev { + int num; + struct vme_bridge *bridge; + struct device dev; + struct list_head drv_list; + struct list_head bridge_list; +}; + +/** + * struct vme_driver - Structure representing a VME driver + * @name: Driver name, should be unique among VME drivers and usually the same + * as the module name. + * @match: Callback used to determine whether probe should be run. + * @probe: Callback for device binding, called when new device is detected. + * @remove: Callback, called on device removal. + * @driver: Underlying generic device driver structure. + * @devices: List of VME devices (struct vme_dev) associated with this driver. + */ +struct vme_driver { + const char *name; + int (*match)(struct vme_dev *); + int (*probe)(struct vme_dev *); + void (*remove)(struct vme_dev *); + struct device_driver driver; + struct list_head devices; +}; + +void *vme_alloc_consistent(struct vme_resource *, size_t, dma_addr_t *); +void vme_free_consistent(struct vme_resource *, size_t, void *, + dma_addr_t); + +size_t vme_get_size(struct vme_resource *); +int vme_check_window(u32 aspace, unsigned long long vme_base, + unsigned long long size); + +struct vme_resource *vme_slave_request(struct vme_dev *, u32, u32); +int vme_slave_set(struct vme_resource *, int, unsigned long long, + unsigned long long, dma_addr_t, u32, u32); +int vme_slave_get(struct vme_resource *, int *, unsigned long long *, + unsigned long long *, dma_addr_t *, u32 *, u32 *); +void vme_slave_free(struct vme_resource *); + +struct vme_resource *vme_master_request(struct vme_dev *, u32, u32, u32); +int vme_master_set(struct vme_resource *, int, unsigned long long, + unsigned long long, u32, u32, u32); +int vme_master_get(struct vme_resource *, int *, unsigned long long *, + unsigned long long *, u32 *, u32 *, u32 *); +ssize_t vme_master_read(struct vme_resource *, void *, size_t, loff_t); +ssize_t vme_master_write(struct vme_resource *, void *, size_t, loff_t); +unsigned int vme_master_rmw(struct vme_resource *, unsigned int, unsigned int, + unsigned int, loff_t); +int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma); +void vme_master_free(struct vme_resource *); + +struct vme_resource *vme_dma_request(struct vme_dev *, u32); +struct vme_dma_list *vme_new_dma_list(struct vme_resource *); +struct vme_dma_attr *vme_dma_pattern_attribute(u32, u32); +struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t); +struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long, u32, u32, u32); +void vme_dma_free_attribute(struct vme_dma_attr *); +int vme_dma_list_add(struct vme_dma_list *, struct vme_dma_attr *, + struct vme_dma_attr *, size_t); +int vme_dma_list_exec(struct vme_dma_list *); +int vme_dma_list_free(struct vme_dma_list *); +int vme_dma_free(struct vme_resource *); + +int vme_irq_request(struct vme_dev *, int, int, + void (*callback)(int, int, void *), void *); +void vme_irq_free(struct vme_dev *, int, int); +int vme_irq_generate(struct vme_dev *, int, int); + +struct vme_resource *vme_lm_request(struct vme_dev *); +int vme_lm_count(struct vme_resource *); +int vme_lm_set(struct vme_resource *, unsigned long long, u32, u32); +int vme_lm_get(struct vme_resource *, unsigned long long *, u32 *, u32 *); +int vme_lm_attach(struct vme_resource *, int, void (*callback)(void *), void *); +int vme_lm_detach(struct vme_resource *, int); +void vme_lm_free(struct vme_resource *); + +int vme_slot_num(struct vme_dev *); +int vme_bus_num(struct vme_dev *); + +int vme_register_driver(struct vme_driver *, unsigned int); +void vme_unregister_driver(struct vme_driver *); + + +#endif /* _VME_H_ */ + diff --git a/drivers/staging/vme_user/vme_bridge.h b/drivers/staging/vme_user/vme_bridge.h new file mode 100644 index 000000000000..0bbefe9851d7 --- /dev/null +++ b/drivers/staging/vme_user/vme_bridge.h @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _VME_BRIDGE_H_ +#define _VME_BRIDGE_H_ + +#include "vme.h" + +#define VME_CRCSR_BUF_SIZE (508*1024) +/* + * Resource structures + */ +struct vme_master_resource { + struct list_head list; + struct vme_bridge *parent; + /* + * We are likely to need to access the VME bus in interrupt context, so + * protect master routines with a spinlock rather than a mutex. + */ + spinlock_t lock; + int locked; + int number; + u32 address_attr; + u32 cycle_attr; + u32 width_attr; + struct resource bus_resource; + void __iomem *kern_base; +}; + +struct vme_slave_resource { + struct list_head list; + struct vme_bridge *parent; + struct mutex mtx; + int locked; + int number; + u32 address_attr; + u32 cycle_attr; +}; + +struct vme_dma_pattern { + u32 pattern; + u32 type; +}; + +struct vme_dma_pci { + dma_addr_t address; +}; + +struct vme_dma_vme { + unsigned long long address; + u32 aspace; + u32 cycle; + u32 dwidth; +}; + +struct vme_dma_list { + struct list_head list; + struct vme_dma_resource *parent; + struct list_head entries; + struct mutex mtx; +}; + +struct vme_dma_resource { + struct list_head list; + struct vme_bridge *parent; + struct mutex mtx; + int locked; + int number; + struct list_head pending; + struct list_head running; + u32 route_attr; +}; + +struct vme_lm_resource { + struct list_head list; + struct vme_bridge *parent; + struct mutex mtx; + int locked; + int number; + int monitors; +}; + +struct vme_error_handler { + struct list_head list; + unsigned long long start; /* Beginning of error window */ + unsigned long long end; /* End of error window */ + unsigned long long first_error; /* Address of the first error */ + u32 aspace; /* Address space of error window*/ + unsigned num_errors; /* Number of errors */ +}; + +struct vme_callback { + void (*func)(int, int, void*); + void *priv_data; +}; + +struct vme_irq { + int count; + struct vme_callback callback[VME_NUM_STATUSID]; +}; + +/* Allow 16 characters for name (including null character) */ +#define VMENAMSIZ 16 + +/* This structure stores all the information about one bridge + * The structure should be dynamically allocated by the driver and one instance + * of the structure should be present for each VME chip present in the system. + */ +struct vme_bridge { + char name[VMENAMSIZ]; + int num; + struct list_head master_resources; + struct list_head slave_resources; + struct list_head dma_resources; + struct list_head lm_resources; + + /* List for registered errors handlers */ + struct list_head vme_error_handlers; + /* List of devices on this bridge */ + struct list_head devices; + + /* Bridge Info - XXX Move to private structure? */ + struct device *parent; /* Parent device (eg. pdev->dev for PCI) */ + void *driver_priv; /* Private pointer for the bridge driver */ + struct list_head bus_list; /* list of VME buses */ + + /* Interrupt callbacks */ + struct vme_irq irq[7]; + /* Locking for VME irq callback configuration */ + struct mutex irq_mtx; + + /* Slave Functions */ + int (*slave_get) (struct vme_slave_resource *, int *, + unsigned long long *, unsigned long long *, dma_addr_t *, + u32 *, u32 *); + int (*slave_set) (struct vme_slave_resource *, int, unsigned long long, + unsigned long long, dma_addr_t, u32, u32); + + /* Master Functions */ + int (*master_get) (struct vme_master_resource *, int *, + unsigned long long *, unsigned long long *, u32 *, u32 *, + u32 *); + int (*master_set) (struct vme_master_resource *, int, + unsigned long long, unsigned long long, u32, u32, u32); + ssize_t (*master_read) (struct vme_master_resource *, void *, size_t, + loff_t); + ssize_t (*master_write) (struct vme_master_resource *, void *, size_t, + loff_t); + unsigned int (*master_rmw) (struct vme_master_resource *, unsigned int, + unsigned int, unsigned int, loff_t); + + /* DMA Functions */ + int (*dma_list_add) (struct vme_dma_list *, struct vme_dma_attr *, + struct vme_dma_attr *, size_t); + int (*dma_list_exec) (struct vme_dma_list *); + int (*dma_list_empty) (struct vme_dma_list *); + + /* Interrupt Functions */ + void (*irq_set) (struct vme_bridge *, int, int, int); + int (*irq_generate) (struct vme_bridge *, int, int); + + /* Location monitor functions */ + int (*lm_set) (struct vme_lm_resource *, unsigned long long, u32, u32); + int (*lm_get) (struct vme_lm_resource *, unsigned long long *, u32 *, + u32 *); + int (*lm_attach)(struct vme_lm_resource *, int, + void (*callback)(void *), void *); + int (*lm_detach) (struct vme_lm_resource *, int); + + /* CR/CSR space functions */ + int (*slot_get) (struct vme_bridge *); + + /* Bridge parent interface */ + void *(*alloc_consistent)(struct device *dev, size_t size, + dma_addr_t *dma); + void (*free_consistent)(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma); +}; + +void vme_bus_error_handler(struct vme_bridge *bridge, + unsigned long long address, int am); +void vme_irq_handler(struct vme_bridge *, int, int); + +struct vme_bridge *vme_init_bridge(struct vme_bridge *); +int vme_register_bridge(struct vme_bridge *); +void vme_unregister_bridge(struct vme_bridge *); +struct vme_error_handler *vme_register_error_handler( + struct vme_bridge *bridge, u32 aspace, + unsigned long long address, size_t len); +void vme_unregister_error_handler(struct vme_error_handler *handler); + +#endif /* _VME_BRIDGE_H_ */ diff --git a/drivers/staging/vme_user/vme_fake.c b/drivers/staging/vme_user/vme_fake.c new file mode 100644 index 000000000000..dd646b0c531d --- /dev/null +++ b/drivers/staging/vme_user/vme_fake.c @@ -0,0 +1,1305 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Fake VME bridge support. + * + * This drive provides a fake VME bridge chip, this enables debugging of the + * VME framework in the absence of a VME system. + * + * This driver has to do a number of things in software that would be driven + * by hardware if it was available, it will also result in extra overhead at + * times when compared with driving actual hardware. + * + * Author: Martyn Welch + * Copyright (c) 2014 Martyn Welch + * + * Based on vme_tsi148.c: + * + * Author: Martyn Welch + * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. + * + * Based on work by Tom Armistead and Ajit Prem + * Copyright 2004 Motorola Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vme.h" +#include "vme_bridge.h" + +/* + * Define the number of each that the fake driver supports. + */ +#define FAKE_MAX_MASTER 8 /* Max Master Windows */ +#define FAKE_MAX_SLAVE 8 /* Max Slave Windows */ + +/* Structures to hold information normally held in device registers */ +struct fake_slave_window { + int enabled; + unsigned long long vme_base; + unsigned long long size; + void *buf_base; + u32 aspace; + u32 cycle; +}; + +struct fake_master_window { + int enabled; + unsigned long long vme_base; + unsigned long long size; + u32 aspace; + u32 cycle; + u32 dwidth; +}; + +/* Structure used to hold driver specific information */ +struct fake_driver { + struct vme_bridge *parent; + struct fake_slave_window slaves[FAKE_MAX_SLAVE]; + struct fake_master_window masters[FAKE_MAX_MASTER]; + u32 lm_enabled; + unsigned long long lm_base; + u32 lm_aspace; + u32 lm_cycle; + void (*lm_callback[4])(void *); + void *lm_data[4]; + struct tasklet_struct int_tasklet; + int int_level; + int int_statid; + void *crcsr_kernel; + dma_addr_t crcsr_bus; + /* Only one VME interrupt can be generated at a time, provide locking */ + struct mutex vme_int; +}; + +/* Module parameter */ +static int geoid; + +static const char driver_name[] = "vme_fake"; + +static struct vme_bridge *exit_pointer; + +static struct device *vme_root; + +/* + * Calling VME bus interrupt callback if provided. + */ +static void fake_VIRQ_tasklet(unsigned long data) +{ + struct vme_bridge *fake_bridge; + struct fake_driver *bridge; + + fake_bridge = (struct vme_bridge *) data; + bridge = fake_bridge->driver_priv; + + vme_irq_handler(fake_bridge, bridge->int_level, bridge->int_statid); +} + +/* + * Configure VME interrupt + */ +static void fake_irq_set(struct vme_bridge *fake_bridge, int level, + int state, int sync) +{ + /* Nothing to do */ +} + +static void *fake_pci_to_ptr(dma_addr_t addr) +{ + return (void *)(uintptr_t)addr; +} + +static dma_addr_t fake_ptr_to_pci(void *addr) +{ + return (dma_addr_t)(uintptr_t)addr; +} + +/* + * Generate a VME bus interrupt at the requested level & vector. Wait for + * interrupt to be acked. + */ +static int fake_irq_generate(struct vme_bridge *fake_bridge, int level, + int statid) +{ + struct fake_driver *bridge; + + bridge = fake_bridge->driver_priv; + + mutex_lock(&bridge->vme_int); + + bridge->int_level = level; + + bridge->int_statid = statid; + + /* + * Schedule tasklet to run VME handler to emulate normal VME interrupt + * handler behaviour. + */ + tasklet_schedule(&bridge->int_tasklet); + + mutex_unlock(&bridge->vme_int); + + return 0; +} + +/* + * Initialize a slave window with the requested attributes. + */ +static int fake_slave_set(struct vme_slave_resource *image, int enabled, + unsigned long long vme_base, unsigned long long size, + dma_addr_t buf_base, u32 aspace, u32 cycle) +{ + unsigned int i, granularity = 0; + unsigned long long vme_bound; + struct vme_bridge *fake_bridge; + struct fake_driver *bridge; + + fake_bridge = image->parent; + bridge = fake_bridge->driver_priv; + + i = image->number; + + switch (aspace) { + case VME_A16: + granularity = 0x10; + break; + case VME_A24: + granularity = 0x1000; + break; + case VME_A32: + granularity = 0x10000; + break; + case VME_A64: + granularity = 0x10000; + break; + case VME_CRCSR: + case VME_USER1: + case VME_USER2: + case VME_USER3: + case VME_USER4: + default: + pr_err("Invalid address space\n"); + return -EINVAL; + } + + /* + * Bound address is a valid address for the window, adjust + * accordingly + */ + vme_bound = vme_base + size - granularity; + + if (vme_base & (granularity - 1)) { + pr_err("Invalid VME base alignment\n"); + return -EINVAL; + } + if (vme_bound & (granularity - 1)) { + pr_err("Invalid VME bound alignment\n"); + return -EINVAL; + } + + mutex_lock(&image->mtx); + + bridge->slaves[i].enabled = enabled; + bridge->slaves[i].vme_base = vme_base; + bridge->slaves[i].size = size; + bridge->slaves[i].buf_base = fake_pci_to_ptr(buf_base); + bridge->slaves[i].aspace = aspace; + bridge->slaves[i].cycle = cycle; + + mutex_unlock(&image->mtx); + + return 0; +} + +/* + * Get slave window configuration. + */ +static int fake_slave_get(struct vme_slave_resource *image, int *enabled, + unsigned long long *vme_base, unsigned long long *size, + dma_addr_t *buf_base, u32 *aspace, u32 *cycle) +{ + unsigned int i; + struct fake_driver *bridge; + + bridge = image->parent->driver_priv; + + i = image->number; + + mutex_lock(&image->mtx); + + *enabled = bridge->slaves[i].enabled; + *vme_base = bridge->slaves[i].vme_base; + *size = bridge->slaves[i].size; + *buf_base = fake_ptr_to_pci(bridge->slaves[i].buf_base); + *aspace = bridge->slaves[i].aspace; + *cycle = bridge->slaves[i].cycle; + + mutex_unlock(&image->mtx); + + return 0; +} + +/* + * Set the attributes of an outbound window. + */ +static int fake_master_set(struct vme_master_resource *image, int enabled, + unsigned long long vme_base, unsigned long long size, + u32 aspace, u32 cycle, u32 dwidth) +{ + int retval = 0; + unsigned int i; + struct vme_bridge *fake_bridge; + struct fake_driver *bridge; + + fake_bridge = image->parent; + + bridge = fake_bridge->driver_priv; + + /* Verify input data */ + if (vme_base & 0xFFFF) { + pr_err("Invalid VME Window alignment\n"); + retval = -EINVAL; + goto err_window; + } + + if (size & 0xFFFF) { + pr_err("Invalid size alignment\n"); + retval = -EINVAL; + goto err_window; + } + + if ((size == 0) && (enabled != 0)) { + pr_err("Size must be non-zero for enabled windows\n"); + retval = -EINVAL; + goto err_window; + } + + /* Setup data width */ + switch (dwidth) { + case VME_D8: + case VME_D16: + case VME_D32: + break; + default: + pr_err("Invalid data width\n"); + retval = -EINVAL; + goto err_dwidth; + } + + /* Setup address space */ + switch (aspace) { + case VME_A16: + case VME_A24: + case VME_A32: + case VME_A64: + case VME_CRCSR: + case VME_USER1: + case VME_USER2: + case VME_USER3: + case VME_USER4: + break; + default: + pr_err("Invalid address space\n"); + retval = -EINVAL; + goto err_aspace; + } + + spin_lock(&image->lock); + + i = image->number; + + bridge->masters[i].enabled = enabled; + bridge->masters[i].vme_base = vme_base; + bridge->masters[i].size = size; + bridge->masters[i].aspace = aspace; + bridge->masters[i].cycle = cycle; + bridge->masters[i].dwidth = dwidth; + + spin_unlock(&image->lock); + + return 0; + +err_aspace: +err_dwidth: +err_window: + return retval; + +} + +/* + * Set the attributes of an outbound window. + */ +static int __fake_master_get(struct vme_master_resource *image, int *enabled, + unsigned long long *vme_base, unsigned long long *size, + u32 *aspace, u32 *cycle, u32 *dwidth) +{ + unsigned int i; + struct fake_driver *bridge; + + bridge = image->parent->driver_priv; + + i = image->number; + + *enabled = bridge->masters[i].enabled; + *vme_base = bridge->masters[i].vme_base; + *size = bridge->masters[i].size; + *aspace = bridge->masters[i].aspace; + *cycle = bridge->masters[i].cycle; + *dwidth = bridge->masters[i].dwidth; + + return 0; +} + + +static int fake_master_get(struct vme_master_resource *image, int *enabled, + unsigned long long *vme_base, unsigned long long *size, + u32 *aspace, u32 *cycle, u32 *dwidth) +{ + int retval; + + spin_lock(&image->lock); + + retval = __fake_master_get(image, enabled, vme_base, size, aspace, + cycle, dwidth); + + spin_unlock(&image->lock); + + return retval; +} + + +static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr, + u32 aspace, u32 cycle) +{ + struct vme_bridge *fake_bridge; + unsigned long long lm_base; + u32 lm_aspace, lm_cycle; + int i; + struct vme_lm_resource *lm; + struct list_head *pos = NULL, *n; + + /* Get vme_bridge */ + fake_bridge = bridge->parent; + + /* Loop through each location monitor resource */ + list_for_each_safe(pos, n, &fake_bridge->lm_resources) { + lm = list_entry(pos, struct vme_lm_resource, list); + + /* If disabled, we're done */ + if (bridge->lm_enabled == 0) + return; + + lm_base = bridge->lm_base; + lm_aspace = bridge->lm_aspace; + lm_cycle = bridge->lm_cycle; + + /* First make sure that the cycle and address space match */ + if ((lm_aspace == aspace) && (lm_cycle == cycle)) { + for (i = 0; i < lm->monitors; i++) { + /* Each location monitor covers 8 bytes */ + if (((lm_base + (8 * i)) <= addr) && + ((lm_base + (8 * i) + 8) > addr)) { + if (bridge->lm_callback[i]) + bridge->lm_callback[i]( + bridge->lm_data[i]); + } + } + } + } +} + +static noinline_for_stack u8 fake_vmeread8(struct fake_driver *bridge, + unsigned long long addr, + u32 aspace, u32 cycle) +{ + u8 retval = 0xff; + int i; + unsigned long long start, end, offset; + u8 *loc; + + for (i = 0; i < FAKE_MAX_SLAVE; i++) { + start = bridge->slaves[i].vme_base; + end = bridge->slaves[i].vme_base + bridge->slaves[i].size; + + if (aspace != bridge->slaves[i].aspace) + continue; + + if (cycle != bridge->slaves[i].cycle) + continue; + + if ((addr >= start) && (addr < end)) { + offset = addr - bridge->slaves[i].vme_base; + loc = (u8 *)(bridge->slaves[i].buf_base + offset); + retval = *loc; + + break; + } + } + + fake_lm_check(bridge, addr, aspace, cycle); + + return retval; +} + +static noinline_for_stack u16 fake_vmeread16(struct fake_driver *bridge, + unsigned long long addr, + u32 aspace, u32 cycle) +{ + u16 retval = 0xffff; + int i; + unsigned long long start, end, offset; + u16 *loc; + + for (i = 0; i < FAKE_MAX_SLAVE; i++) { + if (aspace != bridge->slaves[i].aspace) + continue; + + if (cycle != bridge->slaves[i].cycle) + continue; + + start = bridge->slaves[i].vme_base; + end = bridge->slaves[i].vme_base + bridge->slaves[i].size; + + if ((addr >= start) && ((addr + 1) < end)) { + offset = addr - bridge->slaves[i].vme_base; + loc = (u16 *)(bridge->slaves[i].buf_base + offset); + retval = *loc; + + break; + } + } + + fake_lm_check(bridge, addr, aspace, cycle); + + return retval; +} + +static noinline_for_stack u32 fake_vmeread32(struct fake_driver *bridge, + unsigned long long addr, + u32 aspace, u32 cycle) +{ + u32 retval = 0xffffffff; + int i; + unsigned long long start, end, offset; + u32 *loc; + + for (i = 0; i < FAKE_MAX_SLAVE; i++) { + if (aspace != bridge->slaves[i].aspace) + continue; + + if (cycle != bridge->slaves[i].cycle) + continue; + + start = bridge->slaves[i].vme_base; + end = bridge->slaves[i].vme_base + bridge->slaves[i].size; + + if ((addr >= start) && ((addr + 3) < end)) { + offset = addr - bridge->slaves[i].vme_base; + loc = (u32 *)(bridge->slaves[i].buf_base + offset); + retval = *loc; + + break; + } + } + + fake_lm_check(bridge, addr, aspace, cycle); + + return retval; +} + +static ssize_t fake_master_read(struct vme_master_resource *image, void *buf, + size_t count, loff_t offset) +{ + int retval; + u32 aspace, cycle, dwidth; + struct vme_bridge *fake_bridge; + struct fake_driver *priv; + int i; + unsigned long long addr; + unsigned int done = 0; + unsigned int count32; + + fake_bridge = image->parent; + + priv = fake_bridge->driver_priv; + + i = image->number; + + addr = (unsigned long long)priv->masters[i].vme_base + offset; + aspace = priv->masters[i].aspace; + cycle = priv->masters[i].cycle; + dwidth = priv->masters[i].dwidth; + + spin_lock(&image->lock); + + /* The following code handles VME address alignment. We cannot use + * memcpy_xxx here because it may cut data transfers in to 8-bit + * cycles when D16 or D32 cycles are required on the VME bus. + * On the other hand, the bridge itself assures that the maximum data + * cycle configured for the transfer is used and splits it + * automatically for non-aligned addresses, so we don't want the + * overhead of needlessly forcing small transfers for the entire cycle. + */ + if (addr & 0x1) { + *(u8 *)buf = fake_vmeread8(priv, addr, aspace, cycle); + done += 1; + if (done == count) + goto out; + } + if ((dwidth == VME_D16) || (dwidth == VME_D32)) { + if ((addr + done) & 0x2) { + if ((count - done) < 2) { + *(u8 *)(buf + done) = fake_vmeread8(priv, + addr + done, aspace, cycle); + done += 1; + goto out; + } else { + *(u16 *)(buf + done) = fake_vmeread16(priv, + addr + done, aspace, cycle); + done += 2; + } + } + } + + if (dwidth == VME_D32) { + count32 = (count - done) & ~0x3; + while (done < count32) { + *(u32 *)(buf + done) = fake_vmeread32(priv, addr + done, + aspace, cycle); + done += 4; + } + } else if (dwidth == VME_D16) { + count32 = (count - done) & ~0x3; + while (done < count32) { + *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done, + aspace, cycle); + done += 2; + } + } else if (dwidth == VME_D8) { + count32 = (count - done); + while (done < count32) { + *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, + aspace, cycle); + done += 1; + } + + } + + if ((dwidth == VME_D16) || (dwidth == VME_D32)) { + if ((count - done) & 0x2) { + *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done, + aspace, cycle); + done += 2; + } + } + if ((count - done) & 0x1) { + *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, aspace, + cycle); + done += 1; + } + +out: + retval = count; + + spin_unlock(&image->lock); + + return retval; +} + +static noinline_for_stack void fake_vmewrite8(struct fake_driver *bridge, + u8 *buf, unsigned long long addr, + u32 aspace, u32 cycle) +{ + int i; + unsigned long long start, end, offset; + u8 *loc; + + for (i = 0; i < FAKE_MAX_SLAVE; i++) { + if (aspace != bridge->slaves[i].aspace) + continue; + + if (cycle != bridge->slaves[i].cycle) + continue; + + start = bridge->slaves[i].vme_base; + end = bridge->slaves[i].vme_base + bridge->slaves[i].size; + + if ((addr >= start) && (addr < end)) { + offset = addr - bridge->slaves[i].vme_base; + loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset); + *loc = *buf; + + break; + } + } + + fake_lm_check(bridge, addr, aspace, cycle); + +} + +static noinline_for_stack void fake_vmewrite16(struct fake_driver *bridge, + u16 *buf, unsigned long long addr, + u32 aspace, u32 cycle) +{ + int i; + unsigned long long start, end, offset; + u16 *loc; + + for (i = 0; i < FAKE_MAX_SLAVE; i++) { + if (aspace != bridge->slaves[i].aspace) + continue; + + if (cycle != bridge->slaves[i].cycle) + continue; + + start = bridge->slaves[i].vme_base; + end = bridge->slaves[i].vme_base + bridge->slaves[i].size; + + if ((addr >= start) && ((addr + 1) < end)) { + offset = addr - bridge->slaves[i].vme_base; + loc = (u16 *)((void *)bridge->slaves[i].buf_base + offset); + *loc = *buf; + + break; + } + } + + fake_lm_check(bridge, addr, aspace, cycle); + +} + +static noinline_for_stack void fake_vmewrite32(struct fake_driver *bridge, + u32 *buf, unsigned long long addr, + u32 aspace, u32 cycle) +{ + int i; + unsigned long long start, end, offset; + u32 *loc; + + for (i = 0; i < FAKE_MAX_SLAVE; i++) { + if (aspace != bridge->slaves[i].aspace) + continue; + + if (cycle != bridge->slaves[i].cycle) + continue; + + start = bridge->slaves[i].vme_base; + end = bridge->slaves[i].vme_base + bridge->slaves[i].size; + + if ((addr >= start) && ((addr + 3) < end)) { + offset = addr - bridge->slaves[i].vme_base; + loc = (u32 *)((void *)bridge->slaves[i].buf_base + offset); + *loc = *buf; + + break; + } + } + + fake_lm_check(bridge, addr, aspace, cycle); + +} + +static ssize_t fake_master_write(struct vme_master_resource *image, void *buf, + size_t count, loff_t offset) +{ + int retval = 0; + u32 aspace, cycle, dwidth; + unsigned long long addr; + int i; + unsigned int done = 0; + unsigned int count32; + + struct vme_bridge *fake_bridge; + struct fake_driver *bridge; + + fake_bridge = image->parent; + + bridge = fake_bridge->driver_priv; + + i = image->number; + + addr = bridge->masters[i].vme_base + offset; + aspace = bridge->masters[i].aspace; + cycle = bridge->masters[i].cycle; + dwidth = bridge->masters[i].dwidth; + + spin_lock(&image->lock); + + /* Here we apply for the same strategy we do in master_read + * function in order to assure the correct cycles. + */ + if (addr & 0x1) { + fake_vmewrite8(bridge, (u8 *)buf, addr, aspace, cycle); + done += 1; + if (done == count) + goto out; + } + + if ((dwidth == VME_D16) || (dwidth == VME_D32)) { + if ((addr + done) & 0x2) { + if ((count - done) < 2) { + fake_vmewrite8(bridge, (u8 *)(buf + done), + addr + done, aspace, cycle); + done += 1; + goto out; + } else { + fake_vmewrite16(bridge, (u16 *)(buf + done), + addr + done, aspace, cycle); + done += 2; + } + } + } + + if (dwidth == VME_D32) { + count32 = (count - done) & ~0x3; + while (done < count32) { + fake_vmewrite32(bridge, (u32 *)(buf + done), + addr + done, aspace, cycle); + done += 4; + } + } else if (dwidth == VME_D16) { + count32 = (count - done) & ~0x3; + while (done < count32) { + fake_vmewrite16(bridge, (u16 *)(buf + done), + addr + done, aspace, cycle); + done += 2; + } + } else if (dwidth == VME_D8) { + count32 = (count - done); + while (done < count32) { + fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, + aspace, cycle); + done += 1; + } + + } + + if ((dwidth == VME_D16) || (dwidth == VME_D32)) { + if ((count - done) & 0x2) { + fake_vmewrite16(bridge, (u16 *)(buf + done), + addr + done, aspace, cycle); + done += 2; + } + } + + if ((count - done) & 0x1) { + fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, aspace, + cycle); + done += 1; + } + +out: + retval = count; + + spin_unlock(&image->lock); + + return retval; +} + +/* + * Perform an RMW cycle on the VME bus. + * + * Requires a previously configured master window, returns final value. + */ +static unsigned int fake_master_rmw(struct vme_master_resource *image, + unsigned int mask, unsigned int compare, unsigned int swap, + loff_t offset) +{ + u32 tmp, base; + u32 aspace, cycle; + int i; + struct fake_driver *bridge; + + bridge = image->parent->driver_priv; + + /* Find the PCI address that maps to the desired VME address */ + i = image->number; + + base = bridge->masters[i].vme_base; + aspace = bridge->masters[i].aspace; + cycle = bridge->masters[i].cycle; + + /* Lock image */ + spin_lock(&image->lock); + + /* Read existing value */ + tmp = fake_vmeread32(bridge, base + offset, aspace, cycle); + + /* Perform check */ + if ((tmp && mask) == (compare && mask)) { + tmp = tmp | (mask | swap); + tmp = tmp & (~mask | swap); + + /* Write back */ + fake_vmewrite32(bridge, &tmp, base + offset, aspace, cycle); + } + + /* Unlock image */ + spin_unlock(&image->lock); + + return tmp; +} + +/* + * All 4 location monitors reside at the same base - this is therefore a + * system wide configuration. + * + * This does not enable the LM monitor - that should be done when the first + * callback is attached and disabled when the last callback is removed. + */ +static int fake_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, + u32 aspace, u32 cycle) +{ + int i; + struct vme_bridge *fake_bridge; + struct fake_driver *bridge; + + fake_bridge = lm->parent; + + bridge = fake_bridge->driver_priv; + + mutex_lock(&lm->mtx); + + /* If we already have a callback attached, we can't move it! */ + for (i = 0; i < lm->monitors; i++) { + if (bridge->lm_callback[i]) { + mutex_unlock(&lm->mtx); + pr_err("Location monitor callback attached, can't reset\n"); + return -EBUSY; + } + } + + switch (aspace) { + case VME_A16: + case VME_A24: + case VME_A32: + case VME_A64: + break; + default: + mutex_unlock(&lm->mtx); + pr_err("Invalid address space\n"); + return -EINVAL; + } + + bridge->lm_base = lm_base; + bridge->lm_aspace = aspace; + bridge->lm_cycle = cycle; + + mutex_unlock(&lm->mtx); + + return 0; +} + +/* Get configuration of the callback monitor and return whether it is enabled + * or disabled. + */ +static int fake_lm_get(struct vme_lm_resource *lm, + unsigned long long *lm_base, u32 *aspace, u32 *cycle) +{ + struct fake_driver *bridge; + + bridge = lm->parent->driver_priv; + + mutex_lock(&lm->mtx); + + *lm_base = bridge->lm_base; + *aspace = bridge->lm_aspace; + *cycle = bridge->lm_cycle; + + mutex_unlock(&lm->mtx); + + return bridge->lm_enabled; +} + +/* + * Attach a callback to a specific location monitor. + * + * Callback will be passed the monitor triggered. + */ +static int fake_lm_attach(struct vme_lm_resource *lm, int monitor, + void (*callback)(void *), void *data) +{ + struct vme_bridge *fake_bridge; + struct fake_driver *bridge; + + fake_bridge = lm->parent; + + bridge = fake_bridge->driver_priv; + + mutex_lock(&lm->mtx); + + /* Ensure that the location monitor is configured - need PGM or DATA */ + if (bridge->lm_cycle == 0) { + mutex_unlock(&lm->mtx); + pr_err("Location monitor not properly configured\n"); + return -EINVAL; + } + + /* Check that a callback isn't already attached */ + if (bridge->lm_callback[monitor]) { + mutex_unlock(&lm->mtx); + pr_err("Existing callback attached\n"); + return -EBUSY; + } + + /* Attach callback */ + bridge->lm_callback[monitor] = callback; + bridge->lm_data[monitor] = data; + + /* Ensure that global Location Monitor Enable set */ + bridge->lm_enabled = 1; + + mutex_unlock(&lm->mtx); + + return 0; +} + +/* + * Detach a callback function forn a specific location monitor. + */ +static int fake_lm_detach(struct vme_lm_resource *lm, int monitor) +{ + u32 tmp; + int i; + struct fake_driver *bridge; + + bridge = lm->parent->driver_priv; + + mutex_lock(&lm->mtx); + + /* Detach callback */ + bridge->lm_callback[monitor] = NULL; + bridge->lm_data[monitor] = NULL; + + /* If all location monitors disabled, disable global Location Monitor */ + tmp = 0; + for (i = 0; i < lm->monitors; i++) { + if (bridge->lm_callback[i]) + tmp = 1; + } + + if (tmp == 0) + bridge->lm_enabled = 0; + + mutex_unlock(&lm->mtx); + + return 0; +} + +/* + * Determine Geographical Addressing + */ +static int fake_slot_get(struct vme_bridge *fake_bridge) +{ + return geoid; +} + +static void *fake_alloc_consistent(struct device *parent, size_t size, + dma_addr_t *dma) +{ + void *alloc = kmalloc(size, GFP_KERNEL); + + if (alloc) + *dma = fake_ptr_to_pci(alloc); + + return alloc; +} + +static void fake_free_consistent(struct device *parent, size_t size, + void *vaddr, dma_addr_t dma) +{ + kfree(vaddr); +/* + dma_free_coherent(parent, size, vaddr, dma); +*/ +} + +/* + * Configure CR/CSR space + * + * Access to the CR/CSR can be configured at power-up. The location of the + * CR/CSR registers in the CR/CSR address space is determined by the boards + * Geographic address. + * + * Each board has a 512kB window, with the highest 4kB being used for the + * boards registers, this means there is a fix length 508kB window which must + * be mapped onto PCI memory. + */ +static int fake_crcsr_init(struct vme_bridge *fake_bridge) +{ + u32 vstat; + struct fake_driver *bridge; + + bridge = fake_bridge->driver_priv; + + /* Allocate mem for CR/CSR image */ + bridge->crcsr_kernel = kzalloc(VME_CRCSR_BUF_SIZE, GFP_KERNEL); + bridge->crcsr_bus = fake_ptr_to_pci(bridge->crcsr_kernel); + if (!bridge->crcsr_kernel) + return -ENOMEM; + + vstat = fake_slot_get(fake_bridge); + + pr_info("CR/CSR Offset: %d\n", vstat); + + return 0; +} + +static void fake_crcsr_exit(struct vme_bridge *fake_bridge) +{ + struct fake_driver *bridge; + + bridge = fake_bridge->driver_priv; + + kfree(bridge->crcsr_kernel); +} + + +static int __init fake_init(void) +{ + int retval, i; + struct list_head *pos = NULL, *n; + struct vme_bridge *fake_bridge; + struct fake_driver *fake_device; + struct vme_master_resource *master_image; + struct vme_slave_resource *slave_image; + struct vme_lm_resource *lm; + + /* We need a fake parent device */ + vme_root = __root_device_register("vme", THIS_MODULE); + + /* If we want to support more than one bridge at some point, we need to + * dynamically allocate this so we get one per device. + */ + fake_bridge = kzalloc(sizeof(*fake_bridge), GFP_KERNEL); + if (!fake_bridge) { + retval = -ENOMEM; + goto err_struct; + } + + fake_device = kzalloc(sizeof(*fake_device), GFP_KERNEL); + if (!fake_device) { + retval = -ENOMEM; + goto err_driver; + } + + fake_bridge->driver_priv = fake_device; + + fake_bridge->parent = vme_root; + + fake_device->parent = fake_bridge; + + /* Initialize wait queues & mutual exclusion flags */ + mutex_init(&fake_device->vme_int); + mutex_init(&fake_bridge->irq_mtx); + tasklet_init(&fake_device->int_tasklet, fake_VIRQ_tasklet, + (unsigned long) fake_bridge); + + strcpy(fake_bridge->name, driver_name); + + /* Add master windows to list */ + INIT_LIST_HEAD(&fake_bridge->master_resources); + for (i = 0; i < FAKE_MAX_MASTER; i++) { + master_image = kmalloc(sizeof(*master_image), GFP_KERNEL); + if (!master_image) { + retval = -ENOMEM; + goto err_master; + } + master_image->parent = fake_bridge; + spin_lock_init(&master_image->lock); + master_image->locked = 0; + master_image->number = i; + master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | + VME_A64; + master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | + VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | + VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | + VME_PROG | VME_DATA; + master_image->width_attr = VME_D16 | VME_D32; + memset(&master_image->bus_resource, 0, + sizeof(struct resource)); + master_image->kern_base = NULL; + list_add_tail(&master_image->list, + &fake_bridge->master_resources); + } + + /* Add slave windows to list */ + INIT_LIST_HEAD(&fake_bridge->slave_resources); + for (i = 0; i < FAKE_MAX_SLAVE; i++) { + slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL); + if (!slave_image) { + retval = -ENOMEM; + goto err_slave; + } + slave_image->parent = fake_bridge; + mutex_init(&slave_image->mtx); + slave_image->locked = 0; + slave_image->number = i; + slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 | + VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 | + VME_USER3 | VME_USER4; + slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | + VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | + VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | + VME_PROG | VME_DATA; + list_add_tail(&slave_image->list, + &fake_bridge->slave_resources); + } + + /* Add location monitor to list */ + INIT_LIST_HEAD(&fake_bridge->lm_resources); + lm = kmalloc(sizeof(*lm), GFP_KERNEL); + if (!lm) { + retval = -ENOMEM; + goto err_lm; + } + lm->parent = fake_bridge; + mutex_init(&lm->mtx); + lm->locked = 0; + lm->number = 1; + lm->monitors = 4; + list_add_tail(&lm->list, &fake_bridge->lm_resources); + + fake_bridge->slave_get = fake_slave_get; + fake_bridge->slave_set = fake_slave_set; + fake_bridge->master_get = fake_master_get; + fake_bridge->master_set = fake_master_set; + fake_bridge->master_read = fake_master_read; + fake_bridge->master_write = fake_master_write; + fake_bridge->master_rmw = fake_master_rmw; + fake_bridge->irq_set = fake_irq_set; + fake_bridge->irq_generate = fake_irq_generate; + fake_bridge->lm_set = fake_lm_set; + fake_bridge->lm_get = fake_lm_get; + fake_bridge->lm_attach = fake_lm_attach; + fake_bridge->lm_detach = fake_lm_detach; + fake_bridge->slot_get = fake_slot_get; + fake_bridge->alloc_consistent = fake_alloc_consistent; + fake_bridge->free_consistent = fake_free_consistent; + + pr_info("Board is%s the VME system controller\n", + (geoid == 1) ? "" : " not"); + + pr_info("VME geographical address is set to %d\n", geoid); + + retval = fake_crcsr_init(fake_bridge); + if (retval) { + pr_err("CR/CSR configuration failed.\n"); + goto err_crcsr; + } + + retval = vme_register_bridge(fake_bridge); + if (retval != 0) { + pr_err("Chip Registration failed.\n"); + goto err_reg; + } + + exit_pointer = fake_bridge; + + return 0; + +err_reg: + fake_crcsr_exit(fake_bridge); +err_crcsr: +err_lm: + /* resources are stored in link list */ + list_for_each_safe(pos, n, &fake_bridge->lm_resources) { + lm = list_entry(pos, struct vme_lm_resource, list); + list_del(pos); + kfree(lm); + } +err_slave: + /* resources are stored in link list */ + list_for_each_safe(pos, n, &fake_bridge->slave_resources) { + slave_image = list_entry(pos, struct vme_slave_resource, list); + list_del(pos); + kfree(slave_image); + } +err_master: + /* resources are stored in link list */ + list_for_each_safe(pos, n, &fake_bridge->master_resources) { + master_image = list_entry(pos, struct vme_master_resource, + list); + list_del(pos); + kfree(master_image); + } + + kfree(fake_device); +err_driver: + kfree(fake_bridge); +err_struct: + return retval; + +} + + +static void __exit fake_exit(void) +{ + struct list_head *pos = NULL; + struct list_head *tmplist; + struct vme_master_resource *master_image; + struct vme_slave_resource *slave_image; + int i; + struct vme_bridge *fake_bridge; + struct fake_driver *bridge; + + fake_bridge = exit_pointer; + + bridge = fake_bridge->driver_priv; + + pr_debug("Driver is being unloaded.\n"); + + /* + * Shutdown all inbound and outbound windows. + */ + for (i = 0; i < FAKE_MAX_MASTER; i++) + bridge->masters[i].enabled = 0; + + for (i = 0; i < FAKE_MAX_SLAVE; i++) + bridge->slaves[i].enabled = 0; + + /* + * Shutdown Location monitor. + */ + bridge->lm_enabled = 0; + + vme_unregister_bridge(fake_bridge); + + fake_crcsr_exit(fake_bridge); + /* resources are stored in link list */ + list_for_each_safe(pos, tmplist, &fake_bridge->slave_resources) { + slave_image = list_entry(pos, struct vme_slave_resource, list); + list_del(pos); + kfree(slave_image); + } + + /* resources are stored in link list */ + list_for_each_safe(pos, tmplist, &fake_bridge->master_resources) { + master_image = list_entry(pos, struct vme_master_resource, + list); + list_del(pos); + kfree(master_image); + } + + kfree(fake_bridge->driver_priv); + + kfree(fake_bridge); + + root_device_unregister(vme_root); +} + + +MODULE_PARM_DESC(geoid, "Set geographical addressing"); +module_param(geoid, int, 0); + +MODULE_DESCRIPTION("Fake VME bridge driver"); +MODULE_LICENSE("GPL"); + +module_init(fake_init); +module_exit(fake_exit); diff --git a/drivers/staging/vme_user/vme_tsi148.c b/drivers/staging/vme_user/vme_tsi148.c new file mode 100644 index 000000000000..956476213241 --- /dev/null +++ b/drivers/staging/vme_user/vme_tsi148.c @@ -0,0 +1,2661 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Support for the Tundra TSI148 VME-PCI Bridge Chip + * + * Author: Martyn Welch + * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. + * + * Based on work by Tom Armistead and Ajit Prem + * Copyright 2004 Motorola Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vme.h" +#include "vme_bridge.h" +#include "vme_tsi148.h" + +static int tsi148_probe(struct pci_dev *, const struct pci_device_id *); +static void tsi148_remove(struct pci_dev *); + + +/* Module parameter */ +static bool err_chk; +static int geoid; + +static const char driver_name[] = "vme_tsi148"; + +static const struct pci_device_id tsi148_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) }, + { }, +}; + +MODULE_DEVICE_TABLE(pci, tsi148_ids); + +static struct pci_driver tsi148_driver = { + .name = driver_name, + .id_table = tsi148_ids, + .probe = tsi148_probe, + .remove = tsi148_remove, +}; + +static void reg_join(unsigned int high, unsigned int low, + unsigned long long *variable) +{ + *variable = (unsigned long long)high << 32; + *variable |= (unsigned long long)low; +} + +static void reg_split(unsigned long long variable, unsigned int *high, + unsigned int *low) +{ + *low = (unsigned int)variable & 0xFFFFFFFF; + *high = (unsigned int)(variable >> 32); +} + +/* + * Wakes up DMA queue. + */ +static u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge, + int channel_mask) +{ + u32 serviced = 0; + + if (channel_mask & TSI148_LCSR_INTS_DMA0S) { + wake_up(&bridge->dma_queue[0]); + serviced |= TSI148_LCSR_INTC_DMA0C; + } + if (channel_mask & TSI148_LCSR_INTS_DMA1S) { + wake_up(&bridge->dma_queue[1]); + serviced |= TSI148_LCSR_INTC_DMA1C; + } + + return serviced; +} + +/* + * Wake up location monitor queue + */ +static u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat) +{ + int i; + u32 serviced = 0; + + for (i = 0; i < 4; i++) { + if (stat & TSI148_LCSR_INTS_LMS[i]) { + /* We only enable interrupts if the callback is set */ + bridge->lm_callback[i](bridge->lm_data[i]); + serviced |= TSI148_LCSR_INTC_LMC[i]; + } + } + + return serviced; +} + +/* + * Wake up mail box queue. + * + * XXX This functionality is not exposed up though API. + */ +static u32 tsi148_MB_irqhandler(struct vme_bridge *tsi148_bridge, u32 stat) +{ + int i; + u32 val; + u32 serviced = 0; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + for (i = 0; i < 4; i++) { + if (stat & TSI148_LCSR_INTS_MBS[i]) { + val = ioread32be(bridge->base + TSI148_GCSR_MBOX[i]); + dev_err(tsi148_bridge->parent, "VME Mailbox %d received" + ": 0x%x\n", i, val); + serviced |= TSI148_LCSR_INTC_MBC[i]; + } + } + + return serviced; +} + +/* + * Display error & status message when PERR (PCI) exception interrupt occurs. + */ +static u32 tsi148_PERR_irqhandler(struct vme_bridge *tsi148_bridge) +{ + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + dev_err(tsi148_bridge->parent, "PCI Exception at address: 0x%08x:%08x, " + "attributes: %08x\n", + ioread32be(bridge->base + TSI148_LCSR_EDPAU), + ioread32be(bridge->base + TSI148_LCSR_EDPAL), + ioread32be(bridge->base + TSI148_LCSR_EDPAT)); + + dev_err(tsi148_bridge->parent, "PCI-X attribute reg: %08x, PCI-X split " + "completion reg: %08x\n", + ioread32be(bridge->base + TSI148_LCSR_EDPXA), + ioread32be(bridge->base + TSI148_LCSR_EDPXS)); + + iowrite32be(TSI148_LCSR_EDPAT_EDPCL, bridge->base + TSI148_LCSR_EDPAT); + + return TSI148_LCSR_INTC_PERRC; +} + +/* + * Save address and status when VME error interrupt occurs. + */ +static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge) +{ + unsigned int error_addr_high, error_addr_low; + unsigned long long error_addr; + u32 error_attrib; + int error_am; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + error_addr_high = ioread32be(bridge->base + TSI148_LCSR_VEAU); + error_addr_low = ioread32be(bridge->base + TSI148_LCSR_VEAL); + error_attrib = ioread32be(bridge->base + TSI148_LCSR_VEAT); + error_am = (error_attrib & TSI148_LCSR_VEAT_AM_M) >> 8; + + reg_join(error_addr_high, error_addr_low, &error_addr); + + /* Check for exception register overflow (we have lost error data) */ + if (error_attrib & TSI148_LCSR_VEAT_VEOF) { + dev_err(tsi148_bridge->parent, "VME Bus Exception Overflow " + "Occurred\n"); + } + + if (err_chk) + vme_bus_error_handler(tsi148_bridge, error_addr, error_am); + else + dev_err(tsi148_bridge->parent, + "VME Bus Error at address: 0x%llx, attributes: %08x\n", + error_addr, error_attrib); + + /* Clear Status */ + iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT); + + return TSI148_LCSR_INTC_VERRC; +} + +/* + * Wake up IACK queue. + */ +static u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge) +{ + wake_up(&bridge->iack_queue); + + return TSI148_LCSR_INTC_IACKC; +} + +/* + * Calling VME bus interrupt callback if provided. + */ +static u32 tsi148_VIRQ_irqhandler(struct vme_bridge *tsi148_bridge, + u32 stat) +{ + int vec, i, serviced = 0; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + for (i = 7; i > 0; i--) { + if (stat & (1 << i)) { + /* + * Note: Even though the registers are defined as + * 32-bits in the spec, we only want to issue 8-bit + * IACK cycles on the bus, read from offset 3. + */ + vec = ioread8(bridge->base + TSI148_LCSR_VIACK[i] + 3); + + vme_irq_handler(tsi148_bridge, i, vec); + + serviced |= (1 << i); + } + } + + return serviced; +} + +/* + * Top level interrupt handler. Clears appropriate interrupt status bits and + * then calls appropriate sub handler(s). + */ +static irqreturn_t tsi148_irqhandler(int irq, void *ptr) +{ + u32 stat, enable, serviced = 0; + struct vme_bridge *tsi148_bridge; + struct tsi148_driver *bridge; + + tsi148_bridge = ptr; + + bridge = tsi148_bridge->driver_priv; + + /* Determine which interrupts are unmasked and set */ + enable = ioread32be(bridge->base + TSI148_LCSR_INTEO); + stat = ioread32be(bridge->base + TSI148_LCSR_INTS); + + /* Only look at unmasked interrupts */ + stat &= enable; + + if (unlikely(!stat)) + return IRQ_NONE; + + /* Call subhandlers as appropriate */ + /* DMA irqs */ + if (stat & (TSI148_LCSR_INTS_DMA1S | TSI148_LCSR_INTS_DMA0S)) + serviced |= tsi148_DMA_irqhandler(bridge, stat); + + /* Location monitor irqs */ + if (stat & (TSI148_LCSR_INTS_LM3S | TSI148_LCSR_INTS_LM2S | + TSI148_LCSR_INTS_LM1S | TSI148_LCSR_INTS_LM0S)) + serviced |= tsi148_LM_irqhandler(bridge, stat); + + /* Mail box irqs */ + if (stat & (TSI148_LCSR_INTS_MB3S | TSI148_LCSR_INTS_MB2S | + TSI148_LCSR_INTS_MB1S | TSI148_LCSR_INTS_MB0S)) + serviced |= tsi148_MB_irqhandler(tsi148_bridge, stat); + + /* PCI bus error */ + if (stat & TSI148_LCSR_INTS_PERRS) + serviced |= tsi148_PERR_irqhandler(tsi148_bridge); + + /* VME bus error */ + if (stat & TSI148_LCSR_INTS_VERRS) + serviced |= tsi148_VERR_irqhandler(tsi148_bridge); + + /* IACK irq */ + if (stat & TSI148_LCSR_INTS_IACKS) + serviced |= tsi148_IACK_irqhandler(bridge); + + /* VME bus irqs */ + if (stat & (TSI148_LCSR_INTS_IRQ7S | TSI148_LCSR_INTS_IRQ6S | + TSI148_LCSR_INTS_IRQ5S | TSI148_LCSR_INTS_IRQ4S | + TSI148_LCSR_INTS_IRQ3S | TSI148_LCSR_INTS_IRQ2S | + TSI148_LCSR_INTS_IRQ1S)) + serviced |= tsi148_VIRQ_irqhandler(tsi148_bridge, stat); + + /* Clear serviced interrupts */ + iowrite32be(serviced, bridge->base + TSI148_LCSR_INTC); + + return IRQ_HANDLED; +} + +static int tsi148_irq_init(struct vme_bridge *tsi148_bridge) +{ + int result; + unsigned int tmp; + struct pci_dev *pdev; + struct tsi148_driver *bridge; + + pdev = to_pci_dev(tsi148_bridge->parent); + + bridge = tsi148_bridge->driver_priv; + + result = request_irq(pdev->irq, + tsi148_irqhandler, + IRQF_SHARED, + driver_name, tsi148_bridge); + if (result) { + dev_err(tsi148_bridge->parent, "Can't get assigned pci irq " + "vector %02X\n", pdev->irq); + return result; + } + + /* Enable and unmask interrupts */ + tmp = TSI148_LCSR_INTEO_DMA1EO | TSI148_LCSR_INTEO_DMA0EO | + TSI148_LCSR_INTEO_MB3EO | TSI148_LCSR_INTEO_MB2EO | + TSI148_LCSR_INTEO_MB1EO | TSI148_LCSR_INTEO_MB0EO | + TSI148_LCSR_INTEO_PERREO | TSI148_LCSR_INTEO_VERREO | + TSI148_LCSR_INTEO_IACKEO; + + /* This leaves the following interrupts masked. + * TSI148_LCSR_INTEO_VIEEO + * TSI148_LCSR_INTEO_SYSFLEO + * TSI148_LCSR_INTEO_ACFLEO + */ + + /* Don't enable Location Monitor interrupts here - they will be + * enabled when the location monitors are properly configured and + * a callback has been attached. + * TSI148_LCSR_INTEO_LM0EO + * TSI148_LCSR_INTEO_LM1EO + * TSI148_LCSR_INTEO_LM2EO + * TSI148_LCSR_INTEO_LM3EO + */ + + /* Don't enable VME interrupts until we add a handler, else the board + * will respond to it and we don't want that unless it knows how to + * properly deal with it. + * TSI148_LCSR_INTEO_IRQ7EO + * TSI148_LCSR_INTEO_IRQ6EO + * TSI148_LCSR_INTEO_IRQ5EO + * TSI148_LCSR_INTEO_IRQ4EO + * TSI148_LCSR_INTEO_IRQ3EO + * TSI148_LCSR_INTEO_IRQ2EO + * TSI148_LCSR_INTEO_IRQ1EO + */ + + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN); + + return 0; +} + +static void tsi148_irq_exit(struct vme_bridge *tsi148_bridge, + struct pci_dev *pdev) +{ + struct tsi148_driver *bridge = tsi148_bridge->driver_priv; + + /* Turn off interrupts */ + iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO); + iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN); + + /* Clear all interrupts */ + iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC); + + /* Detach interrupt handler */ + free_irq(pdev->irq, tsi148_bridge); +} + +/* + * Check to see if an IACk has been received, return true (1) or false (0). + */ +static int tsi148_iack_received(struct tsi148_driver *bridge) +{ + u32 tmp; + + tmp = ioread32be(bridge->base + TSI148_LCSR_VICR); + + if (tmp & TSI148_LCSR_VICR_IRQS) + return 0; + else + return 1; +} + +/* + * Configure VME interrupt + */ +static void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level, + int state, int sync) +{ + struct pci_dev *pdev; + u32 tmp; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + /* We need to do the ordering differently for enabling and disabling */ + if (state == 0) { + tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN); + tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1]; + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN); + + tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO); + tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1]; + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); + + if (sync != 0) { + pdev = to_pci_dev(tsi148_bridge->parent); + synchronize_irq(pdev->irq); + } + } else { + tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO); + tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1]; + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); + + tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN); + tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1]; + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN); + } +} + +/* + * Generate a VME bus interrupt at the requested level & vector. Wait for + * interrupt to be acked. + */ +static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, + int statid) +{ + u32 tmp; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + mutex_lock(&bridge->vme_int); + + /* Read VICR register */ + tmp = ioread32be(bridge->base + TSI148_LCSR_VICR); + + /* Set Status/ID */ + tmp = (tmp & ~TSI148_LCSR_VICR_STID_M) | + (statid & TSI148_LCSR_VICR_STID_M); + iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR); + + /* Assert VMEbus IRQ */ + tmp = tmp | TSI148_LCSR_VICR_IRQL[level]; + iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR); + + /* XXX Consider implementing a timeout? */ + wait_event_interruptible(bridge->iack_queue, + tsi148_iack_received(bridge)); + + mutex_unlock(&bridge->vme_int); + + return 0; +} + +/* + * Initialize a slave window with the requested attributes. + */ +static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, + unsigned long long vme_base, unsigned long long size, + dma_addr_t pci_base, u32 aspace, u32 cycle) +{ + unsigned int i, addr = 0, granularity = 0; + unsigned int temp_ctl = 0; + unsigned int vme_base_low, vme_base_high; + unsigned int vme_bound_low, vme_bound_high; + unsigned int pci_offset_low, pci_offset_high; + unsigned long long vme_bound, pci_offset; + struct vme_bridge *tsi148_bridge; + struct tsi148_driver *bridge; + + tsi148_bridge = image->parent; + bridge = tsi148_bridge->driver_priv; + + i = image->number; + + switch (aspace) { + case VME_A16: + granularity = 0x10; + addr |= TSI148_LCSR_ITAT_AS_A16; + break; + case VME_A24: + granularity = 0x1000; + addr |= TSI148_LCSR_ITAT_AS_A24; + break; + case VME_A32: + granularity = 0x10000; + addr |= TSI148_LCSR_ITAT_AS_A32; + break; + case VME_A64: + granularity = 0x10000; + addr |= TSI148_LCSR_ITAT_AS_A64; + break; + default: + dev_err(tsi148_bridge->parent, "Invalid address space\n"); + return -EINVAL; + } + + /* Convert 64-bit variables to 2x 32-bit variables */ + reg_split(vme_base, &vme_base_high, &vme_base_low); + + /* + * Bound address is a valid address for the window, adjust + * accordingly + */ + vme_bound = vme_base + size - granularity; + reg_split(vme_bound, &vme_bound_high, &vme_bound_low); + pci_offset = (unsigned long long)pci_base - vme_base; + reg_split(pci_offset, &pci_offset_high, &pci_offset_low); + + if (vme_base_low & (granularity - 1)) { + dev_err(tsi148_bridge->parent, "Invalid VME base alignment\n"); + return -EINVAL; + } + if (vme_bound_low & (granularity - 1)) { + dev_err(tsi148_bridge->parent, "Invalid VME bound alignment\n"); + return -EINVAL; + } + if (pci_offset_low & (granularity - 1)) { + dev_err(tsi148_bridge->parent, "Invalid PCI Offset " + "alignment\n"); + return -EINVAL; + } + + /* Disable while we are mucking around */ + temp_ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITAT); + temp_ctl &= ~TSI148_LCSR_ITAT_EN; + iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITAT); + + /* Setup mapping */ + iowrite32be(vme_base_high, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITSAU); + iowrite32be(vme_base_low, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITSAL); + iowrite32be(vme_bound_high, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITEAU); + iowrite32be(vme_bound_low, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITEAL); + iowrite32be(pci_offset_high, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITOFU); + iowrite32be(pci_offset_low, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITOFL); + + /* Setup 2eSST speeds */ + temp_ctl &= ~TSI148_LCSR_ITAT_2eSSTM_M; + switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { + case VME_2eSST160: + temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_160; + break; + case VME_2eSST267: + temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_267; + break; + case VME_2eSST320: + temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_320; + break; + } + + /* Setup cycle types */ + temp_ctl &= ~(0x1F << 7); + if (cycle & VME_BLT) + temp_ctl |= TSI148_LCSR_ITAT_BLT; + if (cycle & VME_MBLT) + temp_ctl |= TSI148_LCSR_ITAT_MBLT; + if (cycle & VME_2eVME) + temp_ctl |= TSI148_LCSR_ITAT_2eVME; + if (cycle & VME_2eSST) + temp_ctl |= TSI148_LCSR_ITAT_2eSST; + if (cycle & VME_2eSSTB) + temp_ctl |= TSI148_LCSR_ITAT_2eSSTB; + + /* Setup address space */ + temp_ctl &= ~TSI148_LCSR_ITAT_AS_M; + temp_ctl |= addr; + + temp_ctl &= ~0xF; + if (cycle & VME_SUPER) + temp_ctl |= TSI148_LCSR_ITAT_SUPR ; + if (cycle & VME_USER) + temp_ctl |= TSI148_LCSR_ITAT_NPRIV; + if (cycle & VME_PROG) + temp_ctl |= TSI148_LCSR_ITAT_PGM; + if (cycle & VME_DATA) + temp_ctl |= TSI148_LCSR_ITAT_DATA; + + /* Write ctl reg without enable */ + iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITAT); + + if (enabled) + temp_ctl |= TSI148_LCSR_ITAT_EN; + + iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITAT); + + return 0; +} + +/* + * Get slave window configuration. + */ +static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled, + unsigned long long *vme_base, unsigned long long *size, + dma_addr_t *pci_base, u32 *aspace, u32 *cycle) +{ + unsigned int i, granularity = 0, ctl = 0; + unsigned int vme_base_low, vme_base_high; + unsigned int vme_bound_low, vme_bound_high; + unsigned int pci_offset_low, pci_offset_high; + unsigned long long vme_bound, pci_offset; + struct tsi148_driver *bridge; + + bridge = image->parent->driver_priv; + + i = image->number; + + /* Read registers */ + ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITAT); + + vme_base_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITSAU); + vme_base_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITSAL); + vme_bound_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITEAU); + vme_bound_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITEAL); + pci_offset_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITOFU); + pci_offset_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITOFL); + + /* Convert 64-bit variables to 2x 32-bit variables */ + reg_join(vme_base_high, vme_base_low, vme_base); + reg_join(vme_bound_high, vme_bound_low, &vme_bound); + reg_join(pci_offset_high, pci_offset_low, &pci_offset); + + *pci_base = (dma_addr_t)(*vme_base + pci_offset); + + *enabled = 0; + *aspace = 0; + *cycle = 0; + + if (ctl & TSI148_LCSR_ITAT_EN) + *enabled = 1; + + if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A16) { + granularity = 0x10; + *aspace |= VME_A16; + } + if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A24) { + granularity = 0x1000; + *aspace |= VME_A24; + } + if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A32) { + granularity = 0x10000; + *aspace |= VME_A32; + } + if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A64) { + granularity = 0x10000; + *aspace |= VME_A64; + } + + /* Need granularity before we set the size */ + *size = (unsigned long long)((vme_bound - *vme_base) + granularity); + + + if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_160) + *cycle |= VME_2eSST160; + if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_267) + *cycle |= VME_2eSST267; + if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_320) + *cycle |= VME_2eSST320; + + if (ctl & TSI148_LCSR_ITAT_BLT) + *cycle |= VME_BLT; + if (ctl & TSI148_LCSR_ITAT_MBLT) + *cycle |= VME_MBLT; + if (ctl & TSI148_LCSR_ITAT_2eVME) + *cycle |= VME_2eVME; + if (ctl & TSI148_LCSR_ITAT_2eSST) + *cycle |= VME_2eSST; + if (ctl & TSI148_LCSR_ITAT_2eSSTB) + *cycle |= VME_2eSSTB; + + if (ctl & TSI148_LCSR_ITAT_SUPR) + *cycle |= VME_SUPER; + if (ctl & TSI148_LCSR_ITAT_NPRIV) + *cycle |= VME_USER; + if (ctl & TSI148_LCSR_ITAT_PGM) + *cycle |= VME_PROG; + if (ctl & TSI148_LCSR_ITAT_DATA) + *cycle |= VME_DATA; + + return 0; +} + +/* + * Allocate and map PCI Resource + */ +static int tsi148_alloc_resource(struct vme_master_resource *image, + unsigned long long size) +{ + unsigned long long existing_size; + int retval = 0; + struct pci_dev *pdev; + struct vme_bridge *tsi148_bridge; + + tsi148_bridge = image->parent; + + pdev = to_pci_dev(tsi148_bridge->parent); + + existing_size = (unsigned long long)(image->bus_resource.end - + image->bus_resource.start); + + /* If the existing size is OK, return */ + if ((size != 0) && (existing_size == (size - 1))) + return 0; + + if (existing_size != 0) { + iounmap(image->kern_base); + image->kern_base = NULL; + kfree(image->bus_resource.name); + release_resource(&image->bus_resource); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); + } + + /* Exit here if size is zero */ + if (size == 0) + return 0; + + if (!image->bus_resource.name) { + image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC); + if (!image->bus_resource.name) { + retval = -ENOMEM; + goto err_name; + } + } + + sprintf((char *)image->bus_resource.name, "%s.%d", tsi148_bridge->name, + image->number); + + image->bus_resource.start = 0; + image->bus_resource.end = (unsigned long)size; + image->bus_resource.flags = IORESOURCE_MEM; + + retval = pci_bus_alloc_resource(pdev->bus, + &image->bus_resource, size, 0x10000, PCIBIOS_MIN_MEM, + 0, NULL, NULL); + if (retval) { + dev_err(tsi148_bridge->parent, "Failed to allocate mem " + "resource for window %d size 0x%lx start 0x%lx\n", + image->number, (unsigned long)size, + (unsigned long)image->bus_resource.start); + goto err_resource; + } + + image->kern_base = ioremap( + image->bus_resource.start, size); + if (!image->kern_base) { + dev_err(tsi148_bridge->parent, "Failed to remap resource\n"); + retval = -ENOMEM; + goto err_remap; + } + + return 0; + +err_remap: + release_resource(&image->bus_resource); +err_resource: + kfree(image->bus_resource.name); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); +err_name: + return retval; +} + +/* + * Free and unmap PCI Resource + */ +static void tsi148_free_resource(struct vme_master_resource *image) +{ + iounmap(image->kern_base); + image->kern_base = NULL; + release_resource(&image->bus_resource); + kfree(image->bus_resource.name); + memset(&image->bus_resource, 0, sizeof(image->bus_resource)); +} + +/* + * Set the attributes of an outbound window. + */ +static int tsi148_master_set(struct vme_master_resource *image, int enabled, + unsigned long long vme_base, unsigned long long size, u32 aspace, + u32 cycle, u32 dwidth) +{ + int retval = 0; + unsigned int i; + unsigned int temp_ctl = 0; + unsigned int pci_base_low, pci_base_high; + unsigned int pci_bound_low, pci_bound_high; + unsigned int vme_offset_low, vme_offset_high; + unsigned long long pci_bound, vme_offset, pci_base; + struct vme_bridge *tsi148_bridge; + struct tsi148_driver *bridge; + struct pci_bus_region region; + struct pci_dev *pdev; + + tsi148_bridge = image->parent; + + bridge = tsi148_bridge->driver_priv; + + pdev = to_pci_dev(tsi148_bridge->parent); + + /* Verify input data */ + if (vme_base & 0xFFFF) { + dev_err(tsi148_bridge->parent, "Invalid VME Window " + "alignment\n"); + retval = -EINVAL; + goto err_window; + } + + if ((size == 0) && (enabled != 0)) { + dev_err(tsi148_bridge->parent, "Size must be non-zero for " + "enabled windows\n"); + retval = -EINVAL; + goto err_window; + } + + spin_lock(&image->lock); + + /* Let's allocate the resource here rather than further up the stack as + * it avoids pushing loads of bus dependent stuff up the stack. If size + * is zero, any existing resource will be freed. + */ + retval = tsi148_alloc_resource(image, size); + if (retval) { + spin_unlock(&image->lock); + dev_err(tsi148_bridge->parent, "Unable to allocate memory for " + "resource\n"); + goto err_res; + } + + if (size == 0) { + pci_base = 0; + pci_bound = 0; + vme_offset = 0; + } else { + pcibios_resource_to_bus(pdev->bus, ®ion, + &image->bus_resource); + pci_base = region.start; + + /* + * Bound address is a valid address for the window, adjust + * according to window granularity. + */ + pci_bound = pci_base + (size - 0x10000); + vme_offset = vme_base - pci_base; + } + + /* Convert 64-bit variables to 2x 32-bit variables */ + reg_split(pci_base, &pci_base_high, &pci_base_low); + reg_split(pci_bound, &pci_bound_high, &pci_bound_low); + reg_split(vme_offset, &vme_offset_high, &vme_offset_low); + + if (pci_base_low & 0xFFFF) { + spin_unlock(&image->lock); + dev_err(tsi148_bridge->parent, "Invalid PCI base alignment\n"); + retval = -EINVAL; + goto err_gran; + } + if (pci_bound_low & 0xFFFF) { + spin_unlock(&image->lock); + dev_err(tsi148_bridge->parent, "Invalid PCI bound alignment\n"); + retval = -EINVAL; + goto err_gran; + } + if (vme_offset_low & 0xFFFF) { + spin_unlock(&image->lock); + dev_err(tsi148_bridge->parent, "Invalid VME Offset " + "alignment\n"); + retval = -EINVAL; + goto err_gran; + } + + i = image->number; + + /* Disable while we are mucking around */ + temp_ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTAT); + temp_ctl &= ~TSI148_LCSR_OTAT_EN; + iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTAT); + + /* Setup 2eSST speeds */ + temp_ctl &= ~TSI148_LCSR_OTAT_2eSSTM_M; + switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { + case VME_2eSST160: + temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_160; + break; + case VME_2eSST267: + temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_267; + break; + case VME_2eSST320: + temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_320; + break; + } + + /* Setup cycle types */ + if (cycle & VME_BLT) { + temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; + temp_ctl |= TSI148_LCSR_OTAT_TM_BLT; + } + if (cycle & VME_MBLT) { + temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; + temp_ctl |= TSI148_LCSR_OTAT_TM_MBLT; + } + if (cycle & VME_2eVME) { + temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; + temp_ctl |= TSI148_LCSR_OTAT_TM_2eVME; + } + if (cycle & VME_2eSST) { + temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; + temp_ctl |= TSI148_LCSR_OTAT_TM_2eSST; + } + if (cycle & VME_2eSSTB) { + dev_warn(tsi148_bridge->parent, "Currently not setting " + "Broadcast Select Registers\n"); + temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; + temp_ctl |= TSI148_LCSR_OTAT_TM_2eSSTB; + } + + /* Setup data width */ + temp_ctl &= ~TSI148_LCSR_OTAT_DBW_M; + switch (dwidth) { + case VME_D16: + temp_ctl |= TSI148_LCSR_OTAT_DBW_16; + break; + case VME_D32: + temp_ctl |= TSI148_LCSR_OTAT_DBW_32; + break; + default: + spin_unlock(&image->lock); + dev_err(tsi148_bridge->parent, "Invalid data width\n"); + retval = -EINVAL; + goto err_dwidth; + } + + /* Setup address space */ + temp_ctl &= ~TSI148_LCSR_OTAT_AMODE_M; + switch (aspace) { + case VME_A16: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_A16; + break; + case VME_A24: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_A24; + break; + case VME_A32: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_A32; + break; + case VME_A64: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_A64; + break; + case VME_CRCSR: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_CRCSR; + break; + case VME_USER1: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER1; + break; + case VME_USER2: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER2; + break; + case VME_USER3: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER3; + break; + case VME_USER4: + temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4; + break; + default: + spin_unlock(&image->lock); + dev_err(tsi148_bridge->parent, "Invalid address space\n"); + retval = -EINVAL; + goto err_aspace; + } + + temp_ctl &= ~(3<<4); + if (cycle & VME_SUPER) + temp_ctl |= TSI148_LCSR_OTAT_SUP; + if (cycle & VME_PROG) + temp_ctl |= TSI148_LCSR_OTAT_PGM; + + /* Setup mapping */ + iowrite32be(pci_base_high, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTSAU); + iowrite32be(pci_base_low, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTSAL); + iowrite32be(pci_bound_high, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTEAU); + iowrite32be(pci_bound_low, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTEAL); + iowrite32be(vme_offset_high, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTOFU); + iowrite32be(vme_offset_low, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTOFL); + + /* Write ctl reg without enable */ + iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTAT); + + if (enabled) + temp_ctl |= TSI148_LCSR_OTAT_EN; + + iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTAT); + + spin_unlock(&image->lock); + return 0; + +err_aspace: +err_dwidth: +err_gran: + tsi148_free_resource(image); +err_res: +err_window: + return retval; + +} + +/* + * Set the attributes of an outbound window. + * + * XXX Not parsing prefetch information. + */ +static int __tsi148_master_get(struct vme_master_resource *image, int *enabled, + unsigned long long *vme_base, unsigned long long *size, u32 *aspace, + u32 *cycle, u32 *dwidth) +{ + unsigned int i, ctl; + unsigned int pci_base_low, pci_base_high; + unsigned int pci_bound_low, pci_bound_high; + unsigned int vme_offset_low, vme_offset_high; + + unsigned long long pci_base, pci_bound, vme_offset; + struct tsi148_driver *bridge; + + bridge = image->parent->driver_priv; + + i = image->number; + + ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTAT); + + pci_base_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTSAU); + pci_base_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTSAL); + pci_bound_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTEAU); + pci_bound_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTEAL); + vme_offset_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTOFU); + vme_offset_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTOFL); + + /* Convert 64-bit variables to 2x 32-bit variables */ + reg_join(pci_base_high, pci_base_low, &pci_base); + reg_join(pci_bound_high, pci_bound_low, &pci_bound); + reg_join(vme_offset_high, vme_offset_low, &vme_offset); + + *vme_base = pci_base + vme_offset; + *size = (unsigned long long)(pci_bound - pci_base) + 0x10000; + + *enabled = 0; + *aspace = 0; + *cycle = 0; + *dwidth = 0; + + if (ctl & TSI148_LCSR_OTAT_EN) + *enabled = 1; + + /* Setup address space */ + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A16) + *aspace |= VME_A16; + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A24) + *aspace |= VME_A24; + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A32) + *aspace |= VME_A32; + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A64) + *aspace |= VME_A64; + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_CRCSR) + *aspace |= VME_CRCSR; + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER1) + *aspace |= VME_USER1; + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER2) + *aspace |= VME_USER2; + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER3) + *aspace |= VME_USER3; + if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER4) + *aspace |= VME_USER4; + + /* Setup 2eSST speeds */ + if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_160) + *cycle |= VME_2eSST160; + if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_267) + *cycle |= VME_2eSST267; + if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_320) + *cycle |= VME_2eSST320; + + /* Setup cycle types */ + if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_SCT) + *cycle |= VME_SCT; + if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_BLT) + *cycle |= VME_BLT; + if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_MBLT) + *cycle |= VME_MBLT; + if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eVME) + *cycle |= VME_2eVME; + if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSST) + *cycle |= VME_2eSST; + if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSSTB) + *cycle |= VME_2eSSTB; + + if (ctl & TSI148_LCSR_OTAT_SUP) + *cycle |= VME_SUPER; + else + *cycle |= VME_USER; + + if (ctl & TSI148_LCSR_OTAT_PGM) + *cycle |= VME_PROG; + else + *cycle |= VME_DATA; + + /* Setup data width */ + if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_16) + *dwidth = VME_D16; + if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_32) + *dwidth = VME_D32; + + return 0; +} + + +static int tsi148_master_get(struct vme_master_resource *image, int *enabled, + unsigned long long *vme_base, unsigned long long *size, u32 *aspace, + u32 *cycle, u32 *dwidth) +{ + int retval; + + spin_lock(&image->lock); + + retval = __tsi148_master_get(image, enabled, vme_base, size, aspace, + cycle, dwidth); + + spin_unlock(&image->lock); + + return retval; +} + +static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, + size_t count, loff_t offset) +{ + int retval, enabled; + unsigned long long vme_base, size; + u32 aspace, cycle, dwidth; + struct vme_error_handler *handler = NULL; + struct vme_bridge *tsi148_bridge; + void __iomem *addr = image->kern_base + offset; + unsigned int done = 0; + unsigned int count32; + + tsi148_bridge = image->parent; + + spin_lock(&image->lock); + + if (err_chk) { + __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, + &cycle, &dwidth); + handler = vme_register_error_handler(tsi148_bridge, aspace, + vme_base + offset, count); + if (!handler) { + spin_unlock(&image->lock); + return -ENOMEM; + } + } + + /* The following code handles VME address alignment. We cannot use + * memcpy_xxx here because it may cut data transfers in to 8-bit + * cycles when D16 or D32 cycles are required on the VME bus. + * On the other hand, the bridge itself assures that the maximum data + * cycle configured for the transfer is used and splits it + * automatically for non-aligned addresses, so we don't want the + * overhead of needlessly forcing small transfers for the entire cycle. + */ + if ((uintptr_t)addr & 0x1) { + *(u8 *)buf = ioread8(addr); + done += 1; + if (done == count) + goto out; + } + if ((uintptr_t)(addr + done) & 0x2) { + if ((count - done) < 2) { + *(u8 *)(buf + done) = ioread8(addr + done); + done += 1; + goto out; + } else { + *(u16 *)(buf + done) = ioread16(addr + done); + done += 2; + } + } + + count32 = (count - done) & ~0x3; + while (done < count32) { + *(u32 *)(buf + done) = ioread32(addr + done); + done += 4; + } + + if ((count - done) & 0x2) { + *(u16 *)(buf + done) = ioread16(addr + done); + done += 2; + } + if ((count - done) & 0x1) { + *(u8 *)(buf + done) = ioread8(addr + done); + done += 1; + } + +out: + retval = count; + + if (err_chk) { + if (handler->num_errors) { + dev_err(image->parent->parent, + "First VME read error detected an at address 0x%llx\n", + handler->first_error); + retval = handler->first_error - (vme_base + offset); + } + vme_unregister_error_handler(handler); + } + + spin_unlock(&image->lock); + + return retval; +} + + +static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, + size_t count, loff_t offset) +{ + int retval = 0, enabled; + unsigned long long vme_base, size; + u32 aspace, cycle, dwidth; + void __iomem *addr = image->kern_base + offset; + unsigned int done = 0; + unsigned int count32; + + struct vme_error_handler *handler = NULL; + struct vme_bridge *tsi148_bridge; + struct tsi148_driver *bridge; + + tsi148_bridge = image->parent; + + bridge = tsi148_bridge->driver_priv; + + spin_lock(&image->lock); + + if (err_chk) { + __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, + &cycle, &dwidth); + handler = vme_register_error_handler(tsi148_bridge, aspace, + vme_base + offset, count); + if (!handler) { + spin_unlock(&image->lock); + return -ENOMEM; + } + } + + /* Here we apply for the same strategy we do in master_read + * function in order to assure the correct cycles. + */ + if ((uintptr_t)addr & 0x1) { + iowrite8(*(u8 *)buf, addr); + done += 1; + if (done == count) + goto out; + } + if ((uintptr_t)(addr + done) & 0x2) { + if ((count - done) < 2) { + iowrite8(*(u8 *)(buf + done), addr + done); + done += 1; + goto out; + } else { + iowrite16(*(u16 *)(buf + done), addr + done); + done += 2; + } + } + + count32 = (count - done) & ~0x3; + while (done < count32) { + iowrite32(*(u32 *)(buf + done), addr + done); + done += 4; + } + + if ((count - done) & 0x2) { + iowrite16(*(u16 *)(buf + done), addr + done); + done += 2; + } + if ((count - done) & 0x1) { + iowrite8(*(u8 *)(buf + done), addr + done); + done += 1; + } + +out: + retval = count; + + /* + * Writes are posted. We need to do a read on the VME bus to flush out + * all of the writes before we check for errors. We can't guarantee + * that reading the data we have just written is safe. It is believed + * that there isn't any read, write re-ordering, so we can read any + * location in VME space, so lets read the Device ID from the tsi148's + * own registers as mapped into CR/CSR space. + * + * We check for saved errors in the written address range/space. + */ + + if (err_chk) { + ioread16(bridge->flush_image->kern_base + 0x7F000); + + if (handler->num_errors) { + dev_warn(tsi148_bridge->parent, + "First VME write error detected an at address 0x%llx\n", + handler->first_error); + retval = handler->first_error - (vme_base + offset); + } + vme_unregister_error_handler(handler); + } + + spin_unlock(&image->lock); + + return retval; +} + +/* + * Perform an RMW cycle on the VME bus. + * + * Requires a previously configured master window, returns final value. + */ +static unsigned int tsi148_master_rmw(struct vme_master_resource *image, + unsigned int mask, unsigned int compare, unsigned int swap, + loff_t offset) +{ + unsigned long long pci_addr; + unsigned int pci_addr_high, pci_addr_low; + u32 tmp, result; + int i; + struct tsi148_driver *bridge; + + bridge = image->parent->driver_priv; + + /* Find the PCI address that maps to the desired VME address */ + i = image->number; + + /* Locking as we can only do one of these at a time */ + mutex_lock(&bridge->vme_rmw); + + /* Lock image */ + spin_lock(&image->lock); + + pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTSAU); + pci_addr_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTSAL); + + reg_join(pci_addr_high, pci_addr_low, &pci_addr); + reg_split(pci_addr + offset, &pci_addr_high, &pci_addr_low); + + /* Configure registers */ + iowrite32be(mask, bridge->base + TSI148_LCSR_RMWEN); + iowrite32be(compare, bridge->base + TSI148_LCSR_RMWC); + iowrite32be(swap, bridge->base + TSI148_LCSR_RMWS); + iowrite32be(pci_addr_high, bridge->base + TSI148_LCSR_RMWAU); + iowrite32be(pci_addr_low, bridge->base + TSI148_LCSR_RMWAL); + + /* Enable RMW */ + tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL); + tmp |= TSI148_LCSR_VMCTRL_RMWEN; + iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL); + + /* Kick process off with a read to the required address. */ + result = ioread32be(image->kern_base + offset); + + /* Disable RMW */ + tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL); + tmp &= ~TSI148_LCSR_VMCTRL_RMWEN; + iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL); + + spin_unlock(&image->lock); + + mutex_unlock(&bridge->vme_rmw); + + return result; +} + +static int tsi148_dma_set_vme_src_attributes(struct device *dev, __be32 *attr, + u32 aspace, u32 cycle, u32 dwidth) +{ + u32 val; + + val = be32_to_cpu(*attr); + + /* Setup 2eSST speeds */ + switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { + case VME_2eSST160: + val |= TSI148_LCSR_DSAT_2eSSTM_160; + break; + case VME_2eSST267: + val |= TSI148_LCSR_DSAT_2eSSTM_267; + break; + case VME_2eSST320: + val |= TSI148_LCSR_DSAT_2eSSTM_320; + break; + } + + /* Setup cycle types */ + if (cycle & VME_SCT) + val |= TSI148_LCSR_DSAT_TM_SCT; + + if (cycle & VME_BLT) + val |= TSI148_LCSR_DSAT_TM_BLT; + + if (cycle & VME_MBLT) + val |= TSI148_LCSR_DSAT_TM_MBLT; + + if (cycle & VME_2eVME) + val |= TSI148_LCSR_DSAT_TM_2eVME; + + if (cycle & VME_2eSST) + val |= TSI148_LCSR_DSAT_TM_2eSST; + + if (cycle & VME_2eSSTB) { + dev_err(dev, "Currently not setting Broadcast Select " + "Registers\n"); + val |= TSI148_LCSR_DSAT_TM_2eSSTB; + } + + /* Setup data width */ + switch (dwidth) { + case VME_D16: + val |= TSI148_LCSR_DSAT_DBW_16; + break; + case VME_D32: + val |= TSI148_LCSR_DSAT_DBW_32; + break; + default: + dev_err(dev, "Invalid data width\n"); + return -EINVAL; + } + + /* Setup address space */ + switch (aspace) { + case VME_A16: + val |= TSI148_LCSR_DSAT_AMODE_A16; + break; + case VME_A24: + val |= TSI148_LCSR_DSAT_AMODE_A24; + break; + case VME_A32: + val |= TSI148_LCSR_DSAT_AMODE_A32; + break; + case VME_A64: + val |= TSI148_LCSR_DSAT_AMODE_A64; + break; + case VME_CRCSR: + val |= TSI148_LCSR_DSAT_AMODE_CRCSR; + break; + case VME_USER1: + val |= TSI148_LCSR_DSAT_AMODE_USER1; + break; + case VME_USER2: + val |= TSI148_LCSR_DSAT_AMODE_USER2; + break; + case VME_USER3: + val |= TSI148_LCSR_DSAT_AMODE_USER3; + break; + case VME_USER4: + val |= TSI148_LCSR_DSAT_AMODE_USER4; + break; + default: + dev_err(dev, "Invalid address space\n"); + return -EINVAL; + } + + if (cycle & VME_SUPER) + val |= TSI148_LCSR_DSAT_SUP; + if (cycle & VME_PROG) + val |= TSI148_LCSR_DSAT_PGM; + + *attr = cpu_to_be32(val); + + return 0; +} + +static int tsi148_dma_set_vme_dest_attributes(struct device *dev, __be32 *attr, + u32 aspace, u32 cycle, u32 dwidth) +{ + u32 val; + + val = be32_to_cpu(*attr); + + /* Setup 2eSST speeds */ + switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { + case VME_2eSST160: + val |= TSI148_LCSR_DDAT_2eSSTM_160; + break; + case VME_2eSST267: + val |= TSI148_LCSR_DDAT_2eSSTM_267; + break; + case VME_2eSST320: + val |= TSI148_LCSR_DDAT_2eSSTM_320; + break; + } + + /* Setup cycle types */ + if (cycle & VME_SCT) + val |= TSI148_LCSR_DDAT_TM_SCT; + + if (cycle & VME_BLT) + val |= TSI148_LCSR_DDAT_TM_BLT; + + if (cycle & VME_MBLT) + val |= TSI148_LCSR_DDAT_TM_MBLT; + + if (cycle & VME_2eVME) + val |= TSI148_LCSR_DDAT_TM_2eVME; + + if (cycle & VME_2eSST) + val |= TSI148_LCSR_DDAT_TM_2eSST; + + if (cycle & VME_2eSSTB) { + dev_err(dev, "Currently not setting Broadcast Select " + "Registers\n"); + val |= TSI148_LCSR_DDAT_TM_2eSSTB; + } + + /* Setup data width */ + switch (dwidth) { + case VME_D16: + val |= TSI148_LCSR_DDAT_DBW_16; + break; + case VME_D32: + val |= TSI148_LCSR_DDAT_DBW_32; + break; + default: + dev_err(dev, "Invalid data width\n"); + return -EINVAL; + } + + /* Setup address space */ + switch (aspace) { + case VME_A16: + val |= TSI148_LCSR_DDAT_AMODE_A16; + break; + case VME_A24: + val |= TSI148_LCSR_DDAT_AMODE_A24; + break; + case VME_A32: + val |= TSI148_LCSR_DDAT_AMODE_A32; + break; + case VME_A64: + val |= TSI148_LCSR_DDAT_AMODE_A64; + break; + case VME_CRCSR: + val |= TSI148_LCSR_DDAT_AMODE_CRCSR; + break; + case VME_USER1: + val |= TSI148_LCSR_DDAT_AMODE_USER1; + break; + case VME_USER2: + val |= TSI148_LCSR_DDAT_AMODE_USER2; + break; + case VME_USER3: + val |= TSI148_LCSR_DDAT_AMODE_USER3; + break; + case VME_USER4: + val |= TSI148_LCSR_DDAT_AMODE_USER4; + break; + default: + dev_err(dev, "Invalid address space\n"); + return -EINVAL; + } + + if (cycle & VME_SUPER) + val |= TSI148_LCSR_DDAT_SUP; + if (cycle & VME_PROG) + val |= TSI148_LCSR_DDAT_PGM; + + *attr = cpu_to_be32(val); + + return 0; +} + +/* + * Add a link list descriptor to the list + * + * Note: DMA engine expects the DMA descriptor to be big endian. + */ +static int tsi148_dma_list_add(struct vme_dma_list *list, + struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count) +{ + struct tsi148_dma_entry *entry, *prev; + u32 address_high, address_low, val; + struct vme_dma_pattern *pattern_attr; + struct vme_dma_pci *pci_attr; + struct vme_dma_vme *vme_attr; + int retval = 0; + struct vme_bridge *tsi148_bridge; + + tsi148_bridge = list->parent->parent; + + /* Descriptor must be aligned on 64-bit boundaries */ + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + retval = -ENOMEM; + goto err_mem; + } + + /* Test descriptor alignment */ + if ((unsigned long)&entry->descriptor & 0x7) { + dev_err(tsi148_bridge->parent, "Descriptor not aligned to 8 " + "byte boundary as required: %p\n", + &entry->descriptor); + retval = -EINVAL; + goto err_align; + } + + /* Given we are going to fill out the structure, we probably don't + * need to zero it, but better safe than sorry for now. + */ + memset(&entry->descriptor, 0, sizeof(entry->descriptor)); + + /* Fill out source part */ + switch (src->type) { + case VME_DMA_PATTERN: + pattern_attr = src->private; + + entry->descriptor.dsal = cpu_to_be32(pattern_attr->pattern); + + val = TSI148_LCSR_DSAT_TYP_PAT; + + /* Default behaviour is 32 bit pattern */ + if (pattern_attr->type & VME_DMA_PATTERN_BYTE) + val |= TSI148_LCSR_DSAT_PSZ; + + /* It seems that the default behaviour is to increment */ + if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0) + val |= TSI148_LCSR_DSAT_NIN; + entry->descriptor.dsat = cpu_to_be32(val); + break; + case VME_DMA_PCI: + pci_attr = src->private; + + reg_split((unsigned long long)pci_attr->address, &address_high, + &address_low); + entry->descriptor.dsau = cpu_to_be32(address_high); + entry->descriptor.dsal = cpu_to_be32(address_low); + entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_PCI); + break; + case VME_DMA_VME: + vme_attr = src->private; + + reg_split((unsigned long long)vme_attr->address, &address_high, + &address_low); + entry->descriptor.dsau = cpu_to_be32(address_high); + entry->descriptor.dsal = cpu_to_be32(address_low); + entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_VME); + + retval = tsi148_dma_set_vme_src_attributes( + tsi148_bridge->parent, &entry->descriptor.dsat, + vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth); + if (retval < 0) + goto err_source; + break; + default: + dev_err(tsi148_bridge->parent, "Invalid source type\n"); + retval = -EINVAL; + goto err_source; + } + + /* Assume last link - this will be over-written by adding another */ + entry->descriptor.dnlau = cpu_to_be32(0); + entry->descriptor.dnlal = cpu_to_be32(TSI148_LCSR_DNLAL_LLA); + + /* Fill out destination part */ + switch (dest->type) { + case VME_DMA_PCI: + pci_attr = dest->private; + + reg_split((unsigned long long)pci_attr->address, &address_high, + &address_low); + entry->descriptor.ddau = cpu_to_be32(address_high); + entry->descriptor.ddal = cpu_to_be32(address_low); + entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_PCI); + break; + case VME_DMA_VME: + vme_attr = dest->private; + + reg_split((unsigned long long)vme_attr->address, &address_high, + &address_low); + entry->descriptor.ddau = cpu_to_be32(address_high); + entry->descriptor.ddal = cpu_to_be32(address_low); + entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_VME); + + retval = tsi148_dma_set_vme_dest_attributes( + tsi148_bridge->parent, &entry->descriptor.ddat, + vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth); + if (retval < 0) + goto err_dest; + break; + default: + dev_err(tsi148_bridge->parent, "Invalid destination type\n"); + retval = -EINVAL; + goto err_dest; + } + + /* Fill out count */ + entry->descriptor.dcnt = cpu_to_be32((u32)count); + + /* Add to list */ + list_add_tail(&entry->list, &list->entries); + + entry->dma_handle = dma_map_single(tsi148_bridge->parent, + &entry->descriptor, + sizeof(entry->descriptor), + DMA_TO_DEVICE); + if (dma_mapping_error(tsi148_bridge->parent, entry->dma_handle)) { + dev_err(tsi148_bridge->parent, "DMA mapping error\n"); + retval = -EINVAL; + goto err_dma; + } + + /* Fill out previous descriptors "Next Address" */ + if (entry->list.prev != &list->entries) { + reg_split((unsigned long long)entry->dma_handle, &address_high, + &address_low); + prev = list_entry(entry->list.prev, struct tsi148_dma_entry, + list); + prev->descriptor.dnlau = cpu_to_be32(address_high); + prev->descriptor.dnlal = cpu_to_be32(address_low); + + } + + return 0; + +err_dma: +err_dest: +err_source: +err_align: + kfree(entry); +err_mem: + return retval; +} + +/* + * Check to see if the provided DMA channel is busy. + */ +static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel) +{ + u32 tmp; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + tmp = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] + + TSI148_LCSR_OFFSET_DSTA); + + if (tmp & TSI148_LCSR_DSTA_BSY) + return 0; + else + return 1; + +} + +/* + * Execute a previously generated link list + * + * XXX Need to provide control register configuration. + */ +static int tsi148_dma_list_exec(struct vme_dma_list *list) +{ + struct vme_dma_resource *ctrlr; + int channel, retval; + struct tsi148_dma_entry *entry; + u32 bus_addr_high, bus_addr_low; + u32 val, dctlreg = 0; + struct vme_bridge *tsi148_bridge; + struct tsi148_driver *bridge; + + ctrlr = list->parent; + + tsi148_bridge = ctrlr->parent; + + bridge = tsi148_bridge->driver_priv; + + mutex_lock(&ctrlr->mtx); + + channel = ctrlr->number; + + if (!list_empty(&ctrlr->running)) { + /* + * XXX We have an active DMA transfer and currently haven't + * sorted out the mechanism for "pending" DMA transfers. + * Return busy. + */ + /* Need to add to pending here */ + mutex_unlock(&ctrlr->mtx); + return -EBUSY; + } else { + list_add(&list->list, &ctrlr->running); + } + + /* Get first bus address and write into registers */ + entry = list_first_entry(&list->entries, struct tsi148_dma_entry, + list); + + mutex_unlock(&ctrlr->mtx); + + reg_split(entry->dma_handle, &bus_addr_high, &bus_addr_low); + + iowrite32be(bus_addr_high, bridge->base + + TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU); + iowrite32be(bus_addr_low, bridge->base + + TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL); + + dctlreg = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] + + TSI148_LCSR_OFFSET_DCTL); + + /* Start the operation */ + iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base + + TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL); + + retval = wait_event_interruptible(bridge->dma_queue[channel], + tsi148_dma_busy(ctrlr->parent, channel)); + + if (retval) { + iowrite32be(dctlreg | TSI148_LCSR_DCTL_ABT, bridge->base + + TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL); + /* Wait for the operation to abort */ + wait_event(bridge->dma_queue[channel], + tsi148_dma_busy(ctrlr->parent, channel)); + retval = -EINTR; + goto exit; + } + + /* + * Read status register, this register is valid until we kick off a + * new transfer. + */ + val = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] + + TSI148_LCSR_OFFSET_DSTA); + + if (val & TSI148_LCSR_DSTA_VBE) { + dev_err(tsi148_bridge->parent, "DMA Error. DSTA=%08X\n", val); + retval = -EIO; + } + +exit: + /* Remove list from running list */ + mutex_lock(&ctrlr->mtx); + list_del(&list->list); + mutex_unlock(&ctrlr->mtx); + + return retval; +} + +/* + * Clean up a previously generated link list + * + * We have a separate function, don't assume that the chain can't be reused. + */ +static int tsi148_dma_list_empty(struct vme_dma_list *list) +{ + struct list_head *pos, *temp; + struct tsi148_dma_entry *entry; + + struct vme_bridge *tsi148_bridge = list->parent->parent; + + /* detach and free each entry */ + list_for_each_safe(pos, temp, &list->entries) { + list_del(pos); + entry = list_entry(pos, struct tsi148_dma_entry, list); + + dma_unmap_single(tsi148_bridge->parent, entry->dma_handle, + sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE); + kfree(entry); + } + + return 0; +} + +/* + * All 4 location monitors reside at the same base - this is therefore a + * system wide configuration. + * + * This does not enable the LM monitor - that should be done when the first + * callback is attached and disabled when the last callback is removed. + */ +static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, + u32 aspace, u32 cycle) +{ + u32 lm_base_high, lm_base_low, lm_ctl = 0; + int i; + struct vme_bridge *tsi148_bridge; + struct tsi148_driver *bridge; + + tsi148_bridge = lm->parent; + + bridge = tsi148_bridge->driver_priv; + + mutex_lock(&lm->mtx); + + /* If we already have a callback attached, we can't move it! */ + for (i = 0; i < lm->monitors; i++) { + if (bridge->lm_callback[i]) { + mutex_unlock(&lm->mtx); + dev_err(tsi148_bridge->parent, "Location monitor " + "callback attached, can't reset\n"); + return -EBUSY; + } + } + + switch (aspace) { + case VME_A16: + lm_ctl |= TSI148_LCSR_LMAT_AS_A16; + break; + case VME_A24: + lm_ctl |= TSI148_LCSR_LMAT_AS_A24; + break; + case VME_A32: + lm_ctl |= TSI148_LCSR_LMAT_AS_A32; + break; + case VME_A64: + lm_ctl |= TSI148_LCSR_LMAT_AS_A64; + break; + default: + mutex_unlock(&lm->mtx); + dev_err(tsi148_bridge->parent, "Invalid address space\n"); + return -EINVAL; + } + + if (cycle & VME_SUPER) + lm_ctl |= TSI148_LCSR_LMAT_SUPR ; + if (cycle & VME_USER) + lm_ctl |= TSI148_LCSR_LMAT_NPRIV; + if (cycle & VME_PROG) + lm_ctl |= TSI148_LCSR_LMAT_PGM; + if (cycle & VME_DATA) + lm_ctl |= TSI148_LCSR_LMAT_DATA; + + reg_split(lm_base, &lm_base_high, &lm_base_low); + + iowrite32be(lm_base_high, bridge->base + TSI148_LCSR_LMBAU); + iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL); + iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT); + + mutex_unlock(&lm->mtx); + + return 0; +} + +/* Get configuration of the callback monitor and return whether it is enabled + * or disabled. + */ +static int tsi148_lm_get(struct vme_lm_resource *lm, + unsigned long long *lm_base, u32 *aspace, u32 *cycle) +{ + u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0; + struct tsi148_driver *bridge; + + bridge = lm->parent->driver_priv; + + mutex_lock(&lm->mtx); + + lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU); + lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL); + lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT); + + reg_join(lm_base_high, lm_base_low, lm_base); + + if (lm_ctl & TSI148_LCSR_LMAT_EN) + enabled = 1; + + if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A16) + *aspace |= VME_A16; + + if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A24) + *aspace |= VME_A24; + + if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A32) + *aspace |= VME_A32; + + if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A64) + *aspace |= VME_A64; + + + if (lm_ctl & TSI148_LCSR_LMAT_SUPR) + *cycle |= VME_SUPER; + if (lm_ctl & TSI148_LCSR_LMAT_NPRIV) + *cycle |= VME_USER; + if (lm_ctl & TSI148_LCSR_LMAT_PGM) + *cycle |= VME_PROG; + if (lm_ctl & TSI148_LCSR_LMAT_DATA) + *cycle |= VME_DATA; + + mutex_unlock(&lm->mtx); + + return enabled; +} + +/* + * Attach a callback to a specific location monitor. + * + * Callback will be passed the monitor triggered. + */ +static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, + void (*callback)(void *), void *data) +{ + u32 lm_ctl, tmp; + struct vme_bridge *tsi148_bridge; + struct tsi148_driver *bridge; + + tsi148_bridge = lm->parent; + + bridge = tsi148_bridge->driver_priv; + + mutex_lock(&lm->mtx); + + /* Ensure that the location monitor is configured - need PGM or DATA */ + lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT); + if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) { + mutex_unlock(&lm->mtx); + dev_err(tsi148_bridge->parent, "Location monitor not properly " + "configured\n"); + return -EINVAL; + } + + /* Check that a callback isn't already attached */ + if (bridge->lm_callback[monitor]) { + mutex_unlock(&lm->mtx); + dev_err(tsi148_bridge->parent, "Existing callback attached\n"); + return -EBUSY; + } + + /* Attach callback */ + bridge->lm_callback[monitor] = callback; + bridge->lm_data[monitor] = data; + + /* Enable Location Monitor interrupt */ + tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN); + tmp |= TSI148_LCSR_INTEN_LMEN[monitor]; + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN); + + tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO); + tmp |= TSI148_LCSR_INTEO_LMEO[monitor]; + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); + + /* Ensure that global Location Monitor Enable set */ + if ((lm_ctl & TSI148_LCSR_LMAT_EN) == 0) { + lm_ctl |= TSI148_LCSR_LMAT_EN; + iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT); + } + + mutex_unlock(&lm->mtx); + + return 0; +} + +/* + * Detach a callback function forn a specific location monitor. + */ +static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor) +{ + u32 lm_en, tmp; + struct tsi148_driver *bridge; + + bridge = lm->parent->driver_priv; + + mutex_lock(&lm->mtx); + + /* Disable Location Monitor and ensure previous interrupts are clear */ + lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN); + lm_en &= ~TSI148_LCSR_INTEN_LMEN[monitor]; + iowrite32be(lm_en, bridge->base + TSI148_LCSR_INTEN); + + tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO); + tmp &= ~TSI148_LCSR_INTEO_LMEO[monitor]; + iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); + + iowrite32be(TSI148_LCSR_INTC_LMC[monitor], + bridge->base + TSI148_LCSR_INTC); + + /* Detach callback */ + bridge->lm_callback[monitor] = NULL; + bridge->lm_data[monitor] = NULL; + + /* If all location monitors disabled, disable global Location Monitor */ + if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S | + TSI148_LCSR_INTS_LM2S | TSI148_LCSR_INTS_LM3S)) == 0) { + tmp = ioread32be(bridge->base + TSI148_LCSR_LMAT); + tmp &= ~TSI148_LCSR_LMAT_EN; + iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT); + } + + mutex_unlock(&lm->mtx); + + return 0; +} + +/* + * Determine Geographical Addressing + */ +static int tsi148_slot_get(struct vme_bridge *tsi148_bridge) +{ + u32 slot = 0; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + if (!geoid) { + slot = ioread32be(bridge->base + TSI148_LCSR_VSTAT); + slot = slot & TSI148_LCSR_VSTAT_GA_M; + } else + slot = geoid; + + return (int)slot; +} + +static void *tsi148_alloc_consistent(struct device *parent, size_t size, + dma_addr_t *dma) +{ + struct pci_dev *pdev; + + /* Find pci_dev container of dev */ + pdev = to_pci_dev(parent); + + return dma_alloc_coherent(&pdev->dev, size, dma, GFP_KERNEL); +} + +static void tsi148_free_consistent(struct device *parent, size_t size, + void *vaddr, dma_addr_t dma) +{ + struct pci_dev *pdev; + + /* Find pci_dev container of dev */ + pdev = to_pci_dev(parent); + + dma_free_coherent(&pdev->dev, size, vaddr, dma); +} + +/* + * Configure CR/CSR space + * + * Access to the CR/CSR can be configured at power-up. The location of the + * CR/CSR registers in the CR/CSR address space is determined by the boards + * Auto-ID or Geographic address. This function ensures that the window is + * enabled at an offset consistent with the boards geopgraphic address. + * + * Each board has a 512kB window, with the highest 4kB being used for the + * boards registers, this means there is a fix length 508kB window which must + * be mapped onto PCI memory. + */ +static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge, + struct pci_dev *pdev) +{ + u32 cbar, crat, vstat; + u32 crcsr_bus_high, crcsr_bus_low; + int retval; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + /* Allocate mem for CR/CSR image */ + bridge->crcsr_kernel = dma_alloc_coherent(&pdev->dev, + VME_CRCSR_BUF_SIZE, + &bridge->crcsr_bus, GFP_KERNEL); + if (!bridge->crcsr_kernel) { + dev_err(tsi148_bridge->parent, "Failed to allocate memory for " + "CR/CSR image\n"); + return -ENOMEM; + } + + reg_split(bridge->crcsr_bus, &crcsr_bus_high, &crcsr_bus_low); + + iowrite32be(crcsr_bus_high, bridge->base + TSI148_LCSR_CROU); + iowrite32be(crcsr_bus_low, bridge->base + TSI148_LCSR_CROL); + + /* Ensure that the CR/CSR is configured at the correct offset */ + cbar = ioread32be(bridge->base + TSI148_CBAR); + cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3; + + vstat = tsi148_slot_get(tsi148_bridge); + + if (cbar != vstat) { + cbar = vstat; + dev_info(tsi148_bridge->parent, "Setting CR/CSR offset\n"); + iowrite32be(cbar<<3, bridge->base + TSI148_CBAR); + } + dev_info(tsi148_bridge->parent, "CR/CSR Offset: %d\n", cbar); + + crat = ioread32be(bridge->base + TSI148_LCSR_CRAT); + if (crat & TSI148_LCSR_CRAT_EN) + dev_info(tsi148_bridge->parent, "CR/CSR already enabled\n"); + else { + dev_info(tsi148_bridge->parent, "Enabling CR/CSR space\n"); + iowrite32be(crat | TSI148_LCSR_CRAT_EN, + bridge->base + TSI148_LCSR_CRAT); + } + + /* If we want flushed, error-checked writes, set up a window + * over the CR/CSR registers. We read from here to safely flush + * through VME writes. + */ + if (err_chk) { + retval = tsi148_master_set(bridge->flush_image, 1, + (vstat * 0x80000), 0x80000, VME_CRCSR, VME_SCT, + VME_D16); + if (retval) + dev_err(tsi148_bridge->parent, "Configuring flush image" + " failed\n"); + } + + return 0; + +} + +static void tsi148_crcsr_exit(struct vme_bridge *tsi148_bridge, + struct pci_dev *pdev) +{ + u32 crat; + struct tsi148_driver *bridge; + + bridge = tsi148_bridge->driver_priv; + + /* Turn off CR/CSR space */ + crat = ioread32be(bridge->base + TSI148_LCSR_CRAT); + iowrite32be(crat & ~TSI148_LCSR_CRAT_EN, + bridge->base + TSI148_LCSR_CRAT); + + /* Free image */ + iowrite32be(0, bridge->base + TSI148_LCSR_CROU); + iowrite32be(0, bridge->base + TSI148_LCSR_CROL); + + dma_free_coherent(&pdev->dev, VME_CRCSR_BUF_SIZE, + bridge->crcsr_kernel, bridge->crcsr_bus); +} + +static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int retval, i, master_num; + u32 data; + struct list_head *pos = NULL, *n; + struct vme_bridge *tsi148_bridge; + struct tsi148_driver *tsi148_device; + struct vme_master_resource *master_image; + struct vme_slave_resource *slave_image; + struct vme_dma_resource *dma_ctrlr; + struct vme_lm_resource *lm; + + /* If we want to support more than one of each bridge, we need to + * dynamically generate this so we get one per device + */ + tsi148_bridge = kzalloc(sizeof(*tsi148_bridge), GFP_KERNEL); + if (!tsi148_bridge) { + retval = -ENOMEM; + goto err_struct; + } + vme_init_bridge(tsi148_bridge); + + tsi148_device = kzalloc(sizeof(*tsi148_device), GFP_KERNEL); + if (!tsi148_device) { + retval = -ENOMEM; + goto err_driver; + } + + tsi148_bridge->driver_priv = tsi148_device; + + /* Enable the device */ + retval = pci_enable_device(pdev); + if (retval) { + dev_err(&pdev->dev, "Unable to enable device\n"); + goto err_enable; + } + + /* Map Registers */ + retval = pci_request_regions(pdev, driver_name); + if (retval) { + dev_err(&pdev->dev, "Unable to reserve resources\n"); + goto err_resource; + } + + /* map registers in BAR 0 */ + tsi148_device->base = ioremap(pci_resource_start(pdev, 0), + 4096); + if (!tsi148_device->base) { + dev_err(&pdev->dev, "Unable to remap CRG region\n"); + retval = -EIO; + goto err_remap; + } + + /* Check to see if the mapping worked out */ + data = ioread32(tsi148_device->base + TSI148_PCFS_ID) & 0x0000FFFF; + if (data != PCI_VENDOR_ID_TUNDRA) { + dev_err(&pdev->dev, "CRG region check failed\n"); + retval = -EIO; + goto err_test; + } + + /* Initialize wait queues & mutual exclusion flags */ + init_waitqueue_head(&tsi148_device->dma_queue[0]); + init_waitqueue_head(&tsi148_device->dma_queue[1]); + init_waitqueue_head(&tsi148_device->iack_queue); + mutex_init(&tsi148_device->vme_int); + mutex_init(&tsi148_device->vme_rmw); + + tsi148_bridge->parent = &pdev->dev; + strcpy(tsi148_bridge->name, driver_name); + + /* Setup IRQ */ + retval = tsi148_irq_init(tsi148_bridge); + if (retval != 0) { + dev_err(&pdev->dev, "Chip Initialization failed.\n"); + goto err_irq; + } + + /* If we are going to flush writes, we need to read from the VME bus. + * We need to do this safely, thus we read the devices own CR/CSR + * register. To do this we must set up a window in CR/CSR space and + * hence have one less master window resource available. + */ + master_num = TSI148_MAX_MASTER; + if (err_chk) { + master_num--; + + tsi148_device->flush_image = + kmalloc(sizeof(*tsi148_device->flush_image), + GFP_KERNEL); + if (!tsi148_device->flush_image) { + retval = -ENOMEM; + goto err_master; + } + tsi148_device->flush_image->parent = tsi148_bridge; + spin_lock_init(&tsi148_device->flush_image->lock); + tsi148_device->flush_image->locked = 1; + tsi148_device->flush_image->number = master_num; + memset(&tsi148_device->flush_image->bus_resource, 0, + sizeof(tsi148_device->flush_image->bus_resource)); + tsi148_device->flush_image->kern_base = NULL; + } + + /* Add master windows to list */ + for (i = 0; i < master_num; i++) { + master_image = kmalloc(sizeof(*master_image), GFP_KERNEL); + if (!master_image) { + retval = -ENOMEM; + goto err_master; + } + master_image->parent = tsi148_bridge; + spin_lock_init(&master_image->lock); + master_image->locked = 0; + master_image->number = i; + master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | + VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 | + VME_USER3 | VME_USER4; + master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | + VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | + VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | + VME_PROG | VME_DATA; + master_image->width_attr = VME_D16 | VME_D32; + memset(&master_image->bus_resource, 0, + sizeof(master_image->bus_resource)); + master_image->kern_base = NULL; + list_add_tail(&master_image->list, + &tsi148_bridge->master_resources); + } + + /* Add slave windows to list */ + for (i = 0; i < TSI148_MAX_SLAVE; i++) { + slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL); + if (!slave_image) { + retval = -ENOMEM; + goto err_slave; + } + slave_image->parent = tsi148_bridge; + mutex_init(&slave_image->mtx); + slave_image->locked = 0; + slave_image->number = i; + slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 | + VME_A64; + slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | + VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | + VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | + VME_PROG | VME_DATA; + list_add_tail(&slave_image->list, + &tsi148_bridge->slave_resources); + } + + /* Add dma engines to list */ + for (i = 0; i < TSI148_MAX_DMA; i++) { + dma_ctrlr = kmalloc(sizeof(*dma_ctrlr), GFP_KERNEL); + if (!dma_ctrlr) { + retval = -ENOMEM; + goto err_dma; + } + dma_ctrlr->parent = tsi148_bridge; + mutex_init(&dma_ctrlr->mtx); + dma_ctrlr->locked = 0; + dma_ctrlr->number = i; + dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM | + VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME | + VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME | + VME_DMA_PATTERN_TO_MEM; + INIT_LIST_HEAD(&dma_ctrlr->pending); + INIT_LIST_HEAD(&dma_ctrlr->running); + list_add_tail(&dma_ctrlr->list, + &tsi148_bridge->dma_resources); + } + + /* Add location monitor to list */ + lm = kmalloc(sizeof(*lm), GFP_KERNEL); + if (!lm) { + retval = -ENOMEM; + goto err_lm; + } + lm->parent = tsi148_bridge; + mutex_init(&lm->mtx); + lm->locked = 0; + lm->number = 1; + lm->monitors = 4; + list_add_tail(&lm->list, &tsi148_bridge->lm_resources); + + tsi148_bridge->slave_get = tsi148_slave_get; + tsi148_bridge->slave_set = tsi148_slave_set; + tsi148_bridge->master_get = tsi148_master_get; + tsi148_bridge->master_set = tsi148_master_set; + tsi148_bridge->master_read = tsi148_master_read; + tsi148_bridge->master_write = tsi148_master_write; + tsi148_bridge->master_rmw = tsi148_master_rmw; + tsi148_bridge->dma_list_add = tsi148_dma_list_add; + tsi148_bridge->dma_list_exec = tsi148_dma_list_exec; + tsi148_bridge->dma_list_empty = tsi148_dma_list_empty; + tsi148_bridge->irq_set = tsi148_irq_set; + tsi148_bridge->irq_generate = tsi148_irq_generate; + tsi148_bridge->lm_set = tsi148_lm_set; + tsi148_bridge->lm_get = tsi148_lm_get; + tsi148_bridge->lm_attach = tsi148_lm_attach; + tsi148_bridge->lm_detach = tsi148_lm_detach; + tsi148_bridge->slot_get = tsi148_slot_get; + tsi148_bridge->alloc_consistent = tsi148_alloc_consistent; + tsi148_bridge->free_consistent = tsi148_free_consistent; + + data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT); + dev_info(&pdev->dev, "Board is%s the VME system controller\n", + (data & TSI148_LCSR_VSTAT_SCONS) ? "" : " not"); + if (!geoid) + dev_info(&pdev->dev, "VME geographical address is %d\n", + data & TSI148_LCSR_VSTAT_GA_M); + else + dev_info(&pdev->dev, "VME geographical address is set to %d\n", + geoid); + + dev_info(&pdev->dev, "VME Write and flush and error check is %s\n", + err_chk ? "enabled" : "disabled"); + + retval = tsi148_crcsr_init(tsi148_bridge, pdev); + if (retval) { + dev_err(&pdev->dev, "CR/CSR configuration failed.\n"); + goto err_crcsr; + } + + retval = vme_register_bridge(tsi148_bridge); + if (retval != 0) { + dev_err(&pdev->dev, "Chip Registration failed.\n"); + goto err_reg; + } + + pci_set_drvdata(pdev, tsi148_bridge); + + /* Clear VME bus "board fail", and "power-up reset" lines */ + data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT); + data &= ~TSI148_LCSR_VSTAT_BRDFL; + data |= TSI148_LCSR_VSTAT_CPURST; + iowrite32be(data, tsi148_device->base + TSI148_LCSR_VSTAT); + + return 0; + +err_reg: + tsi148_crcsr_exit(tsi148_bridge, pdev); +err_crcsr: +err_lm: + /* resources are stored in link list */ + list_for_each_safe(pos, n, &tsi148_bridge->lm_resources) { + lm = list_entry(pos, struct vme_lm_resource, list); + list_del(pos); + kfree(lm); + } +err_dma: + /* resources are stored in link list */ + list_for_each_safe(pos, n, &tsi148_bridge->dma_resources) { + dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); + list_del(pos); + kfree(dma_ctrlr); + } +err_slave: + /* resources are stored in link list */ + list_for_each_safe(pos, n, &tsi148_bridge->slave_resources) { + slave_image = list_entry(pos, struct vme_slave_resource, list); + list_del(pos); + kfree(slave_image); + } +err_master: + /* resources are stored in link list */ + list_for_each_safe(pos, n, &tsi148_bridge->master_resources) { + master_image = list_entry(pos, struct vme_master_resource, + list); + list_del(pos); + kfree(master_image); + } + + tsi148_irq_exit(tsi148_bridge, pdev); +err_irq: +err_test: + iounmap(tsi148_device->base); +err_remap: + pci_release_regions(pdev); +err_resource: + pci_disable_device(pdev); +err_enable: + kfree(tsi148_device); +err_driver: + kfree(tsi148_bridge); +err_struct: + return retval; + +} + +static void tsi148_remove(struct pci_dev *pdev) +{ + struct list_head *pos = NULL; + struct list_head *tmplist; + struct vme_master_resource *master_image; + struct vme_slave_resource *slave_image; + struct vme_dma_resource *dma_ctrlr; + int i; + struct tsi148_driver *bridge; + struct vme_bridge *tsi148_bridge = pci_get_drvdata(pdev); + + bridge = tsi148_bridge->driver_priv; + + + dev_dbg(&pdev->dev, "Driver is being unloaded.\n"); + + /* + * Shutdown all inbound and outbound windows. + */ + for (i = 0; i < 8; i++) { + iowrite32be(0, bridge->base + TSI148_LCSR_IT[i] + + TSI148_LCSR_OFFSET_ITAT); + iowrite32be(0, bridge->base + TSI148_LCSR_OT[i] + + TSI148_LCSR_OFFSET_OTAT); + } + + /* + * Shutdown Location monitor. + */ + iowrite32be(0, bridge->base + TSI148_LCSR_LMAT); + + /* + * Shutdown CRG map. + */ + iowrite32be(0, bridge->base + TSI148_LCSR_CSRAT); + + /* + * Clear error status. + */ + iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_EDPAT); + iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_VEAT); + iowrite32be(0x07000700, bridge->base + TSI148_LCSR_PSTAT); + + /* + * Remove VIRQ interrupt (if any) + */ + if (ioread32be(bridge->base + TSI148_LCSR_VICR) & 0x800) + iowrite32be(0x8000, bridge->base + TSI148_LCSR_VICR); + + /* + * Map all Interrupts to PCI INTA + */ + iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1); + iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2); + + tsi148_irq_exit(tsi148_bridge, pdev); + + vme_unregister_bridge(tsi148_bridge); + + tsi148_crcsr_exit(tsi148_bridge, pdev); + + /* resources are stored in link list */ + list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) { + dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); + list_del(pos); + kfree(dma_ctrlr); + } + + /* resources are stored in link list */ + list_for_each_safe(pos, tmplist, &tsi148_bridge->slave_resources) { + slave_image = list_entry(pos, struct vme_slave_resource, list); + list_del(pos); + kfree(slave_image); + } + + /* resources are stored in link list */ + list_for_each_safe(pos, tmplist, &tsi148_bridge->master_resources) { + master_image = list_entry(pos, struct vme_master_resource, + list); + list_del(pos); + kfree(master_image); + } + + iounmap(bridge->base); + + pci_release_regions(pdev); + + pci_disable_device(pdev); + + kfree(tsi148_bridge->driver_priv); + + kfree(tsi148_bridge); +} + +module_pci_driver(tsi148_driver); + +MODULE_PARM_DESC(err_chk, "Check for VME errors on reads and writes"); +module_param(err_chk, bool, 0); + +MODULE_PARM_DESC(geoid, "Override geographical addressing"); +module_param(geoid, int, 0); + +MODULE_DESCRIPTION("VME driver for the Tundra Tempe VME bridge"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/vme_user/vme_tsi148.h b/drivers/staging/vme_user/vme_tsi148.h new file mode 100644 index 000000000000..226fedc6f167 --- /dev/null +++ b/drivers/staging/vme_user/vme_tsi148.h @@ -0,0 +1,1407 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * tsi148.h + * + * Support for the Tundra TSI148 VME Bridge chip + * + * Author: Tom Armistead + * Updated and maintained by Ajit Prem + * Copyright 2004 Motorola Inc. + */ + +#ifndef TSI148_H +#define TSI148_H + +#ifndef PCI_VENDOR_ID_TUNDRA +#define PCI_VENDOR_ID_TUNDRA 0x10e3 +#endif + +#ifndef PCI_DEVICE_ID_TUNDRA_TSI148 +#define PCI_DEVICE_ID_TUNDRA_TSI148 0x148 +#endif + +/* + * Define the number of each that the Tsi148 supports. + */ +#define TSI148_MAX_MASTER 8 /* Max Master Windows */ +#define TSI148_MAX_SLAVE 8 /* Max Slave Windows */ +#define TSI148_MAX_DMA 2 /* Max DMA Controllers */ +#define TSI148_MAX_MAILBOX 4 /* Max Mail Box registers */ +#define TSI148_MAX_SEMAPHORE 8 /* Max Semaphores */ + +/* Structure used to hold driver specific information */ +struct tsi148_driver { + void __iomem *base; /* Base Address of device registers */ + wait_queue_head_t dma_queue[2]; + wait_queue_head_t iack_queue; + void (*lm_callback[4])(void *); /* Called in interrupt handler */ + void *lm_data[4]; + void *crcsr_kernel; + dma_addr_t crcsr_bus; + struct vme_master_resource *flush_image; + struct mutex vme_rmw; /* Only one RMW cycle at a time */ + struct mutex vme_int; /* + * Only one VME interrupt can be + * generated at a time, provide locking + */ +}; + +/* + * Layout of a DMAC Linked-List Descriptor + * + * Note: This structure is accessed via the chip and therefore must be + * correctly laid out - It must also be aligned on 64-bit boundaries. + */ +struct tsi148_dma_descriptor { + __be32 dsau; /* Source Address */ + __be32 dsal; + __be32 ddau; /* Destination Address */ + __be32 ddal; + __be32 dsat; /* Source attributes */ + __be32 ddat; /* Destination attributes */ + __be32 dnlau; /* Next link address */ + __be32 dnlal; + __be32 dcnt; /* Byte count */ + __be32 ddbs; /* 2eSST Broadcast select */ +}; + +struct tsi148_dma_entry { + /* + * The descriptor needs to be aligned on a 64-bit boundary, we increase + * the chance of this by putting it first in the structure. + */ + struct tsi148_dma_descriptor descriptor; + struct list_head list; + dma_addr_t dma_handle; +}; + +/* + * TSI148 ASIC register structure overlays and bit field definitions. + * + * Note: Tsi148 Register Group (CRG) consists of the following + * combination of registers: + * PCFS - PCI Configuration Space Registers + * LCSR - Local Control and Status Registers + * GCSR - Global Control and Status Registers + * CR/CSR - Subset of Configuration ROM / + * Control and Status Registers + */ + + +/* + * Command/Status Registers (CRG + $004) + */ +#define TSI148_PCFS_ID 0x0 +#define TSI148_PCFS_CSR 0x4 +#define TSI148_PCFS_CLASS 0x8 +#define TSI148_PCFS_MISC0 0xC +#define TSI148_PCFS_MBARL 0x10 +#define TSI148_PCFS_MBARU 0x14 + +#define TSI148_PCFS_SUBID 0x28 + +#define TSI148_PCFS_CAPP 0x34 + +#define TSI148_PCFS_MISC1 0x3C + +#define TSI148_PCFS_XCAPP 0x40 +#define TSI148_PCFS_XSTAT 0x44 + +/* + * LCSR definitions + */ + +/* + * Outbound Translations + */ +#define TSI148_LCSR_OT0_OTSAU 0x100 +#define TSI148_LCSR_OT0_OTSAL 0x104 +#define TSI148_LCSR_OT0_OTEAU 0x108 +#define TSI148_LCSR_OT0_OTEAL 0x10C +#define TSI148_LCSR_OT0_OTOFU 0x110 +#define TSI148_LCSR_OT0_OTOFL 0x114 +#define TSI148_LCSR_OT0_OTBS 0x118 +#define TSI148_LCSR_OT0_OTAT 0x11C + +#define TSI148_LCSR_OT1_OTSAU 0x120 +#define TSI148_LCSR_OT1_OTSAL 0x124 +#define TSI148_LCSR_OT1_OTEAU 0x128 +#define TSI148_LCSR_OT1_OTEAL 0x12C +#define TSI148_LCSR_OT1_OTOFU 0x130 +#define TSI148_LCSR_OT1_OTOFL 0x134 +#define TSI148_LCSR_OT1_OTBS 0x138 +#define TSI148_LCSR_OT1_OTAT 0x13C + +#define TSI148_LCSR_OT2_OTSAU 0x140 +#define TSI148_LCSR_OT2_OTSAL 0x144 +#define TSI148_LCSR_OT2_OTEAU 0x148 +#define TSI148_LCSR_OT2_OTEAL 0x14C +#define TSI148_LCSR_OT2_OTOFU 0x150 +#define TSI148_LCSR_OT2_OTOFL 0x154 +#define TSI148_LCSR_OT2_OTBS 0x158 +#define TSI148_LCSR_OT2_OTAT 0x15C + +#define TSI148_LCSR_OT3_OTSAU 0x160 +#define TSI148_LCSR_OT3_OTSAL 0x164 +#define TSI148_LCSR_OT3_OTEAU 0x168 +#define TSI148_LCSR_OT3_OTEAL 0x16C +#define TSI148_LCSR_OT3_OTOFU 0x170 +#define TSI148_LCSR_OT3_OTOFL 0x174 +#define TSI148_LCSR_OT3_OTBS 0x178 +#define TSI148_LCSR_OT3_OTAT 0x17C + +#define TSI148_LCSR_OT4_OTSAU 0x180 +#define TSI148_LCSR_OT4_OTSAL 0x184 +#define TSI148_LCSR_OT4_OTEAU 0x188 +#define TSI148_LCSR_OT4_OTEAL 0x18C +#define TSI148_LCSR_OT4_OTOFU 0x190 +#define TSI148_LCSR_OT4_OTOFL 0x194 +#define TSI148_LCSR_OT4_OTBS 0x198 +#define TSI148_LCSR_OT4_OTAT 0x19C + +#define TSI148_LCSR_OT5_OTSAU 0x1A0 +#define TSI148_LCSR_OT5_OTSAL 0x1A4 +#define TSI148_LCSR_OT5_OTEAU 0x1A8 +#define TSI148_LCSR_OT5_OTEAL 0x1AC +#define TSI148_LCSR_OT5_OTOFU 0x1B0 +#define TSI148_LCSR_OT5_OTOFL 0x1B4 +#define TSI148_LCSR_OT5_OTBS 0x1B8 +#define TSI148_LCSR_OT5_OTAT 0x1BC + +#define TSI148_LCSR_OT6_OTSAU 0x1C0 +#define TSI148_LCSR_OT6_OTSAL 0x1C4 +#define TSI148_LCSR_OT6_OTEAU 0x1C8 +#define TSI148_LCSR_OT6_OTEAL 0x1CC +#define TSI148_LCSR_OT6_OTOFU 0x1D0 +#define TSI148_LCSR_OT6_OTOFL 0x1D4 +#define TSI148_LCSR_OT6_OTBS 0x1D8 +#define TSI148_LCSR_OT6_OTAT 0x1DC + +#define TSI148_LCSR_OT7_OTSAU 0x1E0 +#define TSI148_LCSR_OT7_OTSAL 0x1E4 +#define TSI148_LCSR_OT7_OTEAU 0x1E8 +#define TSI148_LCSR_OT7_OTEAL 0x1EC +#define TSI148_LCSR_OT7_OTOFU 0x1F0 +#define TSI148_LCSR_OT7_OTOFL 0x1F4 +#define TSI148_LCSR_OT7_OTBS 0x1F8 +#define TSI148_LCSR_OT7_OTAT 0x1FC + +#define TSI148_LCSR_OT0 0x100 +#define TSI148_LCSR_OT1 0x120 +#define TSI148_LCSR_OT2 0x140 +#define TSI148_LCSR_OT3 0x160 +#define TSI148_LCSR_OT4 0x180 +#define TSI148_LCSR_OT5 0x1A0 +#define TSI148_LCSR_OT6 0x1C0 +#define TSI148_LCSR_OT7 0x1E0 + +static const int TSI148_LCSR_OT[8] = { TSI148_LCSR_OT0, TSI148_LCSR_OT1, + TSI148_LCSR_OT2, TSI148_LCSR_OT3, + TSI148_LCSR_OT4, TSI148_LCSR_OT5, + TSI148_LCSR_OT6, TSI148_LCSR_OT7 }; + +#define TSI148_LCSR_OFFSET_OTSAU 0x0 +#define TSI148_LCSR_OFFSET_OTSAL 0x4 +#define TSI148_LCSR_OFFSET_OTEAU 0x8 +#define TSI148_LCSR_OFFSET_OTEAL 0xC +#define TSI148_LCSR_OFFSET_OTOFU 0x10 +#define TSI148_LCSR_OFFSET_OTOFL 0x14 +#define TSI148_LCSR_OFFSET_OTBS 0x18 +#define TSI148_LCSR_OFFSET_OTAT 0x1C + +/* + * VMEbus interrupt ack + * offset 200 + */ +#define TSI148_LCSR_VIACK1 0x204 +#define TSI148_LCSR_VIACK2 0x208 +#define TSI148_LCSR_VIACK3 0x20C +#define TSI148_LCSR_VIACK4 0x210 +#define TSI148_LCSR_VIACK5 0x214 +#define TSI148_LCSR_VIACK6 0x218 +#define TSI148_LCSR_VIACK7 0x21C + +static const int TSI148_LCSR_VIACK[8] = { 0, TSI148_LCSR_VIACK1, + TSI148_LCSR_VIACK2, TSI148_LCSR_VIACK3, + TSI148_LCSR_VIACK4, TSI148_LCSR_VIACK5, + TSI148_LCSR_VIACK6, TSI148_LCSR_VIACK7 }; + +/* + * RMW + * offset 220 + */ +#define TSI148_LCSR_RMWAU 0x220 +#define TSI148_LCSR_RMWAL 0x224 +#define TSI148_LCSR_RMWEN 0x228 +#define TSI148_LCSR_RMWC 0x22C +#define TSI148_LCSR_RMWS 0x230 + +/* + * VMEbus control + * offset 234 + */ +#define TSI148_LCSR_VMCTRL 0x234 +#define TSI148_LCSR_VCTRL 0x238 +#define TSI148_LCSR_VSTAT 0x23C + +/* + * PCI status + * offset 240 + */ +#define TSI148_LCSR_PSTAT 0x240 + +/* + * VME filter. + * offset 250 + */ +#define TSI148_LCSR_VMEFL 0x250 + + /* + * VME exception. + * offset 260 + */ +#define TSI148_LCSR_VEAU 0x260 +#define TSI148_LCSR_VEAL 0x264 +#define TSI148_LCSR_VEAT 0x268 + + /* + * PCI error + * offset 270 + */ +#define TSI148_LCSR_EDPAU 0x270 +#define TSI148_LCSR_EDPAL 0x274 +#define TSI148_LCSR_EDPXA 0x278 +#define TSI148_LCSR_EDPXS 0x27C +#define TSI148_LCSR_EDPAT 0x280 + + /* + * Inbound Translations + * offset 300 + */ +#define TSI148_LCSR_IT0_ITSAU 0x300 +#define TSI148_LCSR_IT0_ITSAL 0x304 +#define TSI148_LCSR_IT0_ITEAU 0x308 +#define TSI148_LCSR_IT0_ITEAL 0x30C +#define TSI148_LCSR_IT0_ITOFU 0x310 +#define TSI148_LCSR_IT0_ITOFL 0x314 +#define TSI148_LCSR_IT0_ITAT 0x318 + +#define TSI148_LCSR_IT1_ITSAU 0x320 +#define TSI148_LCSR_IT1_ITSAL 0x324 +#define TSI148_LCSR_IT1_ITEAU 0x328 +#define TSI148_LCSR_IT1_ITEAL 0x32C +#define TSI148_LCSR_IT1_ITOFU 0x330 +#define TSI148_LCSR_IT1_ITOFL 0x334 +#define TSI148_LCSR_IT1_ITAT 0x338 + +#define TSI148_LCSR_IT2_ITSAU 0x340 +#define TSI148_LCSR_IT2_ITSAL 0x344 +#define TSI148_LCSR_IT2_ITEAU 0x348 +#define TSI148_LCSR_IT2_ITEAL 0x34C +#define TSI148_LCSR_IT2_ITOFU 0x350 +#define TSI148_LCSR_IT2_ITOFL 0x354 +#define TSI148_LCSR_IT2_ITAT 0x358 + +#define TSI148_LCSR_IT3_ITSAU 0x360 +#define TSI148_LCSR_IT3_ITSAL 0x364 +#define TSI148_LCSR_IT3_ITEAU 0x368 +#define TSI148_LCSR_IT3_ITEAL 0x36C +#define TSI148_LCSR_IT3_ITOFU 0x370 +#define TSI148_LCSR_IT3_ITOFL 0x374 +#define TSI148_LCSR_IT3_ITAT 0x378 + +#define TSI148_LCSR_IT4_ITSAU 0x380 +#define TSI148_LCSR_IT4_ITSAL 0x384 +#define TSI148_LCSR_IT4_ITEAU 0x388 +#define TSI148_LCSR_IT4_ITEAL 0x38C +#define TSI148_LCSR_IT4_ITOFU 0x390 +#define TSI148_LCSR_IT4_ITOFL 0x394 +#define TSI148_LCSR_IT4_ITAT 0x398 + +#define TSI148_LCSR_IT5_ITSAU 0x3A0 +#define TSI148_LCSR_IT5_ITSAL 0x3A4 +#define TSI148_LCSR_IT5_ITEAU 0x3A8 +#define TSI148_LCSR_IT5_ITEAL 0x3AC +#define TSI148_LCSR_IT5_ITOFU 0x3B0 +#define TSI148_LCSR_IT5_ITOFL 0x3B4 +#define TSI148_LCSR_IT5_ITAT 0x3B8 + +#define TSI148_LCSR_IT6_ITSAU 0x3C0 +#define TSI148_LCSR_IT6_ITSAL 0x3C4 +#define TSI148_LCSR_IT6_ITEAU 0x3C8 +#define TSI148_LCSR_IT6_ITEAL 0x3CC +#define TSI148_LCSR_IT6_ITOFU 0x3D0 +#define TSI148_LCSR_IT6_ITOFL 0x3D4 +#define TSI148_LCSR_IT6_ITAT 0x3D8 + +#define TSI148_LCSR_IT7_ITSAU 0x3E0 +#define TSI148_LCSR_IT7_ITSAL 0x3E4 +#define TSI148_LCSR_IT7_ITEAU 0x3E8 +#define TSI148_LCSR_IT7_ITEAL 0x3EC +#define TSI148_LCSR_IT7_ITOFU 0x3F0 +#define TSI148_LCSR_IT7_ITOFL 0x3F4 +#define TSI148_LCSR_IT7_ITAT 0x3F8 + + +#define TSI148_LCSR_IT0 0x300 +#define TSI148_LCSR_IT1 0x320 +#define TSI148_LCSR_IT2 0x340 +#define TSI148_LCSR_IT3 0x360 +#define TSI148_LCSR_IT4 0x380 +#define TSI148_LCSR_IT5 0x3A0 +#define TSI148_LCSR_IT6 0x3C0 +#define TSI148_LCSR_IT7 0x3E0 + +static const int TSI148_LCSR_IT[8] = { TSI148_LCSR_IT0, TSI148_LCSR_IT1, + TSI148_LCSR_IT2, TSI148_LCSR_IT3, + TSI148_LCSR_IT4, TSI148_LCSR_IT5, + TSI148_LCSR_IT6, TSI148_LCSR_IT7 }; + +#define TSI148_LCSR_OFFSET_ITSAU 0x0 +#define TSI148_LCSR_OFFSET_ITSAL 0x4 +#define TSI148_LCSR_OFFSET_ITEAU 0x8 +#define TSI148_LCSR_OFFSET_ITEAL 0xC +#define TSI148_LCSR_OFFSET_ITOFU 0x10 +#define TSI148_LCSR_OFFSET_ITOFL 0x14 +#define TSI148_LCSR_OFFSET_ITAT 0x18 + + /* + * Inbound Translation GCSR + * offset 400 + */ +#define TSI148_LCSR_GBAU 0x400 +#define TSI148_LCSR_GBAL 0x404 +#define TSI148_LCSR_GCSRAT 0x408 + + /* + * Inbound Translation CRG + * offset 40C + */ +#define TSI148_LCSR_CBAU 0x40C +#define TSI148_LCSR_CBAL 0x410 +#define TSI148_LCSR_CSRAT 0x414 + + /* + * Inbound Translation CR/CSR + * CRG + * offset 418 + */ +#define TSI148_LCSR_CROU 0x418 +#define TSI148_LCSR_CROL 0x41C +#define TSI148_LCSR_CRAT 0x420 + + /* + * Inbound Translation Location Monitor + * offset 424 + */ +#define TSI148_LCSR_LMBAU 0x424 +#define TSI148_LCSR_LMBAL 0x428 +#define TSI148_LCSR_LMAT 0x42C + + /* + * VMEbus Interrupt Control. + * offset 430 + */ +#define TSI148_LCSR_BCU 0x430 +#define TSI148_LCSR_BCL 0x434 +#define TSI148_LCSR_BPGTR 0x438 +#define TSI148_LCSR_BPCTR 0x43C +#define TSI148_LCSR_VICR 0x440 + + /* + * Local Bus Interrupt Control. + * offset 448 + */ +#define TSI148_LCSR_INTEN 0x448 +#define TSI148_LCSR_INTEO 0x44C +#define TSI148_LCSR_INTS 0x450 +#define TSI148_LCSR_INTC 0x454 +#define TSI148_LCSR_INTM1 0x458 +#define TSI148_LCSR_INTM2 0x45C + + /* + * DMA Controllers + * offset 500 + */ +#define TSI148_LCSR_DCTL0 0x500 +#define TSI148_LCSR_DSTA0 0x504 +#define TSI148_LCSR_DCSAU0 0x508 +#define TSI148_LCSR_DCSAL0 0x50C +#define TSI148_LCSR_DCDAU0 0x510 +#define TSI148_LCSR_DCDAL0 0x514 +#define TSI148_LCSR_DCLAU0 0x518 +#define TSI148_LCSR_DCLAL0 0x51C +#define TSI148_LCSR_DSAU0 0x520 +#define TSI148_LCSR_DSAL0 0x524 +#define TSI148_LCSR_DDAU0 0x528 +#define TSI148_LCSR_DDAL0 0x52C +#define TSI148_LCSR_DSAT0 0x530 +#define TSI148_LCSR_DDAT0 0x534 +#define TSI148_LCSR_DNLAU0 0x538 +#define TSI148_LCSR_DNLAL0 0x53C +#define TSI148_LCSR_DCNT0 0x540 +#define TSI148_LCSR_DDBS0 0x544 + +#define TSI148_LCSR_DCTL1 0x580 +#define TSI148_LCSR_DSTA1 0x584 +#define TSI148_LCSR_DCSAU1 0x588 +#define TSI148_LCSR_DCSAL1 0x58C +#define TSI148_LCSR_DCDAU1 0x590 +#define TSI148_LCSR_DCDAL1 0x594 +#define TSI148_LCSR_DCLAU1 0x598 +#define TSI148_LCSR_DCLAL1 0x59C +#define TSI148_LCSR_DSAU1 0x5A0 +#define TSI148_LCSR_DSAL1 0x5A4 +#define TSI148_LCSR_DDAU1 0x5A8 +#define TSI148_LCSR_DDAL1 0x5AC +#define TSI148_LCSR_DSAT1 0x5B0 +#define TSI148_LCSR_DDAT1 0x5B4 +#define TSI148_LCSR_DNLAU1 0x5B8 +#define TSI148_LCSR_DNLAL1 0x5BC +#define TSI148_LCSR_DCNT1 0x5C0 +#define TSI148_LCSR_DDBS1 0x5C4 + +#define TSI148_LCSR_DMA0 0x500 +#define TSI148_LCSR_DMA1 0x580 + + +static const int TSI148_LCSR_DMA[TSI148_MAX_DMA] = { TSI148_LCSR_DMA0, + TSI148_LCSR_DMA1 }; + +#define TSI148_LCSR_OFFSET_DCTL 0x0 +#define TSI148_LCSR_OFFSET_DSTA 0x4 +#define TSI148_LCSR_OFFSET_DCSAU 0x8 +#define TSI148_LCSR_OFFSET_DCSAL 0xC +#define TSI148_LCSR_OFFSET_DCDAU 0x10 +#define TSI148_LCSR_OFFSET_DCDAL 0x14 +#define TSI148_LCSR_OFFSET_DCLAU 0x18 +#define TSI148_LCSR_OFFSET_DCLAL 0x1C +#define TSI148_LCSR_OFFSET_DSAU 0x20 +#define TSI148_LCSR_OFFSET_DSAL 0x24 +#define TSI148_LCSR_OFFSET_DDAU 0x28 +#define TSI148_LCSR_OFFSET_DDAL 0x2C +#define TSI148_LCSR_OFFSET_DSAT 0x30 +#define TSI148_LCSR_OFFSET_DDAT 0x34 +#define TSI148_LCSR_OFFSET_DNLAU 0x38 +#define TSI148_LCSR_OFFSET_DNLAL 0x3C +#define TSI148_LCSR_OFFSET_DCNT 0x40 +#define TSI148_LCSR_OFFSET_DDBS 0x44 + + /* + * GCSR Register Group + */ + + /* + * GCSR CRG + * offset 00 600 - DEVI/VENI + * offset 04 604 - CTRL/GA/REVID + * offset 08 608 - Semaphore3/2/1/0 + * offset 0C 60C - Seamphore7/6/5/4 + */ +#define TSI148_GCSR_ID 0x600 +#define TSI148_GCSR_CSR 0x604 +#define TSI148_GCSR_SEMA0 0x608 +#define TSI148_GCSR_SEMA1 0x60C + + /* + * Mail Box + * GCSR CRG + * offset 10 610 - Mailbox0 + */ +#define TSI148_GCSR_MBOX0 0x610 +#define TSI148_GCSR_MBOX1 0x614 +#define TSI148_GCSR_MBOX2 0x618 +#define TSI148_GCSR_MBOX3 0x61C + +static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, + TSI148_GCSR_MBOX1, + TSI148_GCSR_MBOX2, + TSI148_GCSR_MBOX3 }; + + /* + * CR/CSR + */ + + /* + * CR/CSR CRG + * offset 7FFF4 FF4 - CSRBCR + * offset 7FFF8 FF8 - CSRBSR + * offset 7FFFC FFC - CBAR + */ +#define TSI148_CSRBCR 0xFF4 +#define TSI148_CSRBSR 0xFF8 +#define TSI148_CBAR 0xFFC + + + + + /* + * TSI148 Register Bit Definitions + */ + + /* + * PFCS Register Set + */ +#define TSI148_PCFS_CMMD_SERR (1<<8) /* SERR_L out pin ssys err */ +#define TSI148_PCFS_CMMD_PERR (1<<6) /* PERR_L out pin parity */ +#define TSI148_PCFS_CMMD_MSTR (1<<2) /* PCI bus master */ +#define TSI148_PCFS_CMMD_MEMSP (1<<1) /* PCI mem space access */ +#define TSI148_PCFS_CMMD_IOSP (1<<0) /* PCI I/O space enable */ + +#define TSI148_PCFS_STAT_RCPVE (1<<15) /* Detected Parity Error */ +#define TSI148_PCFS_STAT_SIGSE (1<<14) /* Signalled System Error */ +#define TSI148_PCFS_STAT_RCVMA (1<<13) /* Received Master Abort */ +#define TSI148_PCFS_STAT_RCVTA (1<<12) /* Received Target Abort */ +#define TSI148_PCFS_STAT_SIGTA (1<<11) /* Signalled Target Abort */ +#define TSI148_PCFS_STAT_SELTIM (3<<9) /* DELSEL Timing */ +#define TSI148_PCFS_STAT_DPAR (1<<8) /* Data Parity Err Reported */ +#define TSI148_PCFS_STAT_FAST (1<<7) /* Fast back-to-back Cap */ +#define TSI148_PCFS_STAT_P66M (1<<5) /* 66 MHz Capable */ +#define TSI148_PCFS_STAT_CAPL (1<<4) /* Capab List - address $34 */ + +/* + * Revision ID/Class Code Registers (CRG +$008) + */ +#define TSI148_PCFS_CLAS_M (0xFF<<24) /* Class ID */ +#define TSI148_PCFS_SUBCLAS_M (0xFF<<16) /* Sub-Class ID */ +#define TSI148_PCFS_PROGIF_M (0xFF<<8) /* Sub-Class ID */ +#define TSI148_PCFS_REVID_M (0xFF<<0) /* Rev ID */ + +/* + * Cache Line Size/ Master Latency Timer/ Header Type Registers (CRG + $00C) + */ +#define TSI148_PCFS_HEAD_M (0xFF<<16) /* Master Lat Timer */ +#define TSI148_PCFS_MLAT_M (0xFF<<8) /* Master Lat Timer */ +#define TSI148_PCFS_CLSZ_M (0xFF<<0) /* Cache Line Size */ + +/* + * Memory Base Address Lower Reg (CRG + $010) + */ +#define TSI148_PCFS_MBARL_BASEL_M (0xFFFFF<<12) /* Base Addr Lower Mask */ +#define TSI148_PCFS_MBARL_PRE (1<<3) /* Prefetch */ +#define TSI148_PCFS_MBARL_MTYPE_M (3<<1) /* Memory Type Mask */ +#define TSI148_PCFS_MBARL_IOMEM (1<<0) /* I/O Space Indicator */ + +/* + * Message Signaled Interrupt Capabilities Register (CRG + $040) + */ +#define TSI148_PCFS_MSICAP_64BAC (1<<7) /* 64-bit Address Capable */ +#define TSI148_PCFS_MSICAP_MME_M (7<<4) /* Multiple Msg Enable Mask */ +#define TSI148_PCFS_MSICAP_MMC_M (7<<1) /* Multiple Msg Capable Mask */ +#define TSI148_PCFS_MSICAP_MSIEN (1<<0) /* Msg signaled INT Enable */ + +/* + * Message Address Lower Register (CRG +$044) + */ +#define TSI148_PCFS_MSIAL_M (0x3FFFFFFF<<2) /* Mask */ + +/* + * Message Data Register (CRG + 4C) + */ +#define TSI148_PCFS_MSIMD_M (0xFFFF<<0) /* Mask */ + +/* + * PCI-X Capabilities Register (CRG + $050) + */ +#define TSI148_PCFS_PCIXCAP_MOST_M (7<<4) /* Max outstanding Split Tran */ +#define TSI148_PCFS_PCIXCAP_MMRBC_M (3<<2) /* Max Mem Read byte cnt */ +#define TSI148_PCFS_PCIXCAP_ERO (1<<1) /* Enable Relaxed Ordering */ +#define TSI148_PCFS_PCIXCAP_DPERE (1<<0) /* Data Parity Recover Enable */ + +/* + * PCI-X Status Register (CRG +$054) + */ +#define TSI148_PCFS_PCIXSTAT_RSCEM (1<<29) /* Received Split Comp Error */ +#define TSI148_PCFS_PCIXSTAT_DMCRS_M (7<<26) /* max Cumulative Read Size */ +#define TSI148_PCFS_PCIXSTAT_DMOST_M (7<<23) /* max outstanding Split Trans + */ +#define TSI148_PCFS_PCIXSTAT_DMMRC_M (3<<21) /* max mem read byte count */ +#define TSI148_PCFS_PCIXSTAT_DC (1<<20) /* Device Complexity */ +#define TSI148_PCFS_PCIXSTAT_USC (1<<19) /* Unexpected Split comp */ +#define TSI148_PCFS_PCIXSTAT_SCD (1<<18) /* Split completion discard */ +#define TSI148_PCFS_PCIXSTAT_133C (1<<17) /* 133MHz capable */ +#define TSI148_PCFS_PCIXSTAT_64D (1<<16) /* 64 bit device */ +#define TSI148_PCFS_PCIXSTAT_BN_M (0xFF<<8) /* Bus number */ +#define TSI148_PCFS_PCIXSTAT_DN_M (0x1F<<3) /* Device number */ +#define TSI148_PCFS_PCIXSTAT_FN_M (7<<0) /* Function Number */ + +/* + * LCSR Registers + */ + +/* + * Outbound Translation Starting Address Lower + */ +#define TSI148_LCSR_OTSAL_M (0xFFFF<<16) /* Mask */ + +/* + * Outbound Translation Ending Address Lower + */ +#define TSI148_LCSR_OTEAL_M (0xFFFF<<16) /* Mask */ + +/* + * Outbound Translation Offset Lower + */ +#define TSI148_LCSR_OTOFFL_M (0xFFFF<<16) /* Mask */ + +/* + * Outbound Translation 2eSST Broadcast Select + */ +#define TSI148_LCSR_OTBS_M (0xFFFFF<<0) /* Mask */ + +/* + * Outbound Translation Attribute + */ +#define TSI148_LCSR_OTAT_EN (1<<31) /* Window Enable */ +#define TSI148_LCSR_OTAT_MRPFD (1<<18) /* Prefetch Disable */ + +#define TSI148_LCSR_OTAT_PFS_M (3<<16) /* Prefetch Size Mask */ +#define TSI148_LCSR_OTAT_PFS_2 (0<<16) /* 2 Cache Lines P Size */ +#define TSI148_LCSR_OTAT_PFS_4 (1<<16) /* 4 Cache Lines P Size */ +#define TSI148_LCSR_OTAT_PFS_8 (2<<16) /* 8 Cache Lines P Size */ +#define TSI148_LCSR_OTAT_PFS_16 (3<<16) /* 16 Cache Lines P Size */ + +#define TSI148_LCSR_OTAT_2eSSTM_M (7<<11) /* 2eSST Xfer Rate Mask */ +#define TSI148_LCSR_OTAT_2eSSTM_160 (0<<11) /* 160MB/s 2eSST Xfer Rate */ +#define TSI148_LCSR_OTAT_2eSSTM_267 (1<<11) /* 267MB/s 2eSST Xfer Rate */ +#define TSI148_LCSR_OTAT_2eSSTM_320 (2<<11) /* 320MB/s 2eSST Xfer Rate */ + +#define TSI148_LCSR_OTAT_TM_M (7<<8) /* Xfer Protocol Mask */ +#define TSI148_LCSR_OTAT_TM_SCT (0<<8) /* SCT Xfer Protocol */ +#define TSI148_LCSR_OTAT_TM_BLT (1<<8) /* BLT Xfer Protocol */ +#define TSI148_LCSR_OTAT_TM_MBLT (2<<8) /* MBLT Xfer Protocol */ +#define TSI148_LCSR_OTAT_TM_2eVME (3<<8) /* 2eVME Xfer Protocol */ +#define TSI148_LCSR_OTAT_TM_2eSST (4<<8) /* 2eSST Xfer Protocol */ +#define TSI148_LCSR_OTAT_TM_2eSSTB (5<<8) /* 2eSST Bcast Xfer Protocol */ + +#define TSI148_LCSR_OTAT_DBW_M (3<<6) /* Max Data Width */ +#define TSI148_LCSR_OTAT_DBW_16 (0<<6) /* 16-bit Data Width */ +#define TSI148_LCSR_OTAT_DBW_32 (1<<6) /* 32-bit Data Width */ + +#define TSI148_LCSR_OTAT_SUP (1<<5) /* Supervisory Access */ +#define TSI148_LCSR_OTAT_PGM (1<<4) /* Program Access */ + +#define TSI148_LCSR_OTAT_AMODE_M (0xf<<0) /* Address Mode Mask */ +#define TSI148_LCSR_OTAT_AMODE_A16 (0<<0) /* A16 Address Space */ +#define TSI148_LCSR_OTAT_AMODE_A24 (1<<0) /* A24 Address Space */ +#define TSI148_LCSR_OTAT_AMODE_A32 (2<<0) /* A32 Address Space */ +#define TSI148_LCSR_OTAT_AMODE_A64 (4<<0) /* A32 Address Space */ +#define TSI148_LCSR_OTAT_AMODE_CRCSR (5<<0) /* CR/CSR Address Space */ +#define TSI148_LCSR_OTAT_AMODE_USER1 (8<<0) /* User1 Address Space */ +#define TSI148_LCSR_OTAT_AMODE_USER2 (9<<0) /* User2 Address Space */ +#define TSI148_LCSR_OTAT_AMODE_USER3 (10<<0) /* User3 Address Space */ +#define TSI148_LCSR_OTAT_AMODE_USER4 (11<<0) /* User4 Address Space */ + +/* + * VME Master Control Register CRG+$234 + */ +#define TSI148_LCSR_VMCTRL_VSA (1<<27) /* VMEbus Stop Ack */ +#define TSI148_LCSR_VMCTRL_VS (1<<26) /* VMEbus Stop */ +#define TSI148_LCSR_VMCTRL_DHB (1<<25) /* Device Has Bus */ +#define TSI148_LCSR_VMCTRL_DWB (1<<24) /* Device Wants Bus */ + +#define TSI148_LCSR_VMCTRL_RMWEN (1<<20) /* RMW Enable */ + +#define TSI148_LCSR_VMCTRL_ATO_M (7<<16) /* Master Access Time-out Mask + */ +#define TSI148_LCSR_VMCTRL_ATO_32 (0<<16) /* 32 us */ +#define TSI148_LCSR_VMCTRL_ATO_128 (1<<16) /* 128 us */ +#define TSI148_LCSR_VMCTRL_ATO_512 (2<<16) /* 512 us */ +#define TSI148_LCSR_VMCTRL_ATO_2M (3<<16) /* 2 ms */ +#define TSI148_LCSR_VMCTRL_ATO_8M (4<<16) /* 8 ms */ +#define TSI148_LCSR_VMCTRL_ATO_32M (5<<16) /* 32 ms */ +#define TSI148_LCSR_VMCTRL_ATO_128M (6<<16) /* 128 ms */ +#define TSI148_LCSR_VMCTRL_ATO_DIS (7<<16) /* Disabled */ + +#define TSI148_LCSR_VMCTRL_VTOFF_M (7<<12) /* VMEbus Master Time off */ +#define TSI148_LCSR_VMCTRL_VTOFF_0 (0<<12) /* 0us */ +#define TSI148_LCSR_VMCTRL_VTOFF_1 (1<<12) /* 1us */ +#define TSI148_LCSR_VMCTRL_VTOFF_2 (2<<12) /* 2us */ +#define TSI148_LCSR_VMCTRL_VTOFF_4 (3<<12) /* 4us */ +#define TSI148_LCSR_VMCTRL_VTOFF_8 (4<<12) /* 8us */ +#define TSI148_LCSR_VMCTRL_VTOFF_16 (5<<12) /* 16us */ +#define TSI148_LCSR_VMCTRL_VTOFF_32 (6<<12) /* 32us */ +#define TSI148_LCSR_VMCTRL_VTOFF_64 (7<<12) /* 64us */ + +#define TSI148_LCSR_VMCTRL_VTON_M (7<<8) /* VMEbus Master Time On */ +#define TSI148_LCSR_VMCTRL_VTON_4 (0<<8) /* 8us */ +#define TSI148_LCSR_VMCTRL_VTON_8 (1<<8) /* 8us */ +#define TSI148_LCSR_VMCTRL_VTON_16 (2<<8) /* 16us */ +#define TSI148_LCSR_VMCTRL_VTON_32 (3<<8) /* 32us */ +#define TSI148_LCSR_VMCTRL_VTON_64 (4<<8) /* 64us */ +#define TSI148_LCSR_VMCTRL_VTON_128 (5<<8) /* 128us */ +#define TSI148_LCSR_VMCTRL_VTON_256 (6<<8) /* 256us */ +#define TSI148_LCSR_VMCTRL_VTON_512 (7<<8) /* 512us */ + +#define TSI148_LCSR_VMCTRL_VREL_M (3<<3) /* VMEbus Master Rel Mode Mask + */ +#define TSI148_LCSR_VMCTRL_VREL_T_D (0<<3) /* Time on or Done */ +#define TSI148_LCSR_VMCTRL_VREL_T_R_D (1<<3) /* Time on and REQ or Done */ +#define TSI148_LCSR_VMCTRL_VREL_T_B_D (2<<3) /* Time on and BCLR or Done */ +#define TSI148_LCSR_VMCTRL_VREL_T_D_R (3<<3) /* Time on or Done and REQ */ + +#define TSI148_LCSR_VMCTRL_VFAIR (1<<2) /* VMEbus Master Fair Mode */ +#define TSI148_LCSR_VMCTRL_VREQL_M (3<<0) /* VMEbus Master Req Level Mask + */ + +/* + * VMEbus Control Register CRG+$238 + */ +#define TSI148_LCSR_VCTRL_LRE (1<<31) /* Late Retry Enable */ + +#define TSI148_LCSR_VCTRL_DLT_M (0xF<<24) /* Deadlock Timer */ +#define TSI148_LCSR_VCTRL_DLT_OFF (0<<24) /* Deadlock Timer Off */ +#define TSI148_LCSR_VCTRL_DLT_16 (1<<24) /* 16 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_32 (2<<24) /* 32 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_64 (3<<24) /* 64 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_128 (4<<24) /* 128 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_256 (5<<24) /* 256 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_512 (6<<24) /* 512 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_1024 (7<<24) /* 1024 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_2048 (8<<24) /* 2048 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_4096 (9<<24) /* 4096 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_8192 (0xA<<24) /* 8192 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_16384 (0xB<<24) /* 16384 VCLKS */ +#define TSI148_LCSR_VCTRL_DLT_32768 (0xC<<24) /* 32768 VCLKS */ + +#define TSI148_LCSR_VCTRL_NERBB (1<<20) /* No Early Release of Bus Busy + */ + +#define TSI148_LCSR_VCTRL_SRESET (1<<17) /* System Reset */ +#define TSI148_LCSR_VCTRL_LRESET (1<<16) /* Local Reset */ + +#define TSI148_LCSR_VCTRL_SFAILAI (1<<15) /* SYSFAIL Auto Slot ID */ +#define TSI148_LCSR_VCTRL_BID_M (0x1F<<8) /* Broadcast ID Mask */ + +#define TSI148_LCSR_VCTRL_ATOEN (1<<7) /* Arbiter Time-out Enable */ +#define TSI148_LCSR_VCTRL_ROBIN (1<<6) /* VMEbus Round Robin */ + +#define TSI148_LCSR_VCTRL_GTO_M (7<<0) /* VMEbus Global Time-out Mask + */ +#define TSI148_LCSR_VCTRL_GTO_8 (0<<0) /* 8 us */ +#define TSI148_LCSR_VCTRL_GTO_16 (1<<0) /* 16 us */ +#define TSI148_LCSR_VCTRL_GTO_32 (2<<0) /* 32 us */ +#define TSI148_LCSR_VCTRL_GTO_64 (3<<0) /* 64 us */ +#define TSI148_LCSR_VCTRL_GTO_128 (4<<0) /* 128 us */ +#define TSI148_LCSR_VCTRL_GTO_256 (5<<0) /* 256 us */ +#define TSI148_LCSR_VCTRL_GTO_512 (6<<0) /* 512 us */ +#define TSI148_LCSR_VCTRL_GTO_DIS (7<<0) /* Disabled */ + +/* + * VMEbus Status Register CRG + $23C + */ +#define TSI148_LCSR_VSTAT_CPURST (1<<15) /* Clear power up reset */ +#define TSI148_LCSR_VSTAT_BRDFL (1<<14) /* Board fail */ +#define TSI148_LCSR_VSTAT_PURSTS (1<<12) /* Power up reset status */ +#define TSI148_LCSR_VSTAT_BDFAILS (1<<11) /* Board Fail Status */ +#define TSI148_LCSR_VSTAT_SYSFAILS (1<<10) /* System Fail Status */ +#define TSI148_LCSR_VSTAT_ACFAILS (1<<9) /* AC fail status */ +#define TSI148_LCSR_VSTAT_SCONS (1<<8) /* System Cont Status */ +#define TSI148_LCSR_VSTAT_GAP (1<<5) /* Geographic Addr Parity */ +#define TSI148_LCSR_VSTAT_GA_M (0x1F<<0) /* Geographic Addr Mask */ + +/* + * PCI Configuration Status Register CRG+$240 + */ +#define TSI148_LCSR_PSTAT_REQ64S (1<<6) /* Request 64 status set */ +#define TSI148_LCSR_PSTAT_M66ENS (1<<5) /* M66ENS 66Mhz enable */ +#define TSI148_LCSR_PSTAT_FRAMES (1<<4) /* Frame Status */ +#define TSI148_LCSR_PSTAT_IRDYS (1<<3) /* IRDY status */ +#define TSI148_LCSR_PSTAT_DEVSELS (1<<2) /* DEVL status */ +#define TSI148_LCSR_PSTAT_STOPS (1<<1) /* STOP status */ +#define TSI148_LCSR_PSTAT_TRDYS (1<<0) /* TRDY status */ + +/* + * VMEbus Exception Attributes Register CRG + $268 + */ +#define TSI148_LCSR_VEAT_VES (1<<31) /* Status */ +#define TSI148_LCSR_VEAT_VEOF (1<<30) /* Overflow */ +#define TSI148_LCSR_VEAT_VESCL (1<<29) /* Status Clear */ +#define TSI148_LCSR_VEAT_2EOT (1<<21) /* 2e Odd Termination */ +#define TSI148_LCSR_VEAT_2EST (1<<20) /* 2e Slave terminated */ +#define TSI148_LCSR_VEAT_BERR (1<<19) /* Bus Error */ +#define TSI148_LCSR_VEAT_LWORD (1<<18) /* LWORD_ signal state */ +#define TSI148_LCSR_VEAT_WRITE (1<<17) /* WRITE_ signal state */ +#define TSI148_LCSR_VEAT_IACK (1<<16) /* IACK_ signal state */ +#define TSI148_LCSR_VEAT_DS1 (1<<15) /* DS1_ signal state */ +#define TSI148_LCSR_VEAT_DS0 (1<<14) /* DS0_ signal state */ +#define TSI148_LCSR_VEAT_AM_M (0x3F<<8) /* Address Mode Mask */ +#define TSI148_LCSR_VEAT_XAM_M (0xFF<<0) /* Master AMode Mask */ + + +/* + * VMEbus PCI Error Diagnostics PCI/X Attributes Register CRG + $280 + */ +#define TSI148_LCSR_EDPAT_EDPCL (1<<29) + +/* + * Inbound Translation Starting Address Lower + */ +#define TSI148_LCSR_ITSAL6432_M (0xFFFF<<16) /* Mask */ +#define TSI148_LCSR_ITSAL24_M (0x00FFF<<12) /* Mask */ +#define TSI148_LCSR_ITSAL16_M (0x0000FFF<<4) /* Mask */ + +/* + * Inbound Translation Ending Address Lower + */ +#define TSI148_LCSR_ITEAL6432_M (0xFFFF<<16) /* Mask */ +#define TSI148_LCSR_ITEAL24_M (0x00FFF<<12) /* Mask */ +#define TSI148_LCSR_ITEAL16_M (0x0000FFF<<4) /* Mask */ + +/* + * Inbound Translation Offset Lower + */ +#define TSI148_LCSR_ITOFFL6432_M (0xFFFF<<16) /* Mask */ +#define TSI148_LCSR_ITOFFL24_M (0xFFFFF<<12) /* Mask */ +#define TSI148_LCSR_ITOFFL16_M (0xFFFFFFF<<4) /* Mask */ + +/* + * Inbound Translation Attribute + */ +#define TSI148_LCSR_ITAT_EN (1<<31) /* Window Enable */ +#define TSI148_LCSR_ITAT_TH (1<<18) /* Prefetch Threshold */ + +#define TSI148_LCSR_ITAT_VFS_M (3<<16) /* Virtual FIFO Size Mask */ +#define TSI148_LCSR_ITAT_VFS_64 (0<<16) /* 64 bytes Virtual FIFO Size */ +#define TSI148_LCSR_ITAT_VFS_128 (1<<16) /* 128 bytes Virtual FIFO Sz */ +#define TSI148_LCSR_ITAT_VFS_256 (2<<16) /* 256 bytes Virtual FIFO Sz */ +#define TSI148_LCSR_ITAT_VFS_512 (3<<16) /* 512 bytes Virtual FIFO Sz */ + +#define TSI148_LCSR_ITAT_2eSSTM_M (7<<12) /* 2eSST Xfer Rate Mask */ +#define TSI148_LCSR_ITAT_2eSSTM_160 (0<<12) /* 160MB/s 2eSST Xfer Rate */ +#define TSI148_LCSR_ITAT_2eSSTM_267 (1<<12) /* 267MB/s 2eSST Xfer Rate */ +#define TSI148_LCSR_ITAT_2eSSTM_320 (2<<12) /* 320MB/s 2eSST Xfer Rate */ + +#define TSI148_LCSR_ITAT_2eSSTB (1<<11) /* 2eSST Bcast Xfer Protocol */ +#define TSI148_LCSR_ITAT_2eSST (1<<10) /* 2eSST Xfer Protocol */ +#define TSI148_LCSR_ITAT_2eVME (1<<9) /* 2eVME Xfer Protocol */ +#define TSI148_LCSR_ITAT_MBLT (1<<8) /* MBLT Xfer Protocol */ +#define TSI148_LCSR_ITAT_BLT (1<<7) /* BLT Xfer Protocol */ + +#define TSI148_LCSR_ITAT_AS_M (7<<4) /* Address Space Mask */ +#define TSI148_LCSR_ITAT_AS_A16 (0<<4) /* A16 Address Space */ +#define TSI148_LCSR_ITAT_AS_A24 (1<<4) /* A24 Address Space */ +#define TSI148_LCSR_ITAT_AS_A32 (2<<4) /* A32 Address Space */ +#define TSI148_LCSR_ITAT_AS_A64 (4<<4) /* A64 Address Space */ + +#define TSI148_LCSR_ITAT_SUPR (1<<3) /* Supervisor Access */ +#define TSI148_LCSR_ITAT_NPRIV (1<<2) /* Non-Priv (User) Access */ +#define TSI148_LCSR_ITAT_PGM (1<<1) /* Program Access */ +#define TSI148_LCSR_ITAT_DATA (1<<0) /* Data Access */ + +/* + * GCSR Base Address Lower Address CRG +$404 + */ +#define TSI148_LCSR_GBAL_M (0x7FFFFFF<<5) /* Mask */ + +/* + * GCSR Attribute Register CRG + $408 + */ +#define TSI148_LCSR_GCSRAT_EN (1<<7) /* Enable access to GCSR */ + +#define TSI148_LCSR_GCSRAT_AS_M (7<<4) /* Address Space Mask */ +#define TSI148_LCSR_GCSRAT_AS_A16 (0<<4) /* Address Space 16 */ +#define TSI148_LCSR_GCSRAT_AS_A24 (1<<4) /* Address Space 24 */ +#define TSI148_LCSR_GCSRAT_AS_A32 (2<<4) /* Address Space 32 */ +#define TSI148_LCSR_GCSRAT_AS_A64 (4<<4) /* Address Space 64 */ + +#define TSI148_LCSR_GCSRAT_SUPR (1<<3) /* Sup set -GCSR decoder */ +#define TSI148_LCSR_GCSRAT_NPRIV (1<<2) /* Non-Privliged set - CGSR */ +#define TSI148_LCSR_GCSRAT_PGM (1<<1) /* Program set - GCSR decoder */ +#define TSI148_LCSR_GCSRAT_DATA (1<<0) /* DATA set GCSR decoder */ + +/* + * CRG Base Address Lower Address CRG + $410 + */ +#define TSI148_LCSR_CBAL_M (0xFFFFF<<12) + +/* + * CRG Attribute Register CRG + $414 + */ +#define TSI148_LCSR_CRGAT_EN (1<<7) /* Enable PRG Access */ + +#define TSI148_LCSR_CRGAT_AS_M (7<<4) /* Address Space */ +#define TSI148_LCSR_CRGAT_AS_A16 (0<<4) /* Address Space 16 */ +#define TSI148_LCSR_CRGAT_AS_A24 (1<<4) /* Address Space 24 */ +#define TSI148_LCSR_CRGAT_AS_A32 (2<<4) /* Address Space 32 */ +#define TSI148_LCSR_CRGAT_AS_A64 (4<<4) /* Address Space 64 */ + +#define TSI148_LCSR_CRGAT_SUPR (1<<3) /* Supervisor Access */ +#define TSI148_LCSR_CRGAT_NPRIV (1<<2) /* Non-Privliged(User) Access */ +#define TSI148_LCSR_CRGAT_PGM (1<<1) /* Program Access */ +#define TSI148_LCSR_CRGAT_DATA (1<<0) /* Data Access */ + +/* + * CR/CSR Offset Lower Register CRG + $41C + */ +#define TSI148_LCSR_CROL_M (0x1FFF<<19) /* Mask */ + +/* + * CR/CSR Attribute register CRG + $420 + */ +#define TSI148_LCSR_CRAT_EN (1<<7) /* Enable access to CR/CSR */ + +/* + * Location Monitor base address lower register CRG + $428 + */ +#define TSI148_LCSR_LMBAL_M (0x7FFFFFF<<5) /* Mask */ + +/* + * Location Monitor Attribute Register CRG + $42C + */ +#define TSI148_LCSR_LMAT_EN (1<<7) /* Enable Location Monitor */ + +#define TSI148_LCSR_LMAT_AS_M (7<<4) /* Address Space MASK */ +#define TSI148_LCSR_LMAT_AS_A16 (0<<4) /* A16 */ +#define TSI148_LCSR_LMAT_AS_A24 (1<<4) /* A24 */ +#define TSI148_LCSR_LMAT_AS_A32 (2<<4) /* A32 */ +#define TSI148_LCSR_LMAT_AS_A64 (4<<4) /* A64 */ + +#define TSI148_LCSR_LMAT_SUPR (1<<3) /* Supervisor Access */ +#define TSI148_LCSR_LMAT_NPRIV (1<<2) /* Non-Priv (User) Access */ +#define TSI148_LCSR_LMAT_PGM (1<<1) /* Program Access */ +#define TSI148_LCSR_LMAT_DATA (1<<0) /* Data Access */ + +/* + * Broadcast Pulse Generator Timer Register CRG + $438 + */ +#define TSI148_LCSR_BPGTR_BPGT_M (0xFFFF<<0) /* Mask */ + +/* + * Broadcast Programmable Clock Timer Register CRG + $43C + */ +#define TSI148_LCSR_BPCTR_BPCT_M (0xFFFFFF<<0) /* Mask */ + +/* + * VMEbus Interrupt Control Register CRG + $43C + */ +#define TSI148_LCSR_VICR_CNTS_M (3<<22) /* Cntr Source MASK */ +#define TSI148_LCSR_VICR_CNTS_DIS (1<<22) /* Cntr Disable */ +#define TSI148_LCSR_VICR_CNTS_IRQ1 (2<<22) /* IRQ1 to Cntr */ +#define TSI148_LCSR_VICR_CNTS_IRQ2 (3<<22) /* IRQ2 to Cntr */ + +#define TSI148_LCSR_VICR_EDGIS_M (3<<20) /* Edge interrupt MASK */ +#define TSI148_LCSR_VICR_EDGIS_DIS (1<<20) /* Edge interrupt Disable */ +#define TSI148_LCSR_VICR_EDGIS_IRQ1 (2<<20) /* IRQ1 to Edge */ +#define TSI148_LCSR_VICR_EDGIS_IRQ2 (3<<20) /* IRQ2 to Edge */ + +#define TSI148_LCSR_VICR_IRQIF_M (3<<18) /* IRQ1* Function MASK */ +#define TSI148_LCSR_VICR_IRQIF_NORM (1<<18) /* Normal */ +#define TSI148_LCSR_VICR_IRQIF_PULSE (2<<18) /* Pulse Generator */ +#define TSI148_LCSR_VICR_IRQIF_PROG (3<<18) /* Programmable Clock */ +#define TSI148_LCSR_VICR_IRQIF_1U (4<<18) /* 1us Clock */ + +#define TSI148_LCSR_VICR_IRQ2F_M (3<<16) /* IRQ2* Function MASK */ +#define TSI148_LCSR_VICR_IRQ2F_NORM (1<<16) /* Normal */ +#define TSI148_LCSR_VICR_IRQ2F_PULSE (2<<16) /* Pulse Generator */ +#define TSI148_LCSR_VICR_IRQ2F_PROG (3<<16) /* Programmable Clock */ +#define TSI148_LCSR_VICR_IRQ2F_1U (4<<16) /* 1us Clock */ + +#define TSI148_LCSR_VICR_BIP (1<<15) /* Broadcast Interrupt Pulse */ + +#define TSI148_LCSR_VICR_IRQC (1<<12) /* VMEbus IRQ Clear */ +#define TSI148_LCSR_VICR_IRQS (1<<11) /* VMEbus IRQ Status */ + +#define TSI148_LCSR_VICR_IRQL_M (7<<8) /* VMEbus SW IRQ Level Mask */ +#define TSI148_LCSR_VICR_IRQL_1 (1<<8) /* VMEbus SW IRQ Level 1 */ +#define TSI148_LCSR_VICR_IRQL_2 (2<<8) /* VMEbus SW IRQ Level 2 */ +#define TSI148_LCSR_VICR_IRQL_3 (3<<8) /* VMEbus SW IRQ Level 3 */ +#define TSI148_LCSR_VICR_IRQL_4 (4<<8) /* VMEbus SW IRQ Level 4 */ +#define TSI148_LCSR_VICR_IRQL_5 (5<<8) /* VMEbus SW IRQ Level 5 */ +#define TSI148_LCSR_VICR_IRQL_6 (6<<8) /* VMEbus SW IRQ Level 6 */ +#define TSI148_LCSR_VICR_IRQL_7 (7<<8) /* VMEbus SW IRQ Level 7 */ + +static const int TSI148_LCSR_VICR_IRQL[8] = { 0, TSI148_LCSR_VICR_IRQL_1, + TSI148_LCSR_VICR_IRQL_2, TSI148_LCSR_VICR_IRQL_3, + TSI148_LCSR_VICR_IRQL_4, TSI148_LCSR_VICR_IRQL_5, + TSI148_LCSR_VICR_IRQL_6, TSI148_LCSR_VICR_IRQL_7 }; + +#define TSI148_LCSR_VICR_STID_M (0xFF<<0) /* Status/ID Mask */ + +/* + * Interrupt Enable Register CRG + $440 + */ +#define TSI148_LCSR_INTEN_DMA1EN (1<<25) /* DMAC 1 */ +#define TSI148_LCSR_INTEN_DMA0EN (1<<24) /* DMAC 0 */ +#define TSI148_LCSR_INTEN_LM3EN (1<<23) /* Location Monitor 3 */ +#define TSI148_LCSR_INTEN_LM2EN (1<<22) /* Location Monitor 2 */ +#define TSI148_LCSR_INTEN_LM1EN (1<<21) /* Location Monitor 1 */ +#define TSI148_LCSR_INTEN_LM0EN (1<<20) /* Location Monitor 0 */ +#define TSI148_LCSR_INTEN_MB3EN (1<<19) /* Mail Box 3 */ +#define TSI148_LCSR_INTEN_MB2EN (1<<18) /* Mail Box 2 */ +#define TSI148_LCSR_INTEN_MB1EN (1<<17) /* Mail Box 1 */ +#define TSI148_LCSR_INTEN_MB0EN (1<<16) /* Mail Box 0 */ +#define TSI148_LCSR_INTEN_PERREN (1<<13) /* PCI/X Error */ +#define TSI148_LCSR_INTEN_VERREN (1<<12) /* VMEbus Error */ +#define TSI148_LCSR_INTEN_VIEEN (1<<11) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTEN_IACKEN (1<<10) /* IACK */ +#define TSI148_LCSR_INTEN_SYSFLEN (1<<9) /* System Fail */ +#define TSI148_LCSR_INTEN_ACFLEN (1<<8) /* AC Fail */ +#define TSI148_LCSR_INTEN_IRQ7EN (1<<7) /* IRQ7 */ +#define TSI148_LCSR_INTEN_IRQ6EN (1<<6) /* IRQ6 */ +#define TSI148_LCSR_INTEN_IRQ5EN (1<<5) /* IRQ5 */ +#define TSI148_LCSR_INTEN_IRQ4EN (1<<4) /* IRQ4 */ +#define TSI148_LCSR_INTEN_IRQ3EN (1<<3) /* IRQ3 */ +#define TSI148_LCSR_INTEN_IRQ2EN (1<<2) /* IRQ2 */ +#define TSI148_LCSR_INTEN_IRQ1EN (1<<1) /* IRQ1 */ + +static const int TSI148_LCSR_INTEN_LMEN[4] = { TSI148_LCSR_INTEN_LM0EN, + TSI148_LCSR_INTEN_LM1EN, + TSI148_LCSR_INTEN_LM2EN, + TSI148_LCSR_INTEN_LM3EN }; + +static const int TSI148_LCSR_INTEN_IRQEN[7] = { TSI148_LCSR_INTEN_IRQ1EN, + TSI148_LCSR_INTEN_IRQ2EN, + TSI148_LCSR_INTEN_IRQ3EN, + TSI148_LCSR_INTEN_IRQ4EN, + TSI148_LCSR_INTEN_IRQ5EN, + TSI148_LCSR_INTEN_IRQ6EN, + TSI148_LCSR_INTEN_IRQ7EN }; + +/* + * Interrupt Enable Out Register CRG + $444 + */ +#define TSI148_LCSR_INTEO_DMA1EO (1<<25) /* DMAC 1 */ +#define TSI148_LCSR_INTEO_DMA0EO (1<<24) /* DMAC 0 */ +#define TSI148_LCSR_INTEO_LM3EO (1<<23) /* Loc Monitor 3 */ +#define TSI148_LCSR_INTEO_LM2EO (1<<22) /* Loc Monitor 2 */ +#define TSI148_LCSR_INTEO_LM1EO (1<<21) /* Loc Monitor 1 */ +#define TSI148_LCSR_INTEO_LM0EO (1<<20) /* Location Monitor 0 */ +#define TSI148_LCSR_INTEO_MB3EO (1<<19) /* Mail Box 3 */ +#define TSI148_LCSR_INTEO_MB2EO (1<<18) /* Mail Box 2 */ +#define TSI148_LCSR_INTEO_MB1EO (1<<17) /* Mail Box 1 */ +#define TSI148_LCSR_INTEO_MB0EO (1<<16) /* Mail Box 0 */ +#define TSI148_LCSR_INTEO_PERREO (1<<13) /* PCI/X Error */ +#define TSI148_LCSR_INTEO_VERREO (1<<12) /* VMEbus Error */ +#define TSI148_LCSR_INTEO_VIEEO (1<<11) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTEO_IACKEO (1<<10) /* IACK */ +#define TSI148_LCSR_INTEO_SYSFLEO (1<<9) /* System Fail */ +#define TSI148_LCSR_INTEO_ACFLEO (1<<8) /* AC Fail */ +#define TSI148_LCSR_INTEO_IRQ7EO (1<<7) /* IRQ7 */ +#define TSI148_LCSR_INTEO_IRQ6EO (1<<6) /* IRQ6 */ +#define TSI148_LCSR_INTEO_IRQ5EO (1<<5) /* IRQ5 */ +#define TSI148_LCSR_INTEO_IRQ4EO (1<<4) /* IRQ4 */ +#define TSI148_LCSR_INTEO_IRQ3EO (1<<3) /* IRQ3 */ +#define TSI148_LCSR_INTEO_IRQ2EO (1<<2) /* IRQ2 */ +#define TSI148_LCSR_INTEO_IRQ1EO (1<<1) /* IRQ1 */ + +static const int TSI148_LCSR_INTEO_LMEO[4] = { TSI148_LCSR_INTEO_LM0EO, + TSI148_LCSR_INTEO_LM1EO, + TSI148_LCSR_INTEO_LM2EO, + TSI148_LCSR_INTEO_LM3EO }; + +static const int TSI148_LCSR_INTEO_IRQEO[7] = { TSI148_LCSR_INTEO_IRQ1EO, + TSI148_LCSR_INTEO_IRQ2EO, + TSI148_LCSR_INTEO_IRQ3EO, + TSI148_LCSR_INTEO_IRQ4EO, + TSI148_LCSR_INTEO_IRQ5EO, + TSI148_LCSR_INTEO_IRQ6EO, + TSI148_LCSR_INTEO_IRQ7EO }; + +/* + * Interrupt Status Register CRG + $448 + */ +#define TSI148_LCSR_INTS_DMA1S (1<<25) /* DMA 1 */ +#define TSI148_LCSR_INTS_DMA0S (1<<24) /* DMA 0 */ +#define TSI148_LCSR_INTS_LM3S (1<<23) /* Location Monitor 3 */ +#define TSI148_LCSR_INTS_LM2S (1<<22) /* Location Monitor 2 */ +#define TSI148_LCSR_INTS_LM1S (1<<21) /* Location Monitor 1 */ +#define TSI148_LCSR_INTS_LM0S (1<<20) /* Location Monitor 0 */ +#define TSI148_LCSR_INTS_MB3S (1<<19) /* Mail Box 3 */ +#define TSI148_LCSR_INTS_MB2S (1<<18) /* Mail Box 2 */ +#define TSI148_LCSR_INTS_MB1S (1<<17) /* Mail Box 1 */ +#define TSI148_LCSR_INTS_MB0S (1<<16) /* Mail Box 0 */ +#define TSI148_LCSR_INTS_PERRS (1<<13) /* PCI/X Error */ +#define TSI148_LCSR_INTS_VERRS (1<<12) /* VMEbus Error */ +#define TSI148_LCSR_INTS_VIES (1<<11) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTS_IACKS (1<<10) /* IACK */ +#define TSI148_LCSR_INTS_SYSFLS (1<<9) /* System Fail */ +#define TSI148_LCSR_INTS_ACFLS (1<<8) /* AC Fail */ +#define TSI148_LCSR_INTS_IRQ7S (1<<7) /* IRQ7 */ +#define TSI148_LCSR_INTS_IRQ6S (1<<6) /* IRQ6 */ +#define TSI148_LCSR_INTS_IRQ5S (1<<5) /* IRQ5 */ +#define TSI148_LCSR_INTS_IRQ4S (1<<4) /* IRQ4 */ +#define TSI148_LCSR_INTS_IRQ3S (1<<3) /* IRQ3 */ +#define TSI148_LCSR_INTS_IRQ2S (1<<2) /* IRQ2 */ +#define TSI148_LCSR_INTS_IRQ1S (1<<1) /* IRQ1 */ + +static const int TSI148_LCSR_INTS_LMS[4] = { TSI148_LCSR_INTS_LM0S, + TSI148_LCSR_INTS_LM1S, + TSI148_LCSR_INTS_LM2S, + TSI148_LCSR_INTS_LM3S }; + +static const int TSI148_LCSR_INTS_MBS[4] = { TSI148_LCSR_INTS_MB0S, + TSI148_LCSR_INTS_MB1S, + TSI148_LCSR_INTS_MB2S, + TSI148_LCSR_INTS_MB3S }; + +/* + * Interrupt Clear Register CRG + $44C + */ +#define TSI148_LCSR_INTC_DMA1C (1<<25) /* DMA 1 */ +#define TSI148_LCSR_INTC_DMA0C (1<<24) /* DMA 0 */ +#define TSI148_LCSR_INTC_LM3C (1<<23) /* Location Monitor 3 */ +#define TSI148_LCSR_INTC_LM2C (1<<22) /* Location Monitor 2 */ +#define TSI148_LCSR_INTC_LM1C (1<<21) /* Location Monitor 1 */ +#define TSI148_LCSR_INTC_LM0C (1<<20) /* Location Monitor 0 */ +#define TSI148_LCSR_INTC_MB3C (1<<19) /* Mail Box 3 */ +#define TSI148_LCSR_INTC_MB2C (1<<18) /* Mail Box 2 */ +#define TSI148_LCSR_INTC_MB1C (1<<17) /* Mail Box 1 */ +#define TSI148_LCSR_INTC_MB0C (1<<16) /* Mail Box 0 */ +#define TSI148_LCSR_INTC_PERRC (1<<13) /* VMEbus Error */ +#define TSI148_LCSR_INTC_VERRC (1<<12) /* VMEbus Access Time-out */ +#define TSI148_LCSR_INTC_VIEC (1<<11) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTC_IACKC (1<<10) /* IACK */ +#define TSI148_LCSR_INTC_SYSFLC (1<<9) /* System Fail */ +#define TSI148_LCSR_INTC_ACFLC (1<<8) /* AC Fail */ + +static const int TSI148_LCSR_INTC_LMC[4] = { TSI148_LCSR_INTC_LM0C, + TSI148_LCSR_INTC_LM1C, + TSI148_LCSR_INTC_LM2C, + TSI148_LCSR_INTC_LM3C }; + +static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, + TSI148_LCSR_INTC_MB1C, + TSI148_LCSR_INTC_MB2C, + TSI148_LCSR_INTC_MB3C }; + +/* + * Interrupt Map Register 1 CRG + $458 + */ +#define TSI148_LCSR_INTM1_DMA1M_M (3<<18) /* DMA 1 */ +#define TSI148_LCSR_INTM1_DMA0M_M (3<<16) /* DMA 0 */ +#define TSI148_LCSR_INTM1_LM3M_M (3<<14) /* Location Monitor 3 */ +#define TSI148_LCSR_INTM1_LM2M_M (3<<12) /* Location Monitor 2 */ +#define TSI148_LCSR_INTM1_LM1M_M (3<<10) /* Location Monitor 1 */ +#define TSI148_LCSR_INTM1_LM0M_M (3<<8) /* Location Monitor 0 */ +#define TSI148_LCSR_INTM1_MB3M_M (3<<6) /* Mail Box 3 */ +#define TSI148_LCSR_INTM1_MB2M_M (3<<4) /* Mail Box 2 */ +#define TSI148_LCSR_INTM1_MB1M_M (3<<2) /* Mail Box 1 */ +#define TSI148_LCSR_INTM1_MB0M_M (3<<0) /* Mail Box 0 */ + +/* + * Interrupt Map Register 2 CRG + $45C + */ +#define TSI148_LCSR_INTM2_PERRM_M (3<<26) /* PCI Bus Error */ +#define TSI148_LCSR_INTM2_VERRM_M (3<<24) /* VMEbus Error */ +#define TSI148_LCSR_INTM2_VIEM_M (3<<22) /* VMEbus IRQ Edge */ +#define TSI148_LCSR_INTM2_IACKM_M (3<<20) /* IACK */ +#define TSI148_LCSR_INTM2_SYSFLM_M (3<<18) /* System Fail */ +#define TSI148_LCSR_INTM2_ACFLM_M (3<<16) /* AC Fail */ +#define TSI148_LCSR_INTM2_IRQ7M_M (3<<14) /* IRQ7 */ +#define TSI148_LCSR_INTM2_IRQ6M_M (3<<12) /* IRQ6 */ +#define TSI148_LCSR_INTM2_IRQ5M_M (3<<10) /* IRQ5 */ +#define TSI148_LCSR_INTM2_IRQ4M_M (3<<8) /* IRQ4 */ +#define TSI148_LCSR_INTM2_IRQ3M_M (3<<6) /* IRQ3 */ +#define TSI148_LCSR_INTM2_IRQ2M_M (3<<4) /* IRQ2 */ +#define TSI148_LCSR_INTM2_IRQ1M_M (3<<2) /* IRQ1 */ + +/* + * DMA Control (0-1) Registers CRG + $500 + */ +#define TSI148_LCSR_DCTL_ABT (1<<27) /* Abort */ +#define TSI148_LCSR_DCTL_PAU (1<<26) /* Pause */ +#define TSI148_LCSR_DCTL_DGO (1<<25) /* DMA Go */ + +#define TSI148_LCSR_DCTL_MOD (1<<23) /* Mode */ + +#define TSI148_LCSR_DCTL_VBKS_M (7<<12) /* VMEbus block Size MASK */ +#define TSI148_LCSR_DCTL_VBKS_32 (0<<12) /* VMEbus block Size 32 */ +#define TSI148_LCSR_DCTL_VBKS_64 (1<<12) /* VMEbus block Size 64 */ +#define TSI148_LCSR_DCTL_VBKS_128 (2<<12) /* VMEbus block Size 128 */ +#define TSI148_LCSR_DCTL_VBKS_256 (3<<12) /* VMEbus block Size 256 */ +#define TSI148_LCSR_DCTL_VBKS_512 (4<<12) /* VMEbus block Size 512 */ +#define TSI148_LCSR_DCTL_VBKS_1024 (5<<12) /* VMEbus block Size 1024 */ +#define TSI148_LCSR_DCTL_VBKS_2048 (6<<12) /* VMEbus block Size 2048 */ +#define TSI148_LCSR_DCTL_VBKS_4096 (7<<12) /* VMEbus block Size 4096 */ + +#define TSI148_LCSR_DCTL_VBOT_M (7<<8) /* VMEbus back-off MASK */ +#define TSI148_LCSR_DCTL_VBOT_0 (0<<8) /* VMEbus back-off 0us */ +#define TSI148_LCSR_DCTL_VBOT_1 (1<<8) /* VMEbus back-off 1us */ +#define TSI148_LCSR_DCTL_VBOT_2 (2<<8) /* VMEbus back-off 2us */ +#define TSI148_LCSR_DCTL_VBOT_4 (3<<8) /* VMEbus back-off 4us */ +#define TSI148_LCSR_DCTL_VBOT_8 (4<<8) /* VMEbus back-off 8us */ +#define TSI148_LCSR_DCTL_VBOT_16 (5<<8) /* VMEbus back-off 16us */ +#define TSI148_LCSR_DCTL_VBOT_32 (6<<8) /* VMEbus back-off 32us */ +#define TSI148_LCSR_DCTL_VBOT_64 (7<<8) /* VMEbus back-off 64us */ + +#define TSI148_LCSR_DCTL_PBKS_M (7<<4) /* PCI block size MASK */ +#define TSI148_LCSR_DCTL_PBKS_32 (0<<4) /* PCI block size 32 bytes */ +#define TSI148_LCSR_DCTL_PBKS_64 (1<<4) /* PCI block size 64 bytes */ +#define TSI148_LCSR_DCTL_PBKS_128 (2<<4) /* PCI block size 128 bytes */ +#define TSI148_LCSR_DCTL_PBKS_256 (3<<4) /* PCI block size 256 bytes */ +#define TSI148_LCSR_DCTL_PBKS_512 (4<<4) /* PCI block size 512 bytes */ +#define TSI148_LCSR_DCTL_PBKS_1024 (5<<4) /* PCI block size 1024 bytes */ +#define TSI148_LCSR_DCTL_PBKS_2048 (6<<4) /* PCI block size 2048 bytes */ +#define TSI148_LCSR_DCTL_PBKS_4096 (7<<4) /* PCI block size 4096 bytes */ + +#define TSI148_LCSR_DCTL_PBOT_M (7<<0) /* PCI back off MASK */ +#define TSI148_LCSR_DCTL_PBOT_0 (0<<0) /* PCI back off 0us */ +#define TSI148_LCSR_DCTL_PBOT_1 (1<<0) /* PCI back off 1us */ +#define TSI148_LCSR_DCTL_PBOT_2 (2<<0) /* PCI back off 2us */ +#define TSI148_LCSR_DCTL_PBOT_4 (3<<0) /* PCI back off 3us */ +#define TSI148_LCSR_DCTL_PBOT_8 (4<<0) /* PCI back off 4us */ +#define TSI148_LCSR_DCTL_PBOT_16 (5<<0) /* PCI back off 8us */ +#define TSI148_LCSR_DCTL_PBOT_32 (6<<0) /* PCI back off 16us */ +#define TSI148_LCSR_DCTL_PBOT_64 (7<<0) /* PCI back off 32us */ + +/* + * DMA Status Registers (0-1) CRG + $504 + */ +#define TSI148_LCSR_DSTA_SMA (1<<31) /* PCI Signalled Master Abt */ +#define TSI148_LCSR_DSTA_RTA (1<<30) /* PCI Received Target Abt */ +#define TSI148_LCSR_DSTA_MRC (1<<29) /* PCI Max Retry Count */ +#define TSI148_LCSR_DSTA_VBE (1<<28) /* VMEbus error */ +#define TSI148_LCSR_DSTA_ABT (1<<27) /* Abort */ +#define TSI148_LCSR_DSTA_PAU (1<<26) /* Pause */ +#define TSI148_LCSR_DSTA_DON (1<<25) /* Done */ +#define TSI148_LCSR_DSTA_BSY (1<<24) /* Busy */ + +/* + * DMA Current Link Address Lower (0-1) + */ +#define TSI148_LCSR_DCLAL_M (0x3FFFFFF<<6) /* Mask */ + +/* + * DMA Source Attribute (0-1) Reg + */ +#define TSI148_LCSR_DSAT_TYP_M (3<<28) /* Source Bus Type */ +#define TSI148_LCSR_DSAT_TYP_PCI (0<<28) /* PCI Bus */ +#define TSI148_LCSR_DSAT_TYP_VME (1<<28) /* VMEbus */ +#define TSI148_LCSR_DSAT_TYP_PAT (2<<28) /* Data Pattern */ + +#define TSI148_LCSR_DSAT_PSZ (1<<25) /* Pattern Size */ +#define TSI148_LCSR_DSAT_NIN (1<<24) /* No Increment */ + +#define TSI148_LCSR_DSAT_2eSSTM_M (3<<11) /* 2eSST Trans Rate Mask */ +#define TSI148_LCSR_DSAT_2eSSTM_160 (0<<11) /* 160 MB/s */ +#define TSI148_LCSR_DSAT_2eSSTM_267 (1<<11) /* 267 MB/s */ +#define TSI148_LCSR_DSAT_2eSSTM_320 (2<<11) /* 320 MB/s */ + +#define TSI148_LCSR_DSAT_TM_M (7<<8) /* Bus Transfer Protocol Mask */ +#define TSI148_LCSR_DSAT_TM_SCT (0<<8) /* SCT */ +#define TSI148_LCSR_DSAT_TM_BLT (1<<8) /* BLT */ +#define TSI148_LCSR_DSAT_TM_MBLT (2<<8) /* MBLT */ +#define TSI148_LCSR_DSAT_TM_2eVME (3<<8) /* 2eVME */ +#define TSI148_LCSR_DSAT_TM_2eSST (4<<8) /* 2eSST */ +#define TSI148_LCSR_DSAT_TM_2eSSTB (5<<8) /* 2eSST Broadcast */ + +#define TSI148_LCSR_DSAT_DBW_M (3<<6) /* Max Data Width MASK */ +#define TSI148_LCSR_DSAT_DBW_16 (0<<6) /* 16 Bits */ +#define TSI148_LCSR_DSAT_DBW_32 (1<<6) /* 32 Bits */ + +#define TSI148_LCSR_DSAT_SUP (1<<5) /* Supervisory Mode */ +#define TSI148_LCSR_DSAT_PGM (1<<4) /* Program Mode */ + +#define TSI148_LCSR_DSAT_AMODE_M (0xf<<0) /* Address Space Mask */ +#define TSI148_LCSR_DSAT_AMODE_A16 (0<<0) /* A16 */ +#define TSI148_LCSR_DSAT_AMODE_A24 (1<<0) /* A24 */ +#define TSI148_LCSR_DSAT_AMODE_A32 (2<<0) /* A32 */ +#define TSI148_LCSR_DSAT_AMODE_A64 (4<<0) /* A64 */ +#define TSI148_LCSR_DSAT_AMODE_CRCSR (5<<0) /* CR/CSR */ +#define TSI148_LCSR_DSAT_AMODE_USER1 (8<<0) /* User1 */ +#define TSI148_LCSR_DSAT_AMODE_USER2 (9<<0) /* User2 */ +#define TSI148_LCSR_DSAT_AMODE_USER3 (0xa<<0) /* User3 */ +#define TSI148_LCSR_DSAT_AMODE_USER4 (0xb<<0) /* User4 */ + +/* + * DMA Destination Attribute Registers (0-1) + */ +#define TSI148_LCSR_DDAT_TYP_PCI (0<<28) /* Destination PCI Bus */ +#define TSI148_LCSR_DDAT_TYP_VME (1<<28) /* Destination VMEbus */ + +#define TSI148_LCSR_DDAT_2eSSTM_M (3<<11) /* 2eSST Transfer Rate Mask */ +#define TSI148_LCSR_DDAT_2eSSTM_160 (0<<11) /* 160 MB/s */ +#define TSI148_LCSR_DDAT_2eSSTM_267 (1<<11) /* 267 MB/s */ +#define TSI148_LCSR_DDAT_2eSSTM_320 (2<<11) /* 320 MB/s */ + +#define TSI148_LCSR_DDAT_TM_M (7<<8) /* Bus Transfer Protocol Mask */ +#define TSI148_LCSR_DDAT_TM_SCT (0<<8) /* SCT */ +#define TSI148_LCSR_DDAT_TM_BLT (1<<8) /* BLT */ +#define TSI148_LCSR_DDAT_TM_MBLT (2<<8) /* MBLT */ +#define TSI148_LCSR_DDAT_TM_2eVME (3<<8) /* 2eVME */ +#define TSI148_LCSR_DDAT_TM_2eSST (4<<8) /* 2eSST */ +#define TSI148_LCSR_DDAT_TM_2eSSTB (5<<8) /* 2eSST Broadcast */ + +#define TSI148_LCSR_DDAT_DBW_M (3<<6) /* Max Data Width MASK */ +#define TSI148_LCSR_DDAT_DBW_16 (0<<6) /* 16 Bits */ +#define TSI148_LCSR_DDAT_DBW_32 (1<<6) /* 32 Bits */ + +#define TSI148_LCSR_DDAT_SUP (1<<5) /* Supervisory/User Access */ +#define TSI148_LCSR_DDAT_PGM (1<<4) /* Program/Data Access */ + +#define TSI148_LCSR_DDAT_AMODE_M (0xf<<0) /* Address Space Mask */ +#define TSI148_LCSR_DDAT_AMODE_A16 (0<<0) /* A16 */ +#define TSI148_LCSR_DDAT_AMODE_A24 (1<<0) /* A24 */ +#define TSI148_LCSR_DDAT_AMODE_A32 (2<<0) /* A32 */ +#define TSI148_LCSR_DDAT_AMODE_A64 (4<<0) /* A64 */ +#define TSI148_LCSR_DDAT_AMODE_CRCSR (5<<0) /* CRC/SR */ +#define TSI148_LCSR_DDAT_AMODE_USER1 (8<<0) /* User1 */ +#define TSI148_LCSR_DDAT_AMODE_USER2 (9<<0) /* User2 */ +#define TSI148_LCSR_DDAT_AMODE_USER3 (0xa<<0) /* User3 */ +#define TSI148_LCSR_DDAT_AMODE_USER4 (0xb<<0) /* User4 */ + +/* + * DMA Next Link Address Lower + */ +#define TSI148_LCSR_DNLAL_DNLAL_M (0x3FFFFFF<<6) /* Address Mask */ +#define TSI148_LCSR_DNLAL_LLA (1<<0) /* Last Link Address Indicator */ + +/* + * DMA 2eSST Broadcast Select + */ +#define TSI148_LCSR_DBS_M (0x1FFFFF<<0) /* Mask */ + +/* + * GCSR Register Group + */ + +/* + * GCSR Control and Status Register CRG + $604 + */ +#define TSI148_GCSR_GCTRL_LRST (1<<15) /* Local Reset */ +#define TSI148_GCSR_GCTRL_SFAILEN (1<<14) /* System Fail enable */ +#define TSI148_GCSR_GCTRL_BDFAILS (1<<13) /* Board Fail Status */ +#define TSI148_GCSR_GCTRL_SCON (1<<12) /* System Copntroller */ +#define TSI148_GCSR_GCTRL_MEN (1<<11) /* Module Enable (READY) */ + +#define TSI148_GCSR_GCTRL_LMI3S (1<<7) /* Loc Monitor 3 Int Status */ +#define TSI148_GCSR_GCTRL_LMI2S (1<<6) /* Loc Monitor 2 Int Status */ +#define TSI148_GCSR_GCTRL_LMI1S (1<<5) /* Loc Monitor 1 Int Status */ +#define TSI148_GCSR_GCTRL_LMI0S (1<<4) /* Loc Monitor 0 Int Status */ +#define TSI148_GCSR_GCTRL_MBI3S (1<<3) /* Mail box 3 Int Status */ +#define TSI148_GCSR_GCTRL_MBI2S (1<<2) /* Mail box 2 Int Status */ +#define TSI148_GCSR_GCTRL_MBI1S (1<<1) /* Mail box 1 Int Status */ +#define TSI148_GCSR_GCTRL_MBI0S (1<<0) /* Mail box 0 Int Status */ + +#define TSI148_GCSR_GAP (1<<5) /* Geographic Addr Parity */ +#define TSI148_GCSR_GA_M (0x1F<<0) /* Geographic Address Mask */ + +/* + * CR/CSR Register Group + */ + +/* + * CR/CSR Bit Clear Register CRG + $FF4 + */ +#define TSI148_CRCSR_CSRBCR_LRSTC (1<<7) /* Local Reset Clear */ +#define TSI148_CRCSR_CSRBCR_SFAILC (1<<6) /* System Fail Enable Clear */ +#define TSI148_CRCSR_CSRBCR_BDFAILS (1<<5) /* Board Fail Status */ +#define TSI148_CRCSR_CSRBCR_MENC (1<<4) /* Module Enable Clear */ +#define TSI148_CRCSR_CSRBCR_BERRSC (1<<3) /* Bus Error Status Clear */ + +/* + * CR/CSR Bit Set Register CRG+$FF8 + */ +#define TSI148_CRCSR_CSRBSR_LISTS (1<<7) /* Local Reset Clear */ +#define TSI148_CRCSR_CSRBSR_SFAILS (1<<6) /* System Fail Enable Clear */ +#define TSI148_CRCSR_CSRBSR_BDFAILS (1<<5) /* Board Fail Status */ +#define TSI148_CRCSR_CSRBSR_MENS (1<<4) /* Module Enable Clear */ +#define TSI148_CRCSR_CSRBSR_BERRS (1<<3) /* Bus Error Status Clear */ + +/* + * CR/CSR Base Address Register CRG + FFC + */ +#define TSI148_CRCSR_CBAR_M (0x1F<<3) /* Mask */ + +#endif /* TSI148_H */ diff --git a/drivers/staging/vme_user/vme_user.c b/drivers/staging/vme_user/vme_user.c index 859af797630c..4e533c0bfe6d 100644 --- a/drivers/staging/vme_user/vme_user.c +++ b/drivers/staging/vme_user/vme_user.c @@ -33,8 +33,8 @@ #include #include -#include +#include "vme.h" #include "vme_user.h" static const char driver_name[] = "vme_user"; diff --git a/drivers/vme/Kconfig b/drivers/vme/Kconfig deleted file mode 100644 index 26feabba19d2..000000000000 --- a/drivers/vme/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# VME configuration. -# - -menuconfig VME_BUS - bool "VME bridge support" - depends on PCI - help - If you say Y here you get support for the VME bridge Framework. - -if VME_BUS - -source "drivers/vme/bridges/Kconfig" - -endif # VME diff --git a/drivers/vme/Makefile b/drivers/vme/Makefile deleted file mode 100644 index 2dfb929a23de..000000000000 --- a/drivers/vme/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the VME bridge device drivers. -# -obj-$(CONFIG_VME_BUS) += vme.o - -obj-y += bridges/ diff --git a/drivers/vme/bridges/Kconfig b/drivers/vme/bridges/Kconfig deleted file mode 100644 index 9493b22b5276..000000000000 --- a/drivers/vme/bridges/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -comment "VME Bridge Drivers" - -config VME_TSI148 - tristate "Tempe" - depends on HAS_DMA - help - If you say Y here you get support for the Tundra TSI148 VME bridge - chip. - -config VME_FAKE - tristate "Fake" - help - If you say Y here you get support for the fake VME bridge. This - provides a virtualised VME Bus for devices with no VME bridge. This - is mainly useful for VME development (in the absence of VME - hardware). diff --git a/drivers/vme/bridges/Makefile b/drivers/vme/bridges/Makefile deleted file mode 100644 index 043f9cd7a510..000000000000 --- a/drivers/vme/bridges/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VME_TSI148) += vme_tsi148.o -obj-$(CONFIG_VME_FAKE) += vme_fake.o diff --git a/drivers/vme/bridges/vme_fake.c b/drivers/vme/bridges/vme_fake.c deleted file mode 100644 index 6a1bc284f297..000000000000 --- a/drivers/vme/bridges/vme_fake.c +++ /dev/null @@ -1,1305 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Fake VME bridge support. - * - * This drive provides a fake VME bridge chip, this enables debugging of the - * VME framework in the absence of a VME system. - * - * This driver has to do a number of things in software that would be driven - * by hardware if it was available, it will also result in extra overhead at - * times when compared with driving actual hardware. - * - * Author: Martyn Welch - * Copyright (c) 2014 Martyn Welch - * - * Based on vme_tsi148.c: - * - * Author: Martyn Welch - * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. - * - * Based on work by Tom Armistead and Ajit Prem - * Copyright 2004 Motorola Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../vme_bridge.h" - -/* - * Define the number of each that the fake driver supports. - */ -#define FAKE_MAX_MASTER 8 /* Max Master Windows */ -#define FAKE_MAX_SLAVE 8 /* Max Slave Windows */ - -/* Structures to hold information normally held in device registers */ -struct fake_slave_window { - int enabled; - unsigned long long vme_base; - unsigned long long size; - void *buf_base; - u32 aspace; - u32 cycle; -}; - -struct fake_master_window { - int enabled; - unsigned long long vme_base; - unsigned long long size; - u32 aspace; - u32 cycle; - u32 dwidth; -}; - -/* Structure used to hold driver specific information */ -struct fake_driver { - struct vme_bridge *parent; - struct fake_slave_window slaves[FAKE_MAX_SLAVE]; - struct fake_master_window masters[FAKE_MAX_MASTER]; - u32 lm_enabled; - unsigned long long lm_base; - u32 lm_aspace; - u32 lm_cycle; - void (*lm_callback[4])(void *); - void *lm_data[4]; - struct tasklet_struct int_tasklet; - int int_level; - int int_statid; - void *crcsr_kernel; - dma_addr_t crcsr_bus; - /* Only one VME interrupt can be generated at a time, provide locking */ - struct mutex vme_int; -}; - -/* Module parameter */ -static int geoid; - -static const char driver_name[] = "vme_fake"; - -static struct vme_bridge *exit_pointer; - -static struct device *vme_root; - -/* - * Calling VME bus interrupt callback if provided. - */ -static void fake_VIRQ_tasklet(unsigned long data) -{ - struct vme_bridge *fake_bridge; - struct fake_driver *bridge; - - fake_bridge = (struct vme_bridge *) data; - bridge = fake_bridge->driver_priv; - - vme_irq_handler(fake_bridge, bridge->int_level, bridge->int_statid); -} - -/* - * Configure VME interrupt - */ -static void fake_irq_set(struct vme_bridge *fake_bridge, int level, - int state, int sync) -{ - /* Nothing to do */ -} - -static void *fake_pci_to_ptr(dma_addr_t addr) -{ - return (void *)(uintptr_t)addr; -} - -static dma_addr_t fake_ptr_to_pci(void *addr) -{ - return (dma_addr_t)(uintptr_t)addr; -} - -/* - * Generate a VME bus interrupt at the requested level & vector. Wait for - * interrupt to be acked. - */ -static int fake_irq_generate(struct vme_bridge *fake_bridge, int level, - int statid) -{ - struct fake_driver *bridge; - - bridge = fake_bridge->driver_priv; - - mutex_lock(&bridge->vme_int); - - bridge->int_level = level; - - bridge->int_statid = statid; - - /* - * Schedule tasklet to run VME handler to emulate normal VME interrupt - * handler behaviour. - */ - tasklet_schedule(&bridge->int_tasklet); - - mutex_unlock(&bridge->vme_int); - - return 0; -} - -/* - * Initialize a slave window with the requested attributes. - */ -static int fake_slave_set(struct vme_slave_resource *image, int enabled, - unsigned long long vme_base, unsigned long long size, - dma_addr_t buf_base, u32 aspace, u32 cycle) -{ - unsigned int i, granularity = 0; - unsigned long long vme_bound; - struct vme_bridge *fake_bridge; - struct fake_driver *bridge; - - fake_bridge = image->parent; - bridge = fake_bridge->driver_priv; - - i = image->number; - - switch (aspace) { - case VME_A16: - granularity = 0x10; - break; - case VME_A24: - granularity = 0x1000; - break; - case VME_A32: - granularity = 0x10000; - break; - case VME_A64: - granularity = 0x10000; - break; - case VME_CRCSR: - case VME_USER1: - case VME_USER2: - case VME_USER3: - case VME_USER4: - default: - pr_err("Invalid address space\n"); - return -EINVAL; - } - - /* - * Bound address is a valid address for the window, adjust - * accordingly - */ - vme_bound = vme_base + size - granularity; - - if (vme_base & (granularity - 1)) { - pr_err("Invalid VME base alignment\n"); - return -EINVAL; - } - if (vme_bound & (granularity - 1)) { - pr_err("Invalid VME bound alignment\n"); - return -EINVAL; - } - - mutex_lock(&image->mtx); - - bridge->slaves[i].enabled = enabled; - bridge->slaves[i].vme_base = vme_base; - bridge->slaves[i].size = size; - bridge->slaves[i].buf_base = fake_pci_to_ptr(buf_base); - bridge->slaves[i].aspace = aspace; - bridge->slaves[i].cycle = cycle; - - mutex_unlock(&image->mtx); - - return 0; -} - -/* - * Get slave window configuration. - */ -static int fake_slave_get(struct vme_slave_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - dma_addr_t *buf_base, u32 *aspace, u32 *cycle) -{ - unsigned int i; - struct fake_driver *bridge; - - bridge = image->parent->driver_priv; - - i = image->number; - - mutex_lock(&image->mtx); - - *enabled = bridge->slaves[i].enabled; - *vme_base = bridge->slaves[i].vme_base; - *size = bridge->slaves[i].size; - *buf_base = fake_ptr_to_pci(bridge->slaves[i].buf_base); - *aspace = bridge->slaves[i].aspace; - *cycle = bridge->slaves[i].cycle; - - mutex_unlock(&image->mtx); - - return 0; -} - -/* - * Set the attributes of an outbound window. - */ -static int fake_master_set(struct vme_master_resource *image, int enabled, - unsigned long long vme_base, unsigned long long size, - u32 aspace, u32 cycle, u32 dwidth) -{ - int retval = 0; - unsigned int i; - struct vme_bridge *fake_bridge; - struct fake_driver *bridge; - - fake_bridge = image->parent; - - bridge = fake_bridge->driver_priv; - - /* Verify input data */ - if (vme_base & 0xFFFF) { - pr_err("Invalid VME Window alignment\n"); - retval = -EINVAL; - goto err_window; - } - - if (size & 0xFFFF) { - pr_err("Invalid size alignment\n"); - retval = -EINVAL; - goto err_window; - } - - if ((size == 0) && (enabled != 0)) { - pr_err("Size must be non-zero for enabled windows\n"); - retval = -EINVAL; - goto err_window; - } - - /* Setup data width */ - switch (dwidth) { - case VME_D8: - case VME_D16: - case VME_D32: - break; - default: - pr_err("Invalid data width\n"); - retval = -EINVAL; - goto err_dwidth; - } - - /* Setup address space */ - switch (aspace) { - case VME_A16: - case VME_A24: - case VME_A32: - case VME_A64: - case VME_CRCSR: - case VME_USER1: - case VME_USER2: - case VME_USER3: - case VME_USER4: - break; - default: - pr_err("Invalid address space\n"); - retval = -EINVAL; - goto err_aspace; - } - - spin_lock(&image->lock); - - i = image->number; - - bridge->masters[i].enabled = enabled; - bridge->masters[i].vme_base = vme_base; - bridge->masters[i].size = size; - bridge->masters[i].aspace = aspace; - bridge->masters[i].cycle = cycle; - bridge->masters[i].dwidth = dwidth; - - spin_unlock(&image->lock); - - return 0; - -err_aspace: -err_dwidth: -err_window: - return retval; - -} - -/* - * Set the attributes of an outbound window. - */ -static int __fake_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - u32 *aspace, u32 *cycle, u32 *dwidth) -{ - unsigned int i; - struct fake_driver *bridge; - - bridge = image->parent->driver_priv; - - i = image->number; - - *enabled = bridge->masters[i].enabled; - *vme_base = bridge->masters[i].vme_base; - *size = bridge->masters[i].size; - *aspace = bridge->masters[i].aspace; - *cycle = bridge->masters[i].cycle; - *dwidth = bridge->masters[i].dwidth; - - return 0; -} - - -static int fake_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - u32 *aspace, u32 *cycle, u32 *dwidth) -{ - int retval; - - spin_lock(&image->lock); - - retval = __fake_master_get(image, enabled, vme_base, size, aspace, - cycle, dwidth); - - spin_unlock(&image->lock); - - return retval; -} - - -static void fake_lm_check(struct fake_driver *bridge, unsigned long long addr, - u32 aspace, u32 cycle) -{ - struct vme_bridge *fake_bridge; - unsigned long long lm_base; - u32 lm_aspace, lm_cycle; - int i; - struct vme_lm_resource *lm; - struct list_head *pos = NULL, *n; - - /* Get vme_bridge */ - fake_bridge = bridge->parent; - - /* Loop through each location monitor resource */ - list_for_each_safe(pos, n, &fake_bridge->lm_resources) { - lm = list_entry(pos, struct vme_lm_resource, list); - - /* If disabled, we're done */ - if (bridge->lm_enabled == 0) - return; - - lm_base = bridge->lm_base; - lm_aspace = bridge->lm_aspace; - lm_cycle = bridge->lm_cycle; - - /* First make sure that the cycle and address space match */ - if ((lm_aspace == aspace) && (lm_cycle == cycle)) { - for (i = 0; i < lm->monitors; i++) { - /* Each location monitor covers 8 bytes */ - if (((lm_base + (8 * i)) <= addr) && - ((lm_base + (8 * i) + 8) > addr)) { - if (bridge->lm_callback[i]) - bridge->lm_callback[i]( - bridge->lm_data[i]); - } - } - } - } -} - -static noinline_for_stack u8 fake_vmeread8(struct fake_driver *bridge, - unsigned long long addr, - u32 aspace, u32 cycle) -{ - u8 retval = 0xff; - int i; - unsigned long long start, end, offset; - u8 *loc; - - for (i = 0; i < FAKE_MAX_SLAVE; i++) { - start = bridge->slaves[i].vme_base; - end = bridge->slaves[i].vme_base + bridge->slaves[i].size; - - if (aspace != bridge->slaves[i].aspace) - continue; - - if (cycle != bridge->slaves[i].cycle) - continue; - - if ((addr >= start) && (addr < end)) { - offset = addr - bridge->slaves[i].vme_base; - loc = (u8 *)(bridge->slaves[i].buf_base + offset); - retval = *loc; - - break; - } - } - - fake_lm_check(bridge, addr, aspace, cycle); - - return retval; -} - -static noinline_for_stack u16 fake_vmeread16(struct fake_driver *bridge, - unsigned long long addr, - u32 aspace, u32 cycle) -{ - u16 retval = 0xffff; - int i; - unsigned long long start, end, offset; - u16 *loc; - - for (i = 0; i < FAKE_MAX_SLAVE; i++) { - if (aspace != bridge->slaves[i].aspace) - continue; - - if (cycle != bridge->slaves[i].cycle) - continue; - - start = bridge->slaves[i].vme_base; - end = bridge->slaves[i].vme_base + bridge->slaves[i].size; - - if ((addr >= start) && ((addr + 1) < end)) { - offset = addr - bridge->slaves[i].vme_base; - loc = (u16 *)(bridge->slaves[i].buf_base + offset); - retval = *loc; - - break; - } - } - - fake_lm_check(bridge, addr, aspace, cycle); - - return retval; -} - -static noinline_for_stack u32 fake_vmeread32(struct fake_driver *bridge, - unsigned long long addr, - u32 aspace, u32 cycle) -{ - u32 retval = 0xffffffff; - int i; - unsigned long long start, end, offset; - u32 *loc; - - for (i = 0; i < FAKE_MAX_SLAVE; i++) { - if (aspace != bridge->slaves[i].aspace) - continue; - - if (cycle != bridge->slaves[i].cycle) - continue; - - start = bridge->slaves[i].vme_base; - end = bridge->slaves[i].vme_base + bridge->slaves[i].size; - - if ((addr >= start) && ((addr + 3) < end)) { - offset = addr - bridge->slaves[i].vme_base; - loc = (u32 *)(bridge->slaves[i].buf_base + offset); - retval = *loc; - - break; - } - } - - fake_lm_check(bridge, addr, aspace, cycle); - - return retval; -} - -static ssize_t fake_master_read(struct vme_master_resource *image, void *buf, - size_t count, loff_t offset) -{ - int retval; - u32 aspace, cycle, dwidth; - struct vme_bridge *fake_bridge; - struct fake_driver *priv; - int i; - unsigned long long addr; - unsigned int done = 0; - unsigned int count32; - - fake_bridge = image->parent; - - priv = fake_bridge->driver_priv; - - i = image->number; - - addr = (unsigned long long)priv->masters[i].vme_base + offset; - aspace = priv->masters[i].aspace; - cycle = priv->masters[i].cycle; - dwidth = priv->masters[i].dwidth; - - spin_lock(&image->lock); - - /* The following code handles VME address alignment. We cannot use - * memcpy_xxx here because it may cut data transfers in to 8-bit - * cycles when D16 or D32 cycles are required on the VME bus. - * On the other hand, the bridge itself assures that the maximum data - * cycle configured for the transfer is used and splits it - * automatically for non-aligned addresses, so we don't want the - * overhead of needlessly forcing small transfers for the entire cycle. - */ - if (addr & 0x1) { - *(u8 *)buf = fake_vmeread8(priv, addr, aspace, cycle); - done += 1; - if (done == count) - goto out; - } - if ((dwidth == VME_D16) || (dwidth == VME_D32)) { - if ((addr + done) & 0x2) { - if ((count - done) < 2) { - *(u8 *)(buf + done) = fake_vmeread8(priv, - addr + done, aspace, cycle); - done += 1; - goto out; - } else { - *(u16 *)(buf + done) = fake_vmeread16(priv, - addr + done, aspace, cycle); - done += 2; - } - } - } - - if (dwidth == VME_D32) { - count32 = (count - done) & ~0x3; - while (done < count32) { - *(u32 *)(buf + done) = fake_vmeread32(priv, addr + done, - aspace, cycle); - done += 4; - } - } else if (dwidth == VME_D16) { - count32 = (count - done) & ~0x3; - while (done < count32) { - *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done, - aspace, cycle); - done += 2; - } - } else if (dwidth == VME_D8) { - count32 = (count - done); - while (done < count32) { - *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, - aspace, cycle); - done += 1; - } - - } - - if ((dwidth == VME_D16) || (dwidth == VME_D32)) { - if ((count - done) & 0x2) { - *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done, - aspace, cycle); - done += 2; - } - } - if ((count - done) & 0x1) { - *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, aspace, - cycle); - done += 1; - } - -out: - retval = count; - - spin_unlock(&image->lock); - - return retval; -} - -static noinline_for_stack void fake_vmewrite8(struct fake_driver *bridge, - u8 *buf, unsigned long long addr, - u32 aspace, u32 cycle) -{ - int i; - unsigned long long start, end, offset; - u8 *loc; - - for (i = 0; i < FAKE_MAX_SLAVE; i++) { - if (aspace != bridge->slaves[i].aspace) - continue; - - if (cycle != bridge->slaves[i].cycle) - continue; - - start = bridge->slaves[i].vme_base; - end = bridge->slaves[i].vme_base + bridge->slaves[i].size; - - if ((addr >= start) && (addr < end)) { - offset = addr - bridge->slaves[i].vme_base; - loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset); - *loc = *buf; - - break; - } - } - - fake_lm_check(bridge, addr, aspace, cycle); - -} - -static noinline_for_stack void fake_vmewrite16(struct fake_driver *bridge, - u16 *buf, unsigned long long addr, - u32 aspace, u32 cycle) -{ - int i; - unsigned long long start, end, offset; - u16 *loc; - - for (i = 0; i < FAKE_MAX_SLAVE; i++) { - if (aspace != bridge->slaves[i].aspace) - continue; - - if (cycle != bridge->slaves[i].cycle) - continue; - - start = bridge->slaves[i].vme_base; - end = bridge->slaves[i].vme_base + bridge->slaves[i].size; - - if ((addr >= start) && ((addr + 1) < end)) { - offset = addr - bridge->slaves[i].vme_base; - loc = (u16 *)((void *)bridge->slaves[i].buf_base + offset); - *loc = *buf; - - break; - } - } - - fake_lm_check(bridge, addr, aspace, cycle); - -} - -static noinline_for_stack void fake_vmewrite32(struct fake_driver *bridge, - u32 *buf, unsigned long long addr, - u32 aspace, u32 cycle) -{ - int i; - unsigned long long start, end, offset; - u32 *loc; - - for (i = 0; i < FAKE_MAX_SLAVE; i++) { - if (aspace != bridge->slaves[i].aspace) - continue; - - if (cycle != bridge->slaves[i].cycle) - continue; - - start = bridge->slaves[i].vme_base; - end = bridge->slaves[i].vme_base + bridge->slaves[i].size; - - if ((addr >= start) && ((addr + 3) < end)) { - offset = addr - bridge->slaves[i].vme_base; - loc = (u32 *)((void *)bridge->slaves[i].buf_base + offset); - *loc = *buf; - - break; - } - } - - fake_lm_check(bridge, addr, aspace, cycle); - -} - -static ssize_t fake_master_write(struct vme_master_resource *image, void *buf, - size_t count, loff_t offset) -{ - int retval = 0; - u32 aspace, cycle, dwidth; - unsigned long long addr; - int i; - unsigned int done = 0; - unsigned int count32; - - struct vme_bridge *fake_bridge; - struct fake_driver *bridge; - - fake_bridge = image->parent; - - bridge = fake_bridge->driver_priv; - - i = image->number; - - addr = bridge->masters[i].vme_base + offset; - aspace = bridge->masters[i].aspace; - cycle = bridge->masters[i].cycle; - dwidth = bridge->masters[i].dwidth; - - spin_lock(&image->lock); - - /* Here we apply for the same strategy we do in master_read - * function in order to assure the correct cycles. - */ - if (addr & 0x1) { - fake_vmewrite8(bridge, (u8 *)buf, addr, aspace, cycle); - done += 1; - if (done == count) - goto out; - } - - if ((dwidth == VME_D16) || (dwidth == VME_D32)) { - if ((addr + done) & 0x2) { - if ((count - done) < 2) { - fake_vmewrite8(bridge, (u8 *)(buf + done), - addr + done, aspace, cycle); - done += 1; - goto out; - } else { - fake_vmewrite16(bridge, (u16 *)(buf + done), - addr + done, aspace, cycle); - done += 2; - } - } - } - - if (dwidth == VME_D32) { - count32 = (count - done) & ~0x3; - while (done < count32) { - fake_vmewrite32(bridge, (u32 *)(buf + done), - addr + done, aspace, cycle); - done += 4; - } - } else if (dwidth == VME_D16) { - count32 = (count - done) & ~0x3; - while (done < count32) { - fake_vmewrite16(bridge, (u16 *)(buf + done), - addr + done, aspace, cycle); - done += 2; - } - } else if (dwidth == VME_D8) { - count32 = (count - done); - while (done < count32) { - fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, - aspace, cycle); - done += 1; - } - - } - - if ((dwidth == VME_D16) || (dwidth == VME_D32)) { - if ((count - done) & 0x2) { - fake_vmewrite16(bridge, (u16 *)(buf + done), - addr + done, aspace, cycle); - done += 2; - } - } - - if ((count - done) & 0x1) { - fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, aspace, - cycle); - done += 1; - } - -out: - retval = count; - - spin_unlock(&image->lock); - - return retval; -} - -/* - * Perform an RMW cycle on the VME bus. - * - * Requires a previously configured master window, returns final value. - */ -static unsigned int fake_master_rmw(struct vme_master_resource *image, - unsigned int mask, unsigned int compare, unsigned int swap, - loff_t offset) -{ - u32 tmp, base; - u32 aspace, cycle; - int i; - struct fake_driver *bridge; - - bridge = image->parent->driver_priv; - - /* Find the PCI address that maps to the desired VME address */ - i = image->number; - - base = bridge->masters[i].vme_base; - aspace = bridge->masters[i].aspace; - cycle = bridge->masters[i].cycle; - - /* Lock image */ - spin_lock(&image->lock); - - /* Read existing value */ - tmp = fake_vmeread32(bridge, base + offset, aspace, cycle); - - /* Perform check */ - if ((tmp && mask) == (compare && mask)) { - tmp = tmp | (mask | swap); - tmp = tmp & (~mask | swap); - - /* Write back */ - fake_vmewrite32(bridge, &tmp, base + offset, aspace, cycle); - } - - /* Unlock image */ - spin_unlock(&image->lock); - - return tmp; -} - -/* - * All 4 location monitors reside at the same base - this is therefore a - * system wide configuration. - * - * This does not enable the LM monitor - that should be done when the first - * callback is attached and disabled when the last callback is removed. - */ -static int fake_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, - u32 aspace, u32 cycle) -{ - int i; - struct vme_bridge *fake_bridge; - struct fake_driver *bridge; - - fake_bridge = lm->parent; - - bridge = fake_bridge->driver_priv; - - mutex_lock(&lm->mtx); - - /* If we already have a callback attached, we can't move it! */ - for (i = 0; i < lm->monitors; i++) { - if (bridge->lm_callback[i]) { - mutex_unlock(&lm->mtx); - pr_err("Location monitor callback attached, can't reset\n"); - return -EBUSY; - } - } - - switch (aspace) { - case VME_A16: - case VME_A24: - case VME_A32: - case VME_A64: - break; - default: - mutex_unlock(&lm->mtx); - pr_err("Invalid address space\n"); - return -EINVAL; - } - - bridge->lm_base = lm_base; - bridge->lm_aspace = aspace; - bridge->lm_cycle = cycle; - - mutex_unlock(&lm->mtx); - - return 0; -} - -/* Get configuration of the callback monitor and return whether it is enabled - * or disabled. - */ -static int fake_lm_get(struct vme_lm_resource *lm, - unsigned long long *lm_base, u32 *aspace, u32 *cycle) -{ - struct fake_driver *bridge; - - bridge = lm->parent->driver_priv; - - mutex_lock(&lm->mtx); - - *lm_base = bridge->lm_base; - *aspace = bridge->lm_aspace; - *cycle = bridge->lm_cycle; - - mutex_unlock(&lm->mtx); - - return bridge->lm_enabled; -} - -/* - * Attach a callback to a specific location monitor. - * - * Callback will be passed the monitor triggered. - */ -static int fake_lm_attach(struct vme_lm_resource *lm, int monitor, - void (*callback)(void *), void *data) -{ - struct vme_bridge *fake_bridge; - struct fake_driver *bridge; - - fake_bridge = lm->parent; - - bridge = fake_bridge->driver_priv; - - mutex_lock(&lm->mtx); - - /* Ensure that the location monitor is configured - need PGM or DATA */ - if (bridge->lm_cycle == 0) { - mutex_unlock(&lm->mtx); - pr_err("Location monitor not properly configured\n"); - return -EINVAL; - } - - /* Check that a callback isn't already attached */ - if (bridge->lm_callback[monitor]) { - mutex_unlock(&lm->mtx); - pr_err("Existing callback attached\n"); - return -EBUSY; - } - - /* Attach callback */ - bridge->lm_callback[monitor] = callback; - bridge->lm_data[monitor] = data; - - /* Ensure that global Location Monitor Enable set */ - bridge->lm_enabled = 1; - - mutex_unlock(&lm->mtx); - - return 0; -} - -/* - * Detach a callback function forn a specific location monitor. - */ -static int fake_lm_detach(struct vme_lm_resource *lm, int monitor) -{ - u32 tmp; - int i; - struct fake_driver *bridge; - - bridge = lm->parent->driver_priv; - - mutex_lock(&lm->mtx); - - /* Detach callback */ - bridge->lm_callback[monitor] = NULL; - bridge->lm_data[monitor] = NULL; - - /* If all location monitors disabled, disable global Location Monitor */ - tmp = 0; - for (i = 0; i < lm->monitors; i++) { - if (bridge->lm_callback[i]) - tmp = 1; - } - - if (tmp == 0) - bridge->lm_enabled = 0; - - mutex_unlock(&lm->mtx); - - return 0; -} - -/* - * Determine Geographical Addressing - */ -static int fake_slot_get(struct vme_bridge *fake_bridge) -{ - return geoid; -} - -static void *fake_alloc_consistent(struct device *parent, size_t size, - dma_addr_t *dma) -{ - void *alloc = kmalloc(size, GFP_KERNEL); - - if (alloc) - *dma = fake_ptr_to_pci(alloc); - - return alloc; -} - -static void fake_free_consistent(struct device *parent, size_t size, - void *vaddr, dma_addr_t dma) -{ - kfree(vaddr); -/* - dma_free_coherent(parent, size, vaddr, dma); -*/ -} - -/* - * Configure CR/CSR space - * - * Access to the CR/CSR can be configured at power-up. The location of the - * CR/CSR registers in the CR/CSR address space is determined by the boards - * Geographic address. - * - * Each board has a 512kB window, with the highest 4kB being used for the - * boards registers, this means there is a fix length 508kB window which must - * be mapped onto PCI memory. - */ -static int fake_crcsr_init(struct vme_bridge *fake_bridge) -{ - u32 vstat; - struct fake_driver *bridge; - - bridge = fake_bridge->driver_priv; - - /* Allocate mem for CR/CSR image */ - bridge->crcsr_kernel = kzalloc(VME_CRCSR_BUF_SIZE, GFP_KERNEL); - bridge->crcsr_bus = fake_ptr_to_pci(bridge->crcsr_kernel); - if (!bridge->crcsr_kernel) - return -ENOMEM; - - vstat = fake_slot_get(fake_bridge); - - pr_info("CR/CSR Offset: %d\n", vstat); - - return 0; -} - -static void fake_crcsr_exit(struct vme_bridge *fake_bridge) -{ - struct fake_driver *bridge; - - bridge = fake_bridge->driver_priv; - - kfree(bridge->crcsr_kernel); -} - - -static int __init fake_init(void) -{ - int retval, i; - struct list_head *pos = NULL, *n; - struct vme_bridge *fake_bridge; - struct fake_driver *fake_device; - struct vme_master_resource *master_image; - struct vme_slave_resource *slave_image; - struct vme_lm_resource *lm; - - /* We need a fake parent device */ - vme_root = __root_device_register("vme", THIS_MODULE); - - /* If we want to support more than one bridge at some point, we need to - * dynamically allocate this so we get one per device. - */ - fake_bridge = kzalloc(sizeof(*fake_bridge), GFP_KERNEL); - if (!fake_bridge) { - retval = -ENOMEM; - goto err_struct; - } - - fake_device = kzalloc(sizeof(*fake_device), GFP_KERNEL); - if (!fake_device) { - retval = -ENOMEM; - goto err_driver; - } - - fake_bridge->driver_priv = fake_device; - - fake_bridge->parent = vme_root; - - fake_device->parent = fake_bridge; - - /* Initialize wait queues & mutual exclusion flags */ - mutex_init(&fake_device->vme_int); - mutex_init(&fake_bridge->irq_mtx); - tasklet_init(&fake_device->int_tasklet, fake_VIRQ_tasklet, - (unsigned long) fake_bridge); - - strcpy(fake_bridge->name, driver_name); - - /* Add master windows to list */ - INIT_LIST_HEAD(&fake_bridge->master_resources); - for (i = 0; i < FAKE_MAX_MASTER; i++) { - master_image = kmalloc(sizeof(*master_image), GFP_KERNEL); - if (!master_image) { - retval = -ENOMEM; - goto err_master; - } - master_image->parent = fake_bridge; - spin_lock_init(&master_image->lock); - master_image->locked = 0; - master_image->number = i; - master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | - VME_A64; - master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | - VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | - VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | - VME_PROG | VME_DATA; - master_image->width_attr = VME_D16 | VME_D32; - memset(&master_image->bus_resource, 0, - sizeof(struct resource)); - master_image->kern_base = NULL; - list_add_tail(&master_image->list, - &fake_bridge->master_resources); - } - - /* Add slave windows to list */ - INIT_LIST_HEAD(&fake_bridge->slave_resources); - for (i = 0; i < FAKE_MAX_SLAVE; i++) { - slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL); - if (!slave_image) { - retval = -ENOMEM; - goto err_slave; - } - slave_image->parent = fake_bridge; - mutex_init(&slave_image->mtx); - slave_image->locked = 0; - slave_image->number = i; - slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 | - VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 | - VME_USER3 | VME_USER4; - slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | - VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | - VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | - VME_PROG | VME_DATA; - list_add_tail(&slave_image->list, - &fake_bridge->slave_resources); - } - - /* Add location monitor to list */ - INIT_LIST_HEAD(&fake_bridge->lm_resources); - lm = kmalloc(sizeof(*lm), GFP_KERNEL); - if (!lm) { - retval = -ENOMEM; - goto err_lm; - } - lm->parent = fake_bridge; - mutex_init(&lm->mtx); - lm->locked = 0; - lm->number = 1; - lm->monitors = 4; - list_add_tail(&lm->list, &fake_bridge->lm_resources); - - fake_bridge->slave_get = fake_slave_get; - fake_bridge->slave_set = fake_slave_set; - fake_bridge->master_get = fake_master_get; - fake_bridge->master_set = fake_master_set; - fake_bridge->master_read = fake_master_read; - fake_bridge->master_write = fake_master_write; - fake_bridge->master_rmw = fake_master_rmw; - fake_bridge->irq_set = fake_irq_set; - fake_bridge->irq_generate = fake_irq_generate; - fake_bridge->lm_set = fake_lm_set; - fake_bridge->lm_get = fake_lm_get; - fake_bridge->lm_attach = fake_lm_attach; - fake_bridge->lm_detach = fake_lm_detach; - fake_bridge->slot_get = fake_slot_get; - fake_bridge->alloc_consistent = fake_alloc_consistent; - fake_bridge->free_consistent = fake_free_consistent; - - pr_info("Board is%s the VME system controller\n", - (geoid == 1) ? "" : " not"); - - pr_info("VME geographical address is set to %d\n", geoid); - - retval = fake_crcsr_init(fake_bridge); - if (retval) { - pr_err("CR/CSR configuration failed.\n"); - goto err_crcsr; - } - - retval = vme_register_bridge(fake_bridge); - if (retval != 0) { - pr_err("Chip Registration failed.\n"); - goto err_reg; - } - - exit_pointer = fake_bridge; - - return 0; - -err_reg: - fake_crcsr_exit(fake_bridge); -err_crcsr: -err_lm: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &fake_bridge->lm_resources) { - lm = list_entry(pos, struct vme_lm_resource, list); - list_del(pos); - kfree(lm); - } -err_slave: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &fake_bridge->slave_resources) { - slave_image = list_entry(pos, struct vme_slave_resource, list); - list_del(pos); - kfree(slave_image); - } -err_master: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &fake_bridge->master_resources) { - master_image = list_entry(pos, struct vme_master_resource, - list); - list_del(pos); - kfree(master_image); - } - - kfree(fake_device); -err_driver: - kfree(fake_bridge); -err_struct: - return retval; - -} - - -static void __exit fake_exit(void) -{ - struct list_head *pos = NULL; - struct list_head *tmplist; - struct vme_master_resource *master_image; - struct vme_slave_resource *slave_image; - int i; - struct vme_bridge *fake_bridge; - struct fake_driver *bridge; - - fake_bridge = exit_pointer; - - bridge = fake_bridge->driver_priv; - - pr_debug("Driver is being unloaded.\n"); - - /* - * Shutdown all inbound and outbound windows. - */ - for (i = 0; i < FAKE_MAX_MASTER; i++) - bridge->masters[i].enabled = 0; - - for (i = 0; i < FAKE_MAX_SLAVE; i++) - bridge->slaves[i].enabled = 0; - - /* - * Shutdown Location monitor. - */ - bridge->lm_enabled = 0; - - vme_unregister_bridge(fake_bridge); - - fake_crcsr_exit(fake_bridge); - /* resources are stored in link list */ - list_for_each_safe(pos, tmplist, &fake_bridge->slave_resources) { - slave_image = list_entry(pos, struct vme_slave_resource, list); - list_del(pos); - kfree(slave_image); - } - - /* resources are stored in link list */ - list_for_each_safe(pos, tmplist, &fake_bridge->master_resources) { - master_image = list_entry(pos, struct vme_master_resource, - list); - list_del(pos); - kfree(master_image); - } - - kfree(fake_bridge->driver_priv); - - kfree(fake_bridge); - - root_device_unregister(vme_root); -} - - -MODULE_PARM_DESC(geoid, "Set geographical addressing"); -module_param(geoid, int, 0); - -MODULE_DESCRIPTION("Fake VME bridge driver"); -MODULE_LICENSE("GPL"); - -module_init(fake_init); -module_exit(fake_exit); diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c deleted file mode 100644 index be9051b02f24..000000000000 --- a/drivers/vme/bridges/vme_tsi148.c +++ /dev/null @@ -1,2661 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Support for the Tundra TSI148 VME-PCI Bridge Chip - * - * Author: Martyn Welch - * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. - * - * Based on work by Tom Armistead and Ajit Prem - * Copyright 2004 Motorola Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../vme_bridge.h" -#include "vme_tsi148.h" - -static int tsi148_probe(struct pci_dev *, const struct pci_device_id *); -static void tsi148_remove(struct pci_dev *); - - -/* Module parameter */ -static bool err_chk; -static int geoid; - -static const char driver_name[] = "vme_tsi148"; - -static const struct pci_device_id tsi148_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) }, - { }, -}; - -MODULE_DEVICE_TABLE(pci, tsi148_ids); - -static struct pci_driver tsi148_driver = { - .name = driver_name, - .id_table = tsi148_ids, - .probe = tsi148_probe, - .remove = tsi148_remove, -}; - -static void reg_join(unsigned int high, unsigned int low, - unsigned long long *variable) -{ - *variable = (unsigned long long)high << 32; - *variable |= (unsigned long long)low; -} - -static void reg_split(unsigned long long variable, unsigned int *high, - unsigned int *low) -{ - *low = (unsigned int)variable & 0xFFFFFFFF; - *high = (unsigned int)(variable >> 32); -} - -/* - * Wakes up DMA queue. - */ -static u32 tsi148_DMA_irqhandler(struct tsi148_driver *bridge, - int channel_mask) -{ - u32 serviced = 0; - - if (channel_mask & TSI148_LCSR_INTS_DMA0S) { - wake_up(&bridge->dma_queue[0]); - serviced |= TSI148_LCSR_INTC_DMA0C; - } - if (channel_mask & TSI148_LCSR_INTS_DMA1S) { - wake_up(&bridge->dma_queue[1]); - serviced |= TSI148_LCSR_INTC_DMA1C; - } - - return serviced; -} - -/* - * Wake up location monitor queue - */ -static u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat) -{ - int i; - u32 serviced = 0; - - for (i = 0; i < 4; i++) { - if (stat & TSI148_LCSR_INTS_LMS[i]) { - /* We only enable interrupts if the callback is set */ - bridge->lm_callback[i](bridge->lm_data[i]); - serviced |= TSI148_LCSR_INTC_LMC[i]; - } - } - - return serviced; -} - -/* - * Wake up mail box queue. - * - * XXX This functionality is not exposed up though API. - */ -static u32 tsi148_MB_irqhandler(struct vme_bridge *tsi148_bridge, u32 stat) -{ - int i; - u32 val; - u32 serviced = 0; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - for (i = 0; i < 4; i++) { - if (stat & TSI148_LCSR_INTS_MBS[i]) { - val = ioread32be(bridge->base + TSI148_GCSR_MBOX[i]); - dev_err(tsi148_bridge->parent, "VME Mailbox %d received" - ": 0x%x\n", i, val); - serviced |= TSI148_LCSR_INTC_MBC[i]; - } - } - - return serviced; -} - -/* - * Display error & status message when PERR (PCI) exception interrupt occurs. - */ -static u32 tsi148_PERR_irqhandler(struct vme_bridge *tsi148_bridge) -{ - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - dev_err(tsi148_bridge->parent, "PCI Exception at address: 0x%08x:%08x, " - "attributes: %08x\n", - ioread32be(bridge->base + TSI148_LCSR_EDPAU), - ioread32be(bridge->base + TSI148_LCSR_EDPAL), - ioread32be(bridge->base + TSI148_LCSR_EDPAT)); - - dev_err(tsi148_bridge->parent, "PCI-X attribute reg: %08x, PCI-X split " - "completion reg: %08x\n", - ioread32be(bridge->base + TSI148_LCSR_EDPXA), - ioread32be(bridge->base + TSI148_LCSR_EDPXS)); - - iowrite32be(TSI148_LCSR_EDPAT_EDPCL, bridge->base + TSI148_LCSR_EDPAT); - - return TSI148_LCSR_INTC_PERRC; -} - -/* - * Save address and status when VME error interrupt occurs. - */ -static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge) -{ - unsigned int error_addr_high, error_addr_low; - unsigned long long error_addr; - u32 error_attrib; - int error_am; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - error_addr_high = ioread32be(bridge->base + TSI148_LCSR_VEAU); - error_addr_low = ioread32be(bridge->base + TSI148_LCSR_VEAL); - error_attrib = ioread32be(bridge->base + TSI148_LCSR_VEAT); - error_am = (error_attrib & TSI148_LCSR_VEAT_AM_M) >> 8; - - reg_join(error_addr_high, error_addr_low, &error_addr); - - /* Check for exception register overflow (we have lost error data) */ - if (error_attrib & TSI148_LCSR_VEAT_VEOF) { - dev_err(tsi148_bridge->parent, "VME Bus Exception Overflow " - "Occurred\n"); - } - - if (err_chk) - vme_bus_error_handler(tsi148_bridge, error_addr, error_am); - else - dev_err(tsi148_bridge->parent, - "VME Bus Error at address: 0x%llx, attributes: %08x\n", - error_addr, error_attrib); - - /* Clear Status */ - iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT); - - return TSI148_LCSR_INTC_VERRC; -} - -/* - * Wake up IACK queue. - */ -static u32 tsi148_IACK_irqhandler(struct tsi148_driver *bridge) -{ - wake_up(&bridge->iack_queue); - - return TSI148_LCSR_INTC_IACKC; -} - -/* - * Calling VME bus interrupt callback if provided. - */ -static u32 tsi148_VIRQ_irqhandler(struct vme_bridge *tsi148_bridge, - u32 stat) -{ - int vec, i, serviced = 0; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - for (i = 7; i > 0; i--) { - if (stat & (1 << i)) { - /* - * Note: Even though the registers are defined as - * 32-bits in the spec, we only want to issue 8-bit - * IACK cycles on the bus, read from offset 3. - */ - vec = ioread8(bridge->base + TSI148_LCSR_VIACK[i] + 3); - - vme_irq_handler(tsi148_bridge, i, vec); - - serviced |= (1 << i); - } - } - - return serviced; -} - -/* - * Top level interrupt handler. Clears appropriate interrupt status bits and - * then calls appropriate sub handler(s). - */ -static irqreturn_t tsi148_irqhandler(int irq, void *ptr) -{ - u32 stat, enable, serviced = 0; - struct vme_bridge *tsi148_bridge; - struct tsi148_driver *bridge; - - tsi148_bridge = ptr; - - bridge = tsi148_bridge->driver_priv; - - /* Determine which interrupts are unmasked and set */ - enable = ioread32be(bridge->base + TSI148_LCSR_INTEO); - stat = ioread32be(bridge->base + TSI148_LCSR_INTS); - - /* Only look at unmasked interrupts */ - stat &= enable; - - if (unlikely(!stat)) - return IRQ_NONE; - - /* Call subhandlers as appropriate */ - /* DMA irqs */ - if (stat & (TSI148_LCSR_INTS_DMA1S | TSI148_LCSR_INTS_DMA0S)) - serviced |= tsi148_DMA_irqhandler(bridge, stat); - - /* Location monitor irqs */ - if (stat & (TSI148_LCSR_INTS_LM3S | TSI148_LCSR_INTS_LM2S | - TSI148_LCSR_INTS_LM1S | TSI148_LCSR_INTS_LM0S)) - serviced |= tsi148_LM_irqhandler(bridge, stat); - - /* Mail box irqs */ - if (stat & (TSI148_LCSR_INTS_MB3S | TSI148_LCSR_INTS_MB2S | - TSI148_LCSR_INTS_MB1S | TSI148_LCSR_INTS_MB0S)) - serviced |= tsi148_MB_irqhandler(tsi148_bridge, stat); - - /* PCI bus error */ - if (stat & TSI148_LCSR_INTS_PERRS) - serviced |= tsi148_PERR_irqhandler(tsi148_bridge); - - /* VME bus error */ - if (stat & TSI148_LCSR_INTS_VERRS) - serviced |= tsi148_VERR_irqhandler(tsi148_bridge); - - /* IACK irq */ - if (stat & TSI148_LCSR_INTS_IACKS) - serviced |= tsi148_IACK_irqhandler(bridge); - - /* VME bus irqs */ - if (stat & (TSI148_LCSR_INTS_IRQ7S | TSI148_LCSR_INTS_IRQ6S | - TSI148_LCSR_INTS_IRQ5S | TSI148_LCSR_INTS_IRQ4S | - TSI148_LCSR_INTS_IRQ3S | TSI148_LCSR_INTS_IRQ2S | - TSI148_LCSR_INTS_IRQ1S)) - serviced |= tsi148_VIRQ_irqhandler(tsi148_bridge, stat); - - /* Clear serviced interrupts */ - iowrite32be(serviced, bridge->base + TSI148_LCSR_INTC); - - return IRQ_HANDLED; -} - -static int tsi148_irq_init(struct vme_bridge *tsi148_bridge) -{ - int result; - unsigned int tmp; - struct pci_dev *pdev; - struct tsi148_driver *bridge; - - pdev = to_pci_dev(tsi148_bridge->parent); - - bridge = tsi148_bridge->driver_priv; - - result = request_irq(pdev->irq, - tsi148_irqhandler, - IRQF_SHARED, - driver_name, tsi148_bridge); - if (result) { - dev_err(tsi148_bridge->parent, "Can't get assigned pci irq " - "vector %02X\n", pdev->irq); - return result; - } - - /* Enable and unmask interrupts */ - tmp = TSI148_LCSR_INTEO_DMA1EO | TSI148_LCSR_INTEO_DMA0EO | - TSI148_LCSR_INTEO_MB3EO | TSI148_LCSR_INTEO_MB2EO | - TSI148_LCSR_INTEO_MB1EO | TSI148_LCSR_INTEO_MB0EO | - TSI148_LCSR_INTEO_PERREO | TSI148_LCSR_INTEO_VERREO | - TSI148_LCSR_INTEO_IACKEO; - - /* This leaves the following interrupts masked. - * TSI148_LCSR_INTEO_VIEEO - * TSI148_LCSR_INTEO_SYSFLEO - * TSI148_LCSR_INTEO_ACFLEO - */ - - /* Don't enable Location Monitor interrupts here - they will be - * enabled when the location monitors are properly configured and - * a callback has been attached. - * TSI148_LCSR_INTEO_LM0EO - * TSI148_LCSR_INTEO_LM1EO - * TSI148_LCSR_INTEO_LM2EO - * TSI148_LCSR_INTEO_LM3EO - */ - - /* Don't enable VME interrupts until we add a handler, else the board - * will respond to it and we don't want that unless it knows how to - * properly deal with it. - * TSI148_LCSR_INTEO_IRQ7EO - * TSI148_LCSR_INTEO_IRQ6EO - * TSI148_LCSR_INTEO_IRQ5EO - * TSI148_LCSR_INTEO_IRQ4EO - * TSI148_LCSR_INTEO_IRQ3EO - * TSI148_LCSR_INTEO_IRQ2EO - * TSI148_LCSR_INTEO_IRQ1EO - */ - - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN); - - return 0; -} - -static void tsi148_irq_exit(struct vme_bridge *tsi148_bridge, - struct pci_dev *pdev) -{ - struct tsi148_driver *bridge = tsi148_bridge->driver_priv; - - /* Turn off interrupts */ - iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEO); - iowrite32be(0x0, bridge->base + TSI148_LCSR_INTEN); - - /* Clear all interrupts */ - iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_INTC); - - /* Detach interrupt handler */ - free_irq(pdev->irq, tsi148_bridge); -} - -/* - * Check to see if an IACk has been received, return true (1) or false (0). - */ -static int tsi148_iack_received(struct tsi148_driver *bridge) -{ - u32 tmp; - - tmp = ioread32be(bridge->base + TSI148_LCSR_VICR); - - if (tmp & TSI148_LCSR_VICR_IRQS) - return 0; - else - return 1; -} - -/* - * Configure VME interrupt - */ -static void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level, - int state, int sync) -{ - struct pci_dev *pdev; - u32 tmp; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - /* We need to do the ordering differently for enabling and disabling */ - if (state == 0) { - tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN); - tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1]; - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN); - - tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO); - tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1]; - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); - - if (sync != 0) { - pdev = to_pci_dev(tsi148_bridge->parent); - synchronize_irq(pdev->irq); - } - } else { - tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO); - tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1]; - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); - - tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN); - tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1]; - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN); - } -} - -/* - * Generate a VME bus interrupt at the requested level & vector. Wait for - * interrupt to be acked. - */ -static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, - int statid) -{ - u32 tmp; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - mutex_lock(&bridge->vme_int); - - /* Read VICR register */ - tmp = ioread32be(bridge->base + TSI148_LCSR_VICR); - - /* Set Status/ID */ - tmp = (tmp & ~TSI148_LCSR_VICR_STID_M) | - (statid & TSI148_LCSR_VICR_STID_M); - iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR); - - /* Assert VMEbus IRQ */ - tmp = tmp | TSI148_LCSR_VICR_IRQL[level]; - iowrite32be(tmp, bridge->base + TSI148_LCSR_VICR); - - /* XXX Consider implementing a timeout? */ - wait_event_interruptible(bridge->iack_queue, - tsi148_iack_received(bridge)); - - mutex_unlock(&bridge->vme_int); - - return 0; -} - -/* - * Initialize a slave window with the requested attributes. - */ -static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, - unsigned long long vme_base, unsigned long long size, - dma_addr_t pci_base, u32 aspace, u32 cycle) -{ - unsigned int i, addr = 0, granularity = 0; - unsigned int temp_ctl = 0; - unsigned int vme_base_low, vme_base_high; - unsigned int vme_bound_low, vme_bound_high; - unsigned int pci_offset_low, pci_offset_high; - unsigned long long vme_bound, pci_offset; - struct vme_bridge *tsi148_bridge; - struct tsi148_driver *bridge; - - tsi148_bridge = image->parent; - bridge = tsi148_bridge->driver_priv; - - i = image->number; - - switch (aspace) { - case VME_A16: - granularity = 0x10; - addr |= TSI148_LCSR_ITAT_AS_A16; - break; - case VME_A24: - granularity = 0x1000; - addr |= TSI148_LCSR_ITAT_AS_A24; - break; - case VME_A32: - granularity = 0x10000; - addr |= TSI148_LCSR_ITAT_AS_A32; - break; - case VME_A64: - granularity = 0x10000; - addr |= TSI148_LCSR_ITAT_AS_A64; - break; - default: - dev_err(tsi148_bridge->parent, "Invalid address space\n"); - return -EINVAL; - } - - /* Convert 64-bit variables to 2x 32-bit variables */ - reg_split(vme_base, &vme_base_high, &vme_base_low); - - /* - * Bound address is a valid address for the window, adjust - * accordingly - */ - vme_bound = vme_base + size - granularity; - reg_split(vme_bound, &vme_bound_high, &vme_bound_low); - pci_offset = (unsigned long long)pci_base - vme_base; - reg_split(pci_offset, &pci_offset_high, &pci_offset_low); - - if (vme_base_low & (granularity - 1)) { - dev_err(tsi148_bridge->parent, "Invalid VME base alignment\n"); - return -EINVAL; - } - if (vme_bound_low & (granularity - 1)) { - dev_err(tsi148_bridge->parent, "Invalid VME bound alignment\n"); - return -EINVAL; - } - if (pci_offset_low & (granularity - 1)) { - dev_err(tsi148_bridge->parent, "Invalid PCI Offset " - "alignment\n"); - return -EINVAL; - } - - /* Disable while we are mucking around */ - temp_ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITAT); - temp_ctl &= ~TSI148_LCSR_ITAT_EN; - iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITAT); - - /* Setup mapping */ - iowrite32be(vme_base_high, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITSAU); - iowrite32be(vme_base_low, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITSAL); - iowrite32be(vme_bound_high, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITEAU); - iowrite32be(vme_bound_low, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITEAL); - iowrite32be(pci_offset_high, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITOFU); - iowrite32be(pci_offset_low, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITOFL); - - /* Setup 2eSST speeds */ - temp_ctl &= ~TSI148_LCSR_ITAT_2eSSTM_M; - switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { - case VME_2eSST160: - temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_160; - break; - case VME_2eSST267: - temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_267; - break; - case VME_2eSST320: - temp_ctl |= TSI148_LCSR_ITAT_2eSSTM_320; - break; - } - - /* Setup cycle types */ - temp_ctl &= ~(0x1F << 7); - if (cycle & VME_BLT) - temp_ctl |= TSI148_LCSR_ITAT_BLT; - if (cycle & VME_MBLT) - temp_ctl |= TSI148_LCSR_ITAT_MBLT; - if (cycle & VME_2eVME) - temp_ctl |= TSI148_LCSR_ITAT_2eVME; - if (cycle & VME_2eSST) - temp_ctl |= TSI148_LCSR_ITAT_2eSST; - if (cycle & VME_2eSSTB) - temp_ctl |= TSI148_LCSR_ITAT_2eSSTB; - - /* Setup address space */ - temp_ctl &= ~TSI148_LCSR_ITAT_AS_M; - temp_ctl |= addr; - - temp_ctl &= ~0xF; - if (cycle & VME_SUPER) - temp_ctl |= TSI148_LCSR_ITAT_SUPR ; - if (cycle & VME_USER) - temp_ctl |= TSI148_LCSR_ITAT_NPRIV; - if (cycle & VME_PROG) - temp_ctl |= TSI148_LCSR_ITAT_PGM; - if (cycle & VME_DATA) - temp_ctl |= TSI148_LCSR_ITAT_DATA; - - /* Write ctl reg without enable */ - iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITAT); - - if (enabled) - temp_ctl |= TSI148_LCSR_ITAT_EN; - - iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITAT); - - return 0; -} - -/* - * Get slave window configuration. - */ -static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - dma_addr_t *pci_base, u32 *aspace, u32 *cycle) -{ - unsigned int i, granularity = 0, ctl = 0; - unsigned int vme_base_low, vme_base_high; - unsigned int vme_bound_low, vme_bound_high; - unsigned int pci_offset_low, pci_offset_high; - unsigned long long vme_bound, pci_offset; - struct tsi148_driver *bridge; - - bridge = image->parent->driver_priv; - - i = image->number; - - /* Read registers */ - ctl = ioread32be(bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITAT); - - vme_base_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITSAU); - vme_base_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITSAL); - vme_bound_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITEAU); - vme_bound_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITEAL); - pci_offset_high = ioread32be(bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITOFU); - pci_offset_low = ioread32be(bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITOFL); - - /* Convert 64-bit variables to 2x 32-bit variables */ - reg_join(vme_base_high, vme_base_low, vme_base); - reg_join(vme_bound_high, vme_bound_low, &vme_bound); - reg_join(pci_offset_high, pci_offset_low, &pci_offset); - - *pci_base = (dma_addr_t)(*vme_base + pci_offset); - - *enabled = 0; - *aspace = 0; - *cycle = 0; - - if (ctl & TSI148_LCSR_ITAT_EN) - *enabled = 1; - - if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A16) { - granularity = 0x10; - *aspace |= VME_A16; - } - if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A24) { - granularity = 0x1000; - *aspace |= VME_A24; - } - if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A32) { - granularity = 0x10000; - *aspace |= VME_A32; - } - if ((ctl & TSI148_LCSR_ITAT_AS_M) == TSI148_LCSR_ITAT_AS_A64) { - granularity = 0x10000; - *aspace |= VME_A64; - } - - /* Need granularity before we set the size */ - *size = (unsigned long long)((vme_bound - *vme_base) + granularity); - - - if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_160) - *cycle |= VME_2eSST160; - if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_267) - *cycle |= VME_2eSST267; - if ((ctl & TSI148_LCSR_ITAT_2eSSTM_M) == TSI148_LCSR_ITAT_2eSSTM_320) - *cycle |= VME_2eSST320; - - if (ctl & TSI148_LCSR_ITAT_BLT) - *cycle |= VME_BLT; - if (ctl & TSI148_LCSR_ITAT_MBLT) - *cycle |= VME_MBLT; - if (ctl & TSI148_LCSR_ITAT_2eVME) - *cycle |= VME_2eVME; - if (ctl & TSI148_LCSR_ITAT_2eSST) - *cycle |= VME_2eSST; - if (ctl & TSI148_LCSR_ITAT_2eSSTB) - *cycle |= VME_2eSSTB; - - if (ctl & TSI148_LCSR_ITAT_SUPR) - *cycle |= VME_SUPER; - if (ctl & TSI148_LCSR_ITAT_NPRIV) - *cycle |= VME_USER; - if (ctl & TSI148_LCSR_ITAT_PGM) - *cycle |= VME_PROG; - if (ctl & TSI148_LCSR_ITAT_DATA) - *cycle |= VME_DATA; - - return 0; -} - -/* - * Allocate and map PCI Resource - */ -static int tsi148_alloc_resource(struct vme_master_resource *image, - unsigned long long size) -{ - unsigned long long existing_size; - int retval = 0; - struct pci_dev *pdev; - struct vme_bridge *tsi148_bridge; - - tsi148_bridge = image->parent; - - pdev = to_pci_dev(tsi148_bridge->parent); - - existing_size = (unsigned long long)(image->bus_resource.end - - image->bus_resource.start); - - /* If the existing size is OK, return */ - if ((size != 0) && (existing_size == (size - 1))) - return 0; - - if (existing_size != 0) { - iounmap(image->kern_base); - image->kern_base = NULL; - kfree(image->bus_resource.name); - release_resource(&image->bus_resource); - memset(&image->bus_resource, 0, sizeof(image->bus_resource)); - } - - /* Exit here if size is zero */ - if (size == 0) - return 0; - - if (!image->bus_resource.name) { - image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC); - if (!image->bus_resource.name) { - retval = -ENOMEM; - goto err_name; - } - } - - sprintf((char *)image->bus_resource.name, "%s.%d", tsi148_bridge->name, - image->number); - - image->bus_resource.start = 0; - image->bus_resource.end = (unsigned long)size; - image->bus_resource.flags = IORESOURCE_MEM; - - retval = pci_bus_alloc_resource(pdev->bus, - &image->bus_resource, size, 0x10000, PCIBIOS_MIN_MEM, - 0, NULL, NULL); - if (retval) { - dev_err(tsi148_bridge->parent, "Failed to allocate mem " - "resource for window %d size 0x%lx start 0x%lx\n", - image->number, (unsigned long)size, - (unsigned long)image->bus_resource.start); - goto err_resource; - } - - image->kern_base = ioremap( - image->bus_resource.start, size); - if (!image->kern_base) { - dev_err(tsi148_bridge->parent, "Failed to remap resource\n"); - retval = -ENOMEM; - goto err_remap; - } - - return 0; - -err_remap: - release_resource(&image->bus_resource); -err_resource: - kfree(image->bus_resource.name); - memset(&image->bus_resource, 0, sizeof(image->bus_resource)); -err_name: - return retval; -} - -/* - * Free and unmap PCI Resource - */ -static void tsi148_free_resource(struct vme_master_resource *image) -{ - iounmap(image->kern_base); - image->kern_base = NULL; - release_resource(&image->bus_resource); - kfree(image->bus_resource.name); - memset(&image->bus_resource, 0, sizeof(image->bus_resource)); -} - -/* - * Set the attributes of an outbound window. - */ -static int tsi148_master_set(struct vme_master_resource *image, int enabled, - unsigned long long vme_base, unsigned long long size, u32 aspace, - u32 cycle, u32 dwidth) -{ - int retval = 0; - unsigned int i; - unsigned int temp_ctl = 0; - unsigned int pci_base_low, pci_base_high; - unsigned int pci_bound_low, pci_bound_high; - unsigned int vme_offset_low, vme_offset_high; - unsigned long long pci_bound, vme_offset, pci_base; - struct vme_bridge *tsi148_bridge; - struct tsi148_driver *bridge; - struct pci_bus_region region; - struct pci_dev *pdev; - - tsi148_bridge = image->parent; - - bridge = tsi148_bridge->driver_priv; - - pdev = to_pci_dev(tsi148_bridge->parent); - - /* Verify input data */ - if (vme_base & 0xFFFF) { - dev_err(tsi148_bridge->parent, "Invalid VME Window " - "alignment\n"); - retval = -EINVAL; - goto err_window; - } - - if ((size == 0) && (enabled != 0)) { - dev_err(tsi148_bridge->parent, "Size must be non-zero for " - "enabled windows\n"); - retval = -EINVAL; - goto err_window; - } - - spin_lock(&image->lock); - - /* Let's allocate the resource here rather than further up the stack as - * it avoids pushing loads of bus dependent stuff up the stack. If size - * is zero, any existing resource will be freed. - */ - retval = tsi148_alloc_resource(image, size); - if (retval) { - spin_unlock(&image->lock); - dev_err(tsi148_bridge->parent, "Unable to allocate memory for " - "resource\n"); - goto err_res; - } - - if (size == 0) { - pci_base = 0; - pci_bound = 0; - vme_offset = 0; - } else { - pcibios_resource_to_bus(pdev->bus, ®ion, - &image->bus_resource); - pci_base = region.start; - - /* - * Bound address is a valid address for the window, adjust - * according to window granularity. - */ - pci_bound = pci_base + (size - 0x10000); - vme_offset = vme_base - pci_base; - } - - /* Convert 64-bit variables to 2x 32-bit variables */ - reg_split(pci_base, &pci_base_high, &pci_base_low); - reg_split(pci_bound, &pci_bound_high, &pci_bound_low); - reg_split(vme_offset, &vme_offset_high, &vme_offset_low); - - if (pci_base_low & 0xFFFF) { - spin_unlock(&image->lock); - dev_err(tsi148_bridge->parent, "Invalid PCI base alignment\n"); - retval = -EINVAL; - goto err_gran; - } - if (pci_bound_low & 0xFFFF) { - spin_unlock(&image->lock); - dev_err(tsi148_bridge->parent, "Invalid PCI bound alignment\n"); - retval = -EINVAL; - goto err_gran; - } - if (vme_offset_low & 0xFFFF) { - spin_unlock(&image->lock); - dev_err(tsi148_bridge->parent, "Invalid VME Offset " - "alignment\n"); - retval = -EINVAL; - goto err_gran; - } - - i = image->number; - - /* Disable while we are mucking around */ - temp_ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTAT); - temp_ctl &= ~TSI148_LCSR_OTAT_EN; - iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTAT); - - /* Setup 2eSST speeds */ - temp_ctl &= ~TSI148_LCSR_OTAT_2eSSTM_M; - switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { - case VME_2eSST160: - temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_160; - break; - case VME_2eSST267: - temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_267; - break; - case VME_2eSST320: - temp_ctl |= TSI148_LCSR_OTAT_2eSSTM_320; - break; - } - - /* Setup cycle types */ - if (cycle & VME_BLT) { - temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; - temp_ctl |= TSI148_LCSR_OTAT_TM_BLT; - } - if (cycle & VME_MBLT) { - temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; - temp_ctl |= TSI148_LCSR_OTAT_TM_MBLT; - } - if (cycle & VME_2eVME) { - temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; - temp_ctl |= TSI148_LCSR_OTAT_TM_2eVME; - } - if (cycle & VME_2eSST) { - temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; - temp_ctl |= TSI148_LCSR_OTAT_TM_2eSST; - } - if (cycle & VME_2eSSTB) { - dev_warn(tsi148_bridge->parent, "Currently not setting " - "Broadcast Select Registers\n"); - temp_ctl &= ~TSI148_LCSR_OTAT_TM_M; - temp_ctl |= TSI148_LCSR_OTAT_TM_2eSSTB; - } - - /* Setup data width */ - temp_ctl &= ~TSI148_LCSR_OTAT_DBW_M; - switch (dwidth) { - case VME_D16: - temp_ctl |= TSI148_LCSR_OTAT_DBW_16; - break; - case VME_D32: - temp_ctl |= TSI148_LCSR_OTAT_DBW_32; - break; - default: - spin_unlock(&image->lock); - dev_err(tsi148_bridge->parent, "Invalid data width\n"); - retval = -EINVAL; - goto err_dwidth; - } - - /* Setup address space */ - temp_ctl &= ~TSI148_LCSR_OTAT_AMODE_M; - switch (aspace) { - case VME_A16: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_A16; - break; - case VME_A24: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_A24; - break; - case VME_A32: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_A32; - break; - case VME_A64: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_A64; - break; - case VME_CRCSR: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_CRCSR; - break; - case VME_USER1: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER1; - break; - case VME_USER2: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER2; - break; - case VME_USER3: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER3; - break; - case VME_USER4: - temp_ctl |= TSI148_LCSR_OTAT_AMODE_USER4; - break; - default: - spin_unlock(&image->lock); - dev_err(tsi148_bridge->parent, "Invalid address space\n"); - retval = -EINVAL; - goto err_aspace; - } - - temp_ctl &= ~(3<<4); - if (cycle & VME_SUPER) - temp_ctl |= TSI148_LCSR_OTAT_SUP; - if (cycle & VME_PROG) - temp_ctl |= TSI148_LCSR_OTAT_PGM; - - /* Setup mapping */ - iowrite32be(pci_base_high, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTSAU); - iowrite32be(pci_base_low, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTSAL); - iowrite32be(pci_bound_high, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTEAU); - iowrite32be(pci_bound_low, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTEAL); - iowrite32be(vme_offset_high, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTOFU); - iowrite32be(vme_offset_low, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTOFL); - - /* Write ctl reg without enable */ - iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTAT); - - if (enabled) - temp_ctl |= TSI148_LCSR_OTAT_EN; - - iowrite32be(temp_ctl, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTAT); - - spin_unlock(&image->lock); - return 0; - -err_aspace: -err_dwidth: -err_gran: - tsi148_free_resource(image); -err_res: -err_window: - return retval; - -} - -/* - * Set the attributes of an outbound window. - * - * XXX Not parsing prefetch information. - */ -static int __tsi148_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, u32 *aspace, - u32 *cycle, u32 *dwidth) -{ - unsigned int i, ctl; - unsigned int pci_base_low, pci_base_high; - unsigned int pci_bound_low, pci_bound_high; - unsigned int vme_offset_low, vme_offset_high; - - unsigned long long pci_base, pci_bound, vme_offset; - struct tsi148_driver *bridge; - - bridge = image->parent->driver_priv; - - i = image->number; - - ctl = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTAT); - - pci_base_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTSAU); - pci_base_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTSAL); - pci_bound_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTEAU); - pci_bound_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTEAL); - vme_offset_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTOFU); - vme_offset_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTOFL); - - /* Convert 64-bit variables to 2x 32-bit variables */ - reg_join(pci_base_high, pci_base_low, &pci_base); - reg_join(pci_bound_high, pci_bound_low, &pci_bound); - reg_join(vme_offset_high, vme_offset_low, &vme_offset); - - *vme_base = pci_base + vme_offset; - *size = (unsigned long long)(pci_bound - pci_base) + 0x10000; - - *enabled = 0; - *aspace = 0; - *cycle = 0; - *dwidth = 0; - - if (ctl & TSI148_LCSR_OTAT_EN) - *enabled = 1; - - /* Setup address space */ - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A16) - *aspace |= VME_A16; - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A24) - *aspace |= VME_A24; - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A32) - *aspace |= VME_A32; - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_A64) - *aspace |= VME_A64; - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_CRCSR) - *aspace |= VME_CRCSR; - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER1) - *aspace |= VME_USER1; - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER2) - *aspace |= VME_USER2; - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER3) - *aspace |= VME_USER3; - if ((ctl & TSI148_LCSR_OTAT_AMODE_M) == TSI148_LCSR_OTAT_AMODE_USER4) - *aspace |= VME_USER4; - - /* Setup 2eSST speeds */ - if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_160) - *cycle |= VME_2eSST160; - if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_267) - *cycle |= VME_2eSST267; - if ((ctl & TSI148_LCSR_OTAT_2eSSTM_M) == TSI148_LCSR_OTAT_2eSSTM_320) - *cycle |= VME_2eSST320; - - /* Setup cycle types */ - if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_SCT) - *cycle |= VME_SCT; - if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_BLT) - *cycle |= VME_BLT; - if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_MBLT) - *cycle |= VME_MBLT; - if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eVME) - *cycle |= VME_2eVME; - if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSST) - *cycle |= VME_2eSST; - if ((ctl & TSI148_LCSR_OTAT_TM_M) == TSI148_LCSR_OTAT_TM_2eSSTB) - *cycle |= VME_2eSSTB; - - if (ctl & TSI148_LCSR_OTAT_SUP) - *cycle |= VME_SUPER; - else - *cycle |= VME_USER; - - if (ctl & TSI148_LCSR_OTAT_PGM) - *cycle |= VME_PROG; - else - *cycle |= VME_DATA; - - /* Setup data width */ - if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_16) - *dwidth = VME_D16; - if ((ctl & TSI148_LCSR_OTAT_DBW_M) == TSI148_LCSR_OTAT_DBW_32) - *dwidth = VME_D32; - - return 0; -} - - -static int tsi148_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, u32 *aspace, - u32 *cycle, u32 *dwidth) -{ - int retval; - - spin_lock(&image->lock); - - retval = __tsi148_master_get(image, enabled, vme_base, size, aspace, - cycle, dwidth); - - spin_unlock(&image->lock); - - return retval; -} - -static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, - size_t count, loff_t offset) -{ - int retval, enabled; - unsigned long long vme_base, size; - u32 aspace, cycle, dwidth; - struct vme_error_handler *handler = NULL; - struct vme_bridge *tsi148_bridge; - void __iomem *addr = image->kern_base + offset; - unsigned int done = 0; - unsigned int count32; - - tsi148_bridge = image->parent; - - spin_lock(&image->lock); - - if (err_chk) { - __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, - &cycle, &dwidth); - handler = vme_register_error_handler(tsi148_bridge, aspace, - vme_base + offset, count); - if (!handler) { - spin_unlock(&image->lock); - return -ENOMEM; - } - } - - /* The following code handles VME address alignment. We cannot use - * memcpy_xxx here because it may cut data transfers in to 8-bit - * cycles when D16 or D32 cycles are required on the VME bus. - * On the other hand, the bridge itself assures that the maximum data - * cycle configured for the transfer is used and splits it - * automatically for non-aligned addresses, so we don't want the - * overhead of needlessly forcing small transfers for the entire cycle. - */ - if ((uintptr_t)addr & 0x1) { - *(u8 *)buf = ioread8(addr); - done += 1; - if (done == count) - goto out; - } - if ((uintptr_t)(addr + done) & 0x2) { - if ((count - done) < 2) { - *(u8 *)(buf + done) = ioread8(addr + done); - done += 1; - goto out; - } else { - *(u16 *)(buf + done) = ioread16(addr + done); - done += 2; - } - } - - count32 = (count - done) & ~0x3; - while (done < count32) { - *(u32 *)(buf + done) = ioread32(addr + done); - done += 4; - } - - if ((count - done) & 0x2) { - *(u16 *)(buf + done) = ioread16(addr + done); - done += 2; - } - if ((count - done) & 0x1) { - *(u8 *)(buf + done) = ioread8(addr + done); - done += 1; - } - -out: - retval = count; - - if (err_chk) { - if (handler->num_errors) { - dev_err(image->parent->parent, - "First VME read error detected an at address 0x%llx\n", - handler->first_error); - retval = handler->first_error - (vme_base + offset); - } - vme_unregister_error_handler(handler); - } - - spin_unlock(&image->lock); - - return retval; -} - - -static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, - size_t count, loff_t offset) -{ - int retval = 0, enabled; - unsigned long long vme_base, size; - u32 aspace, cycle, dwidth; - void __iomem *addr = image->kern_base + offset; - unsigned int done = 0; - unsigned int count32; - - struct vme_error_handler *handler = NULL; - struct vme_bridge *tsi148_bridge; - struct tsi148_driver *bridge; - - tsi148_bridge = image->parent; - - bridge = tsi148_bridge->driver_priv; - - spin_lock(&image->lock); - - if (err_chk) { - __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, - &cycle, &dwidth); - handler = vme_register_error_handler(tsi148_bridge, aspace, - vme_base + offset, count); - if (!handler) { - spin_unlock(&image->lock); - return -ENOMEM; - } - } - - /* Here we apply for the same strategy we do in master_read - * function in order to assure the correct cycles. - */ - if ((uintptr_t)addr & 0x1) { - iowrite8(*(u8 *)buf, addr); - done += 1; - if (done == count) - goto out; - } - if ((uintptr_t)(addr + done) & 0x2) { - if ((count - done) < 2) { - iowrite8(*(u8 *)(buf + done), addr + done); - done += 1; - goto out; - } else { - iowrite16(*(u16 *)(buf + done), addr + done); - done += 2; - } - } - - count32 = (count - done) & ~0x3; - while (done < count32) { - iowrite32(*(u32 *)(buf + done), addr + done); - done += 4; - } - - if ((count - done) & 0x2) { - iowrite16(*(u16 *)(buf + done), addr + done); - done += 2; - } - if ((count - done) & 0x1) { - iowrite8(*(u8 *)(buf + done), addr + done); - done += 1; - } - -out: - retval = count; - - /* - * Writes are posted. We need to do a read on the VME bus to flush out - * all of the writes before we check for errors. We can't guarantee - * that reading the data we have just written is safe. It is believed - * that there isn't any read, write re-ordering, so we can read any - * location in VME space, so lets read the Device ID from the tsi148's - * own registers as mapped into CR/CSR space. - * - * We check for saved errors in the written address range/space. - */ - - if (err_chk) { - ioread16(bridge->flush_image->kern_base + 0x7F000); - - if (handler->num_errors) { - dev_warn(tsi148_bridge->parent, - "First VME write error detected an at address 0x%llx\n", - handler->first_error); - retval = handler->first_error - (vme_base + offset); - } - vme_unregister_error_handler(handler); - } - - spin_unlock(&image->lock); - - return retval; -} - -/* - * Perform an RMW cycle on the VME bus. - * - * Requires a previously configured master window, returns final value. - */ -static unsigned int tsi148_master_rmw(struct vme_master_resource *image, - unsigned int mask, unsigned int compare, unsigned int swap, - loff_t offset) -{ - unsigned long long pci_addr; - unsigned int pci_addr_high, pci_addr_low; - u32 tmp, result; - int i; - struct tsi148_driver *bridge; - - bridge = image->parent->driver_priv; - - /* Find the PCI address that maps to the desired VME address */ - i = image->number; - - /* Locking as we can only do one of these at a time */ - mutex_lock(&bridge->vme_rmw); - - /* Lock image */ - spin_lock(&image->lock); - - pci_addr_high = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTSAU); - pci_addr_low = ioread32be(bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTSAL); - - reg_join(pci_addr_high, pci_addr_low, &pci_addr); - reg_split(pci_addr + offset, &pci_addr_high, &pci_addr_low); - - /* Configure registers */ - iowrite32be(mask, bridge->base + TSI148_LCSR_RMWEN); - iowrite32be(compare, bridge->base + TSI148_LCSR_RMWC); - iowrite32be(swap, bridge->base + TSI148_LCSR_RMWS); - iowrite32be(pci_addr_high, bridge->base + TSI148_LCSR_RMWAU); - iowrite32be(pci_addr_low, bridge->base + TSI148_LCSR_RMWAL); - - /* Enable RMW */ - tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL); - tmp |= TSI148_LCSR_VMCTRL_RMWEN; - iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL); - - /* Kick process off with a read to the required address. */ - result = ioread32be(image->kern_base + offset); - - /* Disable RMW */ - tmp = ioread32be(bridge->base + TSI148_LCSR_VMCTRL); - tmp &= ~TSI148_LCSR_VMCTRL_RMWEN; - iowrite32be(tmp, bridge->base + TSI148_LCSR_VMCTRL); - - spin_unlock(&image->lock); - - mutex_unlock(&bridge->vme_rmw); - - return result; -} - -static int tsi148_dma_set_vme_src_attributes(struct device *dev, __be32 *attr, - u32 aspace, u32 cycle, u32 dwidth) -{ - u32 val; - - val = be32_to_cpu(*attr); - - /* Setup 2eSST speeds */ - switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { - case VME_2eSST160: - val |= TSI148_LCSR_DSAT_2eSSTM_160; - break; - case VME_2eSST267: - val |= TSI148_LCSR_DSAT_2eSSTM_267; - break; - case VME_2eSST320: - val |= TSI148_LCSR_DSAT_2eSSTM_320; - break; - } - - /* Setup cycle types */ - if (cycle & VME_SCT) - val |= TSI148_LCSR_DSAT_TM_SCT; - - if (cycle & VME_BLT) - val |= TSI148_LCSR_DSAT_TM_BLT; - - if (cycle & VME_MBLT) - val |= TSI148_LCSR_DSAT_TM_MBLT; - - if (cycle & VME_2eVME) - val |= TSI148_LCSR_DSAT_TM_2eVME; - - if (cycle & VME_2eSST) - val |= TSI148_LCSR_DSAT_TM_2eSST; - - if (cycle & VME_2eSSTB) { - dev_err(dev, "Currently not setting Broadcast Select " - "Registers\n"); - val |= TSI148_LCSR_DSAT_TM_2eSSTB; - } - - /* Setup data width */ - switch (dwidth) { - case VME_D16: - val |= TSI148_LCSR_DSAT_DBW_16; - break; - case VME_D32: - val |= TSI148_LCSR_DSAT_DBW_32; - break; - default: - dev_err(dev, "Invalid data width\n"); - return -EINVAL; - } - - /* Setup address space */ - switch (aspace) { - case VME_A16: - val |= TSI148_LCSR_DSAT_AMODE_A16; - break; - case VME_A24: - val |= TSI148_LCSR_DSAT_AMODE_A24; - break; - case VME_A32: - val |= TSI148_LCSR_DSAT_AMODE_A32; - break; - case VME_A64: - val |= TSI148_LCSR_DSAT_AMODE_A64; - break; - case VME_CRCSR: - val |= TSI148_LCSR_DSAT_AMODE_CRCSR; - break; - case VME_USER1: - val |= TSI148_LCSR_DSAT_AMODE_USER1; - break; - case VME_USER2: - val |= TSI148_LCSR_DSAT_AMODE_USER2; - break; - case VME_USER3: - val |= TSI148_LCSR_DSAT_AMODE_USER3; - break; - case VME_USER4: - val |= TSI148_LCSR_DSAT_AMODE_USER4; - break; - default: - dev_err(dev, "Invalid address space\n"); - return -EINVAL; - } - - if (cycle & VME_SUPER) - val |= TSI148_LCSR_DSAT_SUP; - if (cycle & VME_PROG) - val |= TSI148_LCSR_DSAT_PGM; - - *attr = cpu_to_be32(val); - - return 0; -} - -static int tsi148_dma_set_vme_dest_attributes(struct device *dev, __be32 *attr, - u32 aspace, u32 cycle, u32 dwidth) -{ - u32 val; - - val = be32_to_cpu(*attr); - - /* Setup 2eSST speeds */ - switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) { - case VME_2eSST160: - val |= TSI148_LCSR_DDAT_2eSSTM_160; - break; - case VME_2eSST267: - val |= TSI148_LCSR_DDAT_2eSSTM_267; - break; - case VME_2eSST320: - val |= TSI148_LCSR_DDAT_2eSSTM_320; - break; - } - - /* Setup cycle types */ - if (cycle & VME_SCT) - val |= TSI148_LCSR_DDAT_TM_SCT; - - if (cycle & VME_BLT) - val |= TSI148_LCSR_DDAT_TM_BLT; - - if (cycle & VME_MBLT) - val |= TSI148_LCSR_DDAT_TM_MBLT; - - if (cycle & VME_2eVME) - val |= TSI148_LCSR_DDAT_TM_2eVME; - - if (cycle & VME_2eSST) - val |= TSI148_LCSR_DDAT_TM_2eSST; - - if (cycle & VME_2eSSTB) { - dev_err(dev, "Currently not setting Broadcast Select " - "Registers\n"); - val |= TSI148_LCSR_DDAT_TM_2eSSTB; - } - - /* Setup data width */ - switch (dwidth) { - case VME_D16: - val |= TSI148_LCSR_DDAT_DBW_16; - break; - case VME_D32: - val |= TSI148_LCSR_DDAT_DBW_32; - break; - default: - dev_err(dev, "Invalid data width\n"); - return -EINVAL; - } - - /* Setup address space */ - switch (aspace) { - case VME_A16: - val |= TSI148_LCSR_DDAT_AMODE_A16; - break; - case VME_A24: - val |= TSI148_LCSR_DDAT_AMODE_A24; - break; - case VME_A32: - val |= TSI148_LCSR_DDAT_AMODE_A32; - break; - case VME_A64: - val |= TSI148_LCSR_DDAT_AMODE_A64; - break; - case VME_CRCSR: - val |= TSI148_LCSR_DDAT_AMODE_CRCSR; - break; - case VME_USER1: - val |= TSI148_LCSR_DDAT_AMODE_USER1; - break; - case VME_USER2: - val |= TSI148_LCSR_DDAT_AMODE_USER2; - break; - case VME_USER3: - val |= TSI148_LCSR_DDAT_AMODE_USER3; - break; - case VME_USER4: - val |= TSI148_LCSR_DDAT_AMODE_USER4; - break; - default: - dev_err(dev, "Invalid address space\n"); - return -EINVAL; - } - - if (cycle & VME_SUPER) - val |= TSI148_LCSR_DDAT_SUP; - if (cycle & VME_PROG) - val |= TSI148_LCSR_DDAT_PGM; - - *attr = cpu_to_be32(val); - - return 0; -} - -/* - * Add a link list descriptor to the list - * - * Note: DMA engine expects the DMA descriptor to be big endian. - */ -static int tsi148_dma_list_add(struct vme_dma_list *list, - struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count) -{ - struct tsi148_dma_entry *entry, *prev; - u32 address_high, address_low, val; - struct vme_dma_pattern *pattern_attr; - struct vme_dma_pci *pci_attr; - struct vme_dma_vme *vme_attr; - int retval = 0; - struct vme_bridge *tsi148_bridge; - - tsi148_bridge = list->parent->parent; - - /* Descriptor must be aligned on 64-bit boundaries */ - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - retval = -ENOMEM; - goto err_mem; - } - - /* Test descriptor alignment */ - if ((unsigned long)&entry->descriptor & 0x7) { - dev_err(tsi148_bridge->parent, "Descriptor not aligned to 8 " - "byte boundary as required: %p\n", - &entry->descriptor); - retval = -EINVAL; - goto err_align; - } - - /* Given we are going to fill out the structure, we probably don't - * need to zero it, but better safe than sorry for now. - */ - memset(&entry->descriptor, 0, sizeof(entry->descriptor)); - - /* Fill out source part */ - switch (src->type) { - case VME_DMA_PATTERN: - pattern_attr = src->private; - - entry->descriptor.dsal = cpu_to_be32(pattern_attr->pattern); - - val = TSI148_LCSR_DSAT_TYP_PAT; - - /* Default behaviour is 32 bit pattern */ - if (pattern_attr->type & VME_DMA_PATTERN_BYTE) - val |= TSI148_LCSR_DSAT_PSZ; - - /* It seems that the default behaviour is to increment */ - if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0) - val |= TSI148_LCSR_DSAT_NIN; - entry->descriptor.dsat = cpu_to_be32(val); - break; - case VME_DMA_PCI: - pci_attr = src->private; - - reg_split((unsigned long long)pci_attr->address, &address_high, - &address_low); - entry->descriptor.dsau = cpu_to_be32(address_high); - entry->descriptor.dsal = cpu_to_be32(address_low); - entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_PCI); - break; - case VME_DMA_VME: - vme_attr = src->private; - - reg_split((unsigned long long)vme_attr->address, &address_high, - &address_low); - entry->descriptor.dsau = cpu_to_be32(address_high); - entry->descriptor.dsal = cpu_to_be32(address_low); - entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_VME); - - retval = tsi148_dma_set_vme_src_attributes( - tsi148_bridge->parent, &entry->descriptor.dsat, - vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth); - if (retval < 0) - goto err_source; - break; - default: - dev_err(tsi148_bridge->parent, "Invalid source type\n"); - retval = -EINVAL; - goto err_source; - } - - /* Assume last link - this will be over-written by adding another */ - entry->descriptor.dnlau = cpu_to_be32(0); - entry->descriptor.dnlal = cpu_to_be32(TSI148_LCSR_DNLAL_LLA); - - /* Fill out destination part */ - switch (dest->type) { - case VME_DMA_PCI: - pci_attr = dest->private; - - reg_split((unsigned long long)pci_attr->address, &address_high, - &address_low); - entry->descriptor.ddau = cpu_to_be32(address_high); - entry->descriptor.ddal = cpu_to_be32(address_low); - entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_PCI); - break; - case VME_DMA_VME: - vme_attr = dest->private; - - reg_split((unsigned long long)vme_attr->address, &address_high, - &address_low); - entry->descriptor.ddau = cpu_to_be32(address_high); - entry->descriptor.ddal = cpu_to_be32(address_low); - entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_VME); - - retval = tsi148_dma_set_vme_dest_attributes( - tsi148_bridge->parent, &entry->descriptor.ddat, - vme_attr->aspace, vme_attr->cycle, vme_attr->dwidth); - if (retval < 0) - goto err_dest; - break; - default: - dev_err(tsi148_bridge->parent, "Invalid destination type\n"); - retval = -EINVAL; - goto err_dest; - } - - /* Fill out count */ - entry->descriptor.dcnt = cpu_to_be32((u32)count); - - /* Add to list */ - list_add_tail(&entry->list, &list->entries); - - entry->dma_handle = dma_map_single(tsi148_bridge->parent, - &entry->descriptor, - sizeof(entry->descriptor), - DMA_TO_DEVICE); - if (dma_mapping_error(tsi148_bridge->parent, entry->dma_handle)) { - dev_err(tsi148_bridge->parent, "DMA mapping error\n"); - retval = -EINVAL; - goto err_dma; - } - - /* Fill out previous descriptors "Next Address" */ - if (entry->list.prev != &list->entries) { - reg_split((unsigned long long)entry->dma_handle, &address_high, - &address_low); - prev = list_entry(entry->list.prev, struct tsi148_dma_entry, - list); - prev->descriptor.dnlau = cpu_to_be32(address_high); - prev->descriptor.dnlal = cpu_to_be32(address_low); - - } - - return 0; - -err_dma: -err_dest: -err_source: -err_align: - kfree(entry); -err_mem: - return retval; -} - -/* - * Check to see if the provided DMA channel is busy. - */ -static int tsi148_dma_busy(struct vme_bridge *tsi148_bridge, int channel) -{ - u32 tmp; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - tmp = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] + - TSI148_LCSR_OFFSET_DSTA); - - if (tmp & TSI148_LCSR_DSTA_BSY) - return 0; - else - return 1; - -} - -/* - * Execute a previously generated link list - * - * XXX Need to provide control register configuration. - */ -static int tsi148_dma_list_exec(struct vme_dma_list *list) -{ - struct vme_dma_resource *ctrlr; - int channel, retval; - struct tsi148_dma_entry *entry; - u32 bus_addr_high, bus_addr_low; - u32 val, dctlreg = 0; - struct vme_bridge *tsi148_bridge; - struct tsi148_driver *bridge; - - ctrlr = list->parent; - - tsi148_bridge = ctrlr->parent; - - bridge = tsi148_bridge->driver_priv; - - mutex_lock(&ctrlr->mtx); - - channel = ctrlr->number; - - if (!list_empty(&ctrlr->running)) { - /* - * XXX We have an active DMA transfer and currently haven't - * sorted out the mechanism for "pending" DMA transfers. - * Return busy. - */ - /* Need to add to pending here */ - mutex_unlock(&ctrlr->mtx); - return -EBUSY; - } else { - list_add(&list->list, &ctrlr->running); - } - - /* Get first bus address and write into registers */ - entry = list_first_entry(&list->entries, struct tsi148_dma_entry, - list); - - mutex_unlock(&ctrlr->mtx); - - reg_split(entry->dma_handle, &bus_addr_high, &bus_addr_low); - - iowrite32be(bus_addr_high, bridge->base + - TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU); - iowrite32be(bus_addr_low, bridge->base + - TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL); - - dctlreg = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] + - TSI148_LCSR_OFFSET_DCTL); - - /* Start the operation */ - iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base + - TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL); - - retval = wait_event_interruptible(bridge->dma_queue[channel], - tsi148_dma_busy(ctrlr->parent, channel)); - - if (retval) { - iowrite32be(dctlreg | TSI148_LCSR_DCTL_ABT, bridge->base + - TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL); - /* Wait for the operation to abort */ - wait_event(bridge->dma_queue[channel], - tsi148_dma_busy(ctrlr->parent, channel)); - retval = -EINTR; - goto exit; - } - - /* - * Read status register, this register is valid until we kick off a - * new transfer. - */ - val = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] + - TSI148_LCSR_OFFSET_DSTA); - - if (val & TSI148_LCSR_DSTA_VBE) { - dev_err(tsi148_bridge->parent, "DMA Error. DSTA=%08X\n", val); - retval = -EIO; - } - -exit: - /* Remove list from running list */ - mutex_lock(&ctrlr->mtx); - list_del(&list->list); - mutex_unlock(&ctrlr->mtx); - - return retval; -} - -/* - * Clean up a previously generated link list - * - * We have a separate function, don't assume that the chain can't be reused. - */ -static int tsi148_dma_list_empty(struct vme_dma_list *list) -{ - struct list_head *pos, *temp; - struct tsi148_dma_entry *entry; - - struct vme_bridge *tsi148_bridge = list->parent->parent; - - /* detach and free each entry */ - list_for_each_safe(pos, temp, &list->entries) { - list_del(pos); - entry = list_entry(pos, struct tsi148_dma_entry, list); - - dma_unmap_single(tsi148_bridge->parent, entry->dma_handle, - sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE); - kfree(entry); - } - - return 0; -} - -/* - * All 4 location monitors reside at the same base - this is therefore a - * system wide configuration. - * - * This does not enable the LM monitor - that should be done when the first - * callback is attached and disabled when the last callback is removed. - */ -static int tsi148_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, - u32 aspace, u32 cycle) -{ - u32 lm_base_high, lm_base_low, lm_ctl = 0; - int i; - struct vme_bridge *tsi148_bridge; - struct tsi148_driver *bridge; - - tsi148_bridge = lm->parent; - - bridge = tsi148_bridge->driver_priv; - - mutex_lock(&lm->mtx); - - /* If we already have a callback attached, we can't move it! */ - for (i = 0; i < lm->monitors; i++) { - if (bridge->lm_callback[i]) { - mutex_unlock(&lm->mtx); - dev_err(tsi148_bridge->parent, "Location monitor " - "callback attached, can't reset\n"); - return -EBUSY; - } - } - - switch (aspace) { - case VME_A16: - lm_ctl |= TSI148_LCSR_LMAT_AS_A16; - break; - case VME_A24: - lm_ctl |= TSI148_LCSR_LMAT_AS_A24; - break; - case VME_A32: - lm_ctl |= TSI148_LCSR_LMAT_AS_A32; - break; - case VME_A64: - lm_ctl |= TSI148_LCSR_LMAT_AS_A64; - break; - default: - mutex_unlock(&lm->mtx); - dev_err(tsi148_bridge->parent, "Invalid address space\n"); - return -EINVAL; - } - - if (cycle & VME_SUPER) - lm_ctl |= TSI148_LCSR_LMAT_SUPR ; - if (cycle & VME_USER) - lm_ctl |= TSI148_LCSR_LMAT_NPRIV; - if (cycle & VME_PROG) - lm_ctl |= TSI148_LCSR_LMAT_PGM; - if (cycle & VME_DATA) - lm_ctl |= TSI148_LCSR_LMAT_DATA; - - reg_split(lm_base, &lm_base_high, &lm_base_low); - - iowrite32be(lm_base_high, bridge->base + TSI148_LCSR_LMBAU); - iowrite32be(lm_base_low, bridge->base + TSI148_LCSR_LMBAL); - iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT); - - mutex_unlock(&lm->mtx); - - return 0; -} - -/* Get configuration of the callback monitor and return whether it is enabled - * or disabled. - */ -static int tsi148_lm_get(struct vme_lm_resource *lm, - unsigned long long *lm_base, u32 *aspace, u32 *cycle) -{ - u32 lm_base_high, lm_base_low, lm_ctl, enabled = 0; - struct tsi148_driver *bridge; - - bridge = lm->parent->driver_priv; - - mutex_lock(&lm->mtx); - - lm_base_high = ioread32be(bridge->base + TSI148_LCSR_LMBAU); - lm_base_low = ioread32be(bridge->base + TSI148_LCSR_LMBAL); - lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT); - - reg_join(lm_base_high, lm_base_low, lm_base); - - if (lm_ctl & TSI148_LCSR_LMAT_EN) - enabled = 1; - - if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A16) - *aspace |= VME_A16; - - if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A24) - *aspace |= VME_A24; - - if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A32) - *aspace |= VME_A32; - - if ((lm_ctl & TSI148_LCSR_LMAT_AS_M) == TSI148_LCSR_LMAT_AS_A64) - *aspace |= VME_A64; - - - if (lm_ctl & TSI148_LCSR_LMAT_SUPR) - *cycle |= VME_SUPER; - if (lm_ctl & TSI148_LCSR_LMAT_NPRIV) - *cycle |= VME_USER; - if (lm_ctl & TSI148_LCSR_LMAT_PGM) - *cycle |= VME_PROG; - if (lm_ctl & TSI148_LCSR_LMAT_DATA) - *cycle |= VME_DATA; - - mutex_unlock(&lm->mtx); - - return enabled; -} - -/* - * Attach a callback to a specific location monitor. - * - * Callback will be passed the monitor triggered. - */ -static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor, - void (*callback)(void *), void *data) -{ - u32 lm_ctl, tmp; - struct vme_bridge *tsi148_bridge; - struct tsi148_driver *bridge; - - tsi148_bridge = lm->parent; - - bridge = tsi148_bridge->driver_priv; - - mutex_lock(&lm->mtx); - - /* Ensure that the location monitor is configured - need PGM or DATA */ - lm_ctl = ioread32be(bridge->base + TSI148_LCSR_LMAT); - if ((lm_ctl & (TSI148_LCSR_LMAT_PGM | TSI148_LCSR_LMAT_DATA)) == 0) { - mutex_unlock(&lm->mtx); - dev_err(tsi148_bridge->parent, "Location monitor not properly " - "configured\n"); - return -EINVAL; - } - - /* Check that a callback isn't already attached */ - if (bridge->lm_callback[monitor]) { - mutex_unlock(&lm->mtx); - dev_err(tsi148_bridge->parent, "Existing callback attached\n"); - return -EBUSY; - } - - /* Attach callback */ - bridge->lm_callback[monitor] = callback; - bridge->lm_data[monitor] = data; - - /* Enable Location Monitor interrupt */ - tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN); - tmp |= TSI148_LCSR_INTEN_LMEN[monitor]; - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEN); - - tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO); - tmp |= TSI148_LCSR_INTEO_LMEO[monitor]; - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); - - /* Ensure that global Location Monitor Enable set */ - if ((lm_ctl & TSI148_LCSR_LMAT_EN) == 0) { - lm_ctl |= TSI148_LCSR_LMAT_EN; - iowrite32be(lm_ctl, bridge->base + TSI148_LCSR_LMAT); - } - - mutex_unlock(&lm->mtx); - - return 0; -} - -/* - * Detach a callback function forn a specific location monitor. - */ -static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor) -{ - u32 lm_en, tmp; - struct tsi148_driver *bridge; - - bridge = lm->parent->driver_priv; - - mutex_lock(&lm->mtx); - - /* Disable Location Monitor and ensure previous interrupts are clear */ - lm_en = ioread32be(bridge->base + TSI148_LCSR_INTEN); - lm_en &= ~TSI148_LCSR_INTEN_LMEN[monitor]; - iowrite32be(lm_en, bridge->base + TSI148_LCSR_INTEN); - - tmp = ioread32be(bridge->base + TSI148_LCSR_INTEO); - tmp &= ~TSI148_LCSR_INTEO_LMEO[monitor]; - iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); - - iowrite32be(TSI148_LCSR_INTC_LMC[monitor], - bridge->base + TSI148_LCSR_INTC); - - /* Detach callback */ - bridge->lm_callback[monitor] = NULL; - bridge->lm_data[monitor] = NULL; - - /* If all location monitors disabled, disable global Location Monitor */ - if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S | - TSI148_LCSR_INTS_LM2S | TSI148_LCSR_INTS_LM3S)) == 0) { - tmp = ioread32be(bridge->base + TSI148_LCSR_LMAT); - tmp &= ~TSI148_LCSR_LMAT_EN; - iowrite32be(tmp, bridge->base + TSI148_LCSR_LMAT); - } - - mutex_unlock(&lm->mtx); - - return 0; -} - -/* - * Determine Geographical Addressing - */ -static int tsi148_slot_get(struct vme_bridge *tsi148_bridge) -{ - u32 slot = 0; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - if (!geoid) { - slot = ioread32be(bridge->base + TSI148_LCSR_VSTAT); - slot = slot & TSI148_LCSR_VSTAT_GA_M; - } else - slot = geoid; - - return (int)slot; -} - -static void *tsi148_alloc_consistent(struct device *parent, size_t size, - dma_addr_t *dma) -{ - struct pci_dev *pdev; - - /* Find pci_dev container of dev */ - pdev = to_pci_dev(parent); - - return dma_alloc_coherent(&pdev->dev, size, dma, GFP_KERNEL); -} - -static void tsi148_free_consistent(struct device *parent, size_t size, - void *vaddr, dma_addr_t dma) -{ - struct pci_dev *pdev; - - /* Find pci_dev container of dev */ - pdev = to_pci_dev(parent); - - dma_free_coherent(&pdev->dev, size, vaddr, dma); -} - -/* - * Configure CR/CSR space - * - * Access to the CR/CSR can be configured at power-up. The location of the - * CR/CSR registers in the CR/CSR address space is determined by the boards - * Auto-ID or Geographic address. This function ensures that the window is - * enabled at an offset consistent with the boards geopgraphic address. - * - * Each board has a 512kB window, with the highest 4kB being used for the - * boards registers, this means there is a fix length 508kB window which must - * be mapped onto PCI memory. - */ -static int tsi148_crcsr_init(struct vme_bridge *tsi148_bridge, - struct pci_dev *pdev) -{ - u32 cbar, crat, vstat; - u32 crcsr_bus_high, crcsr_bus_low; - int retval; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - /* Allocate mem for CR/CSR image */ - bridge->crcsr_kernel = dma_alloc_coherent(&pdev->dev, - VME_CRCSR_BUF_SIZE, - &bridge->crcsr_bus, GFP_KERNEL); - if (!bridge->crcsr_kernel) { - dev_err(tsi148_bridge->parent, "Failed to allocate memory for " - "CR/CSR image\n"); - return -ENOMEM; - } - - reg_split(bridge->crcsr_bus, &crcsr_bus_high, &crcsr_bus_low); - - iowrite32be(crcsr_bus_high, bridge->base + TSI148_LCSR_CROU); - iowrite32be(crcsr_bus_low, bridge->base + TSI148_LCSR_CROL); - - /* Ensure that the CR/CSR is configured at the correct offset */ - cbar = ioread32be(bridge->base + TSI148_CBAR); - cbar = (cbar & TSI148_CRCSR_CBAR_M)>>3; - - vstat = tsi148_slot_get(tsi148_bridge); - - if (cbar != vstat) { - cbar = vstat; - dev_info(tsi148_bridge->parent, "Setting CR/CSR offset\n"); - iowrite32be(cbar<<3, bridge->base + TSI148_CBAR); - } - dev_info(tsi148_bridge->parent, "CR/CSR Offset: %d\n", cbar); - - crat = ioread32be(bridge->base + TSI148_LCSR_CRAT); - if (crat & TSI148_LCSR_CRAT_EN) - dev_info(tsi148_bridge->parent, "CR/CSR already enabled\n"); - else { - dev_info(tsi148_bridge->parent, "Enabling CR/CSR space\n"); - iowrite32be(crat | TSI148_LCSR_CRAT_EN, - bridge->base + TSI148_LCSR_CRAT); - } - - /* If we want flushed, error-checked writes, set up a window - * over the CR/CSR registers. We read from here to safely flush - * through VME writes. - */ - if (err_chk) { - retval = tsi148_master_set(bridge->flush_image, 1, - (vstat * 0x80000), 0x80000, VME_CRCSR, VME_SCT, - VME_D16); - if (retval) - dev_err(tsi148_bridge->parent, "Configuring flush image" - " failed\n"); - } - - return 0; - -} - -static void tsi148_crcsr_exit(struct vme_bridge *tsi148_bridge, - struct pci_dev *pdev) -{ - u32 crat; - struct tsi148_driver *bridge; - - bridge = tsi148_bridge->driver_priv; - - /* Turn off CR/CSR space */ - crat = ioread32be(bridge->base + TSI148_LCSR_CRAT); - iowrite32be(crat & ~TSI148_LCSR_CRAT_EN, - bridge->base + TSI148_LCSR_CRAT); - - /* Free image */ - iowrite32be(0, bridge->base + TSI148_LCSR_CROU); - iowrite32be(0, bridge->base + TSI148_LCSR_CROL); - - dma_free_coherent(&pdev->dev, VME_CRCSR_BUF_SIZE, - bridge->crcsr_kernel, bridge->crcsr_bus); -} - -static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int retval, i, master_num; - u32 data; - struct list_head *pos = NULL, *n; - struct vme_bridge *tsi148_bridge; - struct tsi148_driver *tsi148_device; - struct vme_master_resource *master_image; - struct vme_slave_resource *slave_image; - struct vme_dma_resource *dma_ctrlr; - struct vme_lm_resource *lm; - - /* If we want to support more than one of each bridge, we need to - * dynamically generate this so we get one per device - */ - tsi148_bridge = kzalloc(sizeof(*tsi148_bridge), GFP_KERNEL); - if (!tsi148_bridge) { - retval = -ENOMEM; - goto err_struct; - } - vme_init_bridge(tsi148_bridge); - - tsi148_device = kzalloc(sizeof(*tsi148_device), GFP_KERNEL); - if (!tsi148_device) { - retval = -ENOMEM; - goto err_driver; - } - - tsi148_bridge->driver_priv = tsi148_device; - - /* Enable the device */ - retval = pci_enable_device(pdev); - if (retval) { - dev_err(&pdev->dev, "Unable to enable device\n"); - goto err_enable; - } - - /* Map Registers */ - retval = pci_request_regions(pdev, driver_name); - if (retval) { - dev_err(&pdev->dev, "Unable to reserve resources\n"); - goto err_resource; - } - - /* map registers in BAR 0 */ - tsi148_device->base = ioremap(pci_resource_start(pdev, 0), - 4096); - if (!tsi148_device->base) { - dev_err(&pdev->dev, "Unable to remap CRG region\n"); - retval = -EIO; - goto err_remap; - } - - /* Check to see if the mapping worked out */ - data = ioread32(tsi148_device->base + TSI148_PCFS_ID) & 0x0000FFFF; - if (data != PCI_VENDOR_ID_TUNDRA) { - dev_err(&pdev->dev, "CRG region check failed\n"); - retval = -EIO; - goto err_test; - } - - /* Initialize wait queues & mutual exclusion flags */ - init_waitqueue_head(&tsi148_device->dma_queue[0]); - init_waitqueue_head(&tsi148_device->dma_queue[1]); - init_waitqueue_head(&tsi148_device->iack_queue); - mutex_init(&tsi148_device->vme_int); - mutex_init(&tsi148_device->vme_rmw); - - tsi148_bridge->parent = &pdev->dev; - strcpy(tsi148_bridge->name, driver_name); - - /* Setup IRQ */ - retval = tsi148_irq_init(tsi148_bridge); - if (retval != 0) { - dev_err(&pdev->dev, "Chip Initialization failed.\n"); - goto err_irq; - } - - /* If we are going to flush writes, we need to read from the VME bus. - * We need to do this safely, thus we read the devices own CR/CSR - * register. To do this we must set up a window in CR/CSR space and - * hence have one less master window resource available. - */ - master_num = TSI148_MAX_MASTER; - if (err_chk) { - master_num--; - - tsi148_device->flush_image = - kmalloc(sizeof(*tsi148_device->flush_image), - GFP_KERNEL); - if (!tsi148_device->flush_image) { - retval = -ENOMEM; - goto err_master; - } - tsi148_device->flush_image->parent = tsi148_bridge; - spin_lock_init(&tsi148_device->flush_image->lock); - tsi148_device->flush_image->locked = 1; - tsi148_device->flush_image->number = master_num; - memset(&tsi148_device->flush_image->bus_resource, 0, - sizeof(tsi148_device->flush_image->bus_resource)); - tsi148_device->flush_image->kern_base = NULL; - } - - /* Add master windows to list */ - for (i = 0; i < master_num; i++) { - master_image = kmalloc(sizeof(*master_image), GFP_KERNEL); - if (!master_image) { - retval = -ENOMEM; - goto err_master; - } - master_image->parent = tsi148_bridge; - spin_lock_init(&master_image->lock); - master_image->locked = 0; - master_image->number = i; - master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | - VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 | - VME_USER3 | VME_USER4; - master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | - VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | - VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | - VME_PROG | VME_DATA; - master_image->width_attr = VME_D16 | VME_D32; - memset(&master_image->bus_resource, 0, - sizeof(master_image->bus_resource)); - master_image->kern_base = NULL; - list_add_tail(&master_image->list, - &tsi148_bridge->master_resources); - } - - /* Add slave windows to list */ - for (i = 0; i < TSI148_MAX_SLAVE; i++) { - slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL); - if (!slave_image) { - retval = -ENOMEM; - goto err_slave; - } - slave_image->parent = tsi148_bridge; - mutex_init(&slave_image->mtx); - slave_image->locked = 0; - slave_image->number = i; - slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 | - VME_A64; - slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | - VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | - VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | - VME_PROG | VME_DATA; - list_add_tail(&slave_image->list, - &tsi148_bridge->slave_resources); - } - - /* Add dma engines to list */ - for (i = 0; i < TSI148_MAX_DMA; i++) { - dma_ctrlr = kmalloc(sizeof(*dma_ctrlr), GFP_KERNEL); - if (!dma_ctrlr) { - retval = -ENOMEM; - goto err_dma; - } - dma_ctrlr->parent = tsi148_bridge; - mutex_init(&dma_ctrlr->mtx); - dma_ctrlr->locked = 0; - dma_ctrlr->number = i; - dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM | - VME_DMA_MEM_TO_VME | VME_DMA_VME_TO_VME | - VME_DMA_MEM_TO_MEM | VME_DMA_PATTERN_TO_VME | - VME_DMA_PATTERN_TO_MEM; - INIT_LIST_HEAD(&dma_ctrlr->pending); - INIT_LIST_HEAD(&dma_ctrlr->running); - list_add_tail(&dma_ctrlr->list, - &tsi148_bridge->dma_resources); - } - - /* Add location monitor to list */ - lm = kmalloc(sizeof(*lm), GFP_KERNEL); - if (!lm) { - retval = -ENOMEM; - goto err_lm; - } - lm->parent = tsi148_bridge; - mutex_init(&lm->mtx); - lm->locked = 0; - lm->number = 1; - lm->monitors = 4; - list_add_tail(&lm->list, &tsi148_bridge->lm_resources); - - tsi148_bridge->slave_get = tsi148_slave_get; - tsi148_bridge->slave_set = tsi148_slave_set; - tsi148_bridge->master_get = tsi148_master_get; - tsi148_bridge->master_set = tsi148_master_set; - tsi148_bridge->master_read = tsi148_master_read; - tsi148_bridge->master_write = tsi148_master_write; - tsi148_bridge->master_rmw = tsi148_master_rmw; - tsi148_bridge->dma_list_add = tsi148_dma_list_add; - tsi148_bridge->dma_list_exec = tsi148_dma_list_exec; - tsi148_bridge->dma_list_empty = tsi148_dma_list_empty; - tsi148_bridge->irq_set = tsi148_irq_set; - tsi148_bridge->irq_generate = tsi148_irq_generate; - tsi148_bridge->lm_set = tsi148_lm_set; - tsi148_bridge->lm_get = tsi148_lm_get; - tsi148_bridge->lm_attach = tsi148_lm_attach; - tsi148_bridge->lm_detach = tsi148_lm_detach; - tsi148_bridge->slot_get = tsi148_slot_get; - tsi148_bridge->alloc_consistent = tsi148_alloc_consistent; - tsi148_bridge->free_consistent = tsi148_free_consistent; - - data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT); - dev_info(&pdev->dev, "Board is%s the VME system controller\n", - (data & TSI148_LCSR_VSTAT_SCONS) ? "" : " not"); - if (!geoid) - dev_info(&pdev->dev, "VME geographical address is %d\n", - data & TSI148_LCSR_VSTAT_GA_M); - else - dev_info(&pdev->dev, "VME geographical address is set to %d\n", - geoid); - - dev_info(&pdev->dev, "VME Write and flush and error check is %s\n", - err_chk ? "enabled" : "disabled"); - - retval = tsi148_crcsr_init(tsi148_bridge, pdev); - if (retval) { - dev_err(&pdev->dev, "CR/CSR configuration failed.\n"); - goto err_crcsr; - } - - retval = vme_register_bridge(tsi148_bridge); - if (retval != 0) { - dev_err(&pdev->dev, "Chip Registration failed.\n"); - goto err_reg; - } - - pci_set_drvdata(pdev, tsi148_bridge); - - /* Clear VME bus "board fail", and "power-up reset" lines */ - data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT); - data &= ~TSI148_LCSR_VSTAT_BRDFL; - data |= TSI148_LCSR_VSTAT_CPURST; - iowrite32be(data, tsi148_device->base + TSI148_LCSR_VSTAT); - - return 0; - -err_reg: - tsi148_crcsr_exit(tsi148_bridge, pdev); -err_crcsr: -err_lm: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &tsi148_bridge->lm_resources) { - lm = list_entry(pos, struct vme_lm_resource, list); - list_del(pos); - kfree(lm); - } -err_dma: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &tsi148_bridge->dma_resources) { - dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); - list_del(pos); - kfree(dma_ctrlr); - } -err_slave: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &tsi148_bridge->slave_resources) { - slave_image = list_entry(pos, struct vme_slave_resource, list); - list_del(pos); - kfree(slave_image); - } -err_master: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &tsi148_bridge->master_resources) { - master_image = list_entry(pos, struct vme_master_resource, - list); - list_del(pos); - kfree(master_image); - } - - tsi148_irq_exit(tsi148_bridge, pdev); -err_irq: -err_test: - iounmap(tsi148_device->base); -err_remap: - pci_release_regions(pdev); -err_resource: - pci_disable_device(pdev); -err_enable: - kfree(tsi148_device); -err_driver: - kfree(tsi148_bridge); -err_struct: - return retval; - -} - -static void tsi148_remove(struct pci_dev *pdev) -{ - struct list_head *pos = NULL; - struct list_head *tmplist; - struct vme_master_resource *master_image; - struct vme_slave_resource *slave_image; - struct vme_dma_resource *dma_ctrlr; - int i; - struct tsi148_driver *bridge; - struct vme_bridge *tsi148_bridge = pci_get_drvdata(pdev); - - bridge = tsi148_bridge->driver_priv; - - - dev_dbg(&pdev->dev, "Driver is being unloaded.\n"); - - /* - * Shutdown all inbound and outbound windows. - */ - for (i = 0; i < 8; i++) { - iowrite32be(0, bridge->base + TSI148_LCSR_IT[i] + - TSI148_LCSR_OFFSET_ITAT); - iowrite32be(0, bridge->base + TSI148_LCSR_OT[i] + - TSI148_LCSR_OFFSET_OTAT); - } - - /* - * Shutdown Location monitor. - */ - iowrite32be(0, bridge->base + TSI148_LCSR_LMAT); - - /* - * Shutdown CRG map. - */ - iowrite32be(0, bridge->base + TSI148_LCSR_CSRAT); - - /* - * Clear error status. - */ - iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_EDPAT); - iowrite32be(0xFFFFFFFF, bridge->base + TSI148_LCSR_VEAT); - iowrite32be(0x07000700, bridge->base + TSI148_LCSR_PSTAT); - - /* - * Remove VIRQ interrupt (if any) - */ - if (ioread32be(bridge->base + TSI148_LCSR_VICR) & 0x800) - iowrite32be(0x8000, bridge->base + TSI148_LCSR_VICR); - - /* - * Map all Interrupts to PCI INTA - */ - iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM1); - iowrite32be(0x0, bridge->base + TSI148_LCSR_INTM2); - - tsi148_irq_exit(tsi148_bridge, pdev); - - vme_unregister_bridge(tsi148_bridge); - - tsi148_crcsr_exit(tsi148_bridge, pdev); - - /* resources are stored in link list */ - list_for_each_safe(pos, tmplist, &tsi148_bridge->dma_resources) { - dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); - list_del(pos); - kfree(dma_ctrlr); - } - - /* resources are stored in link list */ - list_for_each_safe(pos, tmplist, &tsi148_bridge->slave_resources) { - slave_image = list_entry(pos, struct vme_slave_resource, list); - list_del(pos); - kfree(slave_image); - } - - /* resources are stored in link list */ - list_for_each_safe(pos, tmplist, &tsi148_bridge->master_resources) { - master_image = list_entry(pos, struct vme_master_resource, - list); - list_del(pos); - kfree(master_image); - } - - iounmap(bridge->base); - - pci_release_regions(pdev); - - pci_disable_device(pdev); - - kfree(tsi148_bridge->driver_priv); - - kfree(tsi148_bridge); -} - -module_pci_driver(tsi148_driver); - -MODULE_PARM_DESC(err_chk, "Check for VME errors on reads and writes"); -module_param(err_chk, bool, 0); - -MODULE_PARM_DESC(geoid, "Override geographical addressing"); -module_param(geoid, int, 0); - -MODULE_DESCRIPTION("VME driver for the Tundra Tempe VME bridge"); -MODULE_LICENSE("GPL"); diff --git a/drivers/vme/bridges/vme_tsi148.h b/drivers/vme/bridges/vme_tsi148.h deleted file mode 100644 index 226fedc6f167..000000000000 --- a/drivers/vme/bridges/vme_tsi148.h +++ /dev/null @@ -1,1407 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * tsi148.h - * - * Support for the Tundra TSI148 VME Bridge chip - * - * Author: Tom Armistead - * Updated and maintained by Ajit Prem - * Copyright 2004 Motorola Inc. - */ - -#ifndef TSI148_H -#define TSI148_H - -#ifndef PCI_VENDOR_ID_TUNDRA -#define PCI_VENDOR_ID_TUNDRA 0x10e3 -#endif - -#ifndef PCI_DEVICE_ID_TUNDRA_TSI148 -#define PCI_DEVICE_ID_TUNDRA_TSI148 0x148 -#endif - -/* - * Define the number of each that the Tsi148 supports. - */ -#define TSI148_MAX_MASTER 8 /* Max Master Windows */ -#define TSI148_MAX_SLAVE 8 /* Max Slave Windows */ -#define TSI148_MAX_DMA 2 /* Max DMA Controllers */ -#define TSI148_MAX_MAILBOX 4 /* Max Mail Box registers */ -#define TSI148_MAX_SEMAPHORE 8 /* Max Semaphores */ - -/* Structure used to hold driver specific information */ -struct tsi148_driver { - void __iomem *base; /* Base Address of device registers */ - wait_queue_head_t dma_queue[2]; - wait_queue_head_t iack_queue; - void (*lm_callback[4])(void *); /* Called in interrupt handler */ - void *lm_data[4]; - void *crcsr_kernel; - dma_addr_t crcsr_bus; - struct vme_master_resource *flush_image; - struct mutex vme_rmw; /* Only one RMW cycle at a time */ - struct mutex vme_int; /* - * Only one VME interrupt can be - * generated at a time, provide locking - */ -}; - -/* - * Layout of a DMAC Linked-List Descriptor - * - * Note: This structure is accessed via the chip and therefore must be - * correctly laid out - It must also be aligned on 64-bit boundaries. - */ -struct tsi148_dma_descriptor { - __be32 dsau; /* Source Address */ - __be32 dsal; - __be32 ddau; /* Destination Address */ - __be32 ddal; - __be32 dsat; /* Source attributes */ - __be32 ddat; /* Destination attributes */ - __be32 dnlau; /* Next link address */ - __be32 dnlal; - __be32 dcnt; /* Byte count */ - __be32 ddbs; /* 2eSST Broadcast select */ -}; - -struct tsi148_dma_entry { - /* - * The descriptor needs to be aligned on a 64-bit boundary, we increase - * the chance of this by putting it first in the structure. - */ - struct tsi148_dma_descriptor descriptor; - struct list_head list; - dma_addr_t dma_handle; -}; - -/* - * TSI148 ASIC register structure overlays and bit field definitions. - * - * Note: Tsi148 Register Group (CRG) consists of the following - * combination of registers: - * PCFS - PCI Configuration Space Registers - * LCSR - Local Control and Status Registers - * GCSR - Global Control and Status Registers - * CR/CSR - Subset of Configuration ROM / - * Control and Status Registers - */ - - -/* - * Command/Status Registers (CRG + $004) - */ -#define TSI148_PCFS_ID 0x0 -#define TSI148_PCFS_CSR 0x4 -#define TSI148_PCFS_CLASS 0x8 -#define TSI148_PCFS_MISC0 0xC -#define TSI148_PCFS_MBARL 0x10 -#define TSI148_PCFS_MBARU 0x14 - -#define TSI148_PCFS_SUBID 0x28 - -#define TSI148_PCFS_CAPP 0x34 - -#define TSI148_PCFS_MISC1 0x3C - -#define TSI148_PCFS_XCAPP 0x40 -#define TSI148_PCFS_XSTAT 0x44 - -/* - * LCSR definitions - */ - -/* - * Outbound Translations - */ -#define TSI148_LCSR_OT0_OTSAU 0x100 -#define TSI148_LCSR_OT0_OTSAL 0x104 -#define TSI148_LCSR_OT0_OTEAU 0x108 -#define TSI148_LCSR_OT0_OTEAL 0x10C -#define TSI148_LCSR_OT0_OTOFU 0x110 -#define TSI148_LCSR_OT0_OTOFL 0x114 -#define TSI148_LCSR_OT0_OTBS 0x118 -#define TSI148_LCSR_OT0_OTAT 0x11C - -#define TSI148_LCSR_OT1_OTSAU 0x120 -#define TSI148_LCSR_OT1_OTSAL 0x124 -#define TSI148_LCSR_OT1_OTEAU 0x128 -#define TSI148_LCSR_OT1_OTEAL 0x12C -#define TSI148_LCSR_OT1_OTOFU 0x130 -#define TSI148_LCSR_OT1_OTOFL 0x134 -#define TSI148_LCSR_OT1_OTBS 0x138 -#define TSI148_LCSR_OT1_OTAT 0x13C - -#define TSI148_LCSR_OT2_OTSAU 0x140 -#define TSI148_LCSR_OT2_OTSAL 0x144 -#define TSI148_LCSR_OT2_OTEAU 0x148 -#define TSI148_LCSR_OT2_OTEAL 0x14C -#define TSI148_LCSR_OT2_OTOFU 0x150 -#define TSI148_LCSR_OT2_OTOFL 0x154 -#define TSI148_LCSR_OT2_OTBS 0x158 -#define TSI148_LCSR_OT2_OTAT 0x15C - -#define TSI148_LCSR_OT3_OTSAU 0x160 -#define TSI148_LCSR_OT3_OTSAL 0x164 -#define TSI148_LCSR_OT3_OTEAU 0x168 -#define TSI148_LCSR_OT3_OTEAL 0x16C -#define TSI148_LCSR_OT3_OTOFU 0x170 -#define TSI148_LCSR_OT3_OTOFL 0x174 -#define TSI148_LCSR_OT3_OTBS 0x178 -#define TSI148_LCSR_OT3_OTAT 0x17C - -#define TSI148_LCSR_OT4_OTSAU 0x180 -#define TSI148_LCSR_OT4_OTSAL 0x184 -#define TSI148_LCSR_OT4_OTEAU 0x188 -#define TSI148_LCSR_OT4_OTEAL 0x18C -#define TSI148_LCSR_OT4_OTOFU 0x190 -#define TSI148_LCSR_OT4_OTOFL 0x194 -#define TSI148_LCSR_OT4_OTBS 0x198 -#define TSI148_LCSR_OT4_OTAT 0x19C - -#define TSI148_LCSR_OT5_OTSAU 0x1A0 -#define TSI148_LCSR_OT5_OTSAL 0x1A4 -#define TSI148_LCSR_OT5_OTEAU 0x1A8 -#define TSI148_LCSR_OT5_OTEAL 0x1AC -#define TSI148_LCSR_OT5_OTOFU 0x1B0 -#define TSI148_LCSR_OT5_OTOFL 0x1B4 -#define TSI148_LCSR_OT5_OTBS 0x1B8 -#define TSI148_LCSR_OT5_OTAT 0x1BC - -#define TSI148_LCSR_OT6_OTSAU 0x1C0 -#define TSI148_LCSR_OT6_OTSAL 0x1C4 -#define TSI148_LCSR_OT6_OTEAU 0x1C8 -#define TSI148_LCSR_OT6_OTEAL 0x1CC -#define TSI148_LCSR_OT6_OTOFU 0x1D0 -#define TSI148_LCSR_OT6_OTOFL 0x1D4 -#define TSI148_LCSR_OT6_OTBS 0x1D8 -#define TSI148_LCSR_OT6_OTAT 0x1DC - -#define TSI148_LCSR_OT7_OTSAU 0x1E0 -#define TSI148_LCSR_OT7_OTSAL 0x1E4 -#define TSI148_LCSR_OT7_OTEAU 0x1E8 -#define TSI148_LCSR_OT7_OTEAL 0x1EC -#define TSI148_LCSR_OT7_OTOFU 0x1F0 -#define TSI148_LCSR_OT7_OTOFL 0x1F4 -#define TSI148_LCSR_OT7_OTBS 0x1F8 -#define TSI148_LCSR_OT7_OTAT 0x1FC - -#define TSI148_LCSR_OT0 0x100 -#define TSI148_LCSR_OT1 0x120 -#define TSI148_LCSR_OT2 0x140 -#define TSI148_LCSR_OT3 0x160 -#define TSI148_LCSR_OT4 0x180 -#define TSI148_LCSR_OT5 0x1A0 -#define TSI148_LCSR_OT6 0x1C0 -#define TSI148_LCSR_OT7 0x1E0 - -static const int TSI148_LCSR_OT[8] = { TSI148_LCSR_OT0, TSI148_LCSR_OT1, - TSI148_LCSR_OT2, TSI148_LCSR_OT3, - TSI148_LCSR_OT4, TSI148_LCSR_OT5, - TSI148_LCSR_OT6, TSI148_LCSR_OT7 }; - -#define TSI148_LCSR_OFFSET_OTSAU 0x0 -#define TSI148_LCSR_OFFSET_OTSAL 0x4 -#define TSI148_LCSR_OFFSET_OTEAU 0x8 -#define TSI148_LCSR_OFFSET_OTEAL 0xC -#define TSI148_LCSR_OFFSET_OTOFU 0x10 -#define TSI148_LCSR_OFFSET_OTOFL 0x14 -#define TSI148_LCSR_OFFSET_OTBS 0x18 -#define TSI148_LCSR_OFFSET_OTAT 0x1C - -/* - * VMEbus interrupt ack - * offset 200 - */ -#define TSI148_LCSR_VIACK1 0x204 -#define TSI148_LCSR_VIACK2 0x208 -#define TSI148_LCSR_VIACK3 0x20C -#define TSI148_LCSR_VIACK4 0x210 -#define TSI148_LCSR_VIACK5 0x214 -#define TSI148_LCSR_VIACK6 0x218 -#define TSI148_LCSR_VIACK7 0x21C - -static const int TSI148_LCSR_VIACK[8] = { 0, TSI148_LCSR_VIACK1, - TSI148_LCSR_VIACK2, TSI148_LCSR_VIACK3, - TSI148_LCSR_VIACK4, TSI148_LCSR_VIACK5, - TSI148_LCSR_VIACK6, TSI148_LCSR_VIACK7 }; - -/* - * RMW - * offset 220 - */ -#define TSI148_LCSR_RMWAU 0x220 -#define TSI148_LCSR_RMWAL 0x224 -#define TSI148_LCSR_RMWEN 0x228 -#define TSI148_LCSR_RMWC 0x22C -#define TSI148_LCSR_RMWS 0x230 - -/* - * VMEbus control - * offset 234 - */ -#define TSI148_LCSR_VMCTRL 0x234 -#define TSI148_LCSR_VCTRL 0x238 -#define TSI148_LCSR_VSTAT 0x23C - -/* - * PCI status - * offset 240 - */ -#define TSI148_LCSR_PSTAT 0x240 - -/* - * VME filter. - * offset 250 - */ -#define TSI148_LCSR_VMEFL 0x250 - - /* - * VME exception. - * offset 260 - */ -#define TSI148_LCSR_VEAU 0x260 -#define TSI148_LCSR_VEAL 0x264 -#define TSI148_LCSR_VEAT 0x268 - - /* - * PCI error - * offset 270 - */ -#define TSI148_LCSR_EDPAU 0x270 -#define TSI148_LCSR_EDPAL 0x274 -#define TSI148_LCSR_EDPXA 0x278 -#define TSI148_LCSR_EDPXS 0x27C -#define TSI148_LCSR_EDPAT 0x280 - - /* - * Inbound Translations - * offset 300 - */ -#define TSI148_LCSR_IT0_ITSAU 0x300 -#define TSI148_LCSR_IT0_ITSAL 0x304 -#define TSI148_LCSR_IT0_ITEAU 0x308 -#define TSI148_LCSR_IT0_ITEAL 0x30C -#define TSI148_LCSR_IT0_ITOFU 0x310 -#define TSI148_LCSR_IT0_ITOFL 0x314 -#define TSI148_LCSR_IT0_ITAT 0x318 - -#define TSI148_LCSR_IT1_ITSAU 0x320 -#define TSI148_LCSR_IT1_ITSAL 0x324 -#define TSI148_LCSR_IT1_ITEAU 0x328 -#define TSI148_LCSR_IT1_ITEAL 0x32C -#define TSI148_LCSR_IT1_ITOFU 0x330 -#define TSI148_LCSR_IT1_ITOFL 0x334 -#define TSI148_LCSR_IT1_ITAT 0x338 - -#define TSI148_LCSR_IT2_ITSAU 0x340 -#define TSI148_LCSR_IT2_ITSAL 0x344 -#define TSI148_LCSR_IT2_ITEAU 0x348 -#define TSI148_LCSR_IT2_ITEAL 0x34C -#define TSI148_LCSR_IT2_ITOFU 0x350 -#define TSI148_LCSR_IT2_ITOFL 0x354 -#define TSI148_LCSR_IT2_ITAT 0x358 - -#define TSI148_LCSR_IT3_ITSAU 0x360 -#define TSI148_LCSR_IT3_ITSAL 0x364 -#define TSI148_LCSR_IT3_ITEAU 0x368 -#define TSI148_LCSR_IT3_ITEAL 0x36C -#define TSI148_LCSR_IT3_ITOFU 0x370 -#define TSI148_LCSR_IT3_ITOFL 0x374 -#define TSI148_LCSR_IT3_ITAT 0x378 - -#define TSI148_LCSR_IT4_ITSAU 0x380 -#define TSI148_LCSR_IT4_ITSAL 0x384 -#define TSI148_LCSR_IT4_ITEAU 0x388 -#define TSI148_LCSR_IT4_ITEAL 0x38C -#define TSI148_LCSR_IT4_ITOFU 0x390 -#define TSI148_LCSR_IT4_ITOFL 0x394 -#define TSI148_LCSR_IT4_ITAT 0x398 - -#define TSI148_LCSR_IT5_ITSAU 0x3A0 -#define TSI148_LCSR_IT5_ITSAL 0x3A4 -#define TSI148_LCSR_IT5_ITEAU 0x3A8 -#define TSI148_LCSR_IT5_ITEAL 0x3AC -#define TSI148_LCSR_IT5_ITOFU 0x3B0 -#define TSI148_LCSR_IT5_ITOFL 0x3B4 -#define TSI148_LCSR_IT5_ITAT 0x3B8 - -#define TSI148_LCSR_IT6_ITSAU 0x3C0 -#define TSI148_LCSR_IT6_ITSAL 0x3C4 -#define TSI148_LCSR_IT6_ITEAU 0x3C8 -#define TSI148_LCSR_IT6_ITEAL 0x3CC -#define TSI148_LCSR_IT6_ITOFU 0x3D0 -#define TSI148_LCSR_IT6_ITOFL 0x3D4 -#define TSI148_LCSR_IT6_ITAT 0x3D8 - -#define TSI148_LCSR_IT7_ITSAU 0x3E0 -#define TSI148_LCSR_IT7_ITSAL 0x3E4 -#define TSI148_LCSR_IT7_ITEAU 0x3E8 -#define TSI148_LCSR_IT7_ITEAL 0x3EC -#define TSI148_LCSR_IT7_ITOFU 0x3F0 -#define TSI148_LCSR_IT7_ITOFL 0x3F4 -#define TSI148_LCSR_IT7_ITAT 0x3F8 - - -#define TSI148_LCSR_IT0 0x300 -#define TSI148_LCSR_IT1 0x320 -#define TSI148_LCSR_IT2 0x340 -#define TSI148_LCSR_IT3 0x360 -#define TSI148_LCSR_IT4 0x380 -#define TSI148_LCSR_IT5 0x3A0 -#define TSI148_LCSR_IT6 0x3C0 -#define TSI148_LCSR_IT7 0x3E0 - -static const int TSI148_LCSR_IT[8] = { TSI148_LCSR_IT0, TSI148_LCSR_IT1, - TSI148_LCSR_IT2, TSI148_LCSR_IT3, - TSI148_LCSR_IT4, TSI148_LCSR_IT5, - TSI148_LCSR_IT6, TSI148_LCSR_IT7 }; - -#define TSI148_LCSR_OFFSET_ITSAU 0x0 -#define TSI148_LCSR_OFFSET_ITSAL 0x4 -#define TSI148_LCSR_OFFSET_ITEAU 0x8 -#define TSI148_LCSR_OFFSET_ITEAL 0xC -#define TSI148_LCSR_OFFSET_ITOFU 0x10 -#define TSI148_LCSR_OFFSET_ITOFL 0x14 -#define TSI148_LCSR_OFFSET_ITAT 0x18 - - /* - * Inbound Translation GCSR - * offset 400 - */ -#define TSI148_LCSR_GBAU 0x400 -#define TSI148_LCSR_GBAL 0x404 -#define TSI148_LCSR_GCSRAT 0x408 - - /* - * Inbound Translation CRG - * offset 40C - */ -#define TSI148_LCSR_CBAU 0x40C -#define TSI148_LCSR_CBAL 0x410 -#define TSI148_LCSR_CSRAT 0x414 - - /* - * Inbound Translation CR/CSR - * CRG - * offset 418 - */ -#define TSI148_LCSR_CROU 0x418 -#define TSI148_LCSR_CROL 0x41C -#define TSI148_LCSR_CRAT 0x420 - - /* - * Inbound Translation Location Monitor - * offset 424 - */ -#define TSI148_LCSR_LMBAU 0x424 -#define TSI148_LCSR_LMBAL 0x428 -#define TSI148_LCSR_LMAT 0x42C - - /* - * VMEbus Interrupt Control. - * offset 430 - */ -#define TSI148_LCSR_BCU 0x430 -#define TSI148_LCSR_BCL 0x434 -#define TSI148_LCSR_BPGTR 0x438 -#define TSI148_LCSR_BPCTR 0x43C -#define TSI148_LCSR_VICR 0x440 - - /* - * Local Bus Interrupt Control. - * offset 448 - */ -#define TSI148_LCSR_INTEN 0x448 -#define TSI148_LCSR_INTEO 0x44C -#define TSI148_LCSR_INTS 0x450 -#define TSI148_LCSR_INTC 0x454 -#define TSI148_LCSR_INTM1 0x458 -#define TSI148_LCSR_INTM2 0x45C - - /* - * DMA Controllers - * offset 500 - */ -#define TSI148_LCSR_DCTL0 0x500 -#define TSI148_LCSR_DSTA0 0x504 -#define TSI148_LCSR_DCSAU0 0x508 -#define TSI148_LCSR_DCSAL0 0x50C -#define TSI148_LCSR_DCDAU0 0x510 -#define TSI148_LCSR_DCDAL0 0x514 -#define TSI148_LCSR_DCLAU0 0x518 -#define TSI148_LCSR_DCLAL0 0x51C -#define TSI148_LCSR_DSAU0 0x520 -#define TSI148_LCSR_DSAL0 0x524 -#define TSI148_LCSR_DDAU0 0x528 -#define TSI148_LCSR_DDAL0 0x52C -#define TSI148_LCSR_DSAT0 0x530 -#define TSI148_LCSR_DDAT0 0x534 -#define TSI148_LCSR_DNLAU0 0x538 -#define TSI148_LCSR_DNLAL0 0x53C -#define TSI148_LCSR_DCNT0 0x540 -#define TSI148_LCSR_DDBS0 0x544 - -#define TSI148_LCSR_DCTL1 0x580 -#define TSI148_LCSR_DSTA1 0x584 -#define TSI148_LCSR_DCSAU1 0x588 -#define TSI148_LCSR_DCSAL1 0x58C -#define TSI148_LCSR_DCDAU1 0x590 -#define TSI148_LCSR_DCDAL1 0x594 -#define TSI148_LCSR_DCLAU1 0x598 -#define TSI148_LCSR_DCLAL1 0x59C -#define TSI148_LCSR_DSAU1 0x5A0 -#define TSI148_LCSR_DSAL1 0x5A4 -#define TSI148_LCSR_DDAU1 0x5A8 -#define TSI148_LCSR_DDAL1 0x5AC -#define TSI148_LCSR_DSAT1 0x5B0 -#define TSI148_LCSR_DDAT1 0x5B4 -#define TSI148_LCSR_DNLAU1 0x5B8 -#define TSI148_LCSR_DNLAL1 0x5BC -#define TSI148_LCSR_DCNT1 0x5C0 -#define TSI148_LCSR_DDBS1 0x5C4 - -#define TSI148_LCSR_DMA0 0x500 -#define TSI148_LCSR_DMA1 0x580 - - -static const int TSI148_LCSR_DMA[TSI148_MAX_DMA] = { TSI148_LCSR_DMA0, - TSI148_LCSR_DMA1 }; - -#define TSI148_LCSR_OFFSET_DCTL 0x0 -#define TSI148_LCSR_OFFSET_DSTA 0x4 -#define TSI148_LCSR_OFFSET_DCSAU 0x8 -#define TSI148_LCSR_OFFSET_DCSAL 0xC -#define TSI148_LCSR_OFFSET_DCDAU 0x10 -#define TSI148_LCSR_OFFSET_DCDAL 0x14 -#define TSI148_LCSR_OFFSET_DCLAU 0x18 -#define TSI148_LCSR_OFFSET_DCLAL 0x1C -#define TSI148_LCSR_OFFSET_DSAU 0x20 -#define TSI148_LCSR_OFFSET_DSAL 0x24 -#define TSI148_LCSR_OFFSET_DDAU 0x28 -#define TSI148_LCSR_OFFSET_DDAL 0x2C -#define TSI148_LCSR_OFFSET_DSAT 0x30 -#define TSI148_LCSR_OFFSET_DDAT 0x34 -#define TSI148_LCSR_OFFSET_DNLAU 0x38 -#define TSI148_LCSR_OFFSET_DNLAL 0x3C -#define TSI148_LCSR_OFFSET_DCNT 0x40 -#define TSI148_LCSR_OFFSET_DDBS 0x44 - - /* - * GCSR Register Group - */ - - /* - * GCSR CRG - * offset 00 600 - DEVI/VENI - * offset 04 604 - CTRL/GA/REVID - * offset 08 608 - Semaphore3/2/1/0 - * offset 0C 60C - Seamphore7/6/5/4 - */ -#define TSI148_GCSR_ID 0x600 -#define TSI148_GCSR_CSR 0x604 -#define TSI148_GCSR_SEMA0 0x608 -#define TSI148_GCSR_SEMA1 0x60C - - /* - * Mail Box - * GCSR CRG - * offset 10 610 - Mailbox0 - */ -#define TSI148_GCSR_MBOX0 0x610 -#define TSI148_GCSR_MBOX1 0x614 -#define TSI148_GCSR_MBOX2 0x618 -#define TSI148_GCSR_MBOX3 0x61C - -static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, - TSI148_GCSR_MBOX1, - TSI148_GCSR_MBOX2, - TSI148_GCSR_MBOX3 }; - - /* - * CR/CSR - */ - - /* - * CR/CSR CRG - * offset 7FFF4 FF4 - CSRBCR - * offset 7FFF8 FF8 - CSRBSR - * offset 7FFFC FFC - CBAR - */ -#define TSI148_CSRBCR 0xFF4 -#define TSI148_CSRBSR 0xFF8 -#define TSI148_CBAR 0xFFC - - - - - /* - * TSI148 Register Bit Definitions - */ - - /* - * PFCS Register Set - */ -#define TSI148_PCFS_CMMD_SERR (1<<8) /* SERR_L out pin ssys err */ -#define TSI148_PCFS_CMMD_PERR (1<<6) /* PERR_L out pin parity */ -#define TSI148_PCFS_CMMD_MSTR (1<<2) /* PCI bus master */ -#define TSI148_PCFS_CMMD_MEMSP (1<<1) /* PCI mem space access */ -#define TSI148_PCFS_CMMD_IOSP (1<<0) /* PCI I/O space enable */ - -#define TSI148_PCFS_STAT_RCPVE (1<<15) /* Detected Parity Error */ -#define TSI148_PCFS_STAT_SIGSE (1<<14) /* Signalled System Error */ -#define TSI148_PCFS_STAT_RCVMA (1<<13) /* Received Master Abort */ -#define TSI148_PCFS_STAT_RCVTA (1<<12) /* Received Target Abort */ -#define TSI148_PCFS_STAT_SIGTA (1<<11) /* Signalled Target Abort */ -#define TSI148_PCFS_STAT_SELTIM (3<<9) /* DELSEL Timing */ -#define TSI148_PCFS_STAT_DPAR (1<<8) /* Data Parity Err Reported */ -#define TSI148_PCFS_STAT_FAST (1<<7) /* Fast back-to-back Cap */ -#define TSI148_PCFS_STAT_P66M (1<<5) /* 66 MHz Capable */ -#define TSI148_PCFS_STAT_CAPL (1<<4) /* Capab List - address $34 */ - -/* - * Revision ID/Class Code Registers (CRG +$008) - */ -#define TSI148_PCFS_CLAS_M (0xFF<<24) /* Class ID */ -#define TSI148_PCFS_SUBCLAS_M (0xFF<<16) /* Sub-Class ID */ -#define TSI148_PCFS_PROGIF_M (0xFF<<8) /* Sub-Class ID */ -#define TSI148_PCFS_REVID_M (0xFF<<0) /* Rev ID */ - -/* - * Cache Line Size/ Master Latency Timer/ Header Type Registers (CRG + $00C) - */ -#define TSI148_PCFS_HEAD_M (0xFF<<16) /* Master Lat Timer */ -#define TSI148_PCFS_MLAT_M (0xFF<<8) /* Master Lat Timer */ -#define TSI148_PCFS_CLSZ_M (0xFF<<0) /* Cache Line Size */ - -/* - * Memory Base Address Lower Reg (CRG + $010) - */ -#define TSI148_PCFS_MBARL_BASEL_M (0xFFFFF<<12) /* Base Addr Lower Mask */ -#define TSI148_PCFS_MBARL_PRE (1<<3) /* Prefetch */ -#define TSI148_PCFS_MBARL_MTYPE_M (3<<1) /* Memory Type Mask */ -#define TSI148_PCFS_MBARL_IOMEM (1<<0) /* I/O Space Indicator */ - -/* - * Message Signaled Interrupt Capabilities Register (CRG + $040) - */ -#define TSI148_PCFS_MSICAP_64BAC (1<<7) /* 64-bit Address Capable */ -#define TSI148_PCFS_MSICAP_MME_M (7<<4) /* Multiple Msg Enable Mask */ -#define TSI148_PCFS_MSICAP_MMC_M (7<<1) /* Multiple Msg Capable Mask */ -#define TSI148_PCFS_MSICAP_MSIEN (1<<0) /* Msg signaled INT Enable */ - -/* - * Message Address Lower Register (CRG +$044) - */ -#define TSI148_PCFS_MSIAL_M (0x3FFFFFFF<<2) /* Mask */ - -/* - * Message Data Register (CRG + 4C) - */ -#define TSI148_PCFS_MSIMD_M (0xFFFF<<0) /* Mask */ - -/* - * PCI-X Capabilities Register (CRG + $050) - */ -#define TSI148_PCFS_PCIXCAP_MOST_M (7<<4) /* Max outstanding Split Tran */ -#define TSI148_PCFS_PCIXCAP_MMRBC_M (3<<2) /* Max Mem Read byte cnt */ -#define TSI148_PCFS_PCIXCAP_ERO (1<<1) /* Enable Relaxed Ordering */ -#define TSI148_PCFS_PCIXCAP_DPERE (1<<0) /* Data Parity Recover Enable */ - -/* - * PCI-X Status Register (CRG +$054) - */ -#define TSI148_PCFS_PCIXSTAT_RSCEM (1<<29) /* Received Split Comp Error */ -#define TSI148_PCFS_PCIXSTAT_DMCRS_M (7<<26) /* max Cumulative Read Size */ -#define TSI148_PCFS_PCIXSTAT_DMOST_M (7<<23) /* max outstanding Split Trans - */ -#define TSI148_PCFS_PCIXSTAT_DMMRC_M (3<<21) /* max mem read byte count */ -#define TSI148_PCFS_PCIXSTAT_DC (1<<20) /* Device Complexity */ -#define TSI148_PCFS_PCIXSTAT_USC (1<<19) /* Unexpected Split comp */ -#define TSI148_PCFS_PCIXSTAT_SCD (1<<18) /* Split completion discard */ -#define TSI148_PCFS_PCIXSTAT_133C (1<<17) /* 133MHz capable */ -#define TSI148_PCFS_PCIXSTAT_64D (1<<16) /* 64 bit device */ -#define TSI148_PCFS_PCIXSTAT_BN_M (0xFF<<8) /* Bus number */ -#define TSI148_PCFS_PCIXSTAT_DN_M (0x1F<<3) /* Device number */ -#define TSI148_PCFS_PCIXSTAT_FN_M (7<<0) /* Function Number */ - -/* - * LCSR Registers - */ - -/* - * Outbound Translation Starting Address Lower - */ -#define TSI148_LCSR_OTSAL_M (0xFFFF<<16) /* Mask */ - -/* - * Outbound Translation Ending Address Lower - */ -#define TSI148_LCSR_OTEAL_M (0xFFFF<<16) /* Mask */ - -/* - * Outbound Translation Offset Lower - */ -#define TSI148_LCSR_OTOFFL_M (0xFFFF<<16) /* Mask */ - -/* - * Outbound Translation 2eSST Broadcast Select - */ -#define TSI148_LCSR_OTBS_M (0xFFFFF<<0) /* Mask */ - -/* - * Outbound Translation Attribute - */ -#define TSI148_LCSR_OTAT_EN (1<<31) /* Window Enable */ -#define TSI148_LCSR_OTAT_MRPFD (1<<18) /* Prefetch Disable */ - -#define TSI148_LCSR_OTAT_PFS_M (3<<16) /* Prefetch Size Mask */ -#define TSI148_LCSR_OTAT_PFS_2 (0<<16) /* 2 Cache Lines P Size */ -#define TSI148_LCSR_OTAT_PFS_4 (1<<16) /* 4 Cache Lines P Size */ -#define TSI148_LCSR_OTAT_PFS_8 (2<<16) /* 8 Cache Lines P Size */ -#define TSI148_LCSR_OTAT_PFS_16 (3<<16) /* 16 Cache Lines P Size */ - -#define TSI148_LCSR_OTAT_2eSSTM_M (7<<11) /* 2eSST Xfer Rate Mask */ -#define TSI148_LCSR_OTAT_2eSSTM_160 (0<<11) /* 160MB/s 2eSST Xfer Rate */ -#define TSI148_LCSR_OTAT_2eSSTM_267 (1<<11) /* 267MB/s 2eSST Xfer Rate */ -#define TSI148_LCSR_OTAT_2eSSTM_320 (2<<11) /* 320MB/s 2eSST Xfer Rate */ - -#define TSI148_LCSR_OTAT_TM_M (7<<8) /* Xfer Protocol Mask */ -#define TSI148_LCSR_OTAT_TM_SCT (0<<8) /* SCT Xfer Protocol */ -#define TSI148_LCSR_OTAT_TM_BLT (1<<8) /* BLT Xfer Protocol */ -#define TSI148_LCSR_OTAT_TM_MBLT (2<<8) /* MBLT Xfer Protocol */ -#define TSI148_LCSR_OTAT_TM_2eVME (3<<8) /* 2eVME Xfer Protocol */ -#define TSI148_LCSR_OTAT_TM_2eSST (4<<8) /* 2eSST Xfer Protocol */ -#define TSI148_LCSR_OTAT_TM_2eSSTB (5<<8) /* 2eSST Bcast Xfer Protocol */ - -#define TSI148_LCSR_OTAT_DBW_M (3<<6) /* Max Data Width */ -#define TSI148_LCSR_OTAT_DBW_16 (0<<6) /* 16-bit Data Width */ -#define TSI148_LCSR_OTAT_DBW_32 (1<<6) /* 32-bit Data Width */ - -#define TSI148_LCSR_OTAT_SUP (1<<5) /* Supervisory Access */ -#define TSI148_LCSR_OTAT_PGM (1<<4) /* Program Access */ - -#define TSI148_LCSR_OTAT_AMODE_M (0xf<<0) /* Address Mode Mask */ -#define TSI148_LCSR_OTAT_AMODE_A16 (0<<0) /* A16 Address Space */ -#define TSI148_LCSR_OTAT_AMODE_A24 (1<<0) /* A24 Address Space */ -#define TSI148_LCSR_OTAT_AMODE_A32 (2<<0) /* A32 Address Space */ -#define TSI148_LCSR_OTAT_AMODE_A64 (4<<0) /* A32 Address Space */ -#define TSI148_LCSR_OTAT_AMODE_CRCSR (5<<0) /* CR/CSR Address Space */ -#define TSI148_LCSR_OTAT_AMODE_USER1 (8<<0) /* User1 Address Space */ -#define TSI148_LCSR_OTAT_AMODE_USER2 (9<<0) /* User2 Address Space */ -#define TSI148_LCSR_OTAT_AMODE_USER3 (10<<0) /* User3 Address Space */ -#define TSI148_LCSR_OTAT_AMODE_USER4 (11<<0) /* User4 Address Space */ - -/* - * VME Master Control Register CRG+$234 - */ -#define TSI148_LCSR_VMCTRL_VSA (1<<27) /* VMEbus Stop Ack */ -#define TSI148_LCSR_VMCTRL_VS (1<<26) /* VMEbus Stop */ -#define TSI148_LCSR_VMCTRL_DHB (1<<25) /* Device Has Bus */ -#define TSI148_LCSR_VMCTRL_DWB (1<<24) /* Device Wants Bus */ - -#define TSI148_LCSR_VMCTRL_RMWEN (1<<20) /* RMW Enable */ - -#define TSI148_LCSR_VMCTRL_ATO_M (7<<16) /* Master Access Time-out Mask - */ -#define TSI148_LCSR_VMCTRL_ATO_32 (0<<16) /* 32 us */ -#define TSI148_LCSR_VMCTRL_ATO_128 (1<<16) /* 128 us */ -#define TSI148_LCSR_VMCTRL_ATO_512 (2<<16) /* 512 us */ -#define TSI148_LCSR_VMCTRL_ATO_2M (3<<16) /* 2 ms */ -#define TSI148_LCSR_VMCTRL_ATO_8M (4<<16) /* 8 ms */ -#define TSI148_LCSR_VMCTRL_ATO_32M (5<<16) /* 32 ms */ -#define TSI148_LCSR_VMCTRL_ATO_128M (6<<16) /* 128 ms */ -#define TSI148_LCSR_VMCTRL_ATO_DIS (7<<16) /* Disabled */ - -#define TSI148_LCSR_VMCTRL_VTOFF_M (7<<12) /* VMEbus Master Time off */ -#define TSI148_LCSR_VMCTRL_VTOFF_0 (0<<12) /* 0us */ -#define TSI148_LCSR_VMCTRL_VTOFF_1 (1<<12) /* 1us */ -#define TSI148_LCSR_VMCTRL_VTOFF_2 (2<<12) /* 2us */ -#define TSI148_LCSR_VMCTRL_VTOFF_4 (3<<12) /* 4us */ -#define TSI148_LCSR_VMCTRL_VTOFF_8 (4<<12) /* 8us */ -#define TSI148_LCSR_VMCTRL_VTOFF_16 (5<<12) /* 16us */ -#define TSI148_LCSR_VMCTRL_VTOFF_32 (6<<12) /* 32us */ -#define TSI148_LCSR_VMCTRL_VTOFF_64 (7<<12) /* 64us */ - -#define TSI148_LCSR_VMCTRL_VTON_M (7<<8) /* VMEbus Master Time On */ -#define TSI148_LCSR_VMCTRL_VTON_4 (0<<8) /* 8us */ -#define TSI148_LCSR_VMCTRL_VTON_8 (1<<8) /* 8us */ -#define TSI148_LCSR_VMCTRL_VTON_16 (2<<8) /* 16us */ -#define TSI148_LCSR_VMCTRL_VTON_32 (3<<8) /* 32us */ -#define TSI148_LCSR_VMCTRL_VTON_64 (4<<8) /* 64us */ -#define TSI148_LCSR_VMCTRL_VTON_128 (5<<8) /* 128us */ -#define TSI148_LCSR_VMCTRL_VTON_256 (6<<8) /* 256us */ -#define TSI148_LCSR_VMCTRL_VTON_512 (7<<8) /* 512us */ - -#define TSI148_LCSR_VMCTRL_VREL_M (3<<3) /* VMEbus Master Rel Mode Mask - */ -#define TSI148_LCSR_VMCTRL_VREL_T_D (0<<3) /* Time on or Done */ -#define TSI148_LCSR_VMCTRL_VREL_T_R_D (1<<3) /* Time on and REQ or Done */ -#define TSI148_LCSR_VMCTRL_VREL_T_B_D (2<<3) /* Time on and BCLR or Done */ -#define TSI148_LCSR_VMCTRL_VREL_T_D_R (3<<3) /* Time on or Done and REQ */ - -#define TSI148_LCSR_VMCTRL_VFAIR (1<<2) /* VMEbus Master Fair Mode */ -#define TSI148_LCSR_VMCTRL_VREQL_M (3<<0) /* VMEbus Master Req Level Mask - */ - -/* - * VMEbus Control Register CRG+$238 - */ -#define TSI148_LCSR_VCTRL_LRE (1<<31) /* Late Retry Enable */ - -#define TSI148_LCSR_VCTRL_DLT_M (0xF<<24) /* Deadlock Timer */ -#define TSI148_LCSR_VCTRL_DLT_OFF (0<<24) /* Deadlock Timer Off */ -#define TSI148_LCSR_VCTRL_DLT_16 (1<<24) /* 16 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_32 (2<<24) /* 32 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_64 (3<<24) /* 64 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_128 (4<<24) /* 128 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_256 (5<<24) /* 256 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_512 (6<<24) /* 512 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_1024 (7<<24) /* 1024 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_2048 (8<<24) /* 2048 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_4096 (9<<24) /* 4096 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_8192 (0xA<<24) /* 8192 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_16384 (0xB<<24) /* 16384 VCLKS */ -#define TSI148_LCSR_VCTRL_DLT_32768 (0xC<<24) /* 32768 VCLKS */ - -#define TSI148_LCSR_VCTRL_NERBB (1<<20) /* No Early Release of Bus Busy - */ - -#define TSI148_LCSR_VCTRL_SRESET (1<<17) /* System Reset */ -#define TSI148_LCSR_VCTRL_LRESET (1<<16) /* Local Reset */ - -#define TSI148_LCSR_VCTRL_SFAILAI (1<<15) /* SYSFAIL Auto Slot ID */ -#define TSI148_LCSR_VCTRL_BID_M (0x1F<<8) /* Broadcast ID Mask */ - -#define TSI148_LCSR_VCTRL_ATOEN (1<<7) /* Arbiter Time-out Enable */ -#define TSI148_LCSR_VCTRL_ROBIN (1<<6) /* VMEbus Round Robin */ - -#define TSI148_LCSR_VCTRL_GTO_M (7<<0) /* VMEbus Global Time-out Mask - */ -#define TSI148_LCSR_VCTRL_GTO_8 (0<<0) /* 8 us */ -#define TSI148_LCSR_VCTRL_GTO_16 (1<<0) /* 16 us */ -#define TSI148_LCSR_VCTRL_GTO_32 (2<<0) /* 32 us */ -#define TSI148_LCSR_VCTRL_GTO_64 (3<<0) /* 64 us */ -#define TSI148_LCSR_VCTRL_GTO_128 (4<<0) /* 128 us */ -#define TSI148_LCSR_VCTRL_GTO_256 (5<<0) /* 256 us */ -#define TSI148_LCSR_VCTRL_GTO_512 (6<<0) /* 512 us */ -#define TSI148_LCSR_VCTRL_GTO_DIS (7<<0) /* Disabled */ - -/* - * VMEbus Status Register CRG + $23C - */ -#define TSI148_LCSR_VSTAT_CPURST (1<<15) /* Clear power up reset */ -#define TSI148_LCSR_VSTAT_BRDFL (1<<14) /* Board fail */ -#define TSI148_LCSR_VSTAT_PURSTS (1<<12) /* Power up reset status */ -#define TSI148_LCSR_VSTAT_BDFAILS (1<<11) /* Board Fail Status */ -#define TSI148_LCSR_VSTAT_SYSFAILS (1<<10) /* System Fail Status */ -#define TSI148_LCSR_VSTAT_ACFAILS (1<<9) /* AC fail status */ -#define TSI148_LCSR_VSTAT_SCONS (1<<8) /* System Cont Status */ -#define TSI148_LCSR_VSTAT_GAP (1<<5) /* Geographic Addr Parity */ -#define TSI148_LCSR_VSTAT_GA_M (0x1F<<0) /* Geographic Addr Mask */ - -/* - * PCI Configuration Status Register CRG+$240 - */ -#define TSI148_LCSR_PSTAT_REQ64S (1<<6) /* Request 64 status set */ -#define TSI148_LCSR_PSTAT_M66ENS (1<<5) /* M66ENS 66Mhz enable */ -#define TSI148_LCSR_PSTAT_FRAMES (1<<4) /* Frame Status */ -#define TSI148_LCSR_PSTAT_IRDYS (1<<3) /* IRDY status */ -#define TSI148_LCSR_PSTAT_DEVSELS (1<<2) /* DEVL status */ -#define TSI148_LCSR_PSTAT_STOPS (1<<1) /* STOP status */ -#define TSI148_LCSR_PSTAT_TRDYS (1<<0) /* TRDY status */ - -/* - * VMEbus Exception Attributes Register CRG + $268 - */ -#define TSI148_LCSR_VEAT_VES (1<<31) /* Status */ -#define TSI148_LCSR_VEAT_VEOF (1<<30) /* Overflow */ -#define TSI148_LCSR_VEAT_VESCL (1<<29) /* Status Clear */ -#define TSI148_LCSR_VEAT_2EOT (1<<21) /* 2e Odd Termination */ -#define TSI148_LCSR_VEAT_2EST (1<<20) /* 2e Slave terminated */ -#define TSI148_LCSR_VEAT_BERR (1<<19) /* Bus Error */ -#define TSI148_LCSR_VEAT_LWORD (1<<18) /* LWORD_ signal state */ -#define TSI148_LCSR_VEAT_WRITE (1<<17) /* WRITE_ signal state */ -#define TSI148_LCSR_VEAT_IACK (1<<16) /* IACK_ signal state */ -#define TSI148_LCSR_VEAT_DS1 (1<<15) /* DS1_ signal state */ -#define TSI148_LCSR_VEAT_DS0 (1<<14) /* DS0_ signal state */ -#define TSI148_LCSR_VEAT_AM_M (0x3F<<8) /* Address Mode Mask */ -#define TSI148_LCSR_VEAT_XAM_M (0xFF<<0) /* Master AMode Mask */ - - -/* - * VMEbus PCI Error Diagnostics PCI/X Attributes Register CRG + $280 - */ -#define TSI148_LCSR_EDPAT_EDPCL (1<<29) - -/* - * Inbound Translation Starting Address Lower - */ -#define TSI148_LCSR_ITSAL6432_M (0xFFFF<<16) /* Mask */ -#define TSI148_LCSR_ITSAL24_M (0x00FFF<<12) /* Mask */ -#define TSI148_LCSR_ITSAL16_M (0x0000FFF<<4) /* Mask */ - -/* - * Inbound Translation Ending Address Lower - */ -#define TSI148_LCSR_ITEAL6432_M (0xFFFF<<16) /* Mask */ -#define TSI148_LCSR_ITEAL24_M (0x00FFF<<12) /* Mask */ -#define TSI148_LCSR_ITEAL16_M (0x0000FFF<<4) /* Mask */ - -/* - * Inbound Translation Offset Lower - */ -#define TSI148_LCSR_ITOFFL6432_M (0xFFFF<<16) /* Mask */ -#define TSI148_LCSR_ITOFFL24_M (0xFFFFF<<12) /* Mask */ -#define TSI148_LCSR_ITOFFL16_M (0xFFFFFFF<<4) /* Mask */ - -/* - * Inbound Translation Attribute - */ -#define TSI148_LCSR_ITAT_EN (1<<31) /* Window Enable */ -#define TSI148_LCSR_ITAT_TH (1<<18) /* Prefetch Threshold */ - -#define TSI148_LCSR_ITAT_VFS_M (3<<16) /* Virtual FIFO Size Mask */ -#define TSI148_LCSR_ITAT_VFS_64 (0<<16) /* 64 bytes Virtual FIFO Size */ -#define TSI148_LCSR_ITAT_VFS_128 (1<<16) /* 128 bytes Virtual FIFO Sz */ -#define TSI148_LCSR_ITAT_VFS_256 (2<<16) /* 256 bytes Virtual FIFO Sz */ -#define TSI148_LCSR_ITAT_VFS_512 (3<<16) /* 512 bytes Virtual FIFO Sz */ - -#define TSI148_LCSR_ITAT_2eSSTM_M (7<<12) /* 2eSST Xfer Rate Mask */ -#define TSI148_LCSR_ITAT_2eSSTM_160 (0<<12) /* 160MB/s 2eSST Xfer Rate */ -#define TSI148_LCSR_ITAT_2eSSTM_267 (1<<12) /* 267MB/s 2eSST Xfer Rate */ -#define TSI148_LCSR_ITAT_2eSSTM_320 (2<<12) /* 320MB/s 2eSST Xfer Rate */ - -#define TSI148_LCSR_ITAT_2eSSTB (1<<11) /* 2eSST Bcast Xfer Protocol */ -#define TSI148_LCSR_ITAT_2eSST (1<<10) /* 2eSST Xfer Protocol */ -#define TSI148_LCSR_ITAT_2eVME (1<<9) /* 2eVME Xfer Protocol */ -#define TSI148_LCSR_ITAT_MBLT (1<<8) /* MBLT Xfer Protocol */ -#define TSI148_LCSR_ITAT_BLT (1<<7) /* BLT Xfer Protocol */ - -#define TSI148_LCSR_ITAT_AS_M (7<<4) /* Address Space Mask */ -#define TSI148_LCSR_ITAT_AS_A16 (0<<4) /* A16 Address Space */ -#define TSI148_LCSR_ITAT_AS_A24 (1<<4) /* A24 Address Space */ -#define TSI148_LCSR_ITAT_AS_A32 (2<<4) /* A32 Address Space */ -#define TSI148_LCSR_ITAT_AS_A64 (4<<4) /* A64 Address Space */ - -#define TSI148_LCSR_ITAT_SUPR (1<<3) /* Supervisor Access */ -#define TSI148_LCSR_ITAT_NPRIV (1<<2) /* Non-Priv (User) Access */ -#define TSI148_LCSR_ITAT_PGM (1<<1) /* Program Access */ -#define TSI148_LCSR_ITAT_DATA (1<<0) /* Data Access */ - -/* - * GCSR Base Address Lower Address CRG +$404 - */ -#define TSI148_LCSR_GBAL_M (0x7FFFFFF<<5) /* Mask */ - -/* - * GCSR Attribute Register CRG + $408 - */ -#define TSI148_LCSR_GCSRAT_EN (1<<7) /* Enable access to GCSR */ - -#define TSI148_LCSR_GCSRAT_AS_M (7<<4) /* Address Space Mask */ -#define TSI148_LCSR_GCSRAT_AS_A16 (0<<4) /* Address Space 16 */ -#define TSI148_LCSR_GCSRAT_AS_A24 (1<<4) /* Address Space 24 */ -#define TSI148_LCSR_GCSRAT_AS_A32 (2<<4) /* Address Space 32 */ -#define TSI148_LCSR_GCSRAT_AS_A64 (4<<4) /* Address Space 64 */ - -#define TSI148_LCSR_GCSRAT_SUPR (1<<3) /* Sup set -GCSR decoder */ -#define TSI148_LCSR_GCSRAT_NPRIV (1<<2) /* Non-Privliged set - CGSR */ -#define TSI148_LCSR_GCSRAT_PGM (1<<1) /* Program set - GCSR decoder */ -#define TSI148_LCSR_GCSRAT_DATA (1<<0) /* DATA set GCSR decoder */ - -/* - * CRG Base Address Lower Address CRG + $410 - */ -#define TSI148_LCSR_CBAL_M (0xFFFFF<<12) - -/* - * CRG Attribute Register CRG + $414 - */ -#define TSI148_LCSR_CRGAT_EN (1<<7) /* Enable PRG Access */ - -#define TSI148_LCSR_CRGAT_AS_M (7<<4) /* Address Space */ -#define TSI148_LCSR_CRGAT_AS_A16 (0<<4) /* Address Space 16 */ -#define TSI148_LCSR_CRGAT_AS_A24 (1<<4) /* Address Space 24 */ -#define TSI148_LCSR_CRGAT_AS_A32 (2<<4) /* Address Space 32 */ -#define TSI148_LCSR_CRGAT_AS_A64 (4<<4) /* Address Space 64 */ - -#define TSI148_LCSR_CRGAT_SUPR (1<<3) /* Supervisor Access */ -#define TSI148_LCSR_CRGAT_NPRIV (1<<2) /* Non-Privliged(User) Access */ -#define TSI148_LCSR_CRGAT_PGM (1<<1) /* Program Access */ -#define TSI148_LCSR_CRGAT_DATA (1<<0) /* Data Access */ - -/* - * CR/CSR Offset Lower Register CRG + $41C - */ -#define TSI148_LCSR_CROL_M (0x1FFF<<19) /* Mask */ - -/* - * CR/CSR Attribute register CRG + $420 - */ -#define TSI148_LCSR_CRAT_EN (1<<7) /* Enable access to CR/CSR */ - -/* - * Location Monitor base address lower register CRG + $428 - */ -#define TSI148_LCSR_LMBAL_M (0x7FFFFFF<<5) /* Mask */ - -/* - * Location Monitor Attribute Register CRG + $42C - */ -#define TSI148_LCSR_LMAT_EN (1<<7) /* Enable Location Monitor */ - -#define TSI148_LCSR_LMAT_AS_M (7<<4) /* Address Space MASK */ -#define TSI148_LCSR_LMAT_AS_A16 (0<<4) /* A16 */ -#define TSI148_LCSR_LMAT_AS_A24 (1<<4) /* A24 */ -#define TSI148_LCSR_LMAT_AS_A32 (2<<4) /* A32 */ -#define TSI148_LCSR_LMAT_AS_A64 (4<<4) /* A64 */ - -#define TSI148_LCSR_LMAT_SUPR (1<<3) /* Supervisor Access */ -#define TSI148_LCSR_LMAT_NPRIV (1<<2) /* Non-Priv (User) Access */ -#define TSI148_LCSR_LMAT_PGM (1<<1) /* Program Access */ -#define TSI148_LCSR_LMAT_DATA (1<<0) /* Data Access */ - -/* - * Broadcast Pulse Generator Timer Register CRG + $438 - */ -#define TSI148_LCSR_BPGTR_BPGT_M (0xFFFF<<0) /* Mask */ - -/* - * Broadcast Programmable Clock Timer Register CRG + $43C - */ -#define TSI148_LCSR_BPCTR_BPCT_M (0xFFFFFF<<0) /* Mask */ - -/* - * VMEbus Interrupt Control Register CRG + $43C - */ -#define TSI148_LCSR_VICR_CNTS_M (3<<22) /* Cntr Source MASK */ -#define TSI148_LCSR_VICR_CNTS_DIS (1<<22) /* Cntr Disable */ -#define TSI148_LCSR_VICR_CNTS_IRQ1 (2<<22) /* IRQ1 to Cntr */ -#define TSI148_LCSR_VICR_CNTS_IRQ2 (3<<22) /* IRQ2 to Cntr */ - -#define TSI148_LCSR_VICR_EDGIS_M (3<<20) /* Edge interrupt MASK */ -#define TSI148_LCSR_VICR_EDGIS_DIS (1<<20) /* Edge interrupt Disable */ -#define TSI148_LCSR_VICR_EDGIS_IRQ1 (2<<20) /* IRQ1 to Edge */ -#define TSI148_LCSR_VICR_EDGIS_IRQ2 (3<<20) /* IRQ2 to Edge */ - -#define TSI148_LCSR_VICR_IRQIF_M (3<<18) /* IRQ1* Function MASK */ -#define TSI148_LCSR_VICR_IRQIF_NORM (1<<18) /* Normal */ -#define TSI148_LCSR_VICR_IRQIF_PULSE (2<<18) /* Pulse Generator */ -#define TSI148_LCSR_VICR_IRQIF_PROG (3<<18) /* Programmable Clock */ -#define TSI148_LCSR_VICR_IRQIF_1U (4<<18) /* 1us Clock */ - -#define TSI148_LCSR_VICR_IRQ2F_M (3<<16) /* IRQ2* Function MASK */ -#define TSI148_LCSR_VICR_IRQ2F_NORM (1<<16) /* Normal */ -#define TSI148_LCSR_VICR_IRQ2F_PULSE (2<<16) /* Pulse Generator */ -#define TSI148_LCSR_VICR_IRQ2F_PROG (3<<16) /* Programmable Clock */ -#define TSI148_LCSR_VICR_IRQ2F_1U (4<<16) /* 1us Clock */ - -#define TSI148_LCSR_VICR_BIP (1<<15) /* Broadcast Interrupt Pulse */ - -#define TSI148_LCSR_VICR_IRQC (1<<12) /* VMEbus IRQ Clear */ -#define TSI148_LCSR_VICR_IRQS (1<<11) /* VMEbus IRQ Status */ - -#define TSI148_LCSR_VICR_IRQL_M (7<<8) /* VMEbus SW IRQ Level Mask */ -#define TSI148_LCSR_VICR_IRQL_1 (1<<8) /* VMEbus SW IRQ Level 1 */ -#define TSI148_LCSR_VICR_IRQL_2 (2<<8) /* VMEbus SW IRQ Level 2 */ -#define TSI148_LCSR_VICR_IRQL_3 (3<<8) /* VMEbus SW IRQ Level 3 */ -#define TSI148_LCSR_VICR_IRQL_4 (4<<8) /* VMEbus SW IRQ Level 4 */ -#define TSI148_LCSR_VICR_IRQL_5 (5<<8) /* VMEbus SW IRQ Level 5 */ -#define TSI148_LCSR_VICR_IRQL_6 (6<<8) /* VMEbus SW IRQ Level 6 */ -#define TSI148_LCSR_VICR_IRQL_7 (7<<8) /* VMEbus SW IRQ Level 7 */ - -static const int TSI148_LCSR_VICR_IRQL[8] = { 0, TSI148_LCSR_VICR_IRQL_1, - TSI148_LCSR_VICR_IRQL_2, TSI148_LCSR_VICR_IRQL_3, - TSI148_LCSR_VICR_IRQL_4, TSI148_LCSR_VICR_IRQL_5, - TSI148_LCSR_VICR_IRQL_6, TSI148_LCSR_VICR_IRQL_7 }; - -#define TSI148_LCSR_VICR_STID_M (0xFF<<0) /* Status/ID Mask */ - -/* - * Interrupt Enable Register CRG + $440 - */ -#define TSI148_LCSR_INTEN_DMA1EN (1<<25) /* DMAC 1 */ -#define TSI148_LCSR_INTEN_DMA0EN (1<<24) /* DMAC 0 */ -#define TSI148_LCSR_INTEN_LM3EN (1<<23) /* Location Monitor 3 */ -#define TSI148_LCSR_INTEN_LM2EN (1<<22) /* Location Monitor 2 */ -#define TSI148_LCSR_INTEN_LM1EN (1<<21) /* Location Monitor 1 */ -#define TSI148_LCSR_INTEN_LM0EN (1<<20) /* Location Monitor 0 */ -#define TSI148_LCSR_INTEN_MB3EN (1<<19) /* Mail Box 3 */ -#define TSI148_LCSR_INTEN_MB2EN (1<<18) /* Mail Box 2 */ -#define TSI148_LCSR_INTEN_MB1EN (1<<17) /* Mail Box 1 */ -#define TSI148_LCSR_INTEN_MB0EN (1<<16) /* Mail Box 0 */ -#define TSI148_LCSR_INTEN_PERREN (1<<13) /* PCI/X Error */ -#define TSI148_LCSR_INTEN_VERREN (1<<12) /* VMEbus Error */ -#define TSI148_LCSR_INTEN_VIEEN (1<<11) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTEN_IACKEN (1<<10) /* IACK */ -#define TSI148_LCSR_INTEN_SYSFLEN (1<<9) /* System Fail */ -#define TSI148_LCSR_INTEN_ACFLEN (1<<8) /* AC Fail */ -#define TSI148_LCSR_INTEN_IRQ7EN (1<<7) /* IRQ7 */ -#define TSI148_LCSR_INTEN_IRQ6EN (1<<6) /* IRQ6 */ -#define TSI148_LCSR_INTEN_IRQ5EN (1<<5) /* IRQ5 */ -#define TSI148_LCSR_INTEN_IRQ4EN (1<<4) /* IRQ4 */ -#define TSI148_LCSR_INTEN_IRQ3EN (1<<3) /* IRQ3 */ -#define TSI148_LCSR_INTEN_IRQ2EN (1<<2) /* IRQ2 */ -#define TSI148_LCSR_INTEN_IRQ1EN (1<<1) /* IRQ1 */ - -static const int TSI148_LCSR_INTEN_LMEN[4] = { TSI148_LCSR_INTEN_LM0EN, - TSI148_LCSR_INTEN_LM1EN, - TSI148_LCSR_INTEN_LM2EN, - TSI148_LCSR_INTEN_LM3EN }; - -static const int TSI148_LCSR_INTEN_IRQEN[7] = { TSI148_LCSR_INTEN_IRQ1EN, - TSI148_LCSR_INTEN_IRQ2EN, - TSI148_LCSR_INTEN_IRQ3EN, - TSI148_LCSR_INTEN_IRQ4EN, - TSI148_LCSR_INTEN_IRQ5EN, - TSI148_LCSR_INTEN_IRQ6EN, - TSI148_LCSR_INTEN_IRQ7EN }; - -/* - * Interrupt Enable Out Register CRG + $444 - */ -#define TSI148_LCSR_INTEO_DMA1EO (1<<25) /* DMAC 1 */ -#define TSI148_LCSR_INTEO_DMA0EO (1<<24) /* DMAC 0 */ -#define TSI148_LCSR_INTEO_LM3EO (1<<23) /* Loc Monitor 3 */ -#define TSI148_LCSR_INTEO_LM2EO (1<<22) /* Loc Monitor 2 */ -#define TSI148_LCSR_INTEO_LM1EO (1<<21) /* Loc Monitor 1 */ -#define TSI148_LCSR_INTEO_LM0EO (1<<20) /* Location Monitor 0 */ -#define TSI148_LCSR_INTEO_MB3EO (1<<19) /* Mail Box 3 */ -#define TSI148_LCSR_INTEO_MB2EO (1<<18) /* Mail Box 2 */ -#define TSI148_LCSR_INTEO_MB1EO (1<<17) /* Mail Box 1 */ -#define TSI148_LCSR_INTEO_MB0EO (1<<16) /* Mail Box 0 */ -#define TSI148_LCSR_INTEO_PERREO (1<<13) /* PCI/X Error */ -#define TSI148_LCSR_INTEO_VERREO (1<<12) /* VMEbus Error */ -#define TSI148_LCSR_INTEO_VIEEO (1<<11) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTEO_IACKEO (1<<10) /* IACK */ -#define TSI148_LCSR_INTEO_SYSFLEO (1<<9) /* System Fail */ -#define TSI148_LCSR_INTEO_ACFLEO (1<<8) /* AC Fail */ -#define TSI148_LCSR_INTEO_IRQ7EO (1<<7) /* IRQ7 */ -#define TSI148_LCSR_INTEO_IRQ6EO (1<<6) /* IRQ6 */ -#define TSI148_LCSR_INTEO_IRQ5EO (1<<5) /* IRQ5 */ -#define TSI148_LCSR_INTEO_IRQ4EO (1<<4) /* IRQ4 */ -#define TSI148_LCSR_INTEO_IRQ3EO (1<<3) /* IRQ3 */ -#define TSI148_LCSR_INTEO_IRQ2EO (1<<2) /* IRQ2 */ -#define TSI148_LCSR_INTEO_IRQ1EO (1<<1) /* IRQ1 */ - -static const int TSI148_LCSR_INTEO_LMEO[4] = { TSI148_LCSR_INTEO_LM0EO, - TSI148_LCSR_INTEO_LM1EO, - TSI148_LCSR_INTEO_LM2EO, - TSI148_LCSR_INTEO_LM3EO }; - -static const int TSI148_LCSR_INTEO_IRQEO[7] = { TSI148_LCSR_INTEO_IRQ1EO, - TSI148_LCSR_INTEO_IRQ2EO, - TSI148_LCSR_INTEO_IRQ3EO, - TSI148_LCSR_INTEO_IRQ4EO, - TSI148_LCSR_INTEO_IRQ5EO, - TSI148_LCSR_INTEO_IRQ6EO, - TSI148_LCSR_INTEO_IRQ7EO }; - -/* - * Interrupt Status Register CRG + $448 - */ -#define TSI148_LCSR_INTS_DMA1S (1<<25) /* DMA 1 */ -#define TSI148_LCSR_INTS_DMA0S (1<<24) /* DMA 0 */ -#define TSI148_LCSR_INTS_LM3S (1<<23) /* Location Monitor 3 */ -#define TSI148_LCSR_INTS_LM2S (1<<22) /* Location Monitor 2 */ -#define TSI148_LCSR_INTS_LM1S (1<<21) /* Location Monitor 1 */ -#define TSI148_LCSR_INTS_LM0S (1<<20) /* Location Monitor 0 */ -#define TSI148_LCSR_INTS_MB3S (1<<19) /* Mail Box 3 */ -#define TSI148_LCSR_INTS_MB2S (1<<18) /* Mail Box 2 */ -#define TSI148_LCSR_INTS_MB1S (1<<17) /* Mail Box 1 */ -#define TSI148_LCSR_INTS_MB0S (1<<16) /* Mail Box 0 */ -#define TSI148_LCSR_INTS_PERRS (1<<13) /* PCI/X Error */ -#define TSI148_LCSR_INTS_VERRS (1<<12) /* VMEbus Error */ -#define TSI148_LCSR_INTS_VIES (1<<11) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTS_IACKS (1<<10) /* IACK */ -#define TSI148_LCSR_INTS_SYSFLS (1<<9) /* System Fail */ -#define TSI148_LCSR_INTS_ACFLS (1<<8) /* AC Fail */ -#define TSI148_LCSR_INTS_IRQ7S (1<<7) /* IRQ7 */ -#define TSI148_LCSR_INTS_IRQ6S (1<<6) /* IRQ6 */ -#define TSI148_LCSR_INTS_IRQ5S (1<<5) /* IRQ5 */ -#define TSI148_LCSR_INTS_IRQ4S (1<<4) /* IRQ4 */ -#define TSI148_LCSR_INTS_IRQ3S (1<<3) /* IRQ3 */ -#define TSI148_LCSR_INTS_IRQ2S (1<<2) /* IRQ2 */ -#define TSI148_LCSR_INTS_IRQ1S (1<<1) /* IRQ1 */ - -static const int TSI148_LCSR_INTS_LMS[4] = { TSI148_LCSR_INTS_LM0S, - TSI148_LCSR_INTS_LM1S, - TSI148_LCSR_INTS_LM2S, - TSI148_LCSR_INTS_LM3S }; - -static const int TSI148_LCSR_INTS_MBS[4] = { TSI148_LCSR_INTS_MB0S, - TSI148_LCSR_INTS_MB1S, - TSI148_LCSR_INTS_MB2S, - TSI148_LCSR_INTS_MB3S }; - -/* - * Interrupt Clear Register CRG + $44C - */ -#define TSI148_LCSR_INTC_DMA1C (1<<25) /* DMA 1 */ -#define TSI148_LCSR_INTC_DMA0C (1<<24) /* DMA 0 */ -#define TSI148_LCSR_INTC_LM3C (1<<23) /* Location Monitor 3 */ -#define TSI148_LCSR_INTC_LM2C (1<<22) /* Location Monitor 2 */ -#define TSI148_LCSR_INTC_LM1C (1<<21) /* Location Monitor 1 */ -#define TSI148_LCSR_INTC_LM0C (1<<20) /* Location Monitor 0 */ -#define TSI148_LCSR_INTC_MB3C (1<<19) /* Mail Box 3 */ -#define TSI148_LCSR_INTC_MB2C (1<<18) /* Mail Box 2 */ -#define TSI148_LCSR_INTC_MB1C (1<<17) /* Mail Box 1 */ -#define TSI148_LCSR_INTC_MB0C (1<<16) /* Mail Box 0 */ -#define TSI148_LCSR_INTC_PERRC (1<<13) /* VMEbus Error */ -#define TSI148_LCSR_INTC_VERRC (1<<12) /* VMEbus Access Time-out */ -#define TSI148_LCSR_INTC_VIEC (1<<11) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTC_IACKC (1<<10) /* IACK */ -#define TSI148_LCSR_INTC_SYSFLC (1<<9) /* System Fail */ -#define TSI148_LCSR_INTC_ACFLC (1<<8) /* AC Fail */ - -static const int TSI148_LCSR_INTC_LMC[4] = { TSI148_LCSR_INTC_LM0C, - TSI148_LCSR_INTC_LM1C, - TSI148_LCSR_INTC_LM2C, - TSI148_LCSR_INTC_LM3C }; - -static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, - TSI148_LCSR_INTC_MB1C, - TSI148_LCSR_INTC_MB2C, - TSI148_LCSR_INTC_MB3C }; - -/* - * Interrupt Map Register 1 CRG + $458 - */ -#define TSI148_LCSR_INTM1_DMA1M_M (3<<18) /* DMA 1 */ -#define TSI148_LCSR_INTM1_DMA0M_M (3<<16) /* DMA 0 */ -#define TSI148_LCSR_INTM1_LM3M_M (3<<14) /* Location Monitor 3 */ -#define TSI148_LCSR_INTM1_LM2M_M (3<<12) /* Location Monitor 2 */ -#define TSI148_LCSR_INTM1_LM1M_M (3<<10) /* Location Monitor 1 */ -#define TSI148_LCSR_INTM1_LM0M_M (3<<8) /* Location Monitor 0 */ -#define TSI148_LCSR_INTM1_MB3M_M (3<<6) /* Mail Box 3 */ -#define TSI148_LCSR_INTM1_MB2M_M (3<<4) /* Mail Box 2 */ -#define TSI148_LCSR_INTM1_MB1M_M (3<<2) /* Mail Box 1 */ -#define TSI148_LCSR_INTM1_MB0M_M (3<<0) /* Mail Box 0 */ - -/* - * Interrupt Map Register 2 CRG + $45C - */ -#define TSI148_LCSR_INTM2_PERRM_M (3<<26) /* PCI Bus Error */ -#define TSI148_LCSR_INTM2_VERRM_M (3<<24) /* VMEbus Error */ -#define TSI148_LCSR_INTM2_VIEM_M (3<<22) /* VMEbus IRQ Edge */ -#define TSI148_LCSR_INTM2_IACKM_M (3<<20) /* IACK */ -#define TSI148_LCSR_INTM2_SYSFLM_M (3<<18) /* System Fail */ -#define TSI148_LCSR_INTM2_ACFLM_M (3<<16) /* AC Fail */ -#define TSI148_LCSR_INTM2_IRQ7M_M (3<<14) /* IRQ7 */ -#define TSI148_LCSR_INTM2_IRQ6M_M (3<<12) /* IRQ6 */ -#define TSI148_LCSR_INTM2_IRQ5M_M (3<<10) /* IRQ5 */ -#define TSI148_LCSR_INTM2_IRQ4M_M (3<<8) /* IRQ4 */ -#define TSI148_LCSR_INTM2_IRQ3M_M (3<<6) /* IRQ3 */ -#define TSI148_LCSR_INTM2_IRQ2M_M (3<<4) /* IRQ2 */ -#define TSI148_LCSR_INTM2_IRQ1M_M (3<<2) /* IRQ1 */ - -/* - * DMA Control (0-1) Registers CRG + $500 - */ -#define TSI148_LCSR_DCTL_ABT (1<<27) /* Abort */ -#define TSI148_LCSR_DCTL_PAU (1<<26) /* Pause */ -#define TSI148_LCSR_DCTL_DGO (1<<25) /* DMA Go */ - -#define TSI148_LCSR_DCTL_MOD (1<<23) /* Mode */ - -#define TSI148_LCSR_DCTL_VBKS_M (7<<12) /* VMEbus block Size MASK */ -#define TSI148_LCSR_DCTL_VBKS_32 (0<<12) /* VMEbus block Size 32 */ -#define TSI148_LCSR_DCTL_VBKS_64 (1<<12) /* VMEbus block Size 64 */ -#define TSI148_LCSR_DCTL_VBKS_128 (2<<12) /* VMEbus block Size 128 */ -#define TSI148_LCSR_DCTL_VBKS_256 (3<<12) /* VMEbus block Size 256 */ -#define TSI148_LCSR_DCTL_VBKS_512 (4<<12) /* VMEbus block Size 512 */ -#define TSI148_LCSR_DCTL_VBKS_1024 (5<<12) /* VMEbus block Size 1024 */ -#define TSI148_LCSR_DCTL_VBKS_2048 (6<<12) /* VMEbus block Size 2048 */ -#define TSI148_LCSR_DCTL_VBKS_4096 (7<<12) /* VMEbus block Size 4096 */ - -#define TSI148_LCSR_DCTL_VBOT_M (7<<8) /* VMEbus back-off MASK */ -#define TSI148_LCSR_DCTL_VBOT_0 (0<<8) /* VMEbus back-off 0us */ -#define TSI148_LCSR_DCTL_VBOT_1 (1<<8) /* VMEbus back-off 1us */ -#define TSI148_LCSR_DCTL_VBOT_2 (2<<8) /* VMEbus back-off 2us */ -#define TSI148_LCSR_DCTL_VBOT_4 (3<<8) /* VMEbus back-off 4us */ -#define TSI148_LCSR_DCTL_VBOT_8 (4<<8) /* VMEbus back-off 8us */ -#define TSI148_LCSR_DCTL_VBOT_16 (5<<8) /* VMEbus back-off 16us */ -#define TSI148_LCSR_DCTL_VBOT_32 (6<<8) /* VMEbus back-off 32us */ -#define TSI148_LCSR_DCTL_VBOT_64 (7<<8) /* VMEbus back-off 64us */ - -#define TSI148_LCSR_DCTL_PBKS_M (7<<4) /* PCI block size MASK */ -#define TSI148_LCSR_DCTL_PBKS_32 (0<<4) /* PCI block size 32 bytes */ -#define TSI148_LCSR_DCTL_PBKS_64 (1<<4) /* PCI block size 64 bytes */ -#define TSI148_LCSR_DCTL_PBKS_128 (2<<4) /* PCI block size 128 bytes */ -#define TSI148_LCSR_DCTL_PBKS_256 (3<<4) /* PCI block size 256 bytes */ -#define TSI148_LCSR_DCTL_PBKS_512 (4<<4) /* PCI block size 512 bytes */ -#define TSI148_LCSR_DCTL_PBKS_1024 (5<<4) /* PCI block size 1024 bytes */ -#define TSI148_LCSR_DCTL_PBKS_2048 (6<<4) /* PCI block size 2048 bytes */ -#define TSI148_LCSR_DCTL_PBKS_4096 (7<<4) /* PCI block size 4096 bytes */ - -#define TSI148_LCSR_DCTL_PBOT_M (7<<0) /* PCI back off MASK */ -#define TSI148_LCSR_DCTL_PBOT_0 (0<<0) /* PCI back off 0us */ -#define TSI148_LCSR_DCTL_PBOT_1 (1<<0) /* PCI back off 1us */ -#define TSI148_LCSR_DCTL_PBOT_2 (2<<0) /* PCI back off 2us */ -#define TSI148_LCSR_DCTL_PBOT_4 (3<<0) /* PCI back off 3us */ -#define TSI148_LCSR_DCTL_PBOT_8 (4<<0) /* PCI back off 4us */ -#define TSI148_LCSR_DCTL_PBOT_16 (5<<0) /* PCI back off 8us */ -#define TSI148_LCSR_DCTL_PBOT_32 (6<<0) /* PCI back off 16us */ -#define TSI148_LCSR_DCTL_PBOT_64 (7<<0) /* PCI back off 32us */ - -/* - * DMA Status Registers (0-1) CRG + $504 - */ -#define TSI148_LCSR_DSTA_SMA (1<<31) /* PCI Signalled Master Abt */ -#define TSI148_LCSR_DSTA_RTA (1<<30) /* PCI Received Target Abt */ -#define TSI148_LCSR_DSTA_MRC (1<<29) /* PCI Max Retry Count */ -#define TSI148_LCSR_DSTA_VBE (1<<28) /* VMEbus error */ -#define TSI148_LCSR_DSTA_ABT (1<<27) /* Abort */ -#define TSI148_LCSR_DSTA_PAU (1<<26) /* Pause */ -#define TSI148_LCSR_DSTA_DON (1<<25) /* Done */ -#define TSI148_LCSR_DSTA_BSY (1<<24) /* Busy */ - -/* - * DMA Current Link Address Lower (0-1) - */ -#define TSI148_LCSR_DCLAL_M (0x3FFFFFF<<6) /* Mask */ - -/* - * DMA Source Attribute (0-1) Reg - */ -#define TSI148_LCSR_DSAT_TYP_M (3<<28) /* Source Bus Type */ -#define TSI148_LCSR_DSAT_TYP_PCI (0<<28) /* PCI Bus */ -#define TSI148_LCSR_DSAT_TYP_VME (1<<28) /* VMEbus */ -#define TSI148_LCSR_DSAT_TYP_PAT (2<<28) /* Data Pattern */ - -#define TSI148_LCSR_DSAT_PSZ (1<<25) /* Pattern Size */ -#define TSI148_LCSR_DSAT_NIN (1<<24) /* No Increment */ - -#define TSI148_LCSR_DSAT_2eSSTM_M (3<<11) /* 2eSST Trans Rate Mask */ -#define TSI148_LCSR_DSAT_2eSSTM_160 (0<<11) /* 160 MB/s */ -#define TSI148_LCSR_DSAT_2eSSTM_267 (1<<11) /* 267 MB/s */ -#define TSI148_LCSR_DSAT_2eSSTM_320 (2<<11) /* 320 MB/s */ - -#define TSI148_LCSR_DSAT_TM_M (7<<8) /* Bus Transfer Protocol Mask */ -#define TSI148_LCSR_DSAT_TM_SCT (0<<8) /* SCT */ -#define TSI148_LCSR_DSAT_TM_BLT (1<<8) /* BLT */ -#define TSI148_LCSR_DSAT_TM_MBLT (2<<8) /* MBLT */ -#define TSI148_LCSR_DSAT_TM_2eVME (3<<8) /* 2eVME */ -#define TSI148_LCSR_DSAT_TM_2eSST (4<<8) /* 2eSST */ -#define TSI148_LCSR_DSAT_TM_2eSSTB (5<<8) /* 2eSST Broadcast */ - -#define TSI148_LCSR_DSAT_DBW_M (3<<6) /* Max Data Width MASK */ -#define TSI148_LCSR_DSAT_DBW_16 (0<<6) /* 16 Bits */ -#define TSI148_LCSR_DSAT_DBW_32 (1<<6) /* 32 Bits */ - -#define TSI148_LCSR_DSAT_SUP (1<<5) /* Supervisory Mode */ -#define TSI148_LCSR_DSAT_PGM (1<<4) /* Program Mode */ - -#define TSI148_LCSR_DSAT_AMODE_M (0xf<<0) /* Address Space Mask */ -#define TSI148_LCSR_DSAT_AMODE_A16 (0<<0) /* A16 */ -#define TSI148_LCSR_DSAT_AMODE_A24 (1<<0) /* A24 */ -#define TSI148_LCSR_DSAT_AMODE_A32 (2<<0) /* A32 */ -#define TSI148_LCSR_DSAT_AMODE_A64 (4<<0) /* A64 */ -#define TSI148_LCSR_DSAT_AMODE_CRCSR (5<<0) /* CR/CSR */ -#define TSI148_LCSR_DSAT_AMODE_USER1 (8<<0) /* User1 */ -#define TSI148_LCSR_DSAT_AMODE_USER2 (9<<0) /* User2 */ -#define TSI148_LCSR_DSAT_AMODE_USER3 (0xa<<0) /* User3 */ -#define TSI148_LCSR_DSAT_AMODE_USER4 (0xb<<0) /* User4 */ - -/* - * DMA Destination Attribute Registers (0-1) - */ -#define TSI148_LCSR_DDAT_TYP_PCI (0<<28) /* Destination PCI Bus */ -#define TSI148_LCSR_DDAT_TYP_VME (1<<28) /* Destination VMEbus */ - -#define TSI148_LCSR_DDAT_2eSSTM_M (3<<11) /* 2eSST Transfer Rate Mask */ -#define TSI148_LCSR_DDAT_2eSSTM_160 (0<<11) /* 160 MB/s */ -#define TSI148_LCSR_DDAT_2eSSTM_267 (1<<11) /* 267 MB/s */ -#define TSI148_LCSR_DDAT_2eSSTM_320 (2<<11) /* 320 MB/s */ - -#define TSI148_LCSR_DDAT_TM_M (7<<8) /* Bus Transfer Protocol Mask */ -#define TSI148_LCSR_DDAT_TM_SCT (0<<8) /* SCT */ -#define TSI148_LCSR_DDAT_TM_BLT (1<<8) /* BLT */ -#define TSI148_LCSR_DDAT_TM_MBLT (2<<8) /* MBLT */ -#define TSI148_LCSR_DDAT_TM_2eVME (3<<8) /* 2eVME */ -#define TSI148_LCSR_DDAT_TM_2eSST (4<<8) /* 2eSST */ -#define TSI148_LCSR_DDAT_TM_2eSSTB (5<<8) /* 2eSST Broadcast */ - -#define TSI148_LCSR_DDAT_DBW_M (3<<6) /* Max Data Width MASK */ -#define TSI148_LCSR_DDAT_DBW_16 (0<<6) /* 16 Bits */ -#define TSI148_LCSR_DDAT_DBW_32 (1<<6) /* 32 Bits */ - -#define TSI148_LCSR_DDAT_SUP (1<<5) /* Supervisory/User Access */ -#define TSI148_LCSR_DDAT_PGM (1<<4) /* Program/Data Access */ - -#define TSI148_LCSR_DDAT_AMODE_M (0xf<<0) /* Address Space Mask */ -#define TSI148_LCSR_DDAT_AMODE_A16 (0<<0) /* A16 */ -#define TSI148_LCSR_DDAT_AMODE_A24 (1<<0) /* A24 */ -#define TSI148_LCSR_DDAT_AMODE_A32 (2<<0) /* A32 */ -#define TSI148_LCSR_DDAT_AMODE_A64 (4<<0) /* A64 */ -#define TSI148_LCSR_DDAT_AMODE_CRCSR (5<<0) /* CRC/SR */ -#define TSI148_LCSR_DDAT_AMODE_USER1 (8<<0) /* User1 */ -#define TSI148_LCSR_DDAT_AMODE_USER2 (9<<0) /* User2 */ -#define TSI148_LCSR_DDAT_AMODE_USER3 (0xa<<0) /* User3 */ -#define TSI148_LCSR_DDAT_AMODE_USER4 (0xb<<0) /* User4 */ - -/* - * DMA Next Link Address Lower - */ -#define TSI148_LCSR_DNLAL_DNLAL_M (0x3FFFFFF<<6) /* Address Mask */ -#define TSI148_LCSR_DNLAL_LLA (1<<0) /* Last Link Address Indicator */ - -/* - * DMA 2eSST Broadcast Select - */ -#define TSI148_LCSR_DBS_M (0x1FFFFF<<0) /* Mask */ - -/* - * GCSR Register Group - */ - -/* - * GCSR Control and Status Register CRG + $604 - */ -#define TSI148_GCSR_GCTRL_LRST (1<<15) /* Local Reset */ -#define TSI148_GCSR_GCTRL_SFAILEN (1<<14) /* System Fail enable */ -#define TSI148_GCSR_GCTRL_BDFAILS (1<<13) /* Board Fail Status */ -#define TSI148_GCSR_GCTRL_SCON (1<<12) /* System Copntroller */ -#define TSI148_GCSR_GCTRL_MEN (1<<11) /* Module Enable (READY) */ - -#define TSI148_GCSR_GCTRL_LMI3S (1<<7) /* Loc Monitor 3 Int Status */ -#define TSI148_GCSR_GCTRL_LMI2S (1<<6) /* Loc Monitor 2 Int Status */ -#define TSI148_GCSR_GCTRL_LMI1S (1<<5) /* Loc Monitor 1 Int Status */ -#define TSI148_GCSR_GCTRL_LMI0S (1<<4) /* Loc Monitor 0 Int Status */ -#define TSI148_GCSR_GCTRL_MBI3S (1<<3) /* Mail box 3 Int Status */ -#define TSI148_GCSR_GCTRL_MBI2S (1<<2) /* Mail box 2 Int Status */ -#define TSI148_GCSR_GCTRL_MBI1S (1<<1) /* Mail box 1 Int Status */ -#define TSI148_GCSR_GCTRL_MBI0S (1<<0) /* Mail box 0 Int Status */ - -#define TSI148_GCSR_GAP (1<<5) /* Geographic Addr Parity */ -#define TSI148_GCSR_GA_M (0x1F<<0) /* Geographic Address Mask */ - -/* - * CR/CSR Register Group - */ - -/* - * CR/CSR Bit Clear Register CRG + $FF4 - */ -#define TSI148_CRCSR_CSRBCR_LRSTC (1<<7) /* Local Reset Clear */ -#define TSI148_CRCSR_CSRBCR_SFAILC (1<<6) /* System Fail Enable Clear */ -#define TSI148_CRCSR_CSRBCR_BDFAILS (1<<5) /* Board Fail Status */ -#define TSI148_CRCSR_CSRBCR_MENC (1<<4) /* Module Enable Clear */ -#define TSI148_CRCSR_CSRBCR_BERRSC (1<<3) /* Bus Error Status Clear */ - -/* - * CR/CSR Bit Set Register CRG+$FF8 - */ -#define TSI148_CRCSR_CSRBSR_LISTS (1<<7) /* Local Reset Clear */ -#define TSI148_CRCSR_CSRBSR_SFAILS (1<<6) /* System Fail Enable Clear */ -#define TSI148_CRCSR_CSRBSR_BDFAILS (1<<5) /* Board Fail Status */ -#define TSI148_CRCSR_CSRBSR_MENS (1<<4) /* Module Enable Clear */ -#define TSI148_CRCSR_CSRBSR_BERRS (1<<3) /* Bus Error Status Clear */ - -/* - * CR/CSR Base Address Register CRG + FFC - */ -#define TSI148_CRCSR_CBAR_M (0x1F<<3) /* Mask */ - -#endif /* TSI148_H */ diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c deleted file mode 100644 index 8dba20186be3..000000000000 --- a/drivers/vme/vme.c +++ /dev/null @@ -1,2015 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * VME Bridge Framework - * - * Author: Martyn Welch - * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. - * - * Based on work by Tom Armistead and Ajit Prem - * Copyright 2004 Motorola Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vme_bridge.h" - -/* Bitmask and list of registered buses both protected by common mutex */ -static unsigned int vme_bus_numbers; -static LIST_HEAD(vme_bus_list); -static DEFINE_MUTEX(vme_buses_lock); - -static int __init vme_init(void); - -static struct vme_dev *dev_to_vme_dev(struct device *dev) -{ - return container_of(dev, struct vme_dev, dev); -} - -/* - * Find the bridge that the resource is associated with. - */ -static struct vme_bridge *find_bridge(struct vme_resource *resource) -{ - /* Get list to search */ - switch (resource->type) { - case VME_MASTER: - return list_entry(resource->entry, struct vme_master_resource, - list)->parent; - case VME_SLAVE: - return list_entry(resource->entry, struct vme_slave_resource, - list)->parent; - case VME_DMA: - return list_entry(resource->entry, struct vme_dma_resource, - list)->parent; - case VME_LM: - return list_entry(resource->entry, struct vme_lm_resource, - list)->parent; - default: - printk(KERN_ERR "Unknown resource type\n"); - return NULL; - } -} - -/** - * vme_alloc_consistent - Allocate contiguous memory. - * @resource: Pointer to VME resource. - * @size: Size of allocation required. - * @dma: Pointer to variable to store physical address of allocation. - * - * Allocate a contiguous block of memory for use by the driver. This is used to - * create the buffers for the slave windows. - * - * Return: Virtual address of allocation on success, NULL on failure. - */ -void *vme_alloc_consistent(struct vme_resource *resource, size_t size, - dma_addr_t *dma) -{ - struct vme_bridge *bridge; - - if (!resource) { - printk(KERN_ERR "No resource\n"); - return NULL; - } - - bridge = find_bridge(resource); - if (!bridge) { - printk(KERN_ERR "Can't find bridge\n"); - return NULL; - } - - if (!bridge->parent) { - printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); - return NULL; - } - - if (!bridge->alloc_consistent) { - printk(KERN_ERR "alloc_consistent not supported by bridge %s\n", - bridge->name); - return NULL; - } - - return bridge->alloc_consistent(bridge->parent, size, dma); -} -EXPORT_SYMBOL(vme_alloc_consistent); - -/** - * vme_free_consistent - Free previously allocated memory. - * @resource: Pointer to VME resource. - * @size: Size of allocation to free. - * @vaddr: Virtual address of allocation. - * @dma: Physical address of allocation. - * - * Free previously allocated block of contiguous memory. - */ -void vme_free_consistent(struct vme_resource *resource, size_t size, - void *vaddr, dma_addr_t dma) -{ - struct vme_bridge *bridge; - - if (!resource) { - printk(KERN_ERR "No resource\n"); - return; - } - - bridge = find_bridge(resource); - if (!bridge) { - printk(KERN_ERR "Can't find bridge\n"); - return; - } - - if (!bridge->parent) { - printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); - return; - } - - if (!bridge->free_consistent) { - printk(KERN_ERR "free_consistent not supported by bridge %s\n", - bridge->name); - return; - } - - bridge->free_consistent(bridge->parent, size, vaddr, dma); -} -EXPORT_SYMBOL(vme_free_consistent); - -/** - * vme_get_size - Helper function returning size of a VME window - * @resource: Pointer to VME slave or master resource. - * - * Determine the size of the VME window provided. This is a helper - * function, wrappering the call to vme_master_get or vme_slave_get - * depending on the type of window resource handed to it. - * - * Return: Size of the window on success, zero on failure. - */ -size_t vme_get_size(struct vme_resource *resource) -{ - int enabled, retval; - unsigned long long base, size; - dma_addr_t buf_base; - u32 aspace, cycle, dwidth; - - switch (resource->type) { - case VME_MASTER: - retval = vme_master_get(resource, &enabled, &base, &size, - &aspace, &cycle, &dwidth); - if (retval) - return 0; - - return size; - case VME_SLAVE: - retval = vme_slave_get(resource, &enabled, &base, &size, - &buf_base, &aspace, &cycle); - if (retval) - return 0; - - return size; - case VME_DMA: - return 0; - default: - printk(KERN_ERR "Unknown resource type\n"); - return 0; - } -} -EXPORT_SYMBOL(vme_get_size); - -int vme_check_window(u32 aspace, unsigned long long vme_base, - unsigned long long size) -{ - int retval = 0; - - if (vme_base + size < size) - return -EINVAL; - - switch (aspace) { - case VME_A16: - if (vme_base + size > VME_A16_MAX) - retval = -EFAULT; - break; - case VME_A24: - if (vme_base + size > VME_A24_MAX) - retval = -EFAULT; - break; - case VME_A32: - if (vme_base + size > VME_A32_MAX) - retval = -EFAULT; - break; - case VME_A64: - /* The VME_A64_MAX limit is actually U64_MAX + 1 */ - break; - case VME_CRCSR: - if (vme_base + size > VME_CRCSR_MAX) - retval = -EFAULT; - break; - case VME_USER1: - case VME_USER2: - case VME_USER3: - case VME_USER4: - /* User Defined */ - break; - default: - printk(KERN_ERR "Invalid address space\n"); - retval = -EINVAL; - break; - } - - return retval; -} -EXPORT_SYMBOL(vme_check_window); - -static u32 vme_get_aspace(int am) -{ - switch (am) { - case 0x29: - case 0x2D: - return VME_A16; - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - return VME_A24; - case 0x8: - case 0x9: - case 0xA: - case 0xB: - case 0xC: - case 0xD: - case 0xE: - case 0xF: - return VME_A32; - case 0x0: - case 0x1: - case 0x3: - return VME_A64; - } - - return 0; -} - -/** - * vme_slave_request - Request a VME slave window resource. - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * @address: Required VME address space. - * @cycle: Required VME data transfer cycle type. - * - * Request use of a VME window resource capable of being set for the requested - * address space and data transfer cycle. - * - * Return: Pointer to VME resource on success, NULL on failure. - */ -struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, - u32 cycle) -{ - struct vme_bridge *bridge; - struct list_head *slave_pos = NULL; - struct vme_slave_resource *allocated_image = NULL; - struct vme_slave_resource *slave_image = NULL; - struct vme_resource *resource = NULL; - - bridge = vdev->bridge; - if (!bridge) { - printk(KERN_ERR "Can't find VME bus\n"); - goto err_bus; - } - - /* Loop through slave resources */ - list_for_each(slave_pos, &bridge->slave_resources) { - slave_image = list_entry(slave_pos, - struct vme_slave_resource, list); - - if (!slave_image) { - printk(KERN_ERR "Registered NULL Slave resource\n"); - continue; - } - - /* Find an unlocked and compatible image */ - mutex_lock(&slave_image->mtx); - if (((slave_image->address_attr & address) == address) && - ((slave_image->cycle_attr & cycle) == cycle) && - (slave_image->locked == 0)) { - - slave_image->locked = 1; - mutex_unlock(&slave_image->mtx); - allocated_image = slave_image; - break; - } - mutex_unlock(&slave_image->mtx); - } - - /* No free image */ - if (!allocated_image) - goto err_image; - - resource = kmalloc(sizeof(*resource), GFP_KERNEL); - if (!resource) - goto err_alloc; - - resource->type = VME_SLAVE; - resource->entry = &allocated_image->list; - - return resource; - -err_alloc: - /* Unlock image */ - mutex_lock(&slave_image->mtx); - slave_image->locked = 0; - mutex_unlock(&slave_image->mtx); -err_image: -err_bus: - return NULL; -} -EXPORT_SYMBOL(vme_slave_request); - -/** - * vme_slave_set - Set VME slave window configuration. - * @resource: Pointer to VME slave resource. - * @enabled: State to which the window should be configured. - * @vme_base: Base address for the window. - * @size: Size of the VME window. - * @buf_base: Based address of buffer used to provide VME slave window storage. - * @aspace: VME address space for the VME window. - * @cycle: VME data transfer cycle type for the VME window. - * - * Set configuration for provided VME slave window. - * - * Return: Zero on success, -EINVAL if operation is not supported on this - * device, if an invalid resource has been provided or invalid - * attributes are provided. Hardware specific errors may also be - * returned. - */ -int vme_slave_set(struct vme_resource *resource, int enabled, - unsigned long long vme_base, unsigned long long size, - dma_addr_t buf_base, u32 aspace, u32 cycle) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_slave_resource *image; - int retval; - - if (resource->type != VME_SLAVE) { - printk(KERN_ERR "Not a slave resource\n"); - return -EINVAL; - } - - image = list_entry(resource->entry, struct vme_slave_resource, list); - - if (!bridge->slave_set) { - printk(KERN_ERR "Function not supported\n"); - return -ENOSYS; - } - - if (!(((image->address_attr & aspace) == aspace) && - ((image->cycle_attr & cycle) == cycle))) { - printk(KERN_ERR "Invalid attributes\n"); - return -EINVAL; - } - - retval = vme_check_window(aspace, vme_base, size); - if (retval) - return retval; - - return bridge->slave_set(image, enabled, vme_base, size, buf_base, - aspace, cycle); -} -EXPORT_SYMBOL(vme_slave_set); - -/** - * vme_slave_get - Retrieve VME slave window configuration. - * @resource: Pointer to VME slave resource. - * @enabled: Pointer to variable for storing state. - * @vme_base: Pointer to variable for storing window base address. - * @size: Pointer to variable for storing window size. - * @buf_base: Pointer to variable for storing slave buffer base address. - * @aspace: Pointer to variable for storing VME address space. - * @cycle: Pointer to variable for storing VME data transfer cycle type. - * - * Return configuration for provided VME slave window. - * - * Return: Zero on success, -EINVAL if operation is not supported on this - * device or if an invalid resource has been provided. - */ -int vme_slave_get(struct vme_resource *resource, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - dma_addr_t *buf_base, u32 *aspace, u32 *cycle) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_slave_resource *image; - - if (resource->type != VME_SLAVE) { - printk(KERN_ERR "Not a slave resource\n"); - return -EINVAL; - } - - image = list_entry(resource->entry, struct vme_slave_resource, list); - - if (!bridge->slave_get) { - printk(KERN_ERR "vme_slave_get not supported\n"); - return -EINVAL; - } - - return bridge->slave_get(image, enabled, vme_base, size, buf_base, - aspace, cycle); -} -EXPORT_SYMBOL(vme_slave_get); - -/** - * vme_slave_free - Free VME slave window - * @resource: Pointer to VME slave resource. - * - * Free the provided slave resource so that it may be reallocated. - */ -void vme_slave_free(struct vme_resource *resource) -{ - struct vme_slave_resource *slave_image; - - if (resource->type != VME_SLAVE) { - printk(KERN_ERR "Not a slave resource\n"); - return; - } - - slave_image = list_entry(resource->entry, struct vme_slave_resource, - list); - if (!slave_image) { - printk(KERN_ERR "Can't find slave resource\n"); - return; - } - - /* Unlock image */ - mutex_lock(&slave_image->mtx); - if (slave_image->locked == 0) - printk(KERN_ERR "Image is already free\n"); - - slave_image->locked = 0; - mutex_unlock(&slave_image->mtx); - - /* Free up resource memory */ - kfree(resource); -} -EXPORT_SYMBOL(vme_slave_free); - -/** - * vme_master_request - Request a VME master window resource. - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * @address: Required VME address space. - * @cycle: Required VME data transfer cycle type. - * @dwidth: Required VME data transfer width. - * - * Request use of a VME window resource capable of being set for the requested - * address space, data transfer cycle and width. - * - * Return: Pointer to VME resource on success, NULL on failure. - */ -struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, - u32 cycle, u32 dwidth) -{ - struct vme_bridge *bridge; - struct list_head *master_pos = NULL; - struct vme_master_resource *allocated_image = NULL; - struct vme_master_resource *master_image = NULL; - struct vme_resource *resource = NULL; - - bridge = vdev->bridge; - if (!bridge) { - printk(KERN_ERR "Can't find VME bus\n"); - goto err_bus; - } - - /* Loop through master resources */ - list_for_each(master_pos, &bridge->master_resources) { - master_image = list_entry(master_pos, - struct vme_master_resource, list); - - if (!master_image) { - printk(KERN_WARNING "Registered NULL master resource\n"); - continue; - } - - /* Find an unlocked and compatible image */ - spin_lock(&master_image->lock); - if (((master_image->address_attr & address) == address) && - ((master_image->cycle_attr & cycle) == cycle) && - ((master_image->width_attr & dwidth) == dwidth) && - (master_image->locked == 0)) { - - master_image->locked = 1; - spin_unlock(&master_image->lock); - allocated_image = master_image; - break; - } - spin_unlock(&master_image->lock); - } - - /* Check to see if we found a resource */ - if (!allocated_image) { - printk(KERN_ERR "Can't find a suitable resource\n"); - goto err_image; - } - - resource = kmalloc(sizeof(*resource), GFP_KERNEL); - if (!resource) - goto err_alloc; - - resource->type = VME_MASTER; - resource->entry = &allocated_image->list; - - return resource; - -err_alloc: - /* Unlock image */ - spin_lock(&master_image->lock); - master_image->locked = 0; - spin_unlock(&master_image->lock); -err_image: -err_bus: - return NULL; -} -EXPORT_SYMBOL(vme_master_request); - -/** - * vme_master_set - Set VME master window configuration. - * @resource: Pointer to VME master resource. - * @enabled: State to which the window should be configured. - * @vme_base: Base address for the window. - * @size: Size of the VME window. - * @aspace: VME address space for the VME window. - * @cycle: VME data transfer cycle type for the VME window. - * @dwidth: VME data transfer width for the VME window. - * - * Set configuration for provided VME master window. - * - * Return: Zero on success, -EINVAL if operation is not supported on this - * device, if an invalid resource has been provided or invalid - * attributes are provided. Hardware specific errors may also be - * returned. - */ -int vme_master_set(struct vme_resource *resource, int enabled, - unsigned long long vme_base, unsigned long long size, u32 aspace, - u32 cycle, u32 dwidth) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_master_resource *image; - int retval; - - if (resource->type != VME_MASTER) { - printk(KERN_ERR "Not a master resource\n"); - return -EINVAL; - } - - image = list_entry(resource->entry, struct vme_master_resource, list); - - if (!bridge->master_set) { - printk(KERN_WARNING "vme_master_set not supported\n"); - return -EINVAL; - } - - if (!(((image->address_attr & aspace) == aspace) && - ((image->cycle_attr & cycle) == cycle) && - ((image->width_attr & dwidth) == dwidth))) { - printk(KERN_WARNING "Invalid attributes\n"); - return -EINVAL; - } - - retval = vme_check_window(aspace, vme_base, size); - if (retval) - return retval; - - return bridge->master_set(image, enabled, vme_base, size, aspace, - cycle, dwidth); -} -EXPORT_SYMBOL(vme_master_set); - -/** - * vme_master_get - Retrieve VME master window configuration. - * @resource: Pointer to VME master resource. - * @enabled: Pointer to variable for storing state. - * @vme_base: Pointer to variable for storing window base address. - * @size: Pointer to variable for storing window size. - * @aspace: Pointer to variable for storing VME address space. - * @cycle: Pointer to variable for storing VME data transfer cycle type. - * @dwidth: Pointer to variable for storing VME data transfer width. - * - * Return configuration for provided VME master window. - * - * Return: Zero on success, -EINVAL if operation is not supported on this - * device or if an invalid resource has been provided. - */ -int vme_master_get(struct vme_resource *resource, int *enabled, - unsigned long long *vme_base, unsigned long long *size, u32 *aspace, - u32 *cycle, u32 *dwidth) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_master_resource *image; - - if (resource->type != VME_MASTER) { - printk(KERN_ERR "Not a master resource\n"); - return -EINVAL; - } - - image = list_entry(resource->entry, struct vme_master_resource, list); - - if (!bridge->master_get) { - printk(KERN_WARNING "%s not supported\n", __func__); - return -EINVAL; - } - - return bridge->master_get(image, enabled, vme_base, size, aspace, - cycle, dwidth); -} -EXPORT_SYMBOL(vme_master_get); - -/** - * vme_master_read - Read data from VME space into a buffer. - * @resource: Pointer to VME master resource. - * @buf: Pointer to buffer where data should be transferred. - * @count: Number of bytes to transfer. - * @offset: Offset into VME master window at which to start transfer. - * - * Perform read of count bytes of data from location on VME bus which maps into - * the VME master window at offset to buf. - * - * Return: Number of bytes read, -EINVAL if resource is not a VME master - * resource or read operation is not supported. -EFAULT returned if - * invalid offset is provided. Hardware specific errors may also be - * returned. - */ -ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, - loff_t offset) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_master_resource *image; - size_t length; - - if (!bridge->master_read) { - printk(KERN_WARNING "Reading from resource not supported\n"); - return -EINVAL; - } - - if (resource->type != VME_MASTER) { - printk(KERN_ERR "Not a master resource\n"); - return -EINVAL; - } - - image = list_entry(resource->entry, struct vme_master_resource, list); - - length = vme_get_size(resource); - - if (offset > length) { - printk(KERN_WARNING "Invalid Offset\n"); - return -EFAULT; - } - - if ((offset + count) > length) - count = length - offset; - - return bridge->master_read(image, buf, count, offset); - -} -EXPORT_SYMBOL(vme_master_read); - -/** - * vme_master_write - Write data out to VME space from a buffer. - * @resource: Pointer to VME master resource. - * @buf: Pointer to buffer holding data to transfer. - * @count: Number of bytes to transfer. - * @offset: Offset into VME master window at which to start transfer. - * - * Perform write of count bytes of data from buf to location on VME bus which - * maps into the VME master window at offset. - * - * Return: Number of bytes written, -EINVAL if resource is not a VME master - * resource or write operation is not supported. -EFAULT returned if - * invalid offset is provided. Hardware specific errors may also be - * returned. - */ -ssize_t vme_master_write(struct vme_resource *resource, void *buf, - size_t count, loff_t offset) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_master_resource *image; - size_t length; - - if (!bridge->master_write) { - printk(KERN_WARNING "Writing to resource not supported\n"); - return -EINVAL; - } - - if (resource->type != VME_MASTER) { - printk(KERN_ERR "Not a master resource\n"); - return -EINVAL; - } - - image = list_entry(resource->entry, struct vme_master_resource, list); - - length = vme_get_size(resource); - - if (offset > length) { - printk(KERN_WARNING "Invalid Offset\n"); - return -EFAULT; - } - - if ((offset + count) > length) - count = length - offset; - - return bridge->master_write(image, buf, count, offset); -} -EXPORT_SYMBOL(vme_master_write); - -/** - * vme_master_rmw - Perform read-modify-write cycle. - * @resource: Pointer to VME master resource. - * @mask: Bits to be compared and swapped in operation. - * @compare: Bits to be compared with data read from offset. - * @swap: Bits to be swapped in data read from offset. - * @offset: Offset into VME master window at which to perform operation. - * - * Perform read-modify-write cycle on provided location: - * - Location on VME bus is read. - * - Bits selected by mask are compared with compare. - * - Where a selected bit matches that in compare and are selected in swap, - * the bit is swapped. - * - Result written back to location on VME bus. - * - * Return: Bytes written on success, -EINVAL if resource is not a VME master - * resource or RMW operation is not supported. Hardware specific - * errors may also be returned. - */ -unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, - unsigned int compare, unsigned int swap, loff_t offset) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_master_resource *image; - - if (!bridge->master_rmw) { - printk(KERN_WARNING "Writing to resource not supported\n"); - return -EINVAL; - } - - if (resource->type != VME_MASTER) { - printk(KERN_ERR "Not a master resource\n"); - return -EINVAL; - } - - image = list_entry(resource->entry, struct vme_master_resource, list); - - return bridge->master_rmw(image, mask, compare, swap, offset); -} -EXPORT_SYMBOL(vme_master_rmw); - -/** - * vme_master_mmap - Mmap region of VME master window. - * @resource: Pointer to VME master resource. - * @vma: Pointer to definition of user mapping. - * - * Memory map a region of the VME master window into user space. - * - * Return: Zero on success, -EINVAL if resource is not a VME master - * resource or -EFAULT if map exceeds window size. Other generic mmap - * errors may also be returned. - */ -int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) -{ - struct vme_master_resource *image; - phys_addr_t phys_addr; - unsigned long vma_size; - - if (resource->type != VME_MASTER) { - pr_err("Not a master resource\n"); - return -EINVAL; - } - - image = list_entry(resource->entry, struct vme_master_resource, list); - phys_addr = image->bus_resource.start + (vma->vm_pgoff << PAGE_SHIFT); - vma_size = vma->vm_end - vma->vm_start; - - if (phys_addr + vma_size > image->bus_resource.end + 1) { - pr_err("Map size cannot exceed the window size\n"); - return -EFAULT; - } - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - return vm_iomap_memory(vma, phys_addr, vma->vm_end - vma->vm_start); -} -EXPORT_SYMBOL(vme_master_mmap); - -/** - * vme_master_free - Free VME master window - * @resource: Pointer to VME master resource. - * - * Free the provided master resource so that it may be reallocated. - */ -void vme_master_free(struct vme_resource *resource) -{ - struct vme_master_resource *master_image; - - if (resource->type != VME_MASTER) { - printk(KERN_ERR "Not a master resource\n"); - return; - } - - master_image = list_entry(resource->entry, struct vme_master_resource, - list); - if (!master_image) { - printk(KERN_ERR "Can't find master resource\n"); - return; - } - - /* Unlock image */ - spin_lock(&master_image->lock); - if (master_image->locked == 0) - printk(KERN_ERR "Image is already free\n"); - - master_image->locked = 0; - spin_unlock(&master_image->lock); - - /* Free up resource memory */ - kfree(resource); -} -EXPORT_SYMBOL(vme_master_free); - -/** - * vme_dma_request - Request a DMA controller. - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * @route: Required src/destination combination. - * - * Request a VME DMA controller with capability to perform transfers bewteen - * requested source/destination combination. - * - * Return: Pointer to VME DMA resource on success, NULL on failure. - */ -struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) -{ - struct vme_bridge *bridge; - struct list_head *dma_pos = NULL; - struct vme_dma_resource *allocated_ctrlr = NULL; - struct vme_dma_resource *dma_ctrlr = NULL; - struct vme_resource *resource = NULL; - - /* XXX Not checking resource attributes */ - printk(KERN_ERR "No VME resource Attribute tests done\n"); - - bridge = vdev->bridge; - if (!bridge) { - printk(KERN_ERR "Can't find VME bus\n"); - goto err_bus; - } - - /* Loop through DMA resources */ - list_for_each(dma_pos, &bridge->dma_resources) { - dma_ctrlr = list_entry(dma_pos, - struct vme_dma_resource, list); - if (!dma_ctrlr) { - printk(KERN_ERR "Registered NULL DMA resource\n"); - continue; - } - - /* Find an unlocked and compatible controller */ - mutex_lock(&dma_ctrlr->mtx); - if (((dma_ctrlr->route_attr & route) == route) && - (dma_ctrlr->locked == 0)) { - - dma_ctrlr->locked = 1; - mutex_unlock(&dma_ctrlr->mtx); - allocated_ctrlr = dma_ctrlr; - break; - } - mutex_unlock(&dma_ctrlr->mtx); - } - - /* Check to see if we found a resource */ - if (!allocated_ctrlr) - goto err_ctrlr; - - resource = kmalloc(sizeof(*resource), GFP_KERNEL); - if (!resource) - goto err_alloc; - - resource->type = VME_DMA; - resource->entry = &allocated_ctrlr->list; - - return resource; - -err_alloc: - /* Unlock image */ - mutex_lock(&dma_ctrlr->mtx); - dma_ctrlr->locked = 0; - mutex_unlock(&dma_ctrlr->mtx); -err_ctrlr: -err_bus: - return NULL; -} -EXPORT_SYMBOL(vme_dma_request); - -/** - * vme_new_dma_list - Create new VME DMA list. - * @resource: Pointer to VME DMA resource. - * - * Create a new VME DMA list. It is the responsibility of the user to free - * the list once it is no longer required with vme_dma_list_free(). - * - * Return: Pointer to new VME DMA list, NULL on allocation failure or invalid - * VME DMA resource. - */ -struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) -{ - struct vme_dma_list *dma_list; - - if (resource->type != VME_DMA) { - printk(KERN_ERR "Not a DMA resource\n"); - return NULL; - } - - dma_list = kmalloc(sizeof(*dma_list), GFP_KERNEL); - if (!dma_list) - return NULL; - - INIT_LIST_HEAD(&dma_list->entries); - dma_list->parent = list_entry(resource->entry, - struct vme_dma_resource, - list); - mutex_init(&dma_list->mtx); - - return dma_list; -} -EXPORT_SYMBOL(vme_new_dma_list); - -/** - * vme_dma_pattern_attribute - Create "Pattern" type VME DMA list attribute. - * @pattern: Value to use used as pattern - * @type: Type of pattern to be written. - * - * Create VME DMA list attribute for pattern generation. It is the - * responsibility of the user to free used attributes using - * vme_dma_free_attribute(). - * - * Return: Pointer to VME DMA attribute, NULL on failure. - */ -struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) -{ - struct vme_dma_attr *attributes; - struct vme_dma_pattern *pattern_attr; - - attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); - if (!attributes) - goto err_attr; - - pattern_attr = kmalloc(sizeof(*pattern_attr), GFP_KERNEL); - if (!pattern_attr) - goto err_pat; - - attributes->type = VME_DMA_PATTERN; - attributes->private = (void *)pattern_attr; - - pattern_attr->pattern = pattern; - pattern_attr->type = type; - - return attributes; - -err_pat: - kfree(attributes); -err_attr: - return NULL; -} -EXPORT_SYMBOL(vme_dma_pattern_attribute); - -/** - * vme_dma_pci_attribute - Create "PCI" type VME DMA list attribute. - * @address: PCI base address for DMA transfer. - * - * Create VME DMA list attribute pointing to a location on PCI for DMA - * transfers. It is the responsibility of the user to free used attributes - * using vme_dma_free_attribute(). - * - * Return: Pointer to VME DMA attribute, NULL on failure. - */ -struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) -{ - struct vme_dma_attr *attributes; - struct vme_dma_pci *pci_attr; - - /* XXX Run some sanity checks here */ - - attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); - if (!attributes) - goto err_attr; - - pci_attr = kmalloc(sizeof(*pci_attr), GFP_KERNEL); - if (!pci_attr) - goto err_pci; - - attributes->type = VME_DMA_PCI; - attributes->private = (void *)pci_attr; - - pci_attr->address = address; - - return attributes; - -err_pci: - kfree(attributes); -err_attr: - return NULL; -} -EXPORT_SYMBOL(vme_dma_pci_attribute); - -/** - * vme_dma_vme_attribute - Create "VME" type VME DMA list attribute. - * @address: VME base address for DMA transfer. - * @aspace: VME address space to use for DMA transfer. - * @cycle: VME bus cycle to use for DMA transfer. - * @dwidth: VME data width to use for DMA transfer. - * - * Create VME DMA list attribute pointing to a location on the VME bus for DMA - * transfers. It is the responsibility of the user to free used attributes - * using vme_dma_free_attribute(). - * - * Return: Pointer to VME DMA attribute, NULL on failure. - */ -struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, - u32 aspace, u32 cycle, u32 dwidth) -{ - struct vme_dma_attr *attributes; - struct vme_dma_vme *vme_attr; - - attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); - if (!attributes) - goto err_attr; - - vme_attr = kmalloc(sizeof(*vme_attr), GFP_KERNEL); - if (!vme_attr) - goto err_vme; - - attributes->type = VME_DMA_VME; - attributes->private = (void *)vme_attr; - - vme_attr->address = address; - vme_attr->aspace = aspace; - vme_attr->cycle = cycle; - vme_attr->dwidth = dwidth; - - return attributes; - -err_vme: - kfree(attributes); -err_attr: - return NULL; -} -EXPORT_SYMBOL(vme_dma_vme_attribute); - -/** - * vme_dma_free_attribute - Free DMA list attribute. - * @attributes: Pointer to DMA list attribute. - * - * Free VME DMA list attribute. VME DMA list attributes can be safely freed - * once vme_dma_list_add() has returned. - */ -void vme_dma_free_attribute(struct vme_dma_attr *attributes) -{ - kfree(attributes->private); - kfree(attributes); -} -EXPORT_SYMBOL(vme_dma_free_attribute); - -/** - * vme_dma_list_add - Add enty to a VME DMA list. - * @list: Pointer to VME list. - * @src: Pointer to DMA list attribute to use as source. - * @dest: Pointer to DMA list attribute to use as destination. - * @count: Number of bytes to transfer. - * - * Add an entry to the provided VME DMA list. Entry requires pointers to source - * and destination DMA attributes and a count. - * - * Please note, the attributes supported as source and destinations for - * transfers are hardware dependent. - * - * Return: Zero on success, -EINVAL if operation is not supported on this - * device or if the link list has already been submitted for execution. - * Hardware specific errors also possible. - */ -int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, - struct vme_dma_attr *dest, size_t count) -{ - struct vme_bridge *bridge = list->parent->parent; - int retval; - - if (!bridge->dma_list_add) { - printk(KERN_WARNING "Link List DMA generation not supported\n"); - return -EINVAL; - } - - if (!mutex_trylock(&list->mtx)) { - printk(KERN_ERR "Link List already submitted\n"); - return -EINVAL; - } - - retval = bridge->dma_list_add(list, src, dest, count); - - mutex_unlock(&list->mtx); - - return retval; -} -EXPORT_SYMBOL(vme_dma_list_add); - -/** - * vme_dma_list_exec - Queue a VME DMA list for execution. - * @list: Pointer to VME list. - * - * Queue the provided VME DMA list for execution. The call will return once the - * list has been executed. - * - * Return: Zero on success, -EINVAL if operation is not supported on this - * device. Hardware specific errors also possible. - */ -int vme_dma_list_exec(struct vme_dma_list *list) -{ - struct vme_bridge *bridge = list->parent->parent; - int retval; - - if (!bridge->dma_list_exec) { - printk(KERN_ERR "Link List DMA execution not supported\n"); - return -EINVAL; - } - - mutex_lock(&list->mtx); - - retval = bridge->dma_list_exec(list); - - mutex_unlock(&list->mtx); - - return retval; -} -EXPORT_SYMBOL(vme_dma_list_exec); - -/** - * vme_dma_list_free - Free a VME DMA list. - * @list: Pointer to VME list. - * - * Free the provided DMA list and all its entries. - * - * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource - * is still in use. Hardware specific errors also possible. - */ -int vme_dma_list_free(struct vme_dma_list *list) -{ - struct vme_bridge *bridge = list->parent->parent; - int retval; - - if (!bridge->dma_list_empty) { - printk(KERN_WARNING "Emptying of Link Lists not supported\n"); - return -EINVAL; - } - - if (!mutex_trylock(&list->mtx)) { - printk(KERN_ERR "Link List in use\n"); - return -EBUSY; - } - - /* - * Empty out all of the entries from the DMA list. We need to go to the - * low level driver as DMA entries are driver specific. - */ - retval = bridge->dma_list_empty(list); - if (retval) { - printk(KERN_ERR "Unable to empty link-list entries\n"); - mutex_unlock(&list->mtx); - return retval; - } - mutex_unlock(&list->mtx); - kfree(list); - - return retval; -} -EXPORT_SYMBOL(vme_dma_list_free); - -/** - * vme_dma_free - Free a VME DMA resource. - * @resource: Pointer to VME DMA resource. - * - * Free the provided DMA resource so that it may be reallocated. - * - * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource - * is still active. - */ -int vme_dma_free(struct vme_resource *resource) -{ - struct vme_dma_resource *ctrlr; - - if (resource->type != VME_DMA) { - printk(KERN_ERR "Not a DMA resource\n"); - return -EINVAL; - } - - ctrlr = list_entry(resource->entry, struct vme_dma_resource, list); - - if (!mutex_trylock(&ctrlr->mtx)) { - printk(KERN_ERR "Resource busy, can't free\n"); - return -EBUSY; - } - - if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) { - printk(KERN_WARNING "Resource still processing transfers\n"); - mutex_unlock(&ctrlr->mtx); - return -EBUSY; - } - - ctrlr->locked = 0; - - mutex_unlock(&ctrlr->mtx); - - kfree(resource); - - return 0; -} -EXPORT_SYMBOL(vme_dma_free); - -void vme_bus_error_handler(struct vme_bridge *bridge, - unsigned long long address, int am) -{ - struct list_head *handler_pos = NULL; - struct vme_error_handler *handler; - int handler_triggered = 0; - u32 aspace = vme_get_aspace(am); - - list_for_each(handler_pos, &bridge->vme_error_handlers) { - handler = list_entry(handler_pos, struct vme_error_handler, - list); - if ((aspace == handler->aspace) && - (address >= handler->start) && - (address < handler->end)) { - if (!handler->num_errors) - handler->first_error = address; - if (handler->num_errors != UINT_MAX) - handler->num_errors++; - handler_triggered = 1; - } - } - - if (!handler_triggered) - dev_err(bridge->parent, - "Unhandled VME access error at address 0x%llx\n", - address); -} -EXPORT_SYMBOL(vme_bus_error_handler); - -struct vme_error_handler *vme_register_error_handler( - struct vme_bridge *bridge, u32 aspace, - unsigned long long address, size_t len) -{ - struct vme_error_handler *handler; - - handler = kmalloc(sizeof(*handler), GFP_ATOMIC); - if (!handler) - return NULL; - - handler->aspace = aspace; - handler->start = address; - handler->end = address + len; - handler->num_errors = 0; - handler->first_error = 0; - list_add_tail(&handler->list, &bridge->vme_error_handlers); - - return handler; -} -EXPORT_SYMBOL(vme_register_error_handler); - -void vme_unregister_error_handler(struct vme_error_handler *handler) -{ - list_del(&handler->list); - kfree(handler); -} -EXPORT_SYMBOL(vme_unregister_error_handler); - -void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) -{ - void (*call)(int, int, void *); - void *priv_data; - - call = bridge->irq[level - 1].callback[statid].func; - priv_data = bridge->irq[level - 1].callback[statid].priv_data; - if (call) - call(level, statid, priv_data); - else - printk(KERN_WARNING "Spurious VME interrupt, level:%x, vector:%x\n", - level, statid); -} -EXPORT_SYMBOL(vme_irq_handler); - -/** - * vme_irq_request - Request a specific VME interrupt. - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * @level: Interrupt priority being requested. - * @statid: Interrupt vector being requested. - * @callback: Pointer to callback function called when VME interrupt/vector - * received. - * @priv_data: Generic pointer that will be passed to the callback function. - * - * Request callback to be attached as a handler for VME interrupts with provided - * level and statid. - * - * Return: Zero on success, -EINVAL on invalid vme device, level or if the - * function is not supported, -EBUSY if the level/statid combination is - * already in use. Hardware specific errors also possible. - */ -int vme_irq_request(struct vme_dev *vdev, int level, int statid, - void (*callback)(int, int, void *), - void *priv_data) -{ - struct vme_bridge *bridge; - - bridge = vdev->bridge; - if (!bridge) { - printk(KERN_ERR "Can't find VME bus\n"); - return -EINVAL; - } - - if ((level < 1) || (level > 7)) { - printk(KERN_ERR "Invalid interrupt level\n"); - return -EINVAL; - } - - if (!bridge->irq_set) { - printk(KERN_ERR "Configuring interrupts not supported\n"); - return -EINVAL; - } - - mutex_lock(&bridge->irq_mtx); - - if (bridge->irq[level - 1].callback[statid].func) { - mutex_unlock(&bridge->irq_mtx); - printk(KERN_WARNING "VME Interrupt already taken\n"); - return -EBUSY; - } - - bridge->irq[level - 1].count++; - bridge->irq[level - 1].callback[statid].priv_data = priv_data; - bridge->irq[level - 1].callback[statid].func = callback; - - /* Enable IRQ level */ - bridge->irq_set(bridge, level, 1, 1); - - mutex_unlock(&bridge->irq_mtx); - - return 0; -} -EXPORT_SYMBOL(vme_irq_request); - -/** - * vme_irq_free - Free a VME interrupt. - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * @level: Interrupt priority of interrupt being freed. - * @statid: Interrupt vector of interrupt being freed. - * - * Remove previously attached callback from VME interrupt priority/vector. - */ -void vme_irq_free(struct vme_dev *vdev, int level, int statid) -{ - struct vme_bridge *bridge; - - bridge = vdev->bridge; - if (!bridge) { - printk(KERN_ERR "Can't find VME bus\n"); - return; - } - - if ((level < 1) || (level > 7)) { - printk(KERN_ERR "Invalid interrupt level\n"); - return; - } - - if (!bridge->irq_set) { - printk(KERN_ERR "Configuring interrupts not supported\n"); - return; - } - - mutex_lock(&bridge->irq_mtx); - - bridge->irq[level - 1].count--; - - /* Disable IRQ level if no more interrupts attached at this level*/ - if (bridge->irq[level - 1].count == 0) - bridge->irq_set(bridge, level, 0, 1); - - bridge->irq[level - 1].callback[statid].func = NULL; - bridge->irq[level - 1].callback[statid].priv_data = NULL; - - mutex_unlock(&bridge->irq_mtx); -} -EXPORT_SYMBOL(vme_irq_free); - -/** - * vme_irq_generate - Generate VME interrupt. - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * @level: Interrupt priority at which to assert the interrupt. - * @statid: Interrupt vector to associate with the interrupt. - * - * Generate a VME interrupt of the provided level and with the provided - * statid. - * - * Return: Zero on success, -EINVAL on invalid vme device, level or if the - * function is not supported. Hardware specific errors also possible. - */ -int vme_irq_generate(struct vme_dev *vdev, int level, int statid) -{ - struct vme_bridge *bridge; - - bridge = vdev->bridge; - if (!bridge) { - printk(KERN_ERR "Can't find VME bus\n"); - return -EINVAL; - } - - if ((level < 1) || (level > 7)) { - printk(KERN_WARNING "Invalid interrupt level\n"); - return -EINVAL; - } - - if (!bridge->irq_generate) { - printk(KERN_WARNING "Interrupt generation not supported\n"); - return -EINVAL; - } - - return bridge->irq_generate(bridge, level, statid); -} -EXPORT_SYMBOL(vme_irq_generate); - -/** - * vme_lm_request - Request a VME location monitor - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * - * Allocate a location monitor resource to the driver. A location monitor - * allows the driver to monitor accesses to a contiguous number of - * addresses on the VME bus. - * - * Return: Pointer to a VME resource on success or NULL on failure. - */ -struct vme_resource *vme_lm_request(struct vme_dev *vdev) -{ - struct vme_bridge *bridge; - struct list_head *lm_pos = NULL; - struct vme_lm_resource *allocated_lm = NULL; - struct vme_lm_resource *lm = NULL; - struct vme_resource *resource = NULL; - - bridge = vdev->bridge; - if (!bridge) { - printk(KERN_ERR "Can't find VME bus\n"); - goto err_bus; - } - - /* Loop through LM resources */ - list_for_each(lm_pos, &bridge->lm_resources) { - lm = list_entry(lm_pos, - struct vme_lm_resource, list); - if (!lm) { - printk(KERN_ERR "Registered NULL Location Monitor resource\n"); - continue; - } - - /* Find an unlocked controller */ - mutex_lock(&lm->mtx); - if (lm->locked == 0) { - lm->locked = 1; - mutex_unlock(&lm->mtx); - allocated_lm = lm; - break; - } - mutex_unlock(&lm->mtx); - } - - /* Check to see if we found a resource */ - if (!allocated_lm) - goto err_lm; - - resource = kmalloc(sizeof(*resource), GFP_KERNEL); - if (!resource) - goto err_alloc; - - resource->type = VME_LM; - resource->entry = &allocated_lm->list; - - return resource; - -err_alloc: - /* Unlock image */ - mutex_lock(&lm->mtx); - lm->locked = 0; - mutex_unlock(&lm->mtx); -err_lm: -err_bus: - return NULL; -} -EXPORT_SYMBOL(vme_lm_request); - -/** - * vme_lm_count - Determine number of VME Addresses monitored - * @resource: Pointer to VME location monitor resource. - * - * The number of contiguous addresses monitored is hardware dependent. - * Return the number of contiguous addresses monitored by the - * location monitor. - * - * Return: Count of addresses monitored or -EINVAL when provided with an - * invalid location monitor resource. - */ -int vme_lm_count(struct vme_resource *resource) -{ - struct vme_lm_resource *lm; - - if (resource->type != VME_LM) { - printk(KERN_ERR "Not a Location Monitor resource\n"); - return -EINVAL; - } - - lm = list_entry(resource->entry, struct vme_lm_resource, list); - - return lm->monitors; -} -EXPORT_SYMBOL(vme_lm_count); - -/** - * vme_lm_set - Configure location monitor - * @resource: Pointer to VME location monitor resource. - * @lm_base: Base address to monitor. - * @aspace: VME address space to monitor. - * @cycle: VME bus cycle type to monitor. - * - * Set the base address, address space and cycle type of accesses to be - * monitored by the location monitor. - * - * Return: Zero on success, -EINVAL when provided with an invalid location - * monitor resource or function is not supported. Hardware specific - * errors may also be returned. - */ -int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, - u32 aspace, u32 cycle) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_lm_resource *lm; - - if (resource->type != VME_LM) { - printk(KERN_ERR "Not a Location Monitor resource\n"); - return -EINVAL; - } - - lm = list_entry(resource->entry, struct vme_lm_resource, list); - - if (!bridge->lm_set) { - printk(KERN_ERR "vme_lm_set not supported\n"); - return -EINVAL; - } - - return bridge->lm_set(lm, lm_base, aspace, cycle); -} -EXPORT_SYMBOL(vme_lm_set); - -/** - * vme_lm_get - Retrieve location monitor settings - * @resource: Pointer to VME location monitor resource. - * @lm_base: Pointer used to output the base address monitored. - * @aspace: Pointer used to output the address space monitored. - * @cycle: Pointer used to output the VME bus cycle type monitored. - * - * Retrieve the base address, address space and cycle type of accesses to - * be monitored by the location monitor. - * - * Return: Zero on success, -EINVAL when provided with an invalid location - * monitor resource or function is not supported. Hardware specific - * errors may also be returned. - */ -int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, - u32 *aspace, u32 *cycle) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_lm_resource *lm; - - if (resource->type != VME_LM) { - printk(KERN_ERR "Not a Location Monitor resource\n"); - return -EINVAL; - } - - lm = list_entry(resource->entry, struct vme_lm_resource, list); - - if (!bridge->lm_get) { - printk(KERN_ERR "vme_lm_get not supported\n"); - return -EINVAL; - } - - return bridge->lm_get(lm, lm_base, aspace, cycle); -} -EXPORT_SYMBOL(vme_lm_get); - -/** - * vme_lm_attach - Provide callback for location monitor address - * @resource: Pointer to VME location monitor resource. - * @monitor: Offset to which callback should be attached. - * @callback: Pointer to callback function called when triggered. - * @data: Generic pointer that will be passed to the callback function. - * - * Attach a callback to the specificed offset into the location monitors - * monitored addresses. A generic pointer is provided to allow data to be - * passed to the callback when called. - * - * Return: Zero on success, -EINVAL when provided with an invalid location - * monitor resource or function is not supported. Hardware specific - * errors may also be returned. - */ -int vme_lm_attach(struct vme_resource *resource, int monitor, - void (*callback)(void *), void *data) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_lm_resource *lm; - - if (resource->type != VME_LM) { - printk(KERN_ERR "Not a Location Monitor resource\n"); - return -EINVAL; - } - - lm = list_entry(resource->entry, struct vme_lm_resource, list); - - if (!bridge->lm_attach) { - printk(KERN_ERR "vme_lm_attach not supported\n"); - return -EINVAL; - } - - return bridge->lm_attach(lm, monitor, callback, data); -} -EXPORT_SYMBOL(vme_lm_attach); - -/** - * vme_lm_detach - Remove callback for location monitor address - * @resource: Pointer to VME location monitor resource. - * @monitor: Offset to which callback should be removed. - * - * Remove the callback associated with the specificed offset into the - * location monitors monitored addresses. - * - * Return: Zero on success, -EINVAL when provided with an invalid location - * monitor resource or function is not supported. Hardware specific - * errors may also be returned. - */ -int vme_lm_detach(struct vme_resource *resource, int monitor) -{ - struct vme_bridge *bridge = find_bridge(resource); - struct vme_lm_resource *lm; - - if (resource->type != VME_LM) { - printk(KERN_ERR "Not a Location Monitor resource\n"); - return -EINVAL; - } - - lm = list_entry(resource->entry, struct vme_lm_resource, list); - - if (!bridge->lm_detach) { - printk(KERN_ERR "vme_lm_detach not supported\n"); - return -EINVAL; - } - - return bridge->lm_detach(lm, monitor); -} -EXPORT_SYMBOL(vme_lm_detach); - -/** - * vme_lm_free - Free allocated VME location monitor - * @resource: Pointer to VME location monitor resource. - * - * Free allocation of a VME location monitor. - * - * WARNING: This function currently expects that any callbacks that have - * been attached to the location monitor have been removed. - * - * Return: Zero on success, -EINVAL when provided with an invalid location - * monitor resource. - */ -void vme_lm_free(struct vme_resource *resource) -{ - struct vme_lm_resource *lm; - - if (resource->type != VME_LM) { - printk(KERN_ERR "Not a Location Monitor resource\n"); - return; - } - - lm = list_entry(resource->entry, struct vme_lm_resource, list); - - mutex_lock(&lm->mtx); - - /* XXX - * Check to see that there aren't any callbacks still attached, if - * there are we should probably be detaching them! - */ - - lm->locked = 0; - - mutex_unlock(&lm->mtx); - - kfree(resource); -} -EXPORT_SYMBOL(vme_lm_free); - -/** - * vme_slot_num - Retrieve slot ID - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * - * Retrieve the slot ID associated with the provided VME device. - * - * Return: The slot ID on success, -EINVAL if VME bridge cannot be determined - * or the function is not supported. Hardware specific errors may also - * be returned. - */ -int vme_slot_num(struct vme_dev *vdev) -{ - struct vme_bridge *bridge; - - bridge = vdev->bridge; - if (!bridge) { - printk(KERN_ERR "Can't find VME bus\n"); - return -EINVAL; - } - - if (!bridge->slot_get) { - printk(KERN_WARNING "vme_slot_num not supported\n"); - return -EINVAL; - } - - return bridge->slot_get(bridge); -} -EXPORT_SYMBOL(vme_slot_num); - -/** - * vme_bus_num - Retrieve bus number - * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. - * - * Retrieve the bus enumeration associated with the provided VME device. - * - * Return: The bus number on success, -EINVAL if VME bridge cannot be - * determined. - */ -int vme_bus_num(struct vme_dev *vdev) -{ - struct vme_bridge *bridge; - - bridge = vdev->bridge; - if (!bridge) { - pr_err("Can't find VME bus\n"); - return -EINVAL; - } - - return bridge->num; -} -EXPORT_SYMBOL(vme_bus_num); - -/* - Bridge Registration --------------------------------------------------- */ - -static void vme_dev_release(struct device *dev) -{ - kfree(dev_to_vme_dev(dev)); -} - -/* Common bridge initialization */ -struct vme_bridge *vme_init_bridge(struct vme_bridge *bridge) -{ - INIT_LIST_HEAD(&bridge->vme_error_handlers); - INIT_LIST_HEAD(&bridge->master_resources); - INIT_LIST_HEAD(&bridge->slave_resources); - INIT_LIST_HEAD(&bridge->dma_resources); - INIT_LIST_HEAD(&bridge->lm_resources); - mutex_init(&bridge->irq_mtx); - - return bridge; -} -EXPORT_SYMBOL(vme_init_bridge); - -int vme_register_bridge(struct vme_bridge *bridge) -{ - int i; - int ret = -1; - - mutex_lock(&vme_buses_lock); - for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) { - if ((vme_bus_numbers & (1 << i)) == 0) { - vme_bus_numbers |= (1 << i); - bridge->num = i; - INIT_LIST_HEAD(&bridge->devices); - list_add_tail(&bridge->bus_list, &vme_bus_list); - ret = 0; - break; - } - } - mutex_unlock(&vme_buses_lock); - - return ret; -} -EXPORT_SYMBOL(vme_register_bridge); - -void vme_unregister_bridge(struct vme_bridge *bridge) -{ - struct vme_dev *vdev; - struct vme_dev *tmp; - - mutex_lock(&vme_buses_lock); - vme_bus_numbers &= ~(1 << bridge->num); - list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) { - list_del(&vdev->drv_list); - list_del(&vdev->bridge_list); - device_unregister(&vdev->dev); - } - list_del(&bridge->bus_list); - mutex_unlock(&vme_buses_lock); -} -EXPORT_SYMBOL(vme_unregister_bridge); - -/* - Driver Registration --------------------------------------------------- */ - -static int __vme_register_driver_bus(struct vme_driver *drv, - struct vme_bridge *bridge, unsigned int ndevs) -{ - int err; - unsigned int i; - struct vme_dev *vdev; - struct vme_dev *tmp; - - for (i = 0; i < ndevs; i++) { - vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); - if (!vdev) { - err = -ENOMEM; - goto err_devalloc; - } - vdev->num = i; - vdev->bridge = bridge; - vdev->dev.platform_data = drv; - vdev->dev.release = vme_dev_release; - vdev->dev.parent = bridge->parent; - vdev->dev.bus = &vme_bus_type; - dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num, - vdev->num); - - err = device_register(&vdev->dev); - if (err) - goto err_reg; - - if (vdev->dev.platform_data) { - list_add_tail(&vdev->drv_list, &drv->devices); - list_add_tail(&vdev->bridge_list, &bridge->devices); - } else - device_unregister(&vdev->dev); - } - return 0; - -err_reg: - put_device(&vdev->dev); -err_devalloc: - list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) { - list_del(&vdev->drv_list); - list_del(&vdev->bridge_list); - device_unregister(&vdev->dev); - } - return err; -} - -static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) -{ - struct vme_bridge *bridge; - int err = 0; - - mutex_lock(&vme_buses_lock); - list_for_each_entry(bridge, &vme_bus_list, bus_list) { - /* - * This cannot cause trouble as we already have vme_buses_lock - * and if the bridge is removed, it will have to go through - * vme_unregister_bridge() to do it (which calls remove() on - * the bridge which in turn tries to acquire vme_buses_lock and - * will have to wait). - */ - err = __vme_register_driver_bus(drv, bridge, ndevs); - if (err) - break; - } - mutex_unlock(&vme_buses_lock); - return err; -} - -/** - * vme_register_driver - Register a VME driver - * @drv: Pointer to VME driver structure to register. - * @ndevs: Maximum number of devices to allow to be enumerated. - * - * Register a VME device driver with the VME subsystem. - * - * Return: Zero on success, error value on registration failure. - */ -int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) -{ - int err; - - drv->driver.name = drv->name; - drv->driver.bus = &vme_bus_type; - INIT_LIST_HEAD(&drv->devices); - - err = driver_register(&drv->driver); - if (err) - return err; - - err = __vme_register_driver(drv, ndevs); - if (err) - driver_unregister(&drv->driver); - - return err; -} -EXPORT_SYMBOL(vme_register_driver); - -/** - * vme_unregister_driver - Unregister a VME driver - * @drv: Pointer to VME driver structure to unregister. - * - * Unregister a VME device driver from the VME subsystem. - */ -void vme_unregister_driver(struct vme_driver *drv) -{ - struct vme_dev *dev, *dev_tmp; - - mutex_lock(&vme_buses_lock); - list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) { - list_del(&dev->drv_list); - list_del(&dev->bridge_list); - device_unregister(&dev->dev); - } - mutex_unlock(&vme_buses_lock); - - driver_unregister(&drv->driver); -} -EXPORT_SYMBOL(vme_unregister_driver); - -/* - Bus Registration ------------------------------------------------------ */ - -static int vme_bus_match(struct device *dev, struct device_driver *drv) -{ - struct vme_driver *vme_drv; - - vme_drv = container_of(drv, struct vme_driver, driver); - - if (dev->platform_data == vme_drv) { - struct vme_dev *vdev = dev_to_vme_dev(dev); - - if (vme_drv->match && vme_drv->match(vdev)) - return 1; - - dev->platform_data = NULL; - } - return 0; -} - -static int vme_bus_probe(struct device *dev) -{ - struct vme_driver *driver; - struct vme_dev *vdev = dev_to_vme_dev(dev); - - driver = dev->platform_data; - if (driver->probe) - return driver->probe(vdev); - - return -ENODEV; -} - -static void vme_bus_remove(struct device *dev) -{ - struct vme_driver *driver; - struct vme_dev *vdev = dev_to_vme_dev(dev); - - driver = dev->platform_data; - if (driver->remove) - driver->remove(vdev); -} - -struct bus_type vme_bus_type = { - .name = "vme", - .match = vme_bus_match, - .probe = vme_bus_probe, - .remove = vme_bus_remove, -}; -EXPORT_SYMBOL(vme_bus_type); - -static int __init vme_init(void) -{ - return bus_register(&vme_bus_type); -} -subsys_initcall(vme_init); diff --git a/drivers/vme/vme_bridge.h b/drivers/vme/vme_bridge.h deleted file mode 100644 index 42ecf961004e..000000000000 --- a/drivers/vme/vme_bridge.h +++ /dev/null @@ -1,190 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _VME_BRIDGE_H_ -#define _VME_BRIDGE_H_ - -#include - -#define VME_CRCSR_BUF_SIZE (508*1024) -/* - * Resource structures - */ -struct vme_master_resource { - struct list_head list; - struct vme_bridge *parent; - /* - * We are likely to need to access the VME bus in interrupt context, so - * protect master routines with a spinlock rather than a mutex. - */ - spinlock_t lock; - int locked; - int number; - u32 address_attr; - u32 cycle_attr; - u32 width_attr; - struct resource bus_resource; - void __iomem *kern_base; -}; - -struct vme_slave_resource { - struct list_head list; - struct vme_bridge *parent; - struct mutex mtx; - int locked; - int number; - u32 address_attr; - u32 cycle_attr; -}; - -struct vme_dma_pattern { - u32 pattern; - u32 type; -}; - -struct vme_dma_pci { - dma_addr_t address; -}; - -struct vme_dma_vme { - unsigned long long address; - u32 aspace; - u32 cycle; - u32 dwidth; -}; - -struct vme_dma_list { - struct list_head list; - struct vme_dma_resource *parent; - struct list_head entries; - struct mutex mtx; -}; - -struct vme_dma_resource { - struct list_head list; - struct vme_bridge *parent; - struct mutex mtx; - int locked; - int number; - struct list_head pending; - struct list_head running; - u32 route_attr; -}; - -struct vme_lm_resource { - struct list_head list; - struct vme_bridge *parent; - struct mutex mtx; - int locked; - int number; - int monitors; -}; - -struct vme_error_handler { - struct list_head list; - unsigned long long start; /* Beginning of error window */ - unsigned long long end; /* End of error window */ - unsigned long long first_error; /* Address of the first error */ - u32 aspace; /* Address space of error window*/ - unsigned num_errors; /* Number of errors */ -}; - -struct vme_callback { - void (*func)(int, int, void*); - void *priv_data; -}; - -struct vme_irq { - int count; - struct vme_callback callback[VME_NUM_STATUSID]; -}; - -/* Allow 16 characters for name (including null character) */ -#define VMENAMSIZ 16 - -/* This structure stores all the information about one bridge - * The structure should be dynamically allocated by the driver and one instance - * of the structure should be present for each VME chip present in the system. - */ -struct vme_bridge { - char name[VMENAMSIZ]; - int num; - struct list_head master_resources; - struct list_head slave_resources; - struct list_head dma_resources; - struct list_head lm_resources; - - /* List for registered errors handlers */ - struct list_head vme_error_handlers; - /* List of devices on this bridge */ - struct list_head devices; - - /* Bridge Info - XXX Move to private structure? */ - struct device *parent; /* Parent device (eg. pdev->dev for PCI) */ - void *driver_priv; /* Private pointer for the bridge driver */ - struct list_head bus_list; /* list of VME buses */ - - /* Interrupt callbacks */ - struct vme_irq irq[7]; - /* Locking for VME irq callback configuration */ - struct mutex irq_mtx; - - /* Slave Functions */ - int (*slave_get) (struct vme_slave_resource *, int *, - unsigned long long *, unsigned long long *, dma_addr_t *, - u32 *, u32 *); - int (*slave_set) (struct vme_slave_resource *, int, unsigned long long, - unsigned long long, dma_addr_t, u32, u32); - - /* Master Functions */ - int (*master_get) (struct vme_master_resource *, int *, - unsigned long long *, unsigned long long *, u32 *, u32 *, - u32 *); - int (*master_set) (struct vme_master_resource *, int, - unsigned long long, unsigned long long, u32, u32, u32); - ssize_t (*master_read) (struct vme_master_resource *, void *, size_t, - loff_t); - ssize_t (*master_write) (struct vme_master_resource *, void *, size_t, - loff_t); - unsigned int (*master_rmw) (struct vme_master_resource *, unsigned int, - unsigned int, unsigned int, loff_t); - - /* DMA Functions */ - int (*dma_list_add) (struct vme_dma_list *, struct vme_dma_attr *, - struct vme_dma_attr *, size_t); - int (*dma_list_exec) (struct vme_dma_list *); - int (*dma_list_empty) (struct vme_dma_list *); - - /* Interrupt Functions */ - void (*irq_set) (struct vme_bridge *, int, int, int); - int (*irq_generate) (struct vme_bridge *, int, int); - - /* Location monitor functions */ - int (*lm_set) (struct vme_lm_resource *, unsigned long long, u32, u32); - int (*lm_get) (struct vme_lm_resource *, unsigned long long *, u32 *, - u32 *); - int (*lm_attach)(struct vme_lm_resource *, int, - void (*callback)(void *), void *); - int (*lm_detach) (struct vme_lm_resource *, int); - - /* CR/CSR space functions */ - int (*slot_get) (struct vme_bridge *); - - /* Bridge parent interface */ - void *(*alloc_consistent)(struct device *dev, size_t size, - dma_addr_t *dma); - void (*free_consistent)(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma); -}; - -void vme_bus_error_handler(struct vme_bridge *bridge, - unsigned long long address, int am); -void vme_irq_handler(struct vme_bridge *, int, int); - -struct vme_bridge *vme_init_bridge(struct vme_bridge *); -int vme_register_bridge(struct vme_bridge *); -void vme_unregister_bridge(struct vme_bridge *); -struct vme_error_handler *vme_register_error_handler( - struct vme_bridge *bridge, u32 aspace, - unsigned long long address, size_t len); -void vme_unregister_error_handler(struct vme_error_handler *handler); - -#endif /* _VME_BRIDGE_H_ */ diff --git a/include/linux/vme.h b/include/linux/vme.h deleted file mode 100644 index b204a9b4be1b..000000000000 --- a/include/linux/vme.h +++ /dev/null @@ -1,190 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _VME_H_ -#define _VME_H_ - -/* Resource Type */ -enum vme_resource_type { - VME_MASTER, - VME_SLAVE, - VME_DMA, - VME_LM -}; - -/* VME Address Spaces */ -#define VME_A16 0x1 -#define VME_A24 0x2 -#define VME_A32 0x4 -#define VME_A64 0x8 -#define VME_CRCSR 0x10 -#define VME_USER1 0x20 -#define VME_USER2 0x40 -#define VME_USER3 0x80 -#define VME_USER4 0x100 - -#define VME_A16_MAX 0x10000ULL -#define VME_A24_MAX 0x1000000ULL -#define VME_A32_MAX 0x100000000ULL -#define VME_A64_MAX 0x10000000000000000ULL -#define VME_CRCSR_MAX 0x1000000ULL - - -/* VME Cycle Types */ -#define VME_SCT 0x1 -#define VME_BLT 0x2 -#define VME_MBLT 0x4 -#define VME_2eVME 0x8 -#define VME_2eSST 0x10 -#define VME_2eSSTB 0x20 - -#define VME_2eSST160 0x100 -#define VME_2eSST267 0x200 -#define VME_2eSST320 0x400 - -#define VME_SUPER 0x1000 -#define VME_USER 0x2000 -#define VME_PROG 0x4000 -#define VME_DATA 0x8000 - -/* VME Data Widths */ -#define VME_D8 0x1 -#define VME_D16 0x2 -#define VME_D32 0x4 -#define VME_D64 0x8 - -/* Arbitration Scheduling Modes */ -#define VME_R_ROBIN_MODE 0x1 -#define VME_PRIORITY_MODE 0x2 - -#define VME_DMA_PATTERN (1<<0) -#define VME_DMA_PCI (1<<1) -#define VME_DMA_VME (1<<2) - -#define VME_DMA_PATTERN_BYTE (1<<0) -#define VME_DMA_PATTERN_WORD (1<<1) -#define VME_DMA_PATTERN_INCREMENT (1<<2) - -#define VME_DMA_VME_TO_MEM (1<<0) -#define VME_DMA_MEM_TO_VME (1<<1) -#define VME_DMA_VME_TO_VME (1<<2) -#define VME_DMA_MEM_TO_MEM (1<<3) -#define VME_DMA_PATTERN_TO_VME (1<<4) -#define VME_DMA_PATTERN_TO_MEM (1<<5) - -struct vme_dma_attr { - u32 type; - void *private; -}; - -struct vme_resource { - enum vme_resource_type type; - struct list_head *entry; -}; - -extern struct bus_type vme_bus_type; - -/* Number of VME interrupt vectors */ -#define VME_NUM_STATUSID 256 - -/* VME_MAX_BRIDGES comes from the type of vme_bus_numbers */ -#define VME_MAX_BRIDGES (sizeof(unsigned int)*8) -#define VME_MAX_SLOTS 32 - -#define VME_SLOT_CURRENT -1 -#define VME_SLOT_ALL -2 - -/** - * struct vme_dev - Structure representing a VME device - * @num: The device number - * @bridge: Pointer to the bridge device this device is on - * @dev: Internal device structure - * @drv_list: List of devices (per driver) - * @bridge_list: List of devices (per bridge) - */ -struct vme_dev { - int num; - struct vme_bridge *bridge; - struct device dev; - struct list_head drv_list; - struct list_head bridge_list; -}; - -/** - * struct vme_driver - Structure representing a VME driver - * @name: Driver name, should be unique among VME drivers and usually the same - * as the module name. - * @match: Callback used to determine whether probe should be run. - * @probe: Callback for device binding, called when new device is detected. - * @remove: Callback, called on device removal. - * @driver: Underlying generic device driver structure. - * @devices: List of VME devices (struct vme_dev) associated with this driver. - */ -struct vme_driver { - const char *name; - int (*match)(struct vme_dev *); - int (*probe)(struct vme_dev *); - void (*remove)(struct vme_dev *); - struct device_driver driver; - struct list_head devices; -}; - -void *vme_alloc_consistent(struct vme_resource *, size_t, dma_addr_t *); -void vme_free_consistent(struct vme_resource *, size_t, void *, - dma_addr_t); - -size_t vme_get_size(struct vme_resource *); -int vme_check_window(u32 aspace, unsigned long long vme_base, - unsigned long long size); - -struct vme_resource *vme_slave_request(struct vme_dev *, u32, u32); -int vme_slave_set(struct vme_resource *, int, unsigned long long, - unsigned long long, dma_addr_t, u32, u32); -int vme_slave_get(struct vme_resource *, int *, unsigned long long *, - unsigned long long *, dma_addr_t *, u32 *, u32 *); -void vme_slave_free(struct vme_resource *); - -struct vme_resource *vme_master_request(struct vme_dev *, u32, u32, u32); -int vme_master_set(struct vme_resource *, int, unsigned long long, - unsigned long long, u32, u32, u32); -int vme_master_get(struct vme_resource *, int *, unsigned long long *, - unsigned long long *, u32 *, u32 *, u32 *); -ssize_t vme_master_read(struct vme_resource *, void *, size_t, loff_t); -ssize_t vme_master_write(struct vme_resource *, void *, size_t, loff_t); -unsigned int vme_master_rmw(struct vme_resource *, unsigned int, unsigned int, - unsigned int, loff_t); -int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma); -void vme_master_free(struct vme_resource *); - -struct vme_resource *vme_dma_request(struct vme_dev *, u32); -struct vme_dma_list *vme_new_dma_list(struct vme_resource *); -struct vme_dma_attr *vme_dma_pattern_attribute(u32, u32); -struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t); -struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long, u32, u32, u32); -void vme_dma_free_attribute(struct vme_dma_attr *); -int vme_dma_list_add(struct vme_dma_list *, struct vme_dma_attr *, - struct vme_dma_attr *, size_t); -int vme_dma_list_exec(struct vme_dma_list *); -int vme_dma_list_free(struct vme_dma_list *); -int vme_dma_free(struct vme_resource *); - -int vme_irq_request(struct vme_dev *, int, int, - void (*callback)(int, int, void *), void *); -void vme_irq_free(struct vme_dev *, int, int); -int vme_irq_generate(struct vme_dev *, int, int); - -struct vme_resource *vme_lm_request(struct vme_dev *); -int vme_lm_count(struct vme_resource *); -int vme_lm_set(struct vme_resource *, unsigned long long, u32, u32); -int vme_lm_get(struct vme_resource *, unsigned long long *, u32 *, u32 *); -int vme_lm_attach(struct vme_resource *, int, void (*callback)(void *), void *); -int vme_lm_detach(struct vme_resource *, int); -void vme_lm_free(struct vme_resource *); - -int vme_slot_num(struct vme_dev *); -int vme_bus_num(struct vme_dev *); - -int vme_register_driver(struct vme_driver *, unsigned int); -void vme_unregister_driver(struct vme_driver *); - - -#endif /* _VME_H_ */ - -- cgit v1.2.3 From 2f8c3ae8288e4a4018330ed5c4e758b878d9c555 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:07:00 -0700 Subject: driver core: Add wait_for_init_devices_probe helper function Some devices might need to be probed and bound successfully before the kernel boot sequence can finish and move on to init/userspace. For example, a network interface might need to be bound to be able to mount a NFS rootfs. With fw_devlink=on by default, some of these devices might be blocked from probing because they are waiting on a optional supplier that doesn't have a driver. While fw_devlink will eventually identify such devices and unblock the probing automatically, it might be too late by the time it unblocks the probing of devices. For example, the IP4 autoconfig might timeout before fw_devlink unblocks probing of the network interface. This function is available to temporarily try and probe all devices that have a driver even if some of their suppliers haven't been added or don't have drivers. The drivers can then decide which of the suppliers are optional vs mandatory and probe the device if possible. By the time this function returns, all such "best effort" probes are guaranteed to be completed. If a device successfully probes in this mode, we delete all fw_devlink discovered dependencies of that device where the supplier hasn't yet probed successfully because they have to be optional dependencies. This also means that some devices that aren't needed for init and could have waited for their optional supplier to probe (when the supplier's module is loaded later on) would end up probing prematurely with limited functionality. So call this function only when boot would fail without it. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-5-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 1 + drivers/base/core.c | 100 +++++++++++++++++++++++++++++++++++++++--- drivers/base/dd.c | 19 +++++--- include/linux/device/driver.h | 1 + 4 files changed, 110 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/base/base.h b/drivers/base/base.h index ab71403d102f..b3a43a164dcd 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -160,6 +160,7 @@ extern int devres_release_all(struct device *dev); extern void device_block_probing(void); extern void device_unblock_probing(void); extern void deferred_probe_extend_timeout(void); +extern void driver_deferred_probe_trigger(void); /* /sys/devices directory */ extern struct kset *devices_kset; diff --git a/drivers/base/core.c b/drivers/base/core.c index 7cd789c4985d..61fdfe99b348 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -54,6 +54,7 @@ static unsigned int defer_sync_state_count = 1; static DEFINE_MUTEX(fwnode_link_lock); static bool fw_devlink_is_permissive(void); static bool fw_devlink_drv_reg_done; +static bool fw_devlink_best_effort; /** * fwnode_link_add - Create a link between two fwnode_handles. @@ -965,6 +966,11 @@ static void device_links_missing_supplier(struct device *dev) } } +static bool dev_is_best_effort(struct device *dev) +{ + return fw_devlink_best_effort && dev->can_match; +} + /** * device_links_check_suppliers - Check presence of supplier drivers. * @dev: Consumer device. @@ -984,7 +990,7 @@ static void device_links_missing_supplier(struct device *dev) int device_links_check_suppliers(struct device *dev) { struct device_link *link; - int ret = 0; + int ret = 0, fwnode_ret = 0; struct fwnode_handle *sup_fw; /* @@ -997,12 +1003,17 @@ int device_links_check_suppliers(struct device *dev) sup_fw = list_first_entry(&dev->fwnode->suppliers, struct fwnode_link, c_hook)->supplier; - dev_err_probe(dev, -EPROBE_DEFER, "wait for supplier %pfwP\n", - sup_fw); - mutex_unlock(&fwnode_link_lock); - return -EPROBE_DEFER; + if (!dev_is_best_effort(dev)) { + fwnode_ret = -EPROBE_DEFER; + dev_err_probe(dev, -EPROBE_DEFER, + "wait for supplier %pfwP\n", sup_fw); + } else { + fwnode_ret = -EAGAIN; + } } mutex_unlock(&fwnode_link_lock); + if (fwnode_ret == -EPROBE_DEFER) + return fwnode_ret; device_links_write_lock(); @@ -1012,6 +1023,14 @@ int device_links_check_suppliers(struct device *dev) if (link->status != DL_STATE_AVAILABLE && !(link->flags & DL_FLAG_SYNC_STATE_ONLY)) { + + if (dev_is_best_effort(dev) && + link->flags & DL_FLAG_INFERRED && + !link->supplier->can_match) { + ret = -EAGAIN; + continue; + } + device_links_missing_supplier(dev); dev_err_probe(dev, -EPROBE_DEFER, "supplier %s not ready\n", @@ -1024,7 +1043,8 @@ int device_links_check_suppliers(struct device *dev) dev->links.status = DL_DEV_PROBING; device_links_write_unlock(); - return ret; + + return ret ? ret : fwnode_ret; } /** @@ -1289,6 +1309,18 @@ void device_links_driver_bound(struct device *dev) * save to drop the managed link completely. */ device_link_drop_managed(link); + } else if (dev_is_best_effort(dev) && + link->flags & DL_FLAG_INFERRED && + link->status != DL_STATE_CONSUMER_PROBE && + !link->supplier->can_match) { + /* + * When dev_is_best_effort() is true, we ignore device + * links to suppliers that don't have a driver. If the + * consumer device still managed to probe, there's no + * point in maintaining a device link in a weird state + * (consumer probed before supplier). So delete it. + */ + device_link_drop_managed(link); } else { WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); WRITE_ONCE(link->status, DL_STATE_ACTIVE); @@ -1655,6 +1687,62 @@ void fw_devlink_drivers_done(void) device_links_write_unlock(); } +/** + * wait_for_init_devices_probe - Try to probe any device needed for init + * + * Some devices might need to be probed and bound successfully before the kernel + * boot sequence can finish and move on to init/userspace. For example, a + * network interface might need to be bound to be able to mount a NFS rootfs. + * + * With fw_devlink=on by default, some of these devices might be blocked from + * probing because they are waiting on a optional supplier that doesn't have a + * driver. While fw_devlink will eventually identify such devices and unblock + * the probing automatically, it might be too late by the time it unblocks the + * probing of devices. For example, the IP4 autoconfig might timeout before + * fw_devlink unblocks probing of the network interface. + * + * This function is available to temporarily try and probe all devices that have + * a driver even if some of their suppliers haven't been added or don't have + * drivers. + * + * The drivers can then decide which of the suppliers are optional vs mandatory + * and probe the device if possible. By the time this function returns, all such + * "best effort" probes are guaranteed to be completed. If a device successfully + * probes in this mode, we delete all fw_devlink discovered dependencies of that + * device where the supplier hasn't yet probed successfully because they have to + * be optional dependencies. + * + * Any devices that didn't successfully probe go back to being treated as if + * this function was never called. + * + * This also means that some devices that aren't needed for init and could have + * waited for their optional supplier to probe (when the supplier's module is + * loaded later on) would end up probing prematurely with limited functionality. + * So call this function only when boot would fail without it. + */ +void __init wait_for_init_devices_probe(void) +{ + if (!fw_devlink_flags || fw_devlink_is_permissive()) + return; + + /* + * Wait for all ongoing probes to finish so that the "best effort" is + * only applied to devices that can't probe otherwise. + */ + wait_for_device_probe(); + + pr_info("Trying to probe devices needed for running init ...\n"); + fw_devlink_best_effort = true; + driver_deferred_probe_trigger(); + + /* + * Wait for all "best effort" probes to finish before going back to + * normal enforcement. + */ + wait_for_device_probe(); + fw_devlink_best_effort = false; +} + static void fw_devlink_unblock_consumers(struct device *dev) { struct device_link *link; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 11b0fb6414d3..4a55fbb7e0da 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -172,7 +172,7 @@ static bool driver_deferred_probe_enable; * changes in the midst of a probe, then deferred processing should be triggered * again. */ -static void driver_deferred_probe_trigger(void) +void driver_deferred_probe_trigger(void) { if (!driver_deferred_probe_enable) return; @@ -580,7 +580,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) { bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) && !drv->suppress_bind_attrs; - int ret; + int ret, link_ret; if (defer_all_probes) { /* @@ -592,9 +592,9 @@ static int really_probe(struct device *dev, struct device_driver *drv) return -EPROBE_DEFER; } - ret = device_links_check_suppliers(dev); - if (ret) - return ret; + link_ret = device_links_check_suppliers(dev); + if (link_ret == -EPROBE_DEFER) + return link_ret; pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); @@ -633,6 +633,15 @@ re_probe: ret = call_driver_probe(dev, drv); if (ret) { + /* + * If fw_devlink_best_effort is active (denoted by -EAGAIN), the + * device might actually probe properly once some of its missing + * suppliers have probed. So, treat this as if the driver + * returned -EPROBE_DEFER. + */ + if (link_ret == -EAGAIN) + ret = -EPROBE_DEFER; + /* * Return probe errors as positive values so that the callers * can distinguish them from other errors. diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 700453017e1c..2114d65b862f 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -129,6 +129,7 @@ extern struct device_driver *driver_find(const char *name, struct bus_type *bus); extern int driver_probe_done(void); extern void wait_for_device_probe(void); +void __init wait_for_init_devices_probe(void); /* sysfs interface for exporting driver attributes */ -- cgit v1.2.3 From 9cbffc7a59561be950ecc675d19a3d2b45202b2b Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:07:05 -0700 Subject: driver core: Delete driver_deferred_probe_check_state() The function is no longer used. So delete it. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-10-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 30 ------------------------------ include/linux/device/driver.h | 1 - 2 files changed, 31 deletions(-) (limited to 'include') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 335e71d3a618..e600dd2afc35 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -274,42 +274,12 @@ static int __init deferred_probe_timeout_setup(char *str) } __setup("deferred_probe_timeout=", deferred_probe_timeout_setup); -/** - * driver_deferred_probe_check_state() - Check deferred probe state - * @dev: device to check - * - * Return: - * * -ENODEV if initcalls have completed and modules are disabled. - * * -ETIMEDOUT if the deferred probe timeout was set and has expired - * and modules are enabled. - * * -EPROBE_DEFER in other cases. - * - * Drivers or subsystems can opt-in to calling this function instead of directly - * returning -EPROBE_DEFER. - */ -int driver_deferred_probe_check_state(struct device *dev) -{ - if (!IS_ENABLED(CONFIG_MODULES) && initcalls_done) { - dev_warn(dev, "ignoring dependency for device, assuming no driver\n"); - return -ENODEV; - } - - if (!driver_deferred_probe_timeout && initcalls_done) { - dev_warn(dev, "deferred probe timeout, ignoring dependency\n"); - return -ETIMEDOUT; - } - - return -EPROBE_DEFER; -} -EXPORT_SYMBOL_GPL(driver_deferred_probe_check_state); - static void deferred_probe_timeout_work_func(struct work_struct *work) { struct device_private *p; fw_devlink_drivers_done(); - driver_deferred_probe_timeout = 0; driver_deferred_probe_trigger(); flush_work(&deferred_probe_work); diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 2114d65b862f..7acaabde5396 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -242,7 +242,6 @@ driver_find_device_by_acpi_dev(struct device_driver *drv, const void *adev) extern int driver_deferred_probe_timeout; void driver_deferred_probe_add(struct device *dev); -int driver_deferred_probe_check_state(struct device *dev); void driver_init(void); /** -- cgit v1.2.3 From 82b070beae1ef55b0049768c8dc91d87565bb191 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Jun 2022 15:02:18 +0300 Subject: driver core: Introduce device_find_any_child() helper There are several places in the kernel where this kind of functionality is being used. Provide a generic helper for such cases. Reviewed-by: Rafael J. Wysocki Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220610120219.18988-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 20 ++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 22 insertions(+) (limited to 'include') diff --git a/drivers/base/core.c b/drivers/base/core.c index 977b379a495b..839f64485a55 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3920,6 +3920,26 @@ struct device *device_find_child_by_name(struct device *parent, } EXPORT_SYMBOL_GPL(device_find_child_by_name); +static int match_any(struct device *dev, void *unused) +{ + return 1; +} + +/** + * device_find_any_child - device iterator for locating a child device, if any. + * @parent: parent struct device + * + * This is similar to the device_find_child() function above, but it + * returns a reference to a child device, if any. + * + * NOTE: you will need to drop the reference with put_device() after use. + */ +struct device *device_find_any_child(struct device *parent) +{ + return device_find_child(parent, NULL, match_any); +} +EXPORT_SYMBOL_GPL(device_find_any_child); + int __init devices_init(void) { devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); diff --git a/include/linux/device.h b/include/linux/device.h index dc941997795c..424b55df0272 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -905,6 +905,8 @@ struct device *device_find_child(struct device *dev, void *data, int (*match)(struct device *dev, void *data)); struct device *device_find_child_by_name(struct device *parent, const char *name); +struct device *device_find_any_child(struct device *parent); + int device_rename(struct device *dev, const char *new_name); int device_move(struct device *dev, struct device *new_parent, enum dpm_order dpm_order); -- cgit v1.2.3 From 81eef68f3bb78f5b3dc29032ffd804a4a2d7aaf0 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 10 Jun 2022 14:44:20 +0200 Subject: ASoC: Remove unused hw_write_t type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 81da8a0b7975 ("ASoC: remove codec hw_write/control_data") removed use of hw_write_t in struct snd_soc_codec, but it left type definition. Fully clean it up. Fixes: 81da8a0b7975 ("ASoC: remove codec hw_write/control_data") Signed-off-by: Amadeusz Sławiński Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20220610124420.4160986-1-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index f20f5f890794..b276dcb5d4e8 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -408,8 +408,6 @@ struct snd_soc_jack_pin; struct snd_soc_jack_gpio; -typedef int (*hw_write_t)(void *,const char* ,int); - enum snd_soc_pcm_subclass { SND_SOC_PCM_CLASS_PCM = 0, SND_SOC_PCM_CLASS_BE = 1, -- cgit v1.2.3 From c3752f44604f3bc4f3ce6e169fa32d16943ff70b Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 9 Jun 2022 11:24:54 +0900 Subject: scsi: libsas: Introduce struct smp_disc_resp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with gcc 12, several warnings are thrown by gcc when compiling drivers/scsi/libsas/sas_expander.c, e.g.: In function ‘sas_get_phy_change_count’, inlined from ‘sas_find_bcast_phy.constprop’ at drivers/scsi/libsas/sas_expander.c:1737:9: drivers/scsi/libsas/sas_expander.c:1697:39: warning: array subscript ‘struct smp_resp[0]’ is partly outside array bounds of ‘unsigned char[56]’ [-Warray-bounds] 1697 | *pcc = disc_resp->disc.change_count; | ~~~~~~~~~~~~~~~^~~~~~~~~~~~~ This is due to the use of the struct smp_resp to aggregate all possible response types using a union but allocating a response buffer with a size exactly equal to the size of the response type needed. This leads to access to fields of struct smp_resp from an allocated memory area that is smaller than the size of struct smp_resp. Fix this by defining struct smp_disc_resp for sas discovery operations. Since this structure and the generic struct smp_resp are identical for the little endian and big endian archs, move the definition of these structures at the end of include/scsi/sas.h to avoid repeating their definition. Link: https://lore.kernel.org/r/20220609022456.409087-2-damien.lemoal@opensource.wdc.com Reviewed-by: John Garry Signed-off-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 32 ++++++++++++++------------------ include/scsi/sas.h | 28 ++++++++++++---------------- 2 files changed, 26 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 260e735d06fa..fb998a8a7d3b 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -175,13 +175,13 @@ static enum sas_device_type to_dev_type(struct discover_resp *dr) return dr->attached_dev_type; } -static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) +static void sas_set_ex_phy(struct domain_device *dev, int phy_id, + struct smp_disc_resp *disc_resp) { enum sas_device_type dev_type; enum sas_linkrate linkrate; u8 sas_addr[SAS_ADDR_SIZE]; - struct smp_resp *resp = rsp; - struct discover_resp *dr = &resp->disc; + struct discover_resp *dr = &disc_resp->disc; struct sas_ha_struct *ha = dev->port->ha; struct expander_device *ex = &dev->ex_dev; struct ex_phy *phy = &ex->ex_phy[phy_id]; @@ -198,7 +198,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) BUG_ON(!phy->phy); } - switch (resp->result) { + switch (disc_resp->result) { case SMP_RESP_PHY_VACANT: phy->phy_state = PHY_VACANT; break; @@ -347,12 +347,13 @@ struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id) } #define DISCOVER_REQ_SIZE 16 -#define DISCOVER_RESP_SIZE 56 +#define DISCOVER_RESP_SIZE sizeof(struct smp_disc_resp) static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, - u8 *disc_resp, int single) + struct smp_disc_resp *disc_resp, + int single) { - struct discover_resp *dr; + struct discover_resp *dr = &disc_resp->disc; int res; disc_req[9] = single; @@ -361,7 +362,6 @@ static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, disc_resp, DISCOVER_RESP_SIZE); if (res) return res; - dr = &((struct smp_resp *)disc_resp)->disc; if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) { pr_notice("Found loopback topology, just ignore it!\n"); return 0; @@ -375,7 +375,7 @@ int sas_ex_phy_discover(struct domain_device *dev, int single) struct expander_device *ex = &dev->ex_dev; int res = 0; u8 *disc_req; - u8 *disc_resp; + struct smp_disc_resp *disc_resp; disc_req = alloc_smp_req(DISCOVER_REQ_SIZE); if (!disc_req) @@ -1657,7 +1657,7 @@ out_err: /* ---------- Domain revalidation ---------- */ static int sas_get_phy_discover(struct domain_device *dev, - int phy_id, struct smp_resp *disc_resp) + int phy_id, struct smp_disc_resp *disc_resp) { int res; u8 *disc_req; @@ -1673,10 +1673,8 @@ static int sas_get_phy_discover(struct domain_device *dev, disc_resp, DISCOVER_RESP_SIZE); if (res) goto out; - else if (disc_resp->result != SMP_RESP_FUNC_ACC) { + if (disc_resp->result != SMP_RESP_FUNC_ACC) res = disc_resp->result; - goto out; - } out: kfree(disc_req); return res; @@ -1686,7 +1684,7 @@ static int sas_get_phy_change_count(struct domain_device *dev, int phy_id, int *pcc) { int res; - struct smp_resp *disc_resp; + struct smp_disc_resp *disc_resp; disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); if (!disc_resp) @@ -1704,19 +1702,17 @@ static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, u8 *sas_addr, enum sas_device_type *type) { int res; - struct smp_resp *disc_resp; - struct discover_resp *dr; + struct smp_disc_resp *disc_resp; disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); if (!disc_resp) return -ENOMEM; - dr = &disc_resp->disc; res = sas_get_phy_discover(dev, phy_id, disc_resp); if (res == 0) { memcpy(sas_addr, disc_resp->disc.attached_sas_addr, SAS_ADDR_SIZE); - *type = to_dev_type(dr); + *type = to_dev_type(&disc_resp->disc); if (*type == 0) memset(sas_addr, 0, SAS_ADDR_SIZE); } diff --git a/include/scsi/sas.h b/include/scsi/sas.h index acfc69fd72d0..b3ee9bd63277 100644 --- a/include/scsi/sas.h +++ b/include/scsi/sas.h @@ -471,18 +471,6 @@ struct report_phy_sata_resp { __be32 crc; } __attribute__ ((packed)); -struct smp_resp { - u8 frame_type; - u8 function; - u8 result; - u8 reserved; - union { - struct report_general_resp rg; - struct discover_resp disc; - struct report_phy_sata_resp rps; - }; -} __attribute__ ((packed)); - #elif defined(__BIG_ENDIAN_BITFIELD) struct sas_identify_frame { /* Byte 0 */ @@ -704,6 +692,18 @@ struct report_phy_sata_resp { __be32 crc; } __attribute__ ((packed)); +#else +#error "Bitfield order not defined!" +#endif + +struct smp_disc_resp { + u8 frame_type; + u8 function; + u8 result; + u8 reserved; + struct discover_resp disc; +} __attribute__ ((packed)); + struct smp_resp { u8 frame_type; u8 function; @@ -716,8 +716,4 @@ struct smp_resp { }; } __attribute__ ((packed)); -#else -#error "Bitfield order not defined!" -#endif - #endif /* _SAS_H_ */ -- cgit v1.2.3 From 44f2bfe9ef082f76184d4a048c995729d14ec45d Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 9 Jun 2022 11:24:55 +0900 Subject: scsi: libsas: Introduce struct smp_rg_resp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with gcc 12, several warnings are thrown by gcc when compiling drivers/scsi/libsas/sas_expander.c, e.g.: In function ‘sas_get_ex_change_count’, inlined from ‘sas_find_bcast_dev’ at drivers/scsi/libsas/sas_expander.c:1816:8: drivers/scsi/libsas/sas_expander.c:1781:20: warning: array subscript ‘struct smp_resp[0]’ is partly outside array bounds of ‘unsigned char[32]’ [-Warray-bounds] 1781 | if (rg_resp->result != SMP_RESP_FUNC_ACC) { | ~~~~~~~^~~~~~~~ This is due to the use of the struct smp_resp to aggregate all possible response types using a union but allocating a response buffer with a size exactly equal to the size of the response type needed. This leads to access to fields of struct smp_resp from an allocated memory area that is smaller than the size of struct smp_resp. Fix this by defining struct smp_rg_resp for sas report general responses. Link: https://lore.kernel.org/r/20220609022456.409087-3-damien.lemoal@opensource.wdc.com Reviewed-by: John Garry Signed-off-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 31 +++++++++++++------------------ include/scsi/sas.h | 8 ++++++++ 2 files changed, 21 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index fb998a8a7d3b..78a38980636e 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -429,27 +429,14 @@ static int sas_expander_discover(struct domain_device *dev) #define MAX_EXPANDER_PHYS 128 -static void ex_assign_report_general(struct domain_device *dev, - struct smp_resp *resp) -{ - struct report_general_resp *rg = &resp->rg; - - dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count); - dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes); - dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS); - dev->ex_dev.t2t_supp = rg->t2t_supp; - dev->ex_dev.conf_route_table = rg->conf_route_table; - dev->ex_dev.configuring = rg->configuring; - memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8); -} - #define RG_REQ_SIZE 8 -#define RG_RESP_SIZE 32 +#define RG_RESP_SIZE sizeof(struct smp_rg_resp) static int sas_ex_general(struct domain_device *dev) { u8 *rg_req; - struct smp_resp *rg_resp; + struct smp_rg_resp *rg_resp; + struct report_general_resp *rg; int res; int i; @@ -480,7 +467,15 @@ static int sas_ex_general(struct domain_device *dev) goto out; } - ex_assign_report_general(dev, rg_resp); + rg = &rg_resp->rg; + dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count); + dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes); + dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS); + dev->ex_dev.t2t_supp = rg->t2t_supp; + dev->ex_dev.conf_route_table = rg->conf_route_table; + dev->ex_dev.configuring = rg->configuring; + memcpy(dev->ex_dev.enclosure_logical_id, + rg->enclosure_logical_id, 8); if (dev->ex_dev.configuring) { pr_debug("RG: ex %016llx self-configuring...\n", @@ -1756,7 +1751,7 @@ static int sas_get_ex_change_count(struct domain_device *dev, int *ecc) { int res; u8 *rg_req; - struct smp_resp *rg_resp; + struct smp_rg_resp *rg_resp; rg_req = alloc_smp_req(RG_REQ_SIZE); if (!rg_req) diff --git a/include/scsi/sas.h b/include/scsi/sas.h index b3ee9bd63277..a8f9743ed6fc 100644 --- a/include/scsi/sas.h +++ b/include/scsi/sas.h @@ -696,6 +696,14 @@ struct report_phy_sata_resp { #error "Bitfield order not defined!" #endif +struct smp_rg_resp { + u8 frame_type; + u8 function; + u8 result; + u8 reserved; + struct report_general_resp rg; +} __attribute__ ((packed)); + struct smp_disc_resp { u8 frame_type; u8 function; -- cgit v1.2.3 From 3dafe0648ddd9c40666069e90b8a8a6162c452aa Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 9 Jun 2022 11:24:56 +0900 Subject: scsi: libsas: Introduce struct smp_rps_resp Similarly to sas report general and discovery responses, define the structure struct smp_rps_resp to handle SATA PHY report responses using a structure with a size that is exactly equal to the sas defined response size. With this change, struct smp_resp becomes unused and is removed. Link: https://lore.kernel.org/r/20220609022456.409087-4-damien.lemoal@opensource.wdc.com Reviewed-by: John Garry Signed-off-by: Damien Le Moal Signed-off-by: Martin K. Petersen --- drivers/scsi/aic94xx/aic94xx_dev.c | 2 +- drivers/scsi/libsas/sas_expander.c | 4 ++-- drivers/scsi/libsas/sas_internal.h | 2 +- include/scsi/libsas.h | 2 +- include/scsi/sas.h | 8 ++------ 5 files changed, 7 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 73506a459bf8..91d196f26b76 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c @@ -159,7 +159,7 @@ static int asd_init_target_ddb(struct domain_device *dev) flags |= OPEN_REQUIRED; if ((dev->dev_type == SAS_SATA_DEV) || (dev->tproto & SAS_PROTOCOL_STP)) { - struct smp_resp *rps_resp = &dev->sata_dev.rps_resp; + struct smp_rps_resp *rps_resp = &dev->sata_dev.rps_resp; if (rps_resp->frame_type == SMP_RESPONSE && rps_resp->function == SMP_REPORT_PHY_SATA && rps_resp->result == SMP_RESP_FUNC_ACC) { diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 78a38980636e..fa2209080cc2 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -676,10 +676,10 @@ int sas_smp_get_phy_events(struct sas_phy *phy) #ifdef CONFIG_SCSI_SAS_ATA #define RPS_REQ_SIZE 16 -#define RPS_RESP_SIZE 60 +#define RPS_RESP_SIZE sizeof(struct smp_rps_resp) int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, - struct smp_resp *rps_resp) + struct smp_rps_resp *rps_resp) { int res; u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE); diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 13d0ffaada93..8d0ad3abc7b5 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -83,7 +83,7 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); int sas_ex_phy_discover(struct domain_device *dev, int single); int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, - struct smp_resp *rps_resp); + struct smp_rps_resp *rps_resp); int sas_try_ata_reset(struct asd_sas_phy *phy); void sas_hae_reset(struct work_struct *work); diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index ff04eb6d250b..2dbead74a2af 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -145,7 +145,7 @@ struct sata_device { struct ata_port *ap; struct ata_host *ata_host; - struct smp_resp rps_resp ____cacheline_aligned; /* report_phy_sata_resp */ + struct smp_rps_resp rps_resp ____cacheline_aligned; /* report_phy_sata_resp */ u8 fis[ATA_RESP_FIS_SIZE]; }; diff --git a/include/scsi/sas.h b/include/scsi/sas.h index a8f9743ed6fc..71b749bed3b0 100644 --- a/include/scsi/sas.h +++ b/include/scsi/sas.h @@ -712,16 +712,12 @@ struct smp_disc_resp { struct discover_resp disc; } __attribute__ ((packed)); -struct smp_resp { +struct smp_rps_resp { u8 frame_type; u8 function; u8 result; u8 reserved; - union { - struct report_general_resp rg; - struct discover_resp disc; - struct report_phy_sata_resp rps; - }; + struct report_phy_sata_resp rps; } __attribute__ ((packed)); #endif /* _SAS_H_ */ -- cgit v1.2.3 From 73b4b53276a1d6290cd4f47dbbc885b6e6e59ac6 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Thu, 19 May 2022 09:47:28 -0400 Subject: Revert "workqueue: remove unused cancel_work()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6417250d3f894e66a68ba1cd93676143f2376a6f. amdpgu need this function in order to prematurly stop pending reset works when another reset work already in progress. Acked-by: Tejun Heo Signed-off-by: Andrey Grodzovsky Reviewed-by: Lai Jiangshan Reviewed-by: Christian König Signed-off-by: Alex Deucher --- include/linux/workqueue.h | 1 + kernel/workqueue.c | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'include') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 7fee9b6cfede..9e41e1226193 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -453,6 +453,7 @@ extern int schedule_on_each_cpu(work_func_t func); int execute_in_process_context(work_func_t fn, struct execute_work *); extern bool flush_work(struct work_struct *work); +extern bool cancel_work(struct work_struct *work); extern bool cancel_work_sync(struct work_struct *work); extern bool flush_delayed_work(struct delayed_work *dwork); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 0d2514b4ff0d..20d226d5bbc2 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3258,6 +3258,15 @@ static bool __cancel_work(struct work_struct *work, bool is_dwork) return ret; } +/* + * See cancel_delayed_work() + */ +bool cancel_work(struct work_struct *work) +{ + return __cancel_work(work, false); +} +EXPORT_SYMBOL(cancel_work); + /** * cancel_delayed_work - cancel a delayed work * @dwork: delayed_work to cancel -- cgit v1.2.3 From 36518b6b4da7e8d4387bc19ad21e772f1060e9d7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 7 Jun 2022 16:04:03 -0400 Subject: teach iomap_dio_rw() to suppress dsync New flag, equivalent to removal of IOCB_DSYNC from iocb flags. This mimics what btrfs is doing (and that's what btrfs will switch to). However, I'm not at all sure that we want to suppress REQ_FUA for those - all btrfs hack really cares about is suppression of generic_write_sync(). For now let's keep the existing behaviour, but I really want to hear more detailed arguments pro or contra. [folded brain fix from willy] Suggested-by: Christoph Hellwig Reviewed-by: Christian Brauner (Microsoft) Signed-off-by: Al Viro --- fs/iomap/direct-io.c | 20 +++++++++++--------- include/linux/iomap.h | 6 ++++++ 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index 370c3241618a..c10c69e2de24 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -548,17 +548,19 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, } /* for data sync or sync, we need sync completion processing */ - if (iocb->ki_flags & IOCB_DSYNC) + if (iocb->ki_flags & IOCB_DSYNC && + !(dio_flags & IOMAP_DIO_NOSYNC)) { dio->flags |= IOMAP_DIO_NEED_SYNC; - /* - * For datasync only writes, we optimistically try using FUA for - * this IO. Any non-FUA write that occurs will clear this flag, - * hence we know before completion whether a cache flush is - * necessary. - */ - if ((iocb->ki_flags & (IOCB_DSYNC | IOCB_SYNC)) == IOCB_DSYNC) - dio->flags |= IOMAP_DIO_WRITE_FUA; + /* + * For datasync only writes, we optimistically try + * using FUA for this IO. Any non-FUA write that + * occurs will clear this flag, hence we know before + * completion whether a cache flush is necessary. + */ + if (!(iocb->ki_flags & IOCB_SYNC)) + dio->flags |= IOMAP_DIO_WRITE_FUA; + } } if (dio_flags & IOMAP_DIO_OVERWRITE_ONLY) { diff --git a/include/linux/iomap.h b/include/linux/iomap.h index e552097c67e0..c8622d8f064e 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -353,6 +353,12 @@ struct iomap_dio_ops { */ #define IOMAP_DIO_PARTIAL (1 << 2) +/* + * The caller will sync the write if needed; do not sync it within + * iomap_dio_rw. Overrides IOMAP_DIO_FORCE_WAIT. + */ +#define IOMAP_DIO_NOSYNC (1 << 3) + ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, const struct iomap_ops *ops, const struct iomap_dio_ops *dops, unsigned int dio_flags, void *private, size_t done_before); -- cgit v1.2.3 From e87f2c26c8085dac59978dee1beeb05cef31a9dd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 May 2022 09:28:12 -0400 Subject: struct file: use anonymous union member for rcuhead and llist Once upon a time we couldn't afford anon unions; these days minimal gcc version had been raised enough to take care of that. Reviewed-by: Jan Kara Reviewed-by: Christian Brauner (Microsoft) Signed-off-by: Al Viro --- fs/file_table.c | 16 ++++++++-------- include/linux/fs.h | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/fs/file_table.c b/fs/file_table.c index 5424e3a8df5f..b989e33aacda 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -45,7 +45,7 @@ static struct percpu_counter nr_files __cacheline_aligned_in_smp; static void file_free_rcu(struct rcu_head *head) { - struct file *f = container_of(head, struct file, f_u.fu_rcuhead); + struct file *f = container_of(head, struct file, f_rcuhead); put_cred(f->f_cred); kmem_cache_free(filp_cachep, f); @@ -56,7 +56,7 @@ static inline void file_free(struct file *f) security_file_free(f); if (!(f->f_mode & FMODE_NOACCOUNT)) percpu_counter_dec(&nr_files); - call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); + call_rcu(&f->f_rcuhead, file_free_rcu); } /* @@ -142,7 +142,7 @@ static struct file *__alloc_file(int flags, const struct cred *cred) f->f_cred = get_cred(cred); error = security_file_alloc(f); if (unlikely(error)) { - file_free_rcu(&f->f_u.fu_rcuhead); + file_free_rcu(&f->f_rcuhead); return ERR_PTR(error); } @@ -341,13 +341,13 @@ static void delayed_fput(struct work_struct *unused) struct llist_node *node = llist_del_all(&delayed_fput_list); struct file *f, *t; - llist_for_each_entry_safe(f, t, node, f_u.fu_llist) + llist_for_each_entry_safe(f, t, node, f_llist) __fput(f); } static void ____fput(struct callback_head *work) { - __fput(container_of(work, struct file, f_u.fu_rcuhead)); + __fput(container_of(work, struct file, f_rcuhead)); } /* @@ -374,8 +374,8 @@ void fput(struct file *file) struct task_struct *task = current; if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { - init_task_work(&file->f_u.fu_rcuhead, ____fput); - if (!task_work_add(task, &file->f_u.fu_rcuhead, TWA_RESUME)) + init_task_work(&file->f_rcuhead, ____fput); + if (!task_work_add(task, &file->f_rcuhead, TWA_RESUME)) return; /* * After this task has run exit_task_work(), @@ -384,7 +384,7 @@ void fput(struct file *file) */ } - if (llist_add(&file->f_u.fu_llist, &delayed_fput_list)) + if (llist_add(&file->f_llist, &delayed_fput_list)) schedule_delayed_work(&delayed_fput_work, 1); } } diff --git a/include/linux/fs.h b/include/linux/fs.h index 9ad5e3520fae..6a2a4906041f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -924,9 +924,9 @@ static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index) struct file { union { - struct llist_node fu_llist; - struct rcu_head fu_rcuhead; - } f_u; + struct llist_node f_llist; + struct rcu_head f_rcuhead; + }; struct path f_path; struct inode *f_inode; /* cached value */ const struct file_operations *f_op; -- cgit v1.2.3 From 91b94c5d6ae55d1161633047ffeea644b110b35f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 May 2022 09:39:27 -0400 Subject: iocb: delay evaluation of IS_SYNC(...) until we want to check IOCB_DSYNC New helper to be used instead of direct checks for IOCB_DSYNC: iocb_is_dsync(iocb). Checks converted, which allows to avoid the IS_SYNC(iocb->ki_filp->f_mapping->host) part (4 cache lines) from iocb_flags() - it's checked in iocb_is_dsync() instead Reviewed-by: Christian Brauner (Microsoft) Signed-off-by: Al Viro --- block/fops.c | 2 +- fs/btrfs/file.c | 2 +- fs/direct-io.c | 2 +- fs/fuse/file.c | 2 +- fs/iomap/direct-io.c | 3 +-- fs/zonefs/super.c | 2 +- include/linux/fs.h | 10 ++++++++-- 7 files changed, 14 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/block/fops.c b/block/fops.c index d6b3276a6c68..6e86931ab847 100644 --- a/block/fops.c +++ b/block/fops.c @@ -37,7 +37,7 @@ static unsigned int dio_bio_write_op(struct kiocb *iocb) unsigned int op = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE; /* avoid the need for a I/O completion work item */ - if (iocb->ki_flags & IOCB_DSYNC) + if (iocb_is_dsync(iocb)) op |= REQ_FUA; return op; } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 98f81e304eb1..54358a5c9d56 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2021,7 +2021,7 @@ ssize_t btrfs_do_write_iter(struct kiocb *iocb, struct iov_iter *from, struct file *file = iocb->ki_filp; struct btrfs_inode *inode = BTRFS_I(file_inode(file)); ssize_t num_written, num_sync; - const bool sync = iocb->ki_flags & IOCB_DSYNC; + const bool sync = iocb_is_dsync(iocb); /* * If the fs flips readonly due to some impossible error, although we diff --git a/fs/direct-io.c b/fs/direct-io.c index 840752006f60..39647eb56904 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1210,7 +1210,7 @@ ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, */ if (dio->is_async && iov_iter_rw(iter) == WRITE) { retval = 0; - if (iocb->ki_flags & IOCB_DSYNC) + if (iocb_is_dsync(iocb)) retval = dio_set_defer_completion(dio); else if (!dio->inode->i_sb->s_dio_done_wq) { /* diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 05caa2b9272e..00fa861aeead 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1042,7 +1042,7 @@ static unsigned int fuse_write_flags(struct kiocb *iocb) { unsigned int flags = iocb->ki_filp->f_flags; - if (iocb->ki_flags & IOCB_DSYNC) + if (iocb_is_dsync(iocb)) flags |= O_DSYNC; if (iocb->ki_flags & IOCB_SYNC) flags |= O_SYNC; diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index c10c69e2de24..31c7f1035b20 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -548,8 +548,7 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, } /* for data sync or sync, we need sync completion processing */ - if (iocb->ki_flags & IOCB_DSYNC && - !(dio_flags & IOMAP_DIO_NOSYNC)) { + if (iocb_is_dsync(iocb) && !(dio_flags & IOMAP_DIO_NOSYNC)) { dio->flags |= IOMAP_DIO_NEED_SYNC; /* diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c index bcb21aea990a..04a98b4cd7ee 100644 --- a/fs/zonefs/super.c +++ b/fs/zonefs/super.c @@ -746,7 +746,7 @@ static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from) REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE, GFP_NOFS); bio->bi_iter.bi_sector = zi->i_zsector; bio->bi_ioprio = iocb->ki_ioprio; - if (iocb->ki_flags & IOCB_DSYNC) + if (iocb_is_dsync(iocb)) bio->bi_opf |= REQ_FUA; ret = bio_iov_iter_get_pages(bio, from); diff --git a/include/linux/fs.h b/include/linux/fs.h index 6a2a4906041f..380a1292f4f9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2720,6 +2720,12 @@ extern int vfs_fsync(struct file *file, int datasync); extern int sync_file_range(struct file *file, loff_t offset, loff_t nbytes, unsigned int flags); +static inline bool iocb_is_dsync(const struct kiocb *iocb) +{ + return (iocb->ki_flags & IOCB_DSYNC) || + IS_SYNC(iocb->ki_filp->f_mapping->host); +} + /* * Sync the bytes written if this was a synchronous write. Expect ki_pos * to already be updated for the write, and will return either the amount @@ -2727,7 +2733,7 @@ extern int sync_file_range(struct file *file, loff_t offset, loff_t nbytes, */ static inline ssize_t generic_write_sync(struct kiocb *iocb, ssize_t count) { - if (iocb->ki_flags & IOCB_DSYNC) { + if (iocb_is_dsync(iocb)) { int ret = vfs_fsync_range(iocb->ki_filp, iocb->ki_pos - count, iocb->ki_pos - 1, (iocb->ki_flags & IOCB_SYNC) ? 0 : 1); @@ -3262,7 +3268,7 @@ static inline int iocb_flags(struct file *file) res |= IOCB_APPEND; if (file->f_flags & O_DIRECT) res |= IOCB_DIRECT; - if ((file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host)) + if (file->f_flags & O_DSYNC) res |= IOCB_DSYNC; if (file->f_flags & __O_SYNC) res |= IOCB_SYNC; -- cgit v1.2.3 From 164f4064ca81eefcea29f7f5dcf394f92be1d0c0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 May 2022 11:38:11 -0400 Subject: keep iocb_flags() result cached in struct file * calculate at the time we set FMODE_OPENED (do_dentry_open() for normal opens, alloc_file() for pipe()/socket()/etc.) * update when handling F_SETFL * keep in a new field - file->f_iocb_flags; since that thing is needed only before the refcount reaches zero, we can put it into the same anon union where ->f_rcuhead and ->f_llist live - those are used only after refcount reaches zero. Reviewed-by: Christian Brauner (Microsoft) Signed-off-by: Al Viro --- drivers/nvme/target/io-cmd-file.c | 2 +- fs/aio.c | 2 +- fs/fcntl.c | 1 + fs/file_table.c | 1 + fs/io_uring.c | 2 +- fs/open.c | 1 + include/linux/fs.h | 5 ++--- 7 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c index f3d58abf11e0..64b47e2a4633 100644 --- a/drivers/nvme/target/io-cmd-file.c +++ b/drivers/nvme/target/io-cmd-file.c @@ -112,7 +112,7 @@ static ssize_t nvmet_file_submit_bvec(struct nvmet_req *req, loff_t pos, iocb->ki_pos = pos; iocb->ki_filp = req->ns->file; - iocb->ki_flags = ki_flags | iocb_flags(req->ns->file); + iocb->ki_flags = ki_flags | iocb->ki_filp->f_iocb_flags; return call_iter(iocb, &iter); } diff --git a/fs/aio.c b/fs/aio.c index 3c249b938632..2bdd444d408b 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1475,7 +1475,7 @@ static int aio_prep_rw(struct kiocb *req, const struct iocb *iocb) req->ki_complete = aio_complete_rw; req->private = NULL; req->ki_pos = iocb->aio_offset; - req->ki_flags = iocb_flags(req->ki_filp); + req->ki_flags = req->ki_filp->f_iocb_flags; if (iocb->aio_flags & IOCB_FLAG_RESFD) req->ki_flags |= IOCB_EVENTFD; if (iocb->aio_flags & IOCB_FLAG_IOPRIO) { diff --git a/fs/fcntl.c b/fs/fcntl.c index 34a3faa4886d..146c9ab0cd4b 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -78,6 +78,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg) } spin_lock(&filp->f_lock); filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); + filp->f_iocb_flags = iocb_flags(filp); spin_unlock(&filp->f_lock); out: diff --git a/fs/file_table.c b/fs/file_table.c index b989e33aacda..905792b0521c 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -241,6 +241,7 @@ static struct file *alloc_file(const struct path *path, int flags, if ((file->f_mode & FMODE_WRITE) && likely(fop->write || fop->write_iter)) file->f_mode |= FMODE_CAN_WRITE; + file->f_iocb_flags = iocb_flags(file); file->f_mode |= FMODE_OPENED; file->f_op = fop; if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) diff --git a/fs/io_uring.c b/fs/io_uring.c index 3aab4182fd89..53424b1f019f 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -4330,7 +4330,7 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode) if (!io_req_ffs_set(req)) req->flags |= io_file_get_flags(file) << REQ_F_SUPPORT_NOWAIT_BIT; - kiocb->ki_flags = iocb_flags(file); + kiocb->ki_flags = file->f_iocb_flags; ret = kiocb_set_rw_flags(kiocb, req->rw.flags); if (unlikely(ret)) return ret; diff --git a/fs/open.c b/fs/open.c index 1d57fbde2feb..d80441a0bf17 100644 --- a/fs/open.c +++ b/fs/open.c @@ -862,6 +862,7 @@ static int do_dentry_open(struct file *f, f->f_mode |= FMODE_CAN_ODIRECT; f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + f->f_iocb_flags = iocb_flags(f); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); diff --git a/include/linux/fs.h b/include/linux/fs.h index 380a1292f4f9..c82b9d442f56 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -926,6 +926,7 @@ struct file { union { struct llist_node f_llist; struct rcu_head f_rcuhead; + unsigned int f_iocb_flags; }; struct path f_path; struct inode *f_inode; /* cached value */ @@ -2199,13 +2200,11 @@ static inline bool HAS_UNMAPPED_ID(struct user_namespace *mnt_userns, !gid_valid(i_gid_into_mnt(mnt_userns, inode)); } -static inline int iocb_flags(struct file *file); - static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp) { *kiocb = (struct kiocb) { .ki_filp = filp, - .ki_flags = iocb_flags(filp), + .ki_flags = filp->f_iocb_flags, .ki_ioprio = get_current_ioprio(), }; } -- cgit v1.2.3 From e70f3c701276a8825414dc650c4f76141a8704b4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:06 -0700 Subject: Revert "net: set SK_MEM_QUANTUM to 4096" This reverts commit bd68a2a854ad5a85f0c8d0a9c8048ca3f6391efb. This change broke memcg on arches with PAGE_SIZE != 4096 Later, commit 2bb2f5fb21b04 ("net: add new socket option SO_RESERVE_MEM") also assumed PAGE_SIZE==SK_MEM_QUANTUM Following patches in the series will greatly reduce the over allocations problem. Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 657873e2d90f..5c5265269899 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1532,25 +1532,15 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind); void __sk_mem_reduce_allocated(struct sock *sk, int amount); void __sk_mem_reclaim(struct sock *sk, int amount); -/* We used to have PAGE_SIZE here, but systems with 64KB pages - * do not necessarily have 16x time more memory than 4KB ones. - */ -#define SK_MEM_QUANTUM 4096 +#define SK_MEM_QUANTUM ((int)PAGE_SIZE) #define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM) #define SK_MEM_SEND 0 #define SK_MEM_RECV 1 -/* sysctl_mem values are in pages, we convert them in SK_MEM_QUANTUM units */ +/* sysctl_mem values are in pages */ static inline long sk_prot_mem_limits(const struct sock *sk, int index) { - long val = sk->sk_prot->sysctl_mem[index]; - -#if PAGE_SIZE > SK_MEM_QUANTUM - val <<= PAGE_SHIFT - SK_MEM_QUANTUM_SHIFT; -#elif PAGE_SIZE < SK_MEM_QUANTUM - val >>= SK_MEM_QUANTUM_SHIFT - PAGE_SHIFT; -#endif - return val; + return sk->sk_prot->sysctl_mem[index]; } static inline int sk_mem_pages(int amt) -- cgit v1.2.3 From 100fdd1faf50557558e2911af4be32e515cb8036 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:07 -0700 Subject: net: remove SK_MEM_QUANTUM and SK_MEM_QUANTUM_SHIFT Due to memcg interface, SK_MEM_QUANTUM is effectively PAGE_SIZE. This might change in the future, but it seems better to avoid the confusion. Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 8 +++----- net/core/sock.c | 16 ++++++++-------- net/ipv4/tcp.c | 4 ++-- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_output.c | 2 +- net/ipv4/udp.c | 10 +++++----- net/mptcp/protocol.c | 8 ++++---- net/sctp/protocol.c | 4 ++-- 8 files changed, 26 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 5c5265269899..298897bbfb3a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1532,8 +1532,6 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind); void __sk_mem_reduce_allocated(struct sock *sk, int amount); void __sk_mem_reclaim(struct sock *sk, int amount); -#define SK_MEM_QUANTUM ((int)PAGE_SIZE) -#define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM) #define SK_MEM_SEND 0 #define SK_MEM_RECV 1 @@ -1545,7 +1543,7 @@ static inline long sk_prot_mem_limits(const struct sock *sk, int index) static inline int sk_mem_pages(int amt) { - return (amt + SK_MEM_QUANTUM - 1) >> SK_MEM_QUANTUM_SHIFT; + return (amt + PAGE_SIZE - 1) >> PAGE_SHIFT; } static inline bool sk_has_account(struct sock *sk) @@ -1594,7 +1592,7 @@ static inline void sk_mem_reclaim(struct sock *sk) reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk); - if (reclaimable >= SK_MEM_QUANTUM) + if (reclaimable >= (int)PAGE_SIZE) __sk_mem_reclaim(sk, reclaimable); } @@ -1613,7 +1611,7 @@ static inline void sk_mem_reclaim_partial(struct sock *sk) reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk); - if (reclaimable > SK_MEM_QUANTUM) + if (reclaimable > (int)PAGE_SIZE) __sk_mem_reclaim(sk, reclaimable - 1); } diff --git a/net/core/sock.c b/net/core/sock.c index f5062d9e1222..063fd7680a84 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -991,7 +991,7 @@ EXPORT_SYMBOL(sock_set_mark); static void sock_release_reserved_memory(struct sock *sk, int bytes) { /* Round down bytes to multiple of pages */ - bytes &= ~(SK_MEM_QUANTUM - 1); + bytes = round_down(bytes, PAGE_SIZE); WARN_ON(bytes > sk->sk_reserved_mem); sk->sk_reserved_mem -= bytes; @@ -1028,9 +1028,9 @@ static int sock_reserve_memory(struct sock *sk, int bytes) mem_cgroup_uncharge_skmem(sk->sk_memcg, pages); return -ENOMEM; } - sk->sk_forward_alloc += pages << SK_MEM_QUANTUM_SHIFT; + sk->sk_forward_alloc += pages << PAGE_SHIFT; - sk->sk_reserved_mem += pages << SK_MEM_QUANTUM_SHIFT; + sk->sk_reserved_mem += pages << PAGE_SHIFT; return 0; } @@ -3003,10 +3003,10 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind) { int ret, amt = sk_mem_pages(size); - sk->sk_forward_alloc += amt << SK_MEM_QUANTUM_SHIFT; + sk->sk_forward_alloc += amt << PAGE_SHIFT; ret = __sk_mem_raise_allocated(sk, size, amt, kind); if (!ret) - sk->sk_forward_alloc -= amt << SK_MEM_QUANTUM_SHIFT; + sk->sk_forward_alloc -= amt << PAGE_SHIFT; return ret; } EXPORT_SYMBOL(__sk_mem_schedule); @@ -3034,12 +3034,12 @@ EXPORT_SYMBOL(__sk_mem_reduce_allocated); /** * __sk_mem_reclaim - reclaim sk_forward_alloc and memory_allocated * @sk: socket - * @amount: number of bytes (rounded down to a SK_MEM_QUANTUM multiple) + * @amount: number of bytes (rounded down to a PAGE_SIZE multiple) */ void __sk_mem_reclaim(struct sock *sk, int amount) { - amount >>= SK_MEM_QUANTUM_SHIFT; - sk->sk_forward_alloc -= amount << SK_MEM_QUANTUM_SHIFT; + amount >>= PAGE_SHIFT; + sk->sk_forward_alloc -= amount << PAGE_SHIFT; __sk_mem_reduce_allocated(sk, amount); } EXPORT_SYMBOL(__sk_mem_reclaim); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9984d23a7f3e..9e696758a4c2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -4661,11 +4661,11 @@ void __init tcp_init(void) max_wshare = min(4UL*1024*1024, limit); max_rshare = min(6UL*1024*1024, limit); - init_net.ipv4.sysctl_tcp_wmem[0] = SK_MEM_QUANTUM; + init_net.ipv4.sysctl_tcp_wmem[0] = PAGE_SIZE; init_net.ipv4.sysctl_tcp_wmem[1] = 16*1024; init_net.ipv4.sysctl_tcp_wmem[2] = max(64*1024, max_wshare); - init_net.ipv4.sysctl_tcp_rmem[0] = SK_MEM_QUANTUM; + init_net.ipv4.sysctl_tcp_rmem[0] = PAGE_SIZE; init_net.ipv4.sysctl_tcp_rmem[1] = 131072; init_net.ipv4.sysctl_tcp_rmem[2] = max(131072, max_rshare); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2e2a9ece9af2..3fb117022558 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5287,7 +5287,7 @@ new_range: before(TCP_SKB_CB(skb)->end_seq, start)) { /* Do not attempt collapsing tiny skbs */ if (range_truesize != head->truesize || - end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) { + end - start >= SKB_WITH_OVERHEAD(PAGE_SIZE)) { tcp_collapse(sk, NULL, &tp->out_of_order_queue, head, skb, start, end); } else { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 1c054431e358..8ab98e1aca67 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3367,7 +3367,7 @@ void sk_forced_mem_schedule(struct sock *sk, int size) if (size <= sk->sk_forward_alloc) return; amt = sk_mem_pages(size); - sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; + sk->sk_forward_alloc += amt << PAGE_SHIFT; sk_memory_allocated_add(sk, amt); if (mem_cgroup_sockets_enabled && sk->sk_memcg) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index aa9f2ec3dc46..bbc9970fa2e9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1461,11 +1461,11 @@ static void udp_rmem_release(struct sock *sk, int size, int partial, sk->sk_forward_alloc += size; - amt = (sk->sk_forward_alloc - partial) & ~(SK_MEM_QUANTUM - 1); + amt = (sk->sk_forward_alloc - partial) & ~(PAGE_SIZE - 1); sk->sk_forward_alloc -= amt; if (amt) - __sk_mem_reduce_allocated(sk, amt >> SK_MEM_QUANTUM_SHIFT); + __sk_mem_reduce_allocated(sk, amt >> PAGE_SHIFT); atomic_sub(size, &sk->sk_rmem_alloc); @@ -1558,7 +1558,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb) spin_lock(&list->lock); if (size >= sk->sk_forward_alloc) { amt = sk_mem_pages(size); - delta = amt << SK_MEM_QUANTUM_SHIFT; + delta = amt << PAGE_SHIFT; if (!__sk_mem_raise_allocated(sk, delta, amt, SK_MEM_RECV)) { err = -ENOBUFS; spin_unlock(&list->lock); @@ -3263,8 +3263,8 @@ EXPORT_SYMBOL(udp_flow_hashrnd); static void __udp_sysctl_init(struct net *net) { - net->ipv4.sysctl_udp_rmem_min = SK_MEM_QUANTUM; - net->ipv4.sysctl_udp_wmem_min = SK_MEM_QUANTUM; + net->ipv4.sysctl_udp_rmem_min = PAGE_SIZE; + net->ipv4.sysctl_udp_wmem_min = PAGE_SIZE; #ifdef CONFIG_NET_L3_MASTER_DEV net->ipv4.sysctl_udp_l3mdev_accept = 0; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 17e13396024a..080a630d6902 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -167,8 +167,8 @@ static bool mptcp_ooo_try_coalesce(struct mptcp_sock *msk, struct sk_buff *to, static void __mptcp_rmem_reclaim(struct sock *sk, int amount) { - amount >>= SK_MEM_QUANTUM_SHIFT; - mptcp_sk(sk)->rmem_fwd_alloc -= amount << SK_MEM_QUANTUM_SHIFT; + amount >>= PAGE_SHIFT; + mptcp_sk(sk)->rmem_fwd_alloc -= amount << PAGE_SHIFT; __sk_mem_reduce_allocated(sk, amount); } @@ -327,7 +327,7 @@ static bool mptcp_rmem_schedule(struct sock *sk, struct sock *ssk, int size) return true; amt = sk_mem_pages(size); - amount = amt << SK_MEM_QUANTUM_SHIFT; + amount = amt << PAGE_SHIFT; msk->rmem_fwd_alloc += amount; if (!__sk_mem_raise_allocated(sk, size, amt, SK_MEM_RECV)) { if (ssk->sk_forward_alloc < amount) { @@ -972,7 +972,7 @@ static void __mptcp_mem_reclaim_partial(struct sock *sk) lockdep_assert_held_once(&sk->sk_lock.slock); - if (reclaimable > SK_MEM_QUANTUM) + if (reclaimable > (int)PAGE_SIZE) __mptcp_rmem_reclaim(sk, reclaimable - 1); sk_mem_reclaim_partial(sk); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 35928fefae33..fa500ea3a1f1 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1523,11 +1523,11 @@ static __init int sctp_init(void) limit = (sysctl_sctp_mem[1]) << (PAGE_SHIFT - 7); max_share = min(4UL*1024*1024, limit); - sysctl_sctp_rmem[0] = SK_MEM_QUANTUM; /* give each asoc 1 page min */ + sysctl_sctp_rmem[0] = PAGE_SIZE; /* give each asoc 1 page min */ sysctl_sctp_rmem[1] = 1500 * SKB_TRUESIZE(1); sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share); - sysctl_sctp_wmem[0] = SK_MEM_QUANTUM; + sysctl_sctp_wmem[0] = PAGE_SIZE; sysctl_sctp_wmem[1] = 16*1024; sysctl_sctp_wmem[2] = max(64*1024, max_share); -- cgit v1.2.3 From 0defbb0af775ef037913786048d099bbe8b9a2c2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:08 -0700 Subject: net: add per_cpu_fw_alloc field to struct proto Each protocol having a ->memory_allocated pointer gets a corresponding per-cpu reserve, that following patches will use. Instead of having reserved bytes per socket, we want to have per-cpu reserves. Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 1 + include/net/tcp.h | 2 ++ include/net/udp.h | 1 + net/core/sock.c | 4 ++++ net/decnet/af_decnet.c | 4 ++++ net/ipv4/tcp.c | 2 ++ net/ipv4/tcp_ipv4.c | 3 +++ net/ipv4/udp.c | 4 ++++ net/ipv4/udplite.c | 3 +++ net/ipv6/tcp_ipv6.c | 3 +++ net/ipv6/udp.c | 3 +++ net/ipv6/udplite.c | 3 +++ net/mptcp/protocol.c | 3 +++ net/sctp/socket.c | 7 +++++++ 14 files changed, 43 insertions(+) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 298897bbfb3a..825f8cbf791f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1254,6 +1254,7 @@ struct proto { void (*enter_memory_pressure)(struct sock *sk); void (*leave_memory_pressure)(struct sock *sk); atomic_long_t *memory_allocated; /* Current allocated memory. */ + int __percpu *per_cpu_fw_alloc; struct percpu_counter *sockets_allocated; /* Current number of sockets. */ /* diff --git a/include/net/tcp.h b/include/net/tcp.h index 1e99f5c61f84..4794cae4577e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -253,6 +253,8 @@ extern long sysctl_tcp_mem[3]; #define TCP_RACK_NO_DUPTHRESH 0x4 /* Do not use DUPACK threshold in RACK */ extern atomic_long_t tcp_memory_allocated; +DECLARE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc); + extern struct percpu_counter tcp_sockets_allocated; extern unsigned long tcp_memory_pressure; diff --git a/include/net/udp.h b/include/net/udp.h index b83a00330566..b60eea2e3fae 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -95,6 +95,7 @@ static inline struct udp_hslot *udp_hashslot2(struct udp_table *table, extern struct proto udp_prot; extern atomic_long_t udp_memory_allocated; +DECLARE_PER_CPU(int, udp_memory_per_cpu_fw_alloc); /* sysctl variables for udp */ extern long sysctl_udp_mem[3]; diff --git a/net/core/sock.c b/net/core/sock.c index 063fd7680a84..f96efc95e334 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -3798,6 +3798,10 @@ int proto_register(struct proto *prot, int alloc_slab) pr_err("%s: missing sysctl_mem\n", prot->name); return -EINVAL; } + if (prot->memory_allocated && !prot->per_cpu_fw_alloc) { + pr_err("%s: missing per_cpu_fw_alloc\n", prot->name); + return -EINVAL; + } if (alloc_slab) { prot->slab = kmem_cache_create_usercopy(prot->name, prot->obj_size, 0, diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index dc92a67baea3..aa4f43f52499 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -149,6 +149,7 @@ static DEFINE_RWLOCK(dn_hash_lock); static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE]; static struct hlist_head dn_wild_sk; static atomic_long_t decnet_memory_allocated; +static DEFINE_PER_CPU(int, decnet_memory_per_cpu_fw_alloc); static int __dn_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, unsigned int optlen, int flags); @@ -454,7 +455,10 @@ static struct proto dn_proto = { .owner = THIS_MODULE, .enter_memory_pressure = dn_enter_memory_pressure, .memory_pressure = &dn_memory_pressure, + .memory_allocated = &decnet_memory_allocated, + .per_cpu_fw_alloc = &decnet_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_decnet_mem, .sysctl_wmem = sysctl_decnet_wmem, .sysctl_rmem = sysctl_decnet_rmem, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9e696758a4c2..e6bdf8e2c09a 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -294,6 +294,8 @@ EXPORT_SYMBOL(sysctl_tcp_mem); atomic_long_t tcp_memory_allocated ____cacheline_aligned_in_smp; /* Current allocated memory. */ EXPORT_SYMBOL(tcp_memory_allocated); +DEFINE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc); +EXPORT_PER_CPU_SYMBOL_GPL(tcp_memory_per_cpu_fw_alloc); #if IS_ENABLED(CONFIG_SMC) DEFINE_STATIC_KEY_FALSE(tcp_have_smc); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fe8f23b95d32..fda811a5251f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3045,7 +3045,10 @@ struct proto tcp_prot = { .stream_memory_free = tcp_stream_memory_free, .sockets_allocated = &tcp_sockets_allocated, .orphan_count = &tcp_orphan_count, + .memory_allocated = &tcp_memory_allocated, + .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, + .memory_pressure = &tcp_memory_pressure, .sysctl_mem = sysctl_tcp_mem, .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_tcp_wmem), diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index bbc9970fa2e9..6172b4750a88 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -125,6 +125,8 @@ EXPORT_SYMBOL(sysctl_udp_mem); atomic_long_t udp_memory_allocated ____cacheline_aligned_in_smp; EXPORT_SYMBOL(udp_memory_allocated); +DEFINE_PER_CPU(int, udp_memory_per_cpu_fw_alloc); +EXPORT_PER_CPU_SYMBOL_GPL(udp_memory_per_cpu_fw_alloc); #define MAX_UDP_PORTS 65536 #define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN) @@ -2946,6 +2948,8 @@ struct proto udp_prot = { .psock_update_sk_prot = udp_bpf_update_proto, #endif .memory_allocated = &udp_memory_allocated, + .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_udp_mem, .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_udp_wmem_min), .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_udp_rmem_min), diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index cd1cd68adeec..6e08a76ae1e7 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -51,7 +51,10 @@ struct proto udplite_prot = { .unhash = udp_lib_unhash, .rehash = udp_v4_rehash, .get_port = udp_v4_get_port, + .memory_allocated = &udp_memory_allocated, + .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_udp_mem, .obj_size = sizeof(struct udp_sock), .h.udp_table = &udplite_table, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f37dd4aa91c6..c72448ba6dc9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2159,7 +2159,10 @@ struct proto tcpv6_prot = { .leave_memory_pressure = tcp_leave_memory_pressure, .stream_memory_free = tcp_stream_memory_free, .sockets_allocated = &tcp_sockets_allocated, + .memory_allocated = &tcp_memory_allocated, + .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, + .memory_pressure = &tcp_memory_pressure, .orphan_count = &tcp_orphan_count, .sysctl_mem = sysctl_tcp_mem, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 55afd7f39c04..be074f07073a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1740,7 +1740,10 @@ struct proto udpv6_prot = { #ifdef CONFIG_BPF_SYSCALL .psock_update_sk_prot = udp_bpf_update_proto, #endif + .memory_allocated = &udp_memory_allocated, + .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_udp_mem, .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_udp_wmem_min), .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_udp_rmem_min), diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index fbb700d3f437..b70725856259 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -48,7 +48,10 @@ struct proto udplitev6_prot = { .unhash = udp_lib_unhash, .rehash = udp_v6_rehash, .get_port = udp_v6_get_port, + .memory_allocated = &udp_memory_allocated, + .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, + .sysctl_mem = sysctl_udp_mem, .obj_size = sizeof(struct udp6_sock), .h.udp_table = &udplite_table, diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 080a630d6902..9563124ac8af 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3437,7 +3437,10 @@ static struct proto mptcp_prot = { .get_port = mptcp_get_port, .forward_alloc_get = mptcp_forward_alloc_get, .sockets_allocated = &mptcp_sockets_allocated, + .memory_allocated = &tcp_memory_allocated, + .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, + .memory_pressure = &tcp_memory_pressure, .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_tcp_wmem), .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6d37d2dfb3da..05174acd981a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -93,6 +93,7 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, static unsigned long sctp_memory_pressure; static atomic_long_t sctp_memory_allocated; +static DEFINE_PER_CPU(int, sctp_memory_per_cpu_fw_alloc); struct percpu_counter sctp_sockets_allocated; static void sctp_enter_memory_pressure(struct sock *sk) @@ -9657,7 +9658,10 @@ struct proto sctp_prot = { .sysctl_wmem = sysctl_sctp_wmem, .memory_pressure = &sctp_memory_pressure, .enter_memory_pressure = sctp_enter_memory_pressure, + .memory_allocated = &sctp_memory_allocated, + .per_cpu_fw_alloc = &sctp_memory_per_cpu_fw_alloc, + .sockets_allocated = &sctp_sockets_allocated, }; @@ -9700,7 +9704,10 @@ struct proto sctpv6_prot = { .sysctl_wmem = sysctl_sctp_wmem, .memory_pressure = &sctp_memory_pressure, .enter_memory_pressure = sctp_enter_memory_pressure, + .memory_allocated = &sctp_memory_allocated, + .per_cpu_fw_alloc = &sctp_memory_per_cpu_fw_alloc, + .sockets_allocated = &sctp_sockets_allocated, }; #endif /* IS_ENABLED(CONFIG_IPV6) */ -- cgit v1.2.3 From 3cd3399dd7a84ada85cb839989cdf7310e302c7d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:09 -0700 Subject: net: implement per-cpu reserves for memory_allocated We plan keeping sk->sk_forward_alloc as small as possible in future patches. This means we are going to call sk_memory_allocated_add() and sk_memory_allocated_sub() more often. Implement a per-cpu cache of +1/-1 MB, to reduce number of changes to sk->sk_prot->memory_allocated, which would otherwise be cause of false sharing. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Reviewed-by: Shakeel Butt Signed-off-by: Jakub Kicinski --- include/net/sock.h | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 825f8cbf791f..59040fee74e7 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1397,22 +1397,48 @@ static inline bool sk_under_memory_pressure(const struct sock *sk) return !!*sk->sk_prot->memory_pressure; } +static inline long +proto_memory_allocated(const struct proto *prot) +{ + return max(0L, atomic_long_read(prot->memory_allocated)); +} + static inline long sk_memory_allocated(const struct sock *sk) { - return atomic_long_read(sk->sk_prot->memory_allocated); + return proto_memory_allocated(sk->sk_prot); } +/* 1 MB per cpu, in page units */ +#define SK_MEMORY_PCPU_RESERVE (1 << (20 - PAGE_SHIFT)) + static inline long sk_memory_allocated_add(struct sock *sk, int amt) { - return atomic_long_add_return(amt, sk->sk_prot->memory_allocated); + int local_reserve; + + preempt_disable(); + local_reserve = __this_cpu_add_return(*sk->sk_prot->per_cpu_fw_alloc, amt); + if (local_reserve >= SK_MEMORY_PCPU_RESERVE) { + __this_cpu_sub(*sk->sk_prot->per_cpu_fw_alloc, local_reserve); + atomic_long_add(local_reserve, sk->sk_prot->memory_allocated); + } + preempt_enable(); + return sk_memory_allocated(sk); } static inline void sk_memory_allocated_sub(struct sock *sk, int amt) { - atomic_long_sub(amt, sk->sk_prot->memory_allocated); + int local_reserve; + + preempt_disable(); + local_reserve = __this_cpu_sub_return(*sk->sk_prot->per_cpu_fw_alloc, amt); + if (local_reserve <= -SK_MEMORY_PCPU_RESERVE) { + __this_cpu_sub(*sk->sk_prot->per_cpu_fw_alloc, local_reserve); + atomic_long_add(local_reserve, sk->sk_prot->memory_allocated); + } + preempt_enable(); } #define SK_ALLOC_PERCPU_COUNTER_BATCH 16 @@ -1441,12 +1467,6 @@ proto_sockets_allocated_sum_positive(struct proto *prot) return percpu_counter_sum_positive(prot->sockets_allocated); } -static inline long -proto_memory_allocated(struct proto *prot) -{ - return atomic_long_read(prot->memory_allocated); -} - static inline bool proto_memory_pressure(struct proto *prot) { -- cgit v1.2.3 From 7c80b038d23e1f4c7fcc311f43f83b8c60e7fb80 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:10 -0700 Subject: net: fix sk_wmem_schedule() and sk_rmem_schedule() errors If sk->sk_forward_alloc is 150000, and we need to schedule 150001 bytes, we want to allocate 1 byte more (rounded up to one page), instead of 150001 :/ Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 59040fee74e7..cf288f7e9019 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1575,19 +1575,23 @@ static inline bool sk_has_account(struct sock *sk) static inline bool sk_wmem_schedule(struct sock *sk, int size) { + int delta; + if (!sk_has_account(sk)) return true; - return size <= sk->sk_forward_alloc || - __sk_mem_schedule(sk, size, SK_MEM_SEND); + delta = size - sk->sk_forward_alloc; + return delta <= 0 || __sk_mem_schedule(sk, delta, SK_MEM_SEND); } static inline bool sk_rmem_schedule(struct sock *sk, struct sk_buff *skb, int size) { + int delta; + if (!sk_has_account(sk)) return true; - return size <= sk->sk_forward_alloc || - __sk_mem_schedule(sk, size, SK_MEM_RECV) || + delta = size - sk->sk_forward_alloc; + return delta <= 0 || __sk_mem_schedule(sk, delta, SK_MEM_RECV) || skb_pfmemalloc(skb); } -- cgit v1.2.3 From 4890b686f4088c90432149bd6de567e621266fa2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2022 23:34:11 -0700 Subject: net: keep sk->sk_forward_alloc as small as possible Currently, tcp_memory_allocated can hit tcp_mem[] limits quite fast. Each TCP socket can forward allocate up to 2 MB of memory, even after flow became less active. 10,000 sockets can have reserved 20 GB of memory, and we have no shrinker in place to reclaim that. Instead of trying to reclaim the extra allocations in some places, just keep sk->sk_forward_alloc values as small as possible. This should not impact performance too much now we have per-cpu reserves: Changes to tcp_memory_allocated should not be too frequent. For sockets not using SO_RESERVE_MEM: - idle sockets (no packets in tx/rx queues) have zero forward alloc. - non idle sockets have a forward alloc smaller than one page. Note: - Removal of SK_RECLAIM_CHUNK and SK_RECLAIM_THRESHOLD is left to MPTCP maintainers as a follow up. Signed-off-by: Eric Dumazet Reviewed-by: Shakeel Butt Acked-by: Soheil Hassas Yeganeh Signed-off-by: Jakub Kicinski --- include/net/sock.h | 29 ++--------------------------- net/core/datagram.c | 3 --- net/ipv4/tcp.c | 7 ------- net/ipv4/tcp_input.c | 4 ---- net/ipv4/tcp_timer.c | 19 ++++--------------- net/iucv/af_iucv.c | 2 -- net/mptcp/protocol.c | 2 +- net/sctp/sm_statefuns.c | 2 -- net/sctp/socket.c | 5 ----- net/sctp/stream_interleave.c | 2 -- net/sctp/ulpqueue.c | 4 ---- 11 files changed, 7 insertions(+), 72 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index cf288f7e9019..0063e8410a4e 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1627,19 +1627,6 @@ static inline void sk_mem_reclaim_final(struct sock *sk) sk_mem_reclaim(sk); } -static inline void sk_mem_reclaim_partial(struct sock *sk) -{ - int reclaimable; - - if (!sk_has_account(sk)) - return; - - reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk); - - if (reclaimable > (int)PAGE_SIZE) - __sk_mem_reclaim(sk, reclaimable - 1); -} - static inline void sk_mem_charge(struct sock *sk, int size) { if (!sk_has_account(sk)) @@ -1647,29 +1634,17 @@ static inline void sk_mem_charge(struct sock *sk, int size) sk->sk_forward_alloc -= size; } -/* the following macros control memory reclaiming in sk_mem_uncharge() +/* the following macros control memory reclaiming in mptcp_rmem_uncharge() */ #define SK_RECLAIM_THRESHOLD (1 << 21) #define SK_RECLAIM_CHUNK (1 << 20) static inline void sk_mem_uncharge(struct sock *sk, int size) { - int reclaimable; - if (!sk_has_account(sk)) return; sk->sk_forward_alloc += size; - reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk); - - /* Avoid a possible overflow. - * TCP send queues can make this happen, if sk_mem_reclaim() - * is not called and more than 2 GBytes are released at once. - * - * If we reach 2 MBytes, reclaim 1 MBytes right now, there is - * no need to hold that much forward allocation anyway. - */ - if (unlikely(reclaimable >= SK_RECLAIM_THRESHOLD)) - __sk_mem_reclaim(sk, SK_RECLAIM_CHUNK); + sk_mem_reclaim(sk); } /* diff --git a/net/core/datagram.c b/net/core/datagram.c index 50f4faeea76c..35791f86bd1a 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -320,7 +320,6 @@ EXPORT_SYMBOL(skb_recv_datagram); void skb_free_datagram(struct sock *sk, struct sk_buff *skb) { consume_skb(skb); - sk_mem_reclaim_partial(sk); } EXPORT_SYMBOL(skb_free_datagram); @@ -336,7 +335,6 @@ void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len) slow = lock_sock_fast(sk); sk_peek_offset_bwd(sk, len); skb_orphan(skb); - sk_mem_reclaim_partial(sk); unlock_sock_fast(sk, slow); /* skb is now orphaned, can be freed outside of locked section */ @@ -396,7 +394,6 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) NULL); kfree_skb(skb); - sk_mem_reclaim_partial(sk); return err; } EXPORT_SYMBOL(skb_kill_datagram); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e6bdf8e2c09a..14ebb4ec4a51 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -858,9 +858,6 @@ struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, { struct sk_buff *skb; - if (unlikely(tcp_under_memory_pressure(sk))) - sk_mem_reclaim_partial(sk); - skb = alloc_skb_fclone(size + MAX_TCP_HEADER, gfp); if (likely(skb)) { bool mem_scheduled; @@ -2764,8 +2761,6 @@ void __tcp_close(struct sock *sk, long timeout) __kfree_skb(skb); } - sk_mem_reclaim(sk); - /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */ if (sk->sk_state == TCP_CLOSE) goto adjudge_to_death; @@ -2873,7 +2868,6 @@ adjudge_to_death: } } if (sk->sk_state != TCP_CLOSE) { - sk_mem_reclaim(sk); if (tcp_check_oom(sk, 0)) { tcp_set_state(sk, TCP_CLOSE); tcp_send_active_reset(sk, GFP_ATOMIC); @@ -2951,7 +2945,6 @@ void tcp_write_queue_purge(struct sock *sk) } tcp_rtx_queue_purge(sk); INIT_LIST_HEAD(&tcp_sk(sk)->tsorted_sent_queue); - sk_mem_reclaim(sk); tcp_clear_all_retrans_hints(tcp_sk(sk)); tcp_sk(sk)->packets_out = 0; inet_csk(sk)->icsk_backoff = 0; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3fb117022558..fdc7beb81b68 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -805,7 +805,6 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) * restart window, so that we send ACKs quickly. */ tcp_incr_quickack(sk, TCP_MAX_QUICKACKS); - sk_mem_reclaim(sk); } } icsk->icsk_ack.lrcvtime = now; @@ -4390,7 +4389,6 @@ void tcp_fin(struct sock *sk) skb_rbtree_purge(&tp->out_of_order_queue); if (tcp_is_sack(tp)) tcp_sack_reset(&tp->rx_opt); - sk_mem_reclaim(sk); if (!sock_flag(sk, SOCK_DEAD)) { sk->sk_state_change(sk); @@ -5336,7 +5334,6 @@ static bool tcp_prune_ofo_queue(struct sock *sk) tcp_drop_reason(sk, rb_to_skb(node), SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE); if (!prev || goal <= 0) { - sk_mem_reclaim(sk); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && !tcp_under_memory_pressure(sk)) break; @@ -5383,7 +5380,6 @@ static int tcp_prune_queue(struct sock *sk) skb_peek(&sk->sk_receive_queue), NULL, tp->copied_seq, tp->rcv_nxt); - sk_mem_reclaim(sk); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) return 0; diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 20cf4a98c69d..2208755e8efc 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -290,15 +290,13 @@ void tcp_delack_timer_handler(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); - sk_mem_reclaim_partial(sk); - if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) - goto out; + return; if (time_after(icsk->icsk_ack.timeout, jiffies)) { sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout); - goto out; + return; } icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER; @@ -317,10 +315,6 @@ void tcp_delack_timer_handler(struct sock *sk) tcp_send_ack(sk); __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS); } - -out: - if (tcp_under_memory_pressure(sk)) - sk_mem_reclaim(sk); } @@ -600,11 +594,11 @@ void tcp_write_timer_handler(struct sock *sk) if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || !icsk->icsk_pending) - goto out; + return; if (time_after(icsk->icsk_timeout, jiffies)) { sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout); - goto out; + return; } tcp_mstamp_refresh(tcp_sk(sk)); @@ -626,9 +620,6 @@ void tcp_write_timer_handler(struct sock *sk) tcp_probe_timer(sk); break; } - -out: - sk_mem_reclaim(sk); } static void tcp_write_timer(struct timer_list *t) @@ -743,8 +734,6 @@ static void tcp_keepalive_timer (struct timer_list *t) elapsed = keepalive_time_when(tp) - elapsed; } - sk_mem_reclaim(sk); - resched: inet_csk_reset_keepalive_timer (sk, elapsed); goto out; diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index a0385ddbffcf..498a0c35b7bb 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -278,8 +278,6 @@ static void iucv_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_error_queue); - sk_mem_reclaim(sk); - if (!sock_flag(sk, SOCK_DEAD)) { pr_err("Attempt to release alive iucv socket %p\n", sk); return; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 9563124ac8af..e0fb9f96c45c 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -975,7 +975,7 @@ static void __mptcp_mem_reclaim_partial(struct sock *sk) if (reclaimable > (int)PAGE_SIZE) __mptcp_rmem_reclaim(sk, reclaimable - 1); - sk_mem_reclaim_partial(sk); + sk_mem_reclaim(sk); } static void mptcp_mem_reclaim_partial(struct sock *sk) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 52edee1322fc..f6ee7f4040c1 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -6590,8 +6590,6 @@ static int sctp_eat_data(const struct sctp_association *asoc, pr_debug("%s: under pressure, reneging for tsn:%u\n", __func__, tsn); deliver = SCTP_CMD_RENEGE; - } else { - sk_mem_reclaim(sk); } } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 05174acd981a..171f1a35d205 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1824,9 +1824,6 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, if (sctp_wspace(asoc) < (int)msg_len) sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc)); - if (sk_under_memory_pressure(sk)) - sk_mem_reclaim(sk); - if (sctp_wspace(asoc) <= 0 || !sk_wmem_schedule(sk, msg_len)) { timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); @@ -9195,8 +9192,6 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, goto do_error; if (signal_pending(current)) goto do_interrupted; - if (sk_under_memory_pressure(sk)) - sk_mem_reclaim(sk); if ((int)msg_len <= sctp_wspace(asoc) && sk_wmem_schedule(sk, msg_len)) break; diff --git a/net/sctp/stream_interleave.c b/net/sctp/stream_interleave.c index 6b13f737ebf2..bb22b71df7a3 100644 --- a/net/sctp/stream_interleave.c +++ b/net/sctp/stream_interleave.c @@ -979,8 +979,6 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, if (freed >= needed && sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0) sctp_intl_start_pd(ulpq, gfp); - - sk_mem_reclaim(asoc->base.sk); } static void sctp_intl_stream_abort_pd(struct sctp_ulpq *ulpq, __u16 sid, diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 407fed46931b..0a8510a0c5e6 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -1100,12 +1100,8 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, else if (retval == 1) sctp_ulpq_reasm_drain(ulpq); } - - sk_mem_reclaim(asoc->base.sk); } - - /* Notify the application if an association is aborted and in * partial delivery mode. Send up any pending received messages. */ -- cgit v1.2.3 From 7cbb6681d7e5b88688234ad370e027a9346ff7a9 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Wed, 27 Apr 2022 12:08:04 -0700 Subject: iio: common: cros_ec_sensors: Add label attribute When sensor location is known, populate iio sysfs "label" attribute: * "accel-base" : the sensor is in the base of the convertible (2-1) device. * "accel-display" : the sensor is in the lid/display plane of the device. * "accel-camera" : the sensor is in the swivel camera subassembly. The non-standard |location| attribute is removed, the field |loc| in cros_ec_sensors_core_state is removed. It apply to standalone accelerometer as well as IMU (accelerometer + gyroscope) and sensors where the location is known (light). Signed-off-by: Gwendal Grignou Link: https://lore.kernel.org/r/20220427190804.961697-3-gwendal@chromium.org Signed-off-by: Jonathan Cameron --- drivers/iio/accel/cros_ec_accel_legacy.c | 2 +- .../common/cros_ec_sensors/cros_ec_sensors_core.c | 30 +++++++--------------- drivers/iio/light/cros_ec_light_prox.c | 2 -- drivers/iio/pressure/cros_ec_baro.c | 2 -- include/linux/iio/common/cros_ec_sensors_core.h | 2 -- 5 files changed, 10 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c index b6f3471b62dc..1c0171f26e99 100644 --- a/drivers/iio/accel/cros_ec_accel_legacy.c +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -230,7 +230,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) indio_dev->channels = cros_ec_accel_legacy_channels; indio_dev->num_channels = ARRAY_SIZE(cros_ec_accel_legacy_channels); /* The lid sensor needs to be presented inverted. */ - if (state->loc == MOTIONSENSE_LOC_LID) { + if (!strcmp(indio_dev->label, "accel-display")) { state->sign[CROS_EC_SENSOR_X] = -1; state->sign[CROS_EC_SENSOR_Z] = -1; } diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index 5976aca48e3b..e5ccedef13a8 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -29,12 +29,6 @@ */ #define CROS_EC_FIFO_SIZE (2048 * 2 / 3) -static char *cros_ec_loc[] = { - [MOTIONSENSE_LOC_BASE] = "base", - [MOTIONSENSE_LOC_LID] = "lid", - [MOTIONSENSE_LOC_MAX] = "unknown", -}; - static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev, u16 cmd_offset, u16 cmd, u32 *mask) { @@ -287,6 +281,8 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, indio_dev->name = pdev->name; if (physical_device) { + enum motionsensor_location loc; + state->param.cmd = MOTIONSENSE_CMD_INFO; state->param.info.sensor_num = sensor_platform->sensor_num; ret = cros_ec_motion_send_host_cmd(state, 0); @@ -295,7 +291,13 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, return ret; } state->type = state->resp->info.type; - state->loc = state->resp->info.location; + loc = state->resp->info.location; + if (loc == MOTIONSENSE_LOC_BASE) + indio_dev->label = "accel-base"; + else if (loc == MOTIONSENSE_LOC_LID) + indio_dev->label = "accel-display"; + else if (loc == MOTIONSENSE_LOC_CAMERA) + indio_dev->label = "accel-camera"; /* Set sign vector, only used for backward compatibility. */ memset(state->sign, 1, CROS_EC_SENSOR_MAX_AXIS); @@ -442,15 +444,6 @@ static ssize_t cros_ec_sensors_id(struct iio_dev *indio_dev, return snprintf(buf, PAGE_SIZE, "%d\n", st->param.info.sensor_num); } -static ssize_t cros_ec_sensors_loc(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, - char *buf) -{ - struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); - - return snprintf(buf, PAGE_SIZE, "%s\n", cros_ec_loc[st->loc]); -} - const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[] = { { .name = "calibrate", @@ -462,11 +455,6 @@ const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[] = { .shared = IIO_SHARED_BY_ALL, .read = cros_ec_sensors_id }, - { - .name = "location", - .shared = IIO_SHARED_BY_ALL, - .read = cros_ec_sensors_loc - }, { }, }; EXPORT_SYMBOL_GPL(cros_ec_sensors_ext_info); diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index de472f23d1cb..a00a8b3b86cf 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -188,8 +188,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) indio_dev->info = &cros_ec_light_prox_info; state = iio_priv(indio_dev); - state->core.type = state->core.resp->info.type; - state->core.loc = state->core.resp->info.location; channel = state->channels; /* Common part */ diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 2f882e109423..1d9d34ae3c0a 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -145,8 +145,6 @@ static int cros_ec_baro_probe(struct platform_device *pdev) indio_dev->info = &cros_ec_baro_info; state = iio_priv(indio_dev); - state->core.type = state->core.resp->info.type; - state->core.loc = state->core.resp->info.location; channel = state->channels; /* Common part */ channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index c582e1a14232..a8259c8822f5 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -41,7 +41,6 @@ typedef irqreturn_t (*cros_ec_sensors_capture_t)(int irq, void *p); * @param: motion sensor parameters structure * @resp: motion sensor response structure * @type: type of motion sensor - * @loc: location where the motion sensor is placed * @range_updated: True if the range of the sensor has been * updated. * @curr_range: If updated, the current range value. @@ -67,7 +66,6 @@ struct cros_ec_sensors_core_state { struct ec_response_motion_sense *resp; enum motionsensor_type type; - enum motionsensor_location loc; bool range_updated; int curr_range; -- cgit v1.2.3 From ccd8a9351f7b44bc1c0c8e4d39c0d6593b106fc4 Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Fri, 10 Jun 2022 23:30:08 +0900 Subject: can: skb: move can_dropped_invalid_skb() and can_skb_headroom_valid() to skb.c The functions can_dropped_invalid_skb() and can_skb_headroom_valid() grew a lot over the years to a point which it does not make much sense to have them defined as static inline in header files. Move those two functions to the .c counterpart of skb.h. can_skb_headroom_valid()'s only caller being can_dropped_invalid_skb(), the declaration is removed from the header. Only can_dropped_invalid_skb() gets its symbol exported. While doing so, do a small cleanup: add brackets around the else block in can_dropped_invalid_skb(). Link: https://lore.kernel.org/all/20220610143009.323579-7-mailhol.vincent@wanadoo.fr Signed-off-by: Vincent Mailhol Reported-by: kernel test robot Acked-by: Max Staudt Tested-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev/skb.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/can/skb.h | 59 +---------------------------------------------- 2 files changed, 59 insertions(+), 58 deletions(-) (limited to 'include') diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c index a4208f125b76..dc9da76c0470 100644 --- a/drivers/net/can/dev/skb.c +++ b/drivers/net/can/dev/skb.c @@ -259,3 +259,61 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf) return skb; } EXPORT_SYMBOL_GPL(alloc_can_err_skb); + +/* Check for outgoing skbs that have not been created by the CAN subsystem */ +static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb) +{ + /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */ + if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv))) + return false; + + /* af_packet does not apply CAN skb specific settings */ + if (skb->ip_summed == CHECKSUM_NONE) { + /* init headroom */ + can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* perform proper loopback on capable devices */ + if (dev->flags & IFF_ECHO) + skb->pkt_type = PACKET_LOOPBACK; + else + skb->pkt_type = PACKET_HOST; + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + } + + return true; +} + +/* Drop a given socketbuffer if it does not contain a valid CAN frame. */ +bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb) +{ + const struct canfd_frame *cfd = (struct canfd_frame *)skb->data; + + if (skb->protocol == htons(ETH_P_CAN)) { + if (unlikely(skb->len != CAN_MTU || + cfd->len > CAN_MAX_DLEN)) + goto inval_skb; + } else if (skb->protocol == htons(ETH_P_CANFD)) { + if (unlikely(skb->len != CANFD_MTU || + cfd->len > CANFD_MAX_DLEN)) + goto inval_skb; + } else { + goto inval_skb; + } + + if (!can_skb_headroom_valid(dev, skb)) + goto inval_skb; + + return false; + +inval_skb: + kfree_skb(skb); + dev->stats.tx_dropped++; + return true; +} +EXPORT_SYMBOL_GPL(can_dropped_invalid_skb); diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h index fdb22b00674a..182749e858b3 100644 --- a/include/linux/can/skb.h +++ b/include/linux/can/skb.h @@ -31,6 +31,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, struct canfd_frame **cfd); struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf); +bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb); /* * The struct can_skb_priv is used to transport additional information along @@ -96,64 +97,6 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb) return nskb; } -/* Check for outgoing skbs that have not been created by the CAN subsystem */ -static inline bool can_skb_headroom_valid(struct net_device *dev, - struct sk_buff *skb) -{ - /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */ - if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv))) - return false; - - /* af_packet does not apply CAN skb specific settings */ - if (skb->ip_summed == CHECKSUM_NONE) { - /* init headroom */ - can_skb_prv(skb)->ifindex = dev->ifindex; - can_skb_prv(skb)->skbcnt = 0; - - skb->ip_summed = CHECKSUM_UNNECESSARY; - - /* perform proper loopback on capable devices */ - if (dev->flags & IFF_ECHO) - skb->pkt_type = PACKET_LOOPBACK; - else - skb->pkt_type = PACKET_HOST; - - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - } - - return true; -} - -/* Drop a given socketbuffer if it does not contain a valid CAN frame. */ -static inline bool can_dropped_invalid_skb(struct net_device *dev, - struct sk_buff *skb) -{ - const struct canfd_frame *cfd = (struct canfd_frame *)skb->data; - - if (skb->protocol == htons(ETH_P_CAN)) { - if (unlikely(skb->len != CAN_MTU || - cfd->len > CAN_MAX_DLEN)) - goto inval_skb; - } else if (skb->protocol == htons(ETH_P_CANFD)) { - if (unlikely(skb->len != CANFD_MTU || - cfd->len > CANFD_MAX_DLEN)) - goto inval_skb; - } else - goto inval_skb; - - if (!can_skb_headroom_valid(dev, skb)) - goto inval_skb; - - return false; - -inval_skb: - kfree_skb(skb); - dev->stats.tx_dropped++; - return true; -} - static inline bool can_is_canfd_skb(const struct sk_buff *skb) { /* the CAN specific type of skb is identified by its data length */ -- cgit v1.2.3 From 7d188c521d9ec3650136e9b9c81c61b22a544ab3 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Sat, 11 Jun 2022 09:55:04 -0700 Subject: drm: Fix htmldocs indentation warning w/ DP AUX power requirements Two blank lines are needed to make the rst valid. Fixes: 69ef4a192bba ("drm: Document the power requirements for DP AUX transfers") Reported-by: Stephen Rothwell Signed-off-by: Douglas Anderson Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20220611095445.1.I534072d346b1ebbf0db565b714de9b65cbb24651@changeid --- include/drm/display/drm_dp_helper.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index dc3c02225fcf..c5f8f45511ed 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -372,8 +372,10 @@ struct drm_dp_aux { * Also note that this callback can be called no matter the * state @dev is in and also no matter what state the panel is * in. It's expected: + * * - If the @dev providing the AUX bus is currently unpowered then * it will power itself up for the transfer. + * * - If we're on eDP (using a drm_panel) and the panel is not in a * state where it can respond (it's not powered or it's in a * low power state) then this function may return an error, but -- cgit v1.2.3 From 662a60102c122e44fdaf5c826f7f415eb57d48ad Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 2 May 2022 16:20:56 +0300 Subject: usb: typec: Separate USB Power Delivery from USB Type-C Introducing a small device class for USB Power Delivery. The idea with it is that we do not mix any more USB Power Delivery information into the USB Type-C connectors only. This separation will make it possible to register USB Power Delivery devices also from other places, for example from USB Type-C Bridges (see USB Type-C Bridge Specification). The device class will not always deal with only the messages and objects that were negotiated with the partner, but instead messages and objects that can be used in the negotiation. That allows the USB PD devices to be shared and reconfigured. The ports can decide which objects are to be advertised to the partner before the contract is negotiated. It is also possible to allow the user space to make that decision if needed. Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220502132058.86236-2-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-class-usb_power_delivery | 240 +++++++ drivers/usb/typec/Makefile | 2 +- drivers/usb/typec/pd.c | 708 +++++++++++++++++++++ drivers/usb/typec/pd.h | 30 + include/linux/usb/pd.h | 38 ++ include/linux/usb/typec.h | 10 + 6 files changed, 1027 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-class-usb_power_delivery create mode 100644 drivers/usb/typec/pd.c create mode 100644 drivers/usb/typec/pd.h (limited to 'include') diff --git a/Documentation/ABI/testing/sysfs-class-usb_power_delivery b/Documentation/ABI/testing/sysfs-class-usb_power_delivery new file mode 100644 index 000000000000..ce2b1b563cb3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-usb_power_delivery @@ -0,0 +1,240 @@ +What: /sys/class/usb_power_delivery +Date: May 2022 +Contact: Heikki Krogerus +Description: + Directory for USB Power Delivery devices. + +What: /sys/class/usb_power_delivery/.../revision +Date: May 2022 +Contact: Heikki Krogerus +Description: + File showing the USB Power Delivery Specification Revision used + in communication. + +What: /sys/class/usb_power_delivery/.../version +Date: May 2022 +Contact: Heikki Krogerus +Description: + This is an optional attribute file showing the version of the + specific revision of the USB Power Delivery Specification. In + most cases the specification version is not known and the file + is not available. + +What: /sys/class/usb_power_delivery/.../source-capabilities +Date: May 2022 +Contact: Heikki Krogerus +Description: + The source capabilities message "Source_Capabilities" contains a + set of Power Data Objects (PDO), each representing a type of + power supply. The order of the PDO objects is defined in the USB + Power Delivery Specification. Each PDO - power supply - will + have its own device, and the PDO device name will start with the + object position number as the first character followed by the + power supply type name (":" as delimiter). + + /sys/class/usb_power_delivery/.../source_capabilities/: + +What: /sys/class/usb_power_delivery/.../sink-capabilities +Date: May 2022 +Contact: Heikki Krogerus +Description: + The sink capability message "Sink_Capabilities" contains a set + of Power Data Objects (PDO) just like with source capabilities, + but instead of describing the power capabilities, these objects + describe the power requirements. + + The order of the objects in the sink capability message is the + same as with the source capabilities message. + +Fixed Supplies + +What: /sys/class/usb_power_delivery/...//:fixed_supply +Date: May 2022 +Contact: Heikki Krogerus +Description: + Devices containing the attributes (the bit fields) defined for + Fixed Supplies. + + The device "1:fixed_supply" is special. USB Power Delivery + Specification dictates that the first PDO (at object position + 1), and the only mandatory PDO, is always the vSafe5V Fixed + Supply Object. vSafe5V Object has additional fields defined for + it that the other Fixed Supply Objects do not have and that are + related to the USB capabilities rather than power capabilities. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/dual_role_power +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file contains boolean value that tells does the device + support both source and sink power roles. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/usb_suspend_supported +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the USB Suspend Supported bit in + vSafe5V Fixed Supply Object. If the bit is set then the device + will follow the USB 2.0 and USB 3.2 rules for suspend and + resume. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/unconstrained_power +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the Unconstrained Power bit in + vSafe5V Fixed Supply Object. The bit is set when an external + source of power, powerful enough to power the entire system on + its own, is available for the device. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/usb_communication_capable +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the USB Communication Capable bit in + vSafe5V Fixed Supply Object. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/dual_role_data +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the Dual-Role Data bit in vSafe5V + Fixed Supply Object. Dual role data means ability act as both + USB host and USB device. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/unchunked_extended_messages_supported +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the Unchunked Extended Messages + Supported bit in vSafe5V Fixed Supply Object. + +What: /sys/class/usb_power_delivery/...//:fixed_supply/voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + The voltage the supply supports in millivolts. + +What: /sys/class/usb_power_delivery/.../source-capabilities/:fixed_supply/maximum_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum current of the fixed source supply in milliamperes. + +What: /sys/class/usb_power_delivery/.../sink-capabilities/:fixed_supply/operational_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + Operational current of the sink in milliamperes. + +What: /sys/class/usb_power_delivery/.../sink-capabilities/:fixed_supply/fast_role_swap_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file contains the value of the "Fast Role Swap USB Type-C + Current" field that tells the current level the sink requires + after a Fast Role Swap. + 0 - Fast Swap not supported" + 1 - Default USB Power" + 2 - 1.5A@5V" + 3 - 3.0A@5V" + +Variable Supplies + +What: /sys/class/usb_power_delivery/...//:variable_supply +Date: May 2022 +Contact: Heikki Krogerus +Description: + Variable Power Supply PDO. + +What: /sys/class/usb_power_delivery/...//:variable_supply/maximum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/...//:variable_supply/minimum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Minimum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/.../source-capabilities/:variable_supply/maximum_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + The maximum current in milliamperes that the source can supply + at the given Voltage range. + +What: /sys/class/usb_power_delivery/.../sink-capabilities/:variable_supply/operational_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + The operational current in milliamperes that the sink requires + at the given Voltage range. + +Battery Supplies + +What: /sys/class/usb_power_delivery/...//:battery +Date: May 2022 +Contact: Heikki Krogerus +Description: + Battery PDO. + +What: /sys/class/usb_power_delivery/...//:battery/maximum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/...//:battery/minimum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Minimum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/.../source-capabilities/:battery/maximum_power +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum allowable Power in milliwatts. + +What: /sys/class/usb_power_delivery/.../sink-capabilities/:battery/operational_power +Date: May 2022 +Contact: Heikki Krogerus +Description: + The operational power that the sink requires at the given + voltage range. + +Standard Power Range (SPR) Programmable Power Supplies + +What: /sys/class/usb_power_delivery/...//:programmable_supply +Date: May 2022 +Contact: Heikki Krogerus +Description: + Programmable Power Supply (PPS) Augmented PDO (APDO). + +What: /sys/class/usb_power_delivery/...//:programmable_supply/maximum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/...//:programmable_supply/minimum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Minimum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/...//:programmable_supply/maximum_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum Current in milliamperes. + +What: /sys/class/usb_power_delivery/.../source-capabilities/:programmable_supply/pps_power_limited +Date: May 2022 +Contact: Heikki Krogerus +Description: + The PPS Power Limited bit indicates whether or not the source + supply will exceed the rated output power if requested. diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index 43626acc0aaf..2f174cd3e5df 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_TYPEC) += typec.o -typec-y := class.o mux.o bus.o +typec-y := class.o mux.o bus.o pd.o typec-$(CONFIG_ACPI) += port-mapper.o obj-$(CONFIG_TYPEC) += altmodes/ obj-$(CONFIG_TYPEC_TCPM) += tcpm/ diff --git a/drivers/usb/typec/pd.c b/drivers/usb/typec/pd.c new file mode 100644 index 000000000000..dc72005d68db --- /dev/null +++ b/drivers/usb/typec/pd.c @@ -0,0 +1,708 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * USB Power Delivery sysfs entries + * + * Copyright (C) 2022, Intel Corporation + * Author: Heikki Krogerus + */ + +#include +#include + +#include "pd.h" + +static DEFINE_IDA(pd_ida); + +static struct class pd_class = { + .name = "usb_power_delivery", + .owner = THIS_MODULE, +}; + +#define to_pdo(o) container_of(o, struct pdo, dev) + +struct pdo { + struct device dev; + int object_position; + u32 pdo; +}; + +static void pdo_release(struct device *dev) +{ + kfree(to_pdo(dev)); +} + +/* -------------------------------------------------------------------------- */ +/* Fixed Supply */ + +static ssize_t +dual_role_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DUAL_ROLE)); +} +static DEVICE_ATTR_RO(dual_role_power); + +static ssize_t +usb_suspend_supported_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_SUSPEND)); +} +static DEVICE_ATTR_RO(usb_suspend_supported); + +static ssize_t +unconstrained_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_EXTPOWER)); +} +static DEVICE_ATTR_RO(unconstrained_power); + +static ssize_t +usb_communication_capable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_USB_COMM)); +} +static DEVICE_ATTR_RO(usb_communication_capable); + +static ssize_t +dual_role_data_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DATA_SWAP)); +} +static DEVICE_ATTR_RO(dual_role_data); + +static ssize_t +unchunked_extended_messages_supported_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_UNCHUNK_EXT)); +} +static DEVICE_ATTR_RO(unchunked_extended_messages_supported); + +/* + * REVISIT: Peak Current requires access also to the RDO. +static ssize_t +peak_current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ... +} +*/ + +static ssize_t +fast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3; +} +static DEVICE_ATTR_RO(fast_role_swap_current); + +static ssize_t voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_fixed_voltage(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(voltage); + +/* Shared with Variable supplies, both source and sink */ +static ssize_t current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umA\n", pdo_max_current(to_pdo(dev)->pdo)); +} + +/* Shared with Variable type supplies */ +static struct device_attribute maximum_current_attr = { + .attr = { + .name = "maximum_current", + .mode = 0444, + }, + .show = current_show, +}; + +static struct device_attribute operational_current_attr = { + .attr = { + .name = "operational_current", + .mode = 0444, + }, + .show = current_show, +}; + +static struct attribute *source_fixed_supply_attrs[] = { + &dev_attr_dual_role_power.attr, + &dev_attr_usb_suspend_supported.attr, + &dev_attr_unconstrained_power.attr, + &dev_attr_usb_communication_capable.attr, + &dev_attr_dual_role_data.attr, + &dev_attr_unchunked_extended_messages_supported.attr, + /*&dev_attr_peak_current.attr,*/ + &dev_attr_voltage.attr, + &maximum_current_attr.attr, + NULL +}; + +static umode_t fixed_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + if (to_pdo(kobj_to_dev(kobj))->object_position && + /*attr != &dev_attr_peak_current.attr &&*/ + attr != &dev_attr_voltage.attr && + attr != &maximum_current_attr.attr && + attr != &operational_current_attr.attr) + return 0; + + return attr->mode; +} + +static const struct attribute_group source_fixed_supply_group = { + .is_visible = fixed_attr_is_visible, + .attrs = source_fixed_supply_attrs, +}; +__ATTRIBUTE_GROUPS(source_fixed_supply); + +static struct device_type source_fixed_supply_type = { + .name = "pdo", + .release = pdo_release, + .groups = source_fixed_supply_groups, +}; + +static struct attribute *sink_fixed_supply_attrs[] = { + &dev_attr_dual_role_power.attr, + &dev_attr_usb_suspend_supported.attr, + &dev_attr_unconstrained_power.attr, + &dev_attr_usb_communication_capable.attr, + &dev_attr_dual_role_data.attr, + &dev_attr_unchunked_extended_messages_supported.attr, + &dev_attr_fast_role_swap_current.attr, + &dev_attr_voltage.attr, + &operational_current_attr.attr, + NULL +}; + +static const struct attribute_group sink_fixed_supply_group = { + .is_visible = fixed_attr_is_visible, + .attrs = sink_fixed_supply_attrs, +}; +__ATTRIBUTE_GROUPS(sink_fixed_supply); + +static struct device_type sink_fixed_supply_type = { + .name = "pdo", + .release = pdo_release, + .groups = sink_fixed_supply_groups, +}; + +/* -------------------------------------------------------------------------- */ +/* Variable Supply */ + +static ssize_t +maximum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_max_voltage(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(maximum_voltage); + +static ssize_t +minimum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_min_voltage(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(minimum_voltage); + +static struct attribute *source_variable_supply_attrs[] = { + &dev_attr_maximum_voltage.attr, + &dev_attr_minimum_voltage.attr, + &maximum_current_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(source_variable_supply); + +static struct device_type source_variable_supply_type = { + .name = "pdo", + .release = pdo_release, + .groups = source_variable_supply_groups, +}; + +static struct attribute *sink_variable_supply_attrs[] = { + &dev_attr_maximum_voltage.attr, + &dev_attr_minimum_voltage.attr, + &operational_current_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(sink_variable_supply); + +static struct device_type sink_variable_supply_type = { + .name = "pdo", + .release = pdo_release, + .groups = sink_variable_supply_groups, +}; + +/* -------------------------------------------------------------------------- */ +/* Battery */ + +static ssize_t +maximum_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(maximum_power); + +static ssize_t +operational_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(operational_power); + +static struct attribute *source_battery_attrs[] = { + &dev_attr_maximum_voltage.attr, + &dev_attr_minimum_voltage.attr, + &dev_attr_maximum_power.attr, + NULL +}; +ATTRIBUTE_GROUPS(source_battery); + +static struct device_type source_battery_type = { + .name = "pdo", + .release = pdo_release, + .groups = source_battery_groups, +}; + +static struct attribute *sink_battery_attrs[] = { + &dev_attr_maximum_voltage.attr, + &dev_attr_minimum_voltage.attr, + &dev_attr_operational_power.attr, + NULL +}; +ATTRIBUTE_GROUPS(sink_battery); + +static struct device_type sink_battery_type = { + .name = "pdo", + .release = pdo_release, + .groups = sink_battery_groups, +}; + +/* -------------------------------------------------------------------------- */ +/* Standard Power Range (SPR) Programmable Power Supply (PPS) */ + +static ssize_t +pps_power_limited_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & BIT(27))); +} +static DEVICE_ATTR_RO(pps_power_limited); + +static ssize_t +pps_max_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_max_voltage(to_pdo(dev)->pdo)); +} + +static ssize_t +pps_min_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_min_voltage(to_pdo(dev)->pdo)); +} + +static ssize_t +pps_max_current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umA\n", pdo_pps_apdo_max_current(to_pdo(dev)->pdo)); +} + +static struct device_attribute pps_max_voltage_attr = { + .attr = { + .name = "maximum_voltage", + .mode = 0444, + }, + .show = pps_max_voltage_show, +}; + +static struct device_attribute pps_min_voltage_attr = { + .attr = { + .name = "minimum_voltage", + .mode = 0444, + }, + .show = pps_min_voltage_show, +}; + +static struct device_attribute pps_max_current_attr = { + .attr = { + .name = "maximum_current", + .mode = 0444, + }, + .show = pps_max_current_show, +}; + +static struct attribute *source_pps_attrs[] = { + &dev_attr_pps_power_limited.attr, + &pps_max_voltage_attr.attr, + &pps_min_voltage_attr.attr, + &pps_max_current_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(source_pps); + +static struct device_type source_pps_type = { + .name = "pdo", + .release = pdo_release, + .groups = source_pps_groups, +}; + +static struct attribute *sink_pps_attrs[] = { + &pps_max_voltage_attr.attr, + &pps_min_voltage_attr.attr, + &pps_max_current_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(sink_pps); + +static struct device_type sink_pps_type = { + .name = "pdo", + .release = pdo_release, + .groups = sink_pps_groups, +}; + +/* -------------------------------------------------------------------------- */ + +static const char * const supply_name[] = { + [PDO_TYPE_FIXED] = "fixed_supply", + [PDO_TYPE_BATT] = "battery", + [PDO_TYPE_VAR] = "variable_supply", +}; + +static const char * const apdo_supply_name[] = { + [APDO_TYPE_PPS] = "programmable_supply", +}; + +static struct device_type *source_type[] = { + [PDO_TYPE_FIXED] = &source_fixed_supply_type, + [PDO_TYPE_BATT] = &source_battery_type, + [PDO_TYPE_VAR] = &source_variable_supply_type, +}; + +static struct device_type *source_apdo_type[] = { + [APDO_TYPE_PPS] = &source_pps_type, +}; + +static struct device_type *sink_type[] = { + [PDO_TYPE_FIXED] = &sink_fixed_supply_type, + [PDO_TYPE_BATT] = &sink_battery_type, + [PDO_TYPE_VAR] = &sink_variable_supply_type, +}; + +static struct device_type *sink_apdo_type[] = { + [APDO_TYPE_PPS] = &sink_pps_type, +}; + +/* REVISIT: Export when EPR_*_Capabilities need to be supported. */ +static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int position) +{ + struct device_type *type; + const char *name; + struct pdo *p; + int ret; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->pdo = pdo; + p->object_position = position; + + if (pdo_type(pdo) == PDO_TYPE_APDO) { + /* FIXME: Only PPS supported for now! Skipping others. */ + if (pdo_apdo_type(pdo) > APDO_TYPE_PPS) { + dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo); + kfree(p); + return 0; + } + + if (is_source(cap->role)) + type = source_apdo_type[pdo_apdo_type(pdo)]; + else + type = sink_apdo_type[pdo_apdo_type(pdo)]; + + name = apdo_supply_name[pdo_apdo_type(pdo)]; + } else { + if (is_source(cap->role)) + type = source_type[pdo_type(pdo)]; + else + type = sink_type[pdo_type(pdo)]; + + name = supply_name[pdo_type(pdo)]; + } + + p->dev.parent = &cap->dev; + p->dev.type = type; + dev_set_name(&p->dev, "%u:%s", position + 1, name); + + ret = device_register(&p->dev); + if (ret) { + put_device(&p->dev); + return ret; + } + + return 0; +} + +static int remove_pdo(struct device *dev, void *data) +{ + device_unregister(dev); + return 0; +} + +/* -------------------------------------------------------------------------- */ + +static const char * const cap_name[] = { + [TYPEC_SINK] = "sink-capabilities", + [TYPEC_SOURCE] = "source-capabilities", +}; + +static void pd_capabilities_release(struct device *dev) +{ + kfree(to_usb_power_delivery_capabilities(dev)); +} + +static struct device_type pd_capabilities_type = { + .name = "capabilities", + .release = pd_capabilities_release, +}; + +/** + * usb_power_delivery_register_capabilities - Register a set of capabilities. + * @pd: The USB PD instance that the capabilities belong to. + * @desc: Description of the Capablities Message. + * + * This function registers a Capabilities Message described in @desc. The + * capabilities will have their own sub-directory under @pd in sysfs. + * + * The function returns pointer to struct usb_power_delivery_capabilities, or + * ERR_PRT(errno). + */ +struct usb_power_delivery_capabilities * +usb_power_delivery_register_capabilities(struct usb_power_delivery *pd, + struct usb_power_delivery_capabilities_desc *desc) +{ + struct usb_power_delivery_capabilities *cap; + int ret; + int i; + + cap = kzalloc(sizeof(*cap), GFP_KERNEL); + if (!cap) + return ERR_PTR(-ENOMEM); + + cap->pd = pd; + cap->role = desc->role; + + cap->dev.parent = &pd->dev; + cap->dev.type = &pd_capabilities_type; + dev_set_name(&cap->dev, "%s", cap_name[cap->role]); + + ret = device_register(&cap->dev); + if (ret) { + put_device(&cap->dev); + return ERR_PTR(ret); + } + + for (i = 0; i < PDO_MAX_OBJECTS && desc->pdo[i]; i++) { + ret = add_pdo(cap, desc->pdo[i], i); + if (ret) { + usb_power_delivery_unregister_capabilities(cap); + return ERR_PTR(ret); + } + } + + return cap; +} +EXPORT_SYMBOL_GPL(usb_power_delivery_register_capabilities); + +/** + * usb_power_delivery_unregister_capabilities - Unregister a set of capabilities + * @cap: The capabilities + */ +void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap) +{ + if (!cap) + return; + + device_for_each_child(&cap->dev, NULL, remove_pdo); + device_unregister(&cap->dev); +} +EXPORT_SYMBOL_GPL(usb_power_delivery_unregister_capabilities); + +/* -------------------------------------------------------------------------- */ + +static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_power_delivery *pd = to_usb_power_delivery(dev); + + return sysfs_emit(buf, "%u.%u\n", (pd->revision >> 8) & 0xff, (pd->revision >> 4) & 0xf); +} +static DEVICE_ATTR_RO(revision); + +static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_power_delivery *pd = to_usb_power_delivery(dev); + + return sysfs_emit(buf, "%u.%u\n", (pd->version >> 8) & 0xff, (pd->version >> 4) & 0xf); +} +static DEVICE_ATTR_RO(version); + +static struct attribute *pd_attrs[] = { + &dev_attr_revision.attr, + &dev_attr_version.attr, + NULL +}; + +static umode_t pd_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + struct usb_power_delivery *pd = to_usb_power_delivery(kobj_to_dev(kobj)); + + if (attr == &dev_attr_version.attr && !pd->version) + return 0; + + return attr->mode; +} + +static const struct attribute_group pd_group = { + .is_visible = pd_attr_is_visible, + .attrs = pd_attrs, +}; +__ATTRIBUTE_GROUPS(pd); + +static void pd_release(struct device *dev) +{ + struct usb_power_delivery *pd = to_usb_power_delivery(dev); + + ida_simple_remove(&pd_ida, pd->id); + kfree(pd); +} + +static struct device_type pd_type = { + .name = "usb_power_delivery", + .release = pd_release, + .groups = pd_groups, +}; + +struct usb_power_delivery *usb_power_delivery_find(const char *name) +{ + struct device *dev; + + dev = class_find_device_by_name(&pd_class, name); + + return dev ? to_usb_power_delivery(dev) : NULL; +} + +/** + * usb_power_delivery_register - Register USB Power Delivery Support. + * @parent: Parent device. + * @desc: Description of the USB PD contract. + * + * This routine can be used to register USB Power Delivery capabilities that a + * device or devices can support. These capabilities represent all the + * capabilities that can be negotiated with a partner, so not only the Power + * Capabilities that are negotiated using the USB PD Capabilities Message. + * + * The USB Power Delivery Support object that this routine generates can be used + * as the parent object for all the actual USB Power Delivery Messages and + * objects that can be negotiated with the partner. + * + * Returns handle to struct usb_power_delivery or ERR_PTR. + */ +struct usb_power_delivery * +usb_power_delivery_register(struct device *parent, struct usb_power_delivery_desc *desc) +{ + struct usb_power_delivery *pd; + int ret; + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) + return ERR_PTR(-ENOMEM); + + ret = ida_simple_get(&pd_ida, 0, 0, GFP_KERNEL); + if (ret < 0) { + kfree(pd); + return ERR_PTR(ret); + } + + pd->id = ret; + pd->revision = desc->revision; + pd->version = desc->version; + + pd->dev.parent = parent; + pd->dev.type = &pd_type; + pd->dev.class = &pd_class; + dev_set_name(&pd->dev, "pd%d", pd->id); + + ret = device_register(&pd->dev); + if (ret) { + put_device(&pd->dev); + return ERR_PTR(ret); + } + + return pd; +} +EXPORT_SYMBOL_GPL(usb_power_delivery_register); + +/** + * usb_power_delivery_unregister - Unregister USB Power Delivery Support. + * @pd: The USB PD contract. + */ +void usb_power_delivery_unregister(struct usb_power_delivery *pd) +{ + if (IS_ERR_OR_NULL(pd)) + return; + + device_unregister(&pd->dev); +} +EXPORT_SYMBOL_GPL(usb_power_delivery_unregister); + +/** + * usb_power_delivery_link_device - Link device to its USB PD object. + * @pd: The USB PD instance. + * @dev: The device. + * + * This function can be used to create a symlink named "usb_power_delivery" for + * @dev that points to @pd. + */ +int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev) +{ + int ret; + + if (IS_ERR_OR_NULL(pd) || !dev) + return 0; + + ret = sysfs_create_link(&dev->kobj, &pd->dev.kobj, "usb_power_delivery"); + if (ret) + return ret; + + get_device(&pd->dev); + get_device(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(usb_power_delivery_link_device); + +/** + * usb_power_delivery_unlink_device - Unlink device from its USB PD object. + * @pd: The USB PD instance. + * @dev: The device. + * + * Remove the symlink that was previously created with pd_link_device(). + */ +void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev) +{ + if (IS_ERR_OR_NULL(pd) || !dev) + return; + + sysfs_remove_link(&dev->kobj, "usb_power_delivery"); + put_device(&pd->dev); + put_device(dev); +} +EXPORT_SYMBOL_GPL(usb_power_delivery_unlink_device); + +/* -------------------------------------------------------------------------- */ + +int __init usb_power_delivery_init(void) +{ + return class_register(&pd_class); +} + +void __exit usb_power_delivery_exit(void) +{ + ida_destroy(&pd_ida); + class_unregister(&pd_class); +} diff --git a/drivers/usb/typec/pd.h b/drivers/usb/typec/pd.h new file mode 100644 index 000000000000..049a1aad440a --- /dev/null +++ b/drivers/usb/typec/pd.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __USB_POWER_DELIVERY__ +#define __USB_POWER_DELIVERY__ + +#include +#include + +struct usb_power_delivery { + struct device dev; + int id; + u16 revision; + u16 version; +}; + +struct usb_power_delivery_capabilities { + struct device dev; + struct usb_power_delivery *pd; + enum typec_role role; +}; + +#define to_usb_power_delivery_capabilities(o) container_of(o, struct usb_power_delivery_capabilities, dev) +#define to_usb_power_delivery(o) container_of(o, struct usb_power_delivery, dev) + +struct usb_power_delivery *usb_power_delivery_find(const char *name); + +int usb_power_delivery_init(void); +void usb_power_delivery_exit(void); + +#endif /* __USB_POWER_DELIVERY__ */ diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index 96b7ff66f074..c59fb79a42e8 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -495,4 +495,42 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_P_SNK_STDBY_MW 2500 /* 2500 mW */ +#if IS_ENABLED(CONFIG_TYPEC) + +struct usb_power_delivery; + +/** + * usb_power_delivery_desc - USB Power Delivery Descriptor + * @revision: USB Power Delivery Specification Revision + * @version: USB Power Delivery Specicication Version - optional + */ +struct usb_power_delivery_desc { + u16 revision; + u16 version; +}; + +/** + * usb_power_delivery_capabilities_desc - Description of USB Power Delivery Capabilities Message + * @pdo: The Power Data Objects in the Capability Message + * @role: Power role of the capabilities + */ +struct usb_power_delivery_capabilities_desc { + u32 pdo[PDO_MAX_OBJECTS]; + enum typec_role role; +}; + +struct usb_power_delivery_capabilities * +usb_power_delivery_register_capabilities(struct usb_power_delivery *pd, + struct usb_power_delivery_capabilities_desc *desc); +void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap); + +struct usb_power_delivery *usb_power_delivery_register(struct device *parent, + struct usb_power_delivery_desc *desc); +void usb_power_delivery_unregister(struct usb_power_delivery *pd); + +int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev); +void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev); + +#endif /* CONFIG_TYPEC */ + #endif /* __LINUX_USB_PD_H */ diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index fdf737d48b3b..45e28d14ae56 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -52,6 +52,16 @@ enum typec_role { TYPEC_SOURCE, }; +static inline int is_sink(enum typec_role role) +{ + return role == TYPEC_SINK; +} + +static inline int is_source(enum typec_role role) +{ + return role == TYPEC_SOURCE; +} + enum typec_pwr_opmode { TYPEC_PWR_MODE_USB, TYPEC_PWR_MODE_1_5A, -- cgit v1.2.3 From a7cff92f0635c794e2198a69a7ff4ecfe0decab9 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 2 May 2022 16:20:57 +0300 Subject: usb: typec: USB Power Delivery helpers for ports and partners All the USB Type-C Connector Class devices are protected, so the drivers can not directly access them. This will adds a few helpers that can be used to link the ports and partners to the correct USB Power Delivery objects. For ports a new optional sysfs attribute file is also added that can be used to select the USB Power Delivery capabilities that the port will advertise to the partner. Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220502132058.86236-3-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-class-typec | 8 ++ drivers/usb/typec/class.c | 149 ++++++++++++++++++++++++++++ drivers/usb/typec/class.h | 4 + include/linux/usb/typec.h | 13 +++ 4 files changed, 174 insertions(+) (limited to 'include') diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec index 75088ecad202..281b995beb05 100644 --- a/Documentation/ABI/testing/sysfs-class-typec +++ b/Documentation/ABI/testing/sysfs-class-typec @@ -141,6 +141,14 @@ Description: - "reverse": CC2 orientation - "unknown": Orientation cannot be determined. +What: /sys/class/typec//select_usb_power_delivery +Date: May 2022 +Contact: Heikki Krogerus +Description: + Lists the USB Power Delivery Capabilities that the port can + advertise to the partner. The currently used capabilities are in + brackets. Selection happens by writing to the file. + USB Type-C partner devices (eg. /sys/class/typec/port0-partner/) What: /sys/class/typec/-partner/accessory_mode diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index ee0e520707dd..bbc46b14f99a 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -15,6 +15,7 @@ #include "bus.h" #include "class.h" +#include "pd.h" static DEFINE_IDA(typec_index_ida); @@ -720,6 +721,39 @@ void typec_partner_set_pd_revision(struct typec_partner *partner, u16 pd_revisio } EXPORT_SYMBOL_GPL(typec_partner_set_pd_revision); +/** + * typec_partner_set_usb_power_delivery - Declare USB Power Delivery Contract. + * @partner: The partner device. + * @pd: The USB PD instance. + * + * This routine can be used to declare USB Power Delivery Contract with @partner + * by linking @partner to @pd which contains the objects that were used during the + * negotiation of the contract. + * + * If @pd is NULL, the link is removed and the contract with @partner has ended. + */ +int typec_partner_set_usb_power_delivery(struct typec_partner *partner, + struct usb_power_delivery *pd) +{ + int ret; + + if (IS_ERR_OR_NULL(partner) || partner->pd == pd) + return 0; + + if (pd) { + ret = usb_power_delivery_link_device(pd, &partner->dev); + if (ret) + return ret; + } else { + usb_power_delivery_unlink_device(partner->pd, &partner->dev); + } + + partner->pd = pd; + + return 0; +} +EXPORT_SYMBOL_GPL(typec_partner_set_usb_power_delivery); + /** * typec_partner_set_num_altmodes - Set the number of available partner altmodes * @partner: The partner to be updated. @@ -1170,6 +1204,104 @@ EXPORT_SYMBOL_GPL(typec_unregister_cable); /* ------------------------------------------------------------------------- */ /* USB Type-C ports */ +/** + * typec_port_set_usb_power_delivery - Assign USB PD for port. + * @port: USB Type-C port. + * @pd: USB PD instance. + * + * This routine can be used to set the USB Power Delivery Capabilities for @port + * that it will advertise to the partner. + * + * If @pd is NULL, the assignment is removed. + */ +int typec_port_set_usb_power_delivery(struct typec_port *port, struct usb_power_delivery *pd) +{ + int ret; + + if (IS_ERR_OR_NULL(port) || port->pd == pd) + return 0; + + if (pd) { + ret = usb_power_delivery_link_device(pd, &port->dev); + if (ret) + return ret; + } else { + usb_power_delivery_unlink_device(port->pd, &port->dev); + } + + port->pd = pd; + + return 0; +} +EXPORT_SYMBOL_GPL(typec_port_set_usb_power_delivery); + +static ssize_t select_usb_power_delivery_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct typec_port *port = to_typec_port(dev); + struct usb_power_delivery *pd; + + if (!port->ops || !port->ops->pd_set) + return -EOPNOTSUPP; + + pd = usb_power_delivery_find(buf); + if (!pd) + return -EINVAL; + + return port->ops->pd_set(port, pd); +} + +static ssize_t select_usb_power_delivery_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct typec_port *port = to_typec_port(dev); + struct usb_power_delivery **pds; + struct usb_power_delivery *pd; + int ret = 0; + + if (!port->ops || !port->ops->pd_get) + return -EOPNOTSUPP; + + pds = port->ops->pd_get(port); + if (!pds) + return 0; + + for (pd = pds[0]; pd; pd++) { + if (pd == port->pd) + ret += sysfs_emit(buf + ret, "[%s] ", dev_name(&pd->dev)); + else + ret += sysfs_emit(buf + ret, "%s ", dev_name(&pd->dev)); + } + + buf[ret - 1] = '\n'; + + return ret; +} +static DEVICE_ATTR_RW(select_usb_power_delivery); + +static struct attribute *port_attrs[] = { + &dev_attr_select_usb_power_delivery.attr, + NULL +}; + +static umode_t port_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + struct typec_port *port = to_typec_port(kobj_to_dev(kobj)); + + if (!port->pd || !port->ops || !port->ops->pd_get) + return 0; + if (!port->ops->pd_set) + return 0444; + + return attr->mode; +} + +static const struct attribute_group pd_group = { + .is_visible = port_attr_is_visible, + .attrs = port_attrs, +}; + static const char * const typec_orientations[] = { [TYPEC_ORIENTATION_NONE] = "unknown", [TYPEC_ORIENTATION_NORMAL] = "normal", @@ -1581,6 +1713,7 @@ static const struct attribute_group typec_group = { static const struct attribute_group *typec_groups[] = { &typec_group, + &pd_group, NULL }; @@ -2123,6 +2256,13 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_PTR(ret); } + ret = typec_port_set_usb_power_delivery(port, cap->pd); + if (ret) { + dev_err(&port->dev, "failed to link pd\n"); + device_unregister(&port->dev); + return ERR_PTR(ret); + } + ret = typec_link_ports(port); if (ret) dev_warn(&port->dev, "failed to create symlinks (%d)\n", ret); @@ -2141,6 +2281,7 @@ void typec_unregister_port(struct typec_port *port) { if (!IS_ERR_OR_NULL(port)) { typec_unlink_ports(port); + typec_port_set_usb_power_delivery(port, NULL); device_unregister(&port->dev); } } @@ -2162,8 +2303,15 @@ static int __init typec_init(void) if (ret) goto err_unregister_mux_class; + ret = usb_power_delivery_init(); + if (ret) + goto err_unregister_class; + return 0; +err_unregister_class: + class_unregister(&typec_class); + err_unregister_mux_class: class_unregister(&typec_mux_class); @@ -2176,6 +2324,7 @@ subsys_initcall(typec_init); static void __exit typec_exit(void) { + usb_power_delivery_exit(); class_unregister(&typec_class); ida_destroy(&typec_index_ida); bus_unregister(&typec_bus); diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index 0f1bd6d19d67..b531f9853bc0 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -33,6 +33,8 @@ struct typec_partner { int num_altmodes; u16 pd_revision; /* 0300H = "3.0" */ enum usb_pd_svdm_ver svdm_version; + + struct usb_power_delivery *pd; }; struct typec_port { @@ -40,6 +42,8 @@ struct typec_port { struct device dev; struct ida mode_ids; + struct usb_power_delivery *pd; + int prefer_role; enum typec_data_role data_role; enum typec_role pwr_role; diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index 45e28d14ae56..7751bedcae5d 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -22,6 +22,8 @@ struct typec_altmode_ops; struct fwnode_handle; struct device; +struct usb_power_delivery; + enum typec_port_type { TYPEC_PORT_SRC, TYPEC_PORT_SNK, @@ -223,6 +225,8 @@ struct typec_partner_desc { * @pr_set: Set Power Role * @vconn_set: Source VCONN * @port_type_set: Set port type + * @pd_get: Get available USB Power Delivery Capabilities. + * @pd_set: Set USB Power Delivery Capabilities. */ struct typec_operations { int (*try_role)(struct typec_port *port, int role); @@ -231,6 +235,8 @@ struct typec_operations { int (*vconn_set)(struct typec_port *port, enum typec_role role); int (*port_type_set)(struct typec_port *port, enum typec_port_type type); + struct usb_power_delivery **(*pd_get)(struct typec_port *port); + int (*pd_set)(struct typec_port *port, struct usb_power_delivery *pd); }; enum usb_pd_svdm_ver { @@ -250,6 +256,7 @@ enum usb_pd_svdm_ver { * @accessory: Supported Accessory Modes * @fwnode: Optional fwnode of the port * @driver_data: Private pointer for driver specific info + * @pd: Optional USB Power Delivery Support * @ops: Port operations vector * * Static capabilities of a single USB Type-C port. @@ -267,6 +274,8 @@ struct typec_capability { struct fwnode_handle *fwnode; void *driver_data; + struct usb_power_delivery *pd; + const struct typec_operations *ops; }; @@ -318,4 +327,8 @@ void typec_partner_set_svdm_version(struct typec_partner *partner, enum usb_pd_svdm_ver svdm_version); int typec_get_negotiated_svdm_version(struct typec_port *port); +int typec_port_set_usb_power_delivery(struct typec_port *port, struct usb_power_delivery *pd); +int typec_partner_set_usb_power_delivery(struct typec_partner *partner, + struct usb_power_delivery *pd); + #endif /* __LINUX_USB_TYPEC_H */ -- cgit v1.2.3 From e146caf303493c4f2458173d7f1598b76a9b1396 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 6 May 2022 19:18:07 +0300 Subject: usb: Avoid extra usb SET_SEL requests when enabling link power management The host needs to tell the device the exit latencies using the SET_SEL request before device initiated link powermanagement can be enabled. The exit latency values do not change after enumeration, it's enough to set them once. So do like Windows 10 and issue the SET_SEL request once just before setting the configuration. This is also the sequence described in USB 3.2 specs "9.1.2 Bus enumeration". SET_SEL is issued once before the Set Configuration request, and won't be cleared by the Set Configuration, Set Interface or ClearFeature (STALL) requests. Only warm reset, hot reset, set Address 0 clears the exit latencies. See USB 3.2 section 9.4.14 Table 9-10 Device parameters and events Add udev->lpm_devinit_allow, and set it if SET_SEL was successful. If not set, then don't try to enable device initiated LPM We used to issue a SET_SEL request every time lpm is enabled for either U1 or U2 link states, meaning a SET_SEL was issued twice after every Set Configuration and Set Interface requests, easily accumulating to over 15 SET_SEL requets during a USB3 webcam enumeration. Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20220506161807.3369439-1-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 60 ++++++++++++++++++-------------------------------- include/linux/usb.h | 2 ++ 2 files changed, 23 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ba406b8d688d..b7f66dcd1fe0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3947,7 +3947,7 @@ static const char * const usb3_lpm_names[] = { * This function will fail if the SEL or PEL values for udev are greater than * the maximum allowed values for the link state to be enabled. */ -static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) +static int usb_req_set_sel(struct usb_device *udev) { struct usb_set_sel_req *sel_values; unsigned long long u1_sel; @@ -3956,7 +3956,7 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) unsigned long long u2_pel; int ret; - if (udev->state != USB_STATE_CONFIGURED) + if (!udev->parent || udev->speed < USB_SPEED_SUPER || !udev->lpm_capable) return 0; /* Convert SEL and PEL stored in ns to us */ @@ -3973,34 +3973,14 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) * latency for the link state, and could start a device-initiated * U1/U2 when the exit latencies are too high. */ - if ((state == USB3_LPM_U1 && - (u1_sel > USB3_LPM_MAX_U1_SEL_PEL || - u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) || - (state == USB3_LPM_U2 && - (u2_sel > USB3_LPM_MAX_U2_SEL_PEL || - u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) { - dev_dbg(&udev->dev, "Device-initiated %s disabled due to long SEL %llu us or PEL %llu us\n", - usb3_lpm_names[state], u1_sel, u1_pel); + if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL || + u1_pel > USB3_LPM_MAX_U1_SEL_PEL || + u2_sel > USB3_LPM_MAX_U2_SEL_PEL || + u2_pel > USB3_LPM_MAX_U2_SEL_PEL) { + dev_dbg(&udev->dev, "Device-initiated U1/U2 disabled due to long SEL or PEL\n"); return -EINVAL; } - /* - * If we're enabling device-initiated LPM for one link state, - * but the other link state has a too high SEL or PEL value, - * just set those values to the max in the Set SEL request. - */ - if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL) - u1_sel = USB3_LPM_MAX_U1_SEL_PEL; - - if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL) - u1_pel = USB3_LPM_MAX_U1_SEL_PEL; - - if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL) - u2_sel = USB3_LPM_MAX_U2_SEL_PEL; - - if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL) - u2_pel = USB3_LPM_MAX_U2_SEL_PEL; - /* * usb_enable_lpm() can be called as part of a failed device reset, * which may be initiated by an error path of a mass storage driver. @@ -4022,6 +4002,10 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) sel_values, sizeof *(sel_values), USB_CTRL_SET_TIMEOUT); kfree(sel_values); + + if (ret > 0) + udev->lpm_devinit_allow = 1; + return ret; } @@ -4137,6 +4121,9 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev, unsigned int sel; /* us */ int i, j; + if (!udev->lpm_devinit_allow) + return false; + if (state == USB3_LPM_U1) sel = DIV_ROUND_UP(udev->u1_params.sel, 1000); else if (state == USB3_LPM_U2) @@ -4185,7 +4172,7 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev, static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, enum usb3_link_state state) { - int timeout, ret; + int timeout; __u8 u1_mel = udev->bos->ss_cap->bU1devExitLat; __le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat; @@ -4197,17 +4184,6 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, (state == USB3_LPM_U2 && u2_mel == 0)) return; - /* - * First, let the device know about the exit latencies - * associated with the link state we're about to enable. - */ - ret = usb_req_set_sel(udev, state); - if (ret < 0) { - dev_warn(&udev->dev, "Set SEL for device-initiated %s failed.\n", - usb3_lpm_names[state]); - return; - } - /* We allow the host controller to set the U1/U2 timeout internally * first, so that it can change its schedule to account for the * additional latency to send data to a device in a lower power @@ -4487,6 +4463,11 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, return 0; } +static int usb_req_set_sel(struct usb_device *udev) +{ + return 0; +} + #endif /* CONFIG_PM */ /* @@ -5012,6 +4993,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, udev->lpm_capable = usb_device_supports_lpm(udev); udev->lpm_disable_count = 1; usb_set_lpm_parameters(udev); + usb_req_set_sel(udev); } } diff --git a/include/linux/usb.h b/include/linux/usb.h index 60bee864d897..f7a9914fc97f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -584,6 +584,7 @@ struct usb3_lpm_parameters { * @authenticated: Crypto authentication passed * @wusb: device is Wireless USB * @lpm_capable: device supports LPM + * @lpm_devinit_allow: Allow USB3 device initiated LPM, exit latency is in range * @usb2_hw_lpm_capable: device can perform USB2 hardware LPM * @usb2_hw_lpm_besl_capable: device can perform USB2 hardware BESL LPM * @usb2_hw_lpm_enabled: USB2 hardware LPM is enabled @@ -666,6 +667,7 @@ struct usb_device { unsigned authenticated:1; unsigned wusb:1; unsigned lpm_capable:1; + unsigned lpm_devinit_allow:1; unsigned usb2_hw_lpm_capable:1; unsigned usb2_hw_lpm_besl_capable:1; unsigned usb2_hw_lpm_enabled:1; -- cgit v1.2.3 From fc801750b197d0f00c09e01e59a7dcd240fddcb5 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 24 May 2022 03:05:12 +0200 Subject: drm: of: Add drm_of_get_data_lanes_count and drm_of_get_data_lanes_ep Add helper function to count and sanitize DT "data-lanes" property and return either error or the data-lanes count. This is useful for both DSI and (e)DP "data-lanes" property. The later version of the function is an extra wrapper which handles the endpoint look up by regs, that's what majority of the drivers duplicate too, but not all of them. Reviewed-by: Andrzej Hajda Signed-off-by: Marek Vasut Cc: Andrzej Hajda Cc: Laurent Pinchart Cc: Lucas Stach Cc: Maxime Ripard Cc: Robert Foss Cc: Sam Ravnborg To: dri-devel@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20220524010522.528569-1-marex@denx.de --- drivers/gpu/drm/drm_of.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_of.h | 20 ++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'include') diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 9a2cfab3a177..2c1ee601f1d8 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -430,3 +430,64 @@ int drm_of_lvds_get_data_mapping(const struct device_node *port) return -EINVAL; } EXPORT_SYMBOL_GPL(drm_of_lvds_get_data_mapping); + +/** + * drm_of_get_data_lanes_count - Get DSI/(e)DP data lane count + * @endpoint: DT endpoint node of the DSI/(e)DP source or sink + * @min: minimum supported number of data lanes + * @max: maximum supported number of data lanes + * + * Count DT "data-lanes" property elements and check for validity. + * + * Return: + * * min..max - positive integer count of "data-lanes" elements + * * -ve - the "data-lanes" property is missing or invalid + * * -EINVAL - the "data-lanes" property is unsupported + */ +int drm_of_get_data_lanes_count(const struct device_node *endpoint, + const unsigned int min, const unsigned int max) +{ + int ret; + + ret = of_property_count_u32_elems(endpoint, "data-lanes"); + if (ret < 0) + return ret; + + if (ret < min || ret > max) + return -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(drm_of_get_data_lanes_count); + +/** + * drm_of_get_data_lanes_count_ep - Get DSI/(e)DP data lane count by endpoint + * @port: DT port node of the DSI/(e)DP source or sink + * @port_reg: identifier (value of reg property) of the parent port node + * @reg: identifier (value of reg property) of the endpoint node + * @min: minimum supported number of data lanes + * @max: maximum supported number of data lanes + * + * Count DT "data-lanes" property elements and check for validity. + * This variant uses endpoint specifier. + * + * Return: + * * min..max - positive integer count of "data-lanes" elements + * * -EINVAL - the "data-mapping" property is unsupported + * * -ENODEV - the "data-mapping" property is missing + */ +int drm_of_get_data_lanes_count_ep(const struct device_node *port, + int port_reg, int reg, + const unsigned int min, + const unsigned int max) +{ + struct device_node *endpoint; + int ret; + + endpoint = of_graph_get_endpoint_by_regs(port, port_reg, reg); + ret = drm_of_get_data_lanes_count(endpoint, min, max); + of_node_put(endpoint); + + return ret; +} +EXPORT_SYMBOL_GPL(drm_of_get_data_lanes_count_ep); diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index 99f79ac8b4cd..92387eabcb6f 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -50,6 +50,12 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, const struct device_node *port2); int drm_of_lvds_get_data_mapping(const struct device_node *port); +int drm_of_get_data_lanes_count(const struct device_node *endpoint, + const unsigned int min, const unsigned int max); +int drm_of_get_data_lanes_count_ep(const struct device_node *port, + int port_reg, int reg, + const unsigned int min, + const unsigned int max); #else static inline uint32_t drm_of_crtc_port_mask(struct drm_device *dev, struct device_node *port) @@ -105,6 +111,20 @@ drm_of_lvds_get_data_mapping(const struct device_node *port) { return -EINVAL; } + +int drm_of_get_data_lanes_count(const struct device_node *endpoint, + const unsigned int min, const unsigned int max) +{ + return -EINVAL; +} + +int drm_of_get_data_lanes_count_ep(const struct device_node *port, + int port_reg, int reg + const unsigned int min, + const unsigned int max) +{ + return -EINVAL; +} #endif /* -- cgit v1.2.3 From eb6b94db2f4a585d4a9b8e503d7377d2a23c1104 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 12 Jun 2022 15:21:50 +0200 Subject: drm: of: Mark empty drm_of_get_data_lanes_count and drm_of_get_data_lanes_ep static Mark empty implementations of drm_of_get_data_lanes_count and drm_of_get_data_lanes_ep as static inline, just like the rest of empty implementations of various functions in drm_of.h . Add missing comma to drm_of_get_data_lanes_count_ep() . Fixes: fc801750b197 ("drm: of: Add drm_of_get_data_lanes_count and drm_of_get_data_lanes_ep") Reported-by: kernel test robot Signed-off-by: Marek Vasut Cc: Andrzej Hajda Cc: Laurent Pinchart Cc: Lucas Stach Cc: Maxime Ripard Cc: Robert Foss Cc: Sam Ravnborg To: dri-devel@lists.freedesktop.org Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20220612132152.91052-1-marex@denx.de --- include/drm/drm_of.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index 92387eabcb6f..10ab58c40746 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -112,16 +112,18 @@ drm_of_lvds_get_data_mapping(const struct device_node *port) return -EINVAL; } -int drm_of_get_data_lanes_count(const struct device_node *endpoint, - const unsigned int min, const unsigned int max) +static inline int +drm_of_get_data_lanes_count(const struct device_node *endpoint, + const unsigned int min, const unsigned int max) { return -EINVAL; } -int drm_of_get_data_lanes_count_ep(const struct device_node *port, - int port_reg, int reg - const unsigned int min, - const unsigned int max) +static inline int +drm_of_get_data_lanes_count_ep(const struct device_node *port, + int port_reg, int reg, + const unsigned int min, + const unsigned int max) { return -EINVAL; } -- cgit v1.2.3 From 6537f79a2aae65748d402d6c46e79d9e473d42a9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 8 Jun 2022 10:50:35 +0300 Subject: drm/edid: add new interfaces around struct drm_edid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new functions drm_edid_read(), drm_edid_read_ddc(), and drm_edid_read_custom() to replace drm_get_edid() and drm_do_get_edid() for reading the EDID. The transition is expected to happen over a fairly long time. Note that the new drm_edid_read*() functions do not do any of the connector updates anymore. The reading and parsing will be completely separated from each other. Add new functions drm_edid_alloc(), drm_edid_dup(), and drm_edid_free() for allocating and freeing drm_edid containers. Cc: David Airlie Cc: Daniel Vetter Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/5a6532a94cad6a79424f6d1918dbe7b7d607ac03.1654674560.git.jani.nikula@intel.com --- drivers/gpu/drm/drm_edid.c | 245 ++++++++++++++++++++++++++++++++++++++++----- include/drm/drm_edid.h | 9 ++ 2 files changed, 230 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 2beaa48301c1..2bdaf1e34a9d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2226,29 +2226,9 @@ static enum edid_block_status edid_block_read(void *block, unsigned int block_nu return status; } -/** - * drm_do_get_edid - get EDID data using a custom EDID block read function - * @connector: connector we're probing - * @read_block: EDID block read function - * @context: private data passed to the block read function - * - * When the I2C adapter connected to the DDC bus is hidden behind a device that - * exposes a different interface to read EDID blocks this function can be used - * to get EDID data using a custom block read function. - * - * As in the general case the DDC bus is accessible by the kernel at the I2C - * level, drivers must make all reasonable efforts to expose it as an I2C - * adapter and use drm_get_edid() instead of abusing this function. - * - * The EDID may be overridden using debugfs override_edid or firmware EDID - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority - * order. Having either of them bypasses actual EDID reads. - * - * Return: Pointer to valid EDID or NULL if we couldn't find any. - */ -struct edid *drm_do_get_edid(struct drm_connector *connector, - read_block_fn read_block, - void *context) +static struct edid *_drm_do_get_edid(struct drm_connector *connector, + read_block_fn read_block, void *context, + size_t *size) { enum edid_block_status status; int i, invalid_blocks = 0; @@ -2315,14 +2295,125 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, } ok: + if (size) + *size = alloc_size; + return edid; fail: kfree(edid); return NULL; } + +/** + * drm_do_get_edid - get EDID data using a custom EDID block read function + * @connector: connector we're probing + * @read_block: EDID block read function + * @context: private data passed to the block read function + * + * When the I2C adapter connected to the DDC bus is hidden behind a device that + * exposes a different interface to read EDID blocks this function can be used + * to get EDID data using a custom block read function. + * + * As in the general case the DDC bus is accessible by the kernel at the I2C + * level, drivers must make all reasonable efforts to expose it as an I2C + * adapter and use drm_get_edid() instead of abusing this function. + * + * The EDID may be overridden using debugfs override_edid or firmware EDID + * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * order. Having either of them bypasses actual EDID reads. + * + * Return: Pointer to valid EDID or NULL if we couldn't find any. + */ +struct edid *drm_do_get_edid(struct drm_connector *connector, + read_block_fn read_block, + void *context) +{ + return _drm_do_get_edid(connector, read_block, context, NULL); +} EXPORT_SYMBOL_GPL(drm_do_get_edid); +/* Allocate struct drm_edid container *without* duplicating the edid data */ +static const struct drm_edid *_drm_edid_alloc(const void *edid, size_t size) +{ + struct drm_edid *drm_edid; + + if (!edid || !size || size < EDID_LENGTH) + return NULL; + + drm_edid = kzalloc(sizeof(*drm_edid), GFP_KERNEL); + if (drm_edid) { + drm_edid->edid = edid; + drm_edid->size = size; + } + + return drm_edid; +} + +/** + * drm_edid_alloc - Allocate a new drm_edid container + * @edid: Pointer to raw EDID data + * @size: Size of memory allocated for EDID + * + * Allocate a new drm_edid container. Do not calculate edid size from edid, pass + * the actual size that has been allocated for the data. There is no validation + * of the raw EDID data against the size, but at least the EDID base block must + * fit in the buffer. + * + * The returned pointer must be freed using drm_edid_free(). + * + * Return: drm_edid container, or NULL on errors + */ +const struct drm_edid *drm_edid_alloc(const void *edid, size_t size) +{ + const struct drm_edid *drm_edid; + + if (!edid || !size || size < EDID_LENGTH) + return NULL; + + edid = kmemdup(edid, size, GFP_KERNEL); + if (!edid) + return NULL; + + drm_edid = _drm_edid_alloc(edid, size); + if (!drm_edid) + kfree(edid); + + return drm_edid; +} +EXPORT_SYMBOL(drm_edid_alloc); + +/** + * drm_edid_dup - Duplicate a drm_edid container + * @drm_edid: EDID to duplicate + * + * The returned pointer must be freed using drm_edid_free(). + * + * Returns: drm_edid container copy, or NULL on errors + */ +const struct drm_edid *drm_edid_dup(const struct drm_edid *drm_edid) +{ + if (!drm_edid) + return NULL; + + return drm_edid_alloc(drm_edid->edid, drm_edid->size); +} +EXPORT_SYMBOL(drm_edid_dup); + +/** + * drm_edid_free - Free the drm_edid container + * @drm_edid: EDID to free + */ +void drm_edid_free(const struct drm_edid *drm_edid) +{ + if (!drm_edid) + return; + + kfree(drm_edid->edid); + kfree(drm_edid); +} +EXPORT_SYMBOL(drm_edid_free); + /** * drm_probe_ddc() - probe DDC presence * @adapter: I2C adapter to probe @@ -2359,12 +2450,118 @@ struct edid *drm_get_edid(struct drm_connector *connector, if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter)) return NULL; - edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); + edid = _drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter, NULL); drm_connector_update_edid_property(connector, edid); return edid; } EXPORT_SYMBOL(drm_get_edid); +/** + * drm_edid_read_custom - Read EDID data using given EDID block read function + * @connector: Connector to use + * @read_block: EDID block read function + * @context: Private data passed to the block read function + * + * When the I2C adapter connected to the DDC bus is hidden behind a device that + * exposes a different interface to read EDID blocks this function can be used + * to get EDID data using a custom block read function. + * + * As in the general case the DDC bus is accessible by the kernel at the I2C + * level, drivers must make all reasonable efforts to expose it as an I2C + * adapter and use drm_edid_read() or drm_edid_read_ddc() instead of abusing + * this function. + * + * The EDID may be overridden using debugfs override_edid or firmware EDID + * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * order. Having either of them bypasses actual EDID reads. + * + * The returned pointer must be freed using drm_edid_free(). + * + * Return: Pointer to EDID, or NULL if probe/read failed. + */ +const struct drm_edid *drm_edid_read_custom(struct drm_connector *connector, + read_block_fn read_block, + void *context) +{ + const struct drm_edid *drm_edid; + struct edid *edid; + size_t size = 0; + + edid = _drm_do_get_edid(connector, read_block, context, &size); + if (!edid) + return NULL; + + /* Sanity check for now */ + drm_WARN_ON(connector->dev, !size); + + drm_edid = _drm_edid_alloc(edid, size); + if (!drm_edid) + kfree(edid); + + return drm_edid; +} +EXPORT_SYMBOL(drm_edid_read_custom); + +/** + * drm_edid_read_ddc - Read EDID data using given I2C adapter + * @connector: Connector to use + * @adapter: I2C adapter to use for DDC + * + * Read EDID using the given I2C adapter. + * + * The EDID may be overridden using debugfs override_edid or firmware EDID + * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * order. Having either of them bypasses actual EDID reads. + * + * Prefer initializing connector->ddc with drm_connector_init_with_ddc() and + * using drm_edid_read() instead of this function. + * + * The returned pointer must be freed using drm_edid_free(). + * + * Return: Pointer to EDID, or NULL if probe/read failed. + */ +const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector, + struct i2c_adapter *adapter) +{ + const struct drm_edid *drm_edid; + + if (connector->force == DRM_FORCE_OFF) + return NULL; + + if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter)) + return NULL; + + drm_edid = drm_edid_read_custom(connector, drm_do_probe_ddc_edid, adapter); + + /* Note: Do *not* call connector updates here. */ + + return drm_edid; +} +EXPORT_SYMBOL(drm_edid_read_ddc); + +/** + * drm_edid_read - Read EDID data using connector's I2C adapter + * @connector: Connector to use + * + * Read EDID using the connector's I2C adapter. + * + * The EDID may be overridden using debugfs override_edid or firmware EDID + * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * order. Having either of them bypasses actual EDID reads. + * + * The returned pointer must be freed using drm_edid_free(). + * + * Return: Pointer to EDID, or NULL if probe/read failed. + */ +const struct drm_edid *drm_edid_read(struct drm_connector *connector) +{ + if (drm_WARN_ON(connector->dev, !connector->ddc)) + return NULL; + + return drm_edid_read_ddc(connector, connector->ddc); +} +EXPORT_SYMBOL(drm_edid_read); + static u32 edid_extract_panel_id(const struct edid *edid) { /* diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 1d5950b5b407..c592d2c1afed 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -594,6 +594,15 @@ drm_display_mode_from_cea_vic(struct drm_device *dev, u8 video_code); /* Interface based on struct drm_edid */ +const struct drm_edid *drm_edid_alloc(const void *edid, size_t size); +const struct drm_edid *drm_edid_dup(const struct drm_edid *drm_edid); +void drm_edid_free(const struct drm_edid *drm_edid); +const struct drm_edid *drm_edid_read(struct drm_connector *connector); +const struct drm_edid *drm_edid_read_ddc(struct drm_connector *connector, + struct i2c_adapter *adapter); +const struct drm_edid *drm_edid_read_custom(struct drm_connector *connector, + int (*read_block)(void *context, u8 *buf, unsigned int block, size_t len), + void *context); const u8 *drm_find_edid_extension(const struct drm_edid *drm_edid, int ext_id, int *ext_index); -- cgit v1.2.3 From 219160be496f7f9cd105c5708e37cf22ab4ce0c7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Jun 2022 20:30:16 -0700 Subject: tcp: sk_forced_mem_schedule() optimization sk_memory_allocated_add() has three callers, and returns to them @memory_allocated. sk_forced_mem_schedule() is one of them, and ignores the returned value. Change sk_memory_allocated_add() to return void. Change sock_reserve_memory() and __sk_mem_raise_allocated() to call sk_memory_allocated(). This removes one cache line miss [1] for RPC workloads, as first skbs in TCP write queue and receive queue go through sk_forced_mem_schedule(). [1] Cache line holding tcp_memory_allocated. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Reviewed-by: Shakeel Butt Signed-off-by: David S. Miller --- include/net/sock.h | 3 +-- net/core/sock.c | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/sock.h b/include/net/sock.h index 0063e8410a4e..304a5e39d41e 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1412,7 +1412,7 @@ sk_memory_allocated(const struct sock *sk) /* 1 MB per cpu, in page units */ #define SK_MEMORY_PCPU_RESERVE (1 << (20 - PAGE_SHIFT)) -static inline long +static inline void sk_memory_allocated_add(struct sock *sk, int amt) { int local_reserve; @@ -1424,7 +1424,6 @@ sk_memory_allocated_add(struct sock *sk, int amt) atomic_long_add(local_reserve, sk->sk_prot->memory_allocated); } preempt_enable(); - return sk_memory_allocated(sk); } static inline void diff --git a/net/core/sock.c b/net/core/sock.c index 697d5c8e2f0d..92a0296ccb18 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1019,7 +1019,8 @@ static int sock_reserve_memory(struct sock *sk, int bytes) return -ENOMEM; /* pre-charge to forward_alloc */ - allocated = sk_memory_allocated_add(sk, pages); + sk_memory_allocated_add(sk, pages); + allocated = sk_memory_allocated(sk); /* If the system goes into memory pressure with this * precharge, give up and return error. */ @@ -2906,11 +2907,13 @@ EXPORT_SYMBOL(sk_wait_data); */ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind) { - struct proto *prot = sk->sk_prot; - long allocated = sk_memory_allocated_add(sk, amt); bool memcg_charge = mem_cgroup_sockets_enabled && sk->sk_memcg; + struct proto *prot = sk->sk_prot; bool charged = true; + long allocated; + sk_memory_allocated_add(sk, amt); + allocated = sk_memory_allocated(sk); if (memcg_charge && !(charged = mem_cgroup_charge_skmem(sk->sk_memcg, amt, gfp_memcg_charge()))) -- cgit v1.2.3 From c04245328dd7e915e21ac6395ffd218616e22754 Mon Sep 17 00:00:00 2001 From: Yajun Deng Date: Fri, 10 Jun 2022 17:10:17 +0800 Subject: net: make __sys_accept4_file() static __sys_accept4_file() isn't used outside of the file, make it static. As the same time, move file_flags and nofile parameters into __sys_accept4_file(). Signed-off-by: Yajun Deng Signed-off-by: David S. Miller --- include/linux/socket.h | 4 ---- net/socket.c | 15 ++++++--------- 2 files changed, 6 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/linux/socket.h b/include/linux/socket.h index 17311ad9f9af..414b8c7bb8f7 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -428,10 +428,6 @@ extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size, extern int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, struct sockaddr __user *addr, int addr_len); -extern int __sys_accept4_file(struct file *file, unsigned file_flags, - struct sockaddr __user *upeer_sockaddr, - int __user *upeer_addrlen, int flags, - unsigned long nofile); extern struct file *do_accept(struct file *file, unsigned file_flags, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen, int flags); diff --git a/net/socket.c b/net/socket.c index 2bc8773d9dc5..1b6f5e2ebef5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1878,10 +1878,8 @@ out_fd: return ERR_PTR(err); } -int __sys_accept4_file(struct file *file, unsigned file_flags, - struct sockaddr __user *upeer_sockaddr, - int __user *upeer_addrlen, int flags, - unsigned long nofile) +static int __sys_accept4_file(struct file *file, struct sockaddr __user *upeer_sockaddr, + int __user *upeer_addrlen, int flags) { struct file *newfile; int newfd; @@ -1892,11 +1890,11 @@ int __sys_accept4_file(struct file *file, unsigned file_flags, if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; - newfd = __get_unused_fd_flags(flags, nofile); + newfd = get_unused_fd_flags(flags); if (unlikely(newfd < 0)) return newfd; - newfile = do_accept(file, file_flags, upeer_sockaddr, upeer_addrlen, + newfile = do_accept(file, 0, upeer_sockaddr, upeer_addrlen, flags); if (IS_ERR(newfile)) { put_unused_fd(newfd); @@ -1926,9 +1924,8 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, f = fdget(fd); if (f.file) { - ret = __sys_accept4_file(f.file, 0, upeer_sockaddr, - upeer_addrlen, flags, - rlimit(RLIMIT_NOFILE)); + ret = __sys_accept4_file(f.file, upeer_sockaddr, + upeer_addrlen, flags); fdput(f); } -- cgit v1.2.3 From 9f1c8677724a0e6a6ac7a74d2b0192a584df859d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Jun 2022 12:30:29 +0200 Subject: ASoC: hdmi-codec: Update to modern DAI terminology As part of retiring the old defines used to specify DAI formats update the hdmi_codec driver to use the modern names, including the variables in the struct hdmi_codec_daifmt exported to the DRM drivers. In updating this I did note that the only use of this information in DRM drivers is to reject clock provider settings, thinking about what this hardware is doing I rather suspect that there might not be any hardware out there which needs the configuration so it may be worth considering just having hdmi-codec support only clock consumer. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20220602103029.3498791-1-broonie@kernel.org Signed-off-by: Mark Brown --- drivers/gpu/drm/bridge/sii902x.c | 5 +++-- drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 2 +- drivers/gpu/drm/exynos/exynos_hdmi.c | 8 ++++---- drivers/gpu/drm/i2c/tda998x_drv.c | 6 +++--- drivers/gpu/drm/sti/sti_hdmi.c | 8 ++++---- include/sound/hdmi-codec.h | 4 ++-- sound/soc/codecs/hdmi-codec.c | 18 +++++++++--------- 7 files changed, 26 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 65549fbfdc87..be9736f67542 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -549,8 +549,9 @@ static int sii902x_audio_hw_params(struct device *dev, void *data, unsigned long mclk_rate; int i, ret; - if (daifmt->bit_clk_master || daifmt->frame_clk_master) { - dev_dbg(dev, "%s: I2S master mode not supported\n", __func__); + if (daifmt->bit_clk_provider || daifmt->frame_clk_provider) { + dev_dbg(dev, "%s: I2S clock provider mode not supported\n", + __func__); return -EINVAL; } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index f50b47ac11a8..a2f0860b20bb 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -45,7 +45,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, u8 inputclkfs = 0; /* it cares I2S only */ - if (fmt->bit_clk_master | fmt->frame_clk_master) { + if (fmt->bit_clk_provider | fmt->frame_clk_provider) { dev_err(dev, "unsupported clock settings\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 7655142a4651..10b0036f8a2e 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1594,12 +1594,12 @@ static int hdmi_audio_hw_params(struct device *dev, void *data, struct hdmi_context *hdata = dev_get_drvdata(dev); if (daifmt->fmt != HDMI_I2S || daifmt->bit_clk_inv || - daifmt->frame_clk_inv || daifmt->bit_clk_master || - daifmt->frame_clk_master) { + daifmt->frame_clk_inv || daifmt->bit_clk_provider || + daifmt->frame_clk_provider) { dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, daifmt->bit_clk_inv, daifmt->frame_clk_inv, - daifmt->bit_clk_master, - daifmt->frame_clk_master); + daifmt->bit_clk_provider, + daifmt->frame_clk_provider); return -EINVAL; } diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index b7ec6c374fbd..c4fadaecbb2d 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1095,11 +1095,11 @@ static int tda998x_audio_hw_params(struct device *dev, void *data, if (!spdif && (daifmt->bit_clk_inv || daifmt->frame_clk_inv || - daifmt->bit_clk_master || daifmt->frame_clk_master)) { + daifmt->bit_clk_provider || daifmt->frame_clk_provider)) { dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, daifmt->bit_clk_inv, daifmt->frame_clk_inv, - daifmt->bit_clk_master, - daifmt->frame_clk_master); + daifmt->bit_clk_provider, + daifmt->frame_clk_provider); return -EINVAL; } diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index b3fbee7eac11..65c76077e866 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -1175,12 +1175,12 @@ static int hdmi_audio_hw_params(struct device *dev, DRM_DEBUG_DRIVER("\n"); if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv || - daifmt->frame_clk_inv || daifmt->bit_clk_master || - daifmt->frame_clk_master) { + daifmt->frame_clk_inv || daifmt->bit_clk_provider || + daifmt->frame_clk_provider) { dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, daifmt->bit_clk_inv, daifmt->frame_clk_inv, - daifmt->bit_clk_master, - daifmt->frame_clk_master); + daifmt->bit_clk_provider, + daifmt->frame_clk_provider); return -EINVAL; } diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h index 4fc733c8c570..48ad33aba393 100644 --- a/include/sound/hdmi-codec.h +++ b/include/sound/hdmi-codec.h @@ -32,8 +32,8 @@ struct hdmi_codec_daifmt { } fmt; unsigned int bit_clk_inv:1; unsigned int frame_clk_inv:1; - unsigned int bit_clk_master:1; - unsigned int frame_clk_master:1; + unsigned int bit_clk_provider:1; + unsigned int frame_clk_provider:1; /* bit_fmt could be standard PCM format or * IEC958 encoded format. ALSA IEC958 plugin will pass * IEC958_SUBFRAME format to the underneath driver. diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index b773466619b2..7d1e351f863a 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -606,18 +606,18 @@ static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, /* Reset daifmt */ memset(cf, 0, sizeof(*cf)); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - cf->bit_clk_master = 1; - cf->frame_clk_master = 1; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + cf->bit_clk_provider = 1; + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFM: - cf->frame_clk_master = 1; + case SND_SOC_DAIFMT_CBC_CFP: + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: - cf->bit_clk_master = 1; + case SND_SOC_DAIFMT_CBP_CFC: + cf->bit_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; -- cgit v1.2.3 From 0eb6584068642767baab17c2e4385a6b9c029caa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:36 +0200 Subject: platform/surface: aggregator: Allow is_ssam_device() to be used when CONFIG_SURFACE_AGGREGATOR_BUS is disabled In SSAM subsystem drivers that handle both ACPI and SSAM-native client devices, we may want to check whether we have a SSAM (native) client device. Further, we may want to do this even when instantiation thereof cannot happen due to CONFIG_SURFACE_AGGREGATOR_BUS=n. Currently, doing so causes an error due to an undefined reference error due to ssam_device_type being placed in the bus source unit. Therefore, if CONFIG_SURFACE_AGGREGATOR_BUS is not defined, simply let is_ssam_device() return false to prevent this error. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-2-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- include/linux/surface_aggregator/device.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index cc257097eb05..62b38b4487eb 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -177,6 +177,8 @@ struct ssam_device_driver { void (*remove)(struct ssam_device *sdev); }; +#ifdef CONFIG_SURFACE_AGGREGATOR_BUS + extern struct bus_type ssam_bus_type; extern const struct device_type ssam_device_type; @@ -193,6 +195,15 @@ static inline bool is_ssam_device(struct device *d) return d->type == &ssam_device_type; } +#else /* CONFIG_SURFACE_AGGREGATOR_BUS */ + +static inline bool is_ssam_device(struct device *d) +{ + return false; +} + +#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ + /** * to_ssam_device() - Casts the given device to a SSAM client device. * @d: The device to cast. -- cgit v1.2.3 From dc0393c76f378f68961587fd4f32de29fb8f0c79 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:37 +0200 Subject: platform/surface: aggregator: Allow devices to be marked as hot-removed Some SSAM devices, notably the keyboard cover (keyboard and touchpad) on the Surface Pro 8, can be hot-removed. When this occurs, communication with the device may fail and time out. This timeout can unnecessarily block and slow down device removal and even cause issues when the devices are detached and re-attached quickly. Thus, communication should generally be avoided once hot-removal is detected. While we already remove a device as soon as we detect its (hot-)removal, the corresponding device driver may still attempt to communicate with the device during teardown. This is especially critical as communication failure may also extend to disabling of events, which is typically done at that stage. Add a flag to allow marking devices as hot-removed. This can then be used during client driver teardown to check if any communication attempts should be avoided. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-3-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- include/linux/surface_aggregator/device.h | 48 +++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 62b38b4487eb..6df7c8d4e50e 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -148,17 +148,30 @@ struct ssam_device_uid { #define SSAM_SDEV(cat, tid, iid, fun) \ SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, tid, iid, fun) +/* + * enum ssam_device_flags - Flags for SSAM client devices. + * @SSAM_DEVICE_HOT_REMOVED_BIT: + * The device has been hot-removed. Further communication with it may time + * out and should be avoided. + */ +enum ssam_device_flags { + SSAM_DEVICE_HOT_REMOVED_BIT = 0, +}; + /** * struct ssam_device - SSAM client device. - * @dev: Driver model representation of the device. - * @ctrl: SSAM controller managing this device. - * @uid: UID identifying the device. + * @dev: Driver model representation of the device. + * @ctrl: SSAM controller managing this device. + * @uid: UID identifying the device. + * @flags: Device state flags, see &enum ssam_device_flags. */ struct ssam_device { struct device dev; struct ssam_controller *ctrl; struct ssam_device_uid uid; + + unsigned long flags; }; /** @@ -251,6 +264,35 @@ struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl, int ssam_device_add(struct ssam_device *sdev); void ssam_device_remove(struct ssam_device *sdev); +/** + * ssam_device_mark_hot_removed() - Mark the given device as hot-removed. + * @sdev: The device to mark as hot-removed. + * + * Mark the device as having been hot-removed. This signals drivers using the + * device that communication with the device should be avoided and may lead to + * timeouts. + */ +static inline void ssam_device_mark_hot_removed(struct ssam_device *sdev) +{ + dev_dbg(&sdev->dev, "marking device as hot-removed\n"); + set_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags); +} + +/** + * ssam_device_is_hot_removed() - Check if the given device has been + * hot-removed. + * @sdev: The device to check. + * + * Checks if the given device has been marked as hot-removed. See + * ssam_device_mark_hot_removed() for more details. + * + * Return: Returns ``true`` if the device has been marked as hot-removed. + */ +static inline bool ssam_device_is_hot_removed(struct ssam_device *sdev) +{ + return test_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags); +} + /** * ssam_device_get() - Increment reference count of SSAM client device. * @sdev: The device to increment the reference count of. -- cgit v1.2.3 From 5c1e88b98c60e4074796e9a05d3c674479ab1919 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:38 +0200 Subject: platform/surface: aggregator: Allow notifiers to avoid communication on unregistering When SSAM client devices have been (physically) hot-removed, communication attempts with those devices may fail and time out. This can even extend to event notifiers, due to which timeouts may occur during device removal, slowing down that process. Add a parameter to the notifier unregister function that allows skipping communication with the EC to prevent this. Furthermore, add wrappers for registering and unregistering notifiers belonging to SSAM client devices that automatically check if the device has been marked as hot-removed and communication should be avoided. Note that non-SSAM client devices can generally not be hot-removed, so also add a convenience wrapper for those, defaulting to allow communication. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-4-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../driver-api/surface_aggregator/client.rst | 6 +- drivers/platform/surface/aggregator/controller.c | 53 +++++++++++------ include/linux/surface_aggregator/controller.h | 24 +++++++- include/linux/surface_aggregator/device.h | 66 ++++++++++++++++++++++ 4 files changed, 128 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst index e519d374c378..27f95abdbe99 100644 --- a/Documentation/driver-api/surface_aggregator/client.rst +++ b/Documentation/driver-api/surface_aggregator/client.rst @@ -17,6 +17,8 @@ .. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE` .. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register` .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister` +.. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register` +.. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister` .. |ssam_request_sync| replace:: :c:func:`ssam_request_sync` .. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask ` @@ -312,7 +314,9 @@ Handling Events To receive events from the SAM EC, an event notifier must be registered for the desired event via |ssam_notifier_register|. The notifier must be unregistered via |ssam_notifier_unregister| once it is not required any -more. +more. For |ssam_device| type clients, the |ssam_device_notifier_register| and +|ssam_device_notifier_unregister| wrappers should be preferred as they properly +handle hot-removal of client devices. Event notifiers are registered by providing (at minimum) a callback to call in case an event has been received, the registry specifying how the event diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c index b8c377b3f932..6de834b52b63 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -2199,16 +2199,26 @@ static int ssam_nf_refcount_enable(struct ssam_controller *ctrl, } /** - * ssam_nf_refcount_disable_free() - Disable event for reference count entry if it is - * no longer in use and free the corresponding entry. + * ssam_nf_refcount_disable_free() - Disable event for reference count entry if + * it is no longer in use and free the corresponding entry. * @ctrl: The controller to disable the event on. * @entry: The reference count entry for the event to be disabled. * @flags: The flags used for enabling the event on the EC. + * @ec: Flag specifying if the event should actually be disabled on the EC. * - * If the reference count equals zero, i.e. the event is no longer requested by - * any client, the event will be disabled and the corresponding reference count - * entry freed. The reference count entry must not be used any more after a - * call to this function. + * If ``ec`` equals ``true`` and the reference count equals zero (i.e. the + * event is no longer requested by any client), the specified event will be + * disabled on the EC via the corresponding request. + * + * If ``ec`` equals ``false``, no request will be sent to the EC and the event + * can be considered in a detached state (i.e. no longer used but still + * enabled). Disabling an event via this method may be required for + * hot-removable devices, where event disable requests may time out after the + * device has been physically removed. + * + * In both cases, if the reference count equals zero, the corresponding + * reference count entry will be freed. The reference count entry must not be + * used any more after a call to this function. * * Also checks if the flags used for disabling the event match the flags used * for enabling the event and warns if they do not (regardless of reference @@ -2223,7 +2233,7 @@ static int ssam_nf_refcount_enable(struct ssam_controller *ctrl, * returns the status of the event-enable EC command. */ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl, - struct ssam_nf_refcount_entry *entry, u8 flags) + struct ssam_nf_refcount_entry *entry, u8 flags, bool ec) { const struct ssam_event_registry reg = entry->key.reg; const struct ssam_event_id id = entry->key.id; @@ -2232,8 +2242,9 @@ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl, lockdep_assert_held(&nf->lock); - ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", - reg.target_category, id.target_category, id.instance, entry->refcount); + ssam_dbg(ctrl, "%s event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", + ec ? "disabling" : "detaching", reg.target_category, id.target_category, + id.instance, entry->refcount); if (entry->flags != flags) { ssam_warn(ctrl, @@ -2242,7 +2253,7 @@ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl, id.instance); } - if (entry->refcount == 0) { + if (ec && entry->refcount == 0) { status = ssam_ssh_event_disable(ctrl, reg, id, flags); kfree(entry); } @@ -2322,20 +2333,26 @@ int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notif EXPORT_SYMBOL_GPL(ssam_notifier_register); /** - * ssam_notifier_unregister() - Unregister an event notifier. - * @ctrl: The controller the notifier has been registered on. - * @n: The event notifier to unregister. + * __ssam_notifier_unregister() - Unregister an event notifier. + * @ctrl: The controller the notifier has been registered on. + * @n: The event notifier to unregister. + * @disable: Whether to disable the corresponding event on the EC. * * Unregister an event notifier. Decrement the usage counter of the associated * SAM event if the notifier is not marked as an observer. If the usage counter - * reaches zero, the event will be disabled. + * reaches zero and ``disable`` equals ``true``, the event will be disabled. + * + * Useful for hot-removable devices, where communication may fail once the + * device has been physically removed. In that case, specifying ``disable`` as + * ``false`` avoids communication with the EC. * * Return: Returns zero on success, %-ENOENT if the given notifier block has * not been registered on the controller. If the given notifier block was the * last one associated with its specific event, returns the status of the * event-disable EC-command. */ -int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n) +int __ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n, + bool disable) { u16 rqid = ssh_tc_to_rqid(n->event.id.target_category); struct ssam_nf_refcount_entry *entry; @@ -2373,7 +2390,7 @@ int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_not goto remove; } - status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags); + status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags, disable); } remove: @@ -2383,7 +2400,7 @@ remove: return status; } -EXPORT_SYMBOL_GPL(ssam_notifier_unregister); +EXPORT_SYMBOL_GPL(__ssam_notifier_unregister); /** * ssam_controller_event_enable() - Enable the specified event. @@ -2477,7 +2494,7 @@ int ssam_controller_event_disable(struct ssam_controller *ctrl, return -ENOENT; } - status = ssam_nf_refcount_disable_free(ctrl, entry, flags); + status = ssam_nf_refcount_disable_free(ctrl, entry, flags, true); mutex_unlock(&nf->lock); return status; diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index 74bfdffaf7b0..50a2b4926c06 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -835,8 +835,28 @@ struct ssam_event_notifier { int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notifier *n); -int ssam_notifier_unregister(struct ssam_controller *ctrl, - struct ssam_event_notifier *n); +int __ssam_notifier_unregister(struct ssam_controller *ctrl, + struct ssam_event_notifier *n, bool disable); + +/** + * ssam_notifier_unregister() - Unregister an event notifier. + * @ctrl: The controller the notifier has been registered on. + * @n: The event notifier to unregister. + * + * Unregister an event notifier. Decrement the usage counter of the associated + * SAM event if the notifier is not marked as an observer. If the usage counter + * reaches zero, the event will be disabled. + * + * Return: Returns zero on success, %-ENOENT if the given notifier block has + * not been registered on the controller. If the given notifier block was the + * last one associated with its specific event, returns the status of the + * event-disable EC-command. + */ +static inline int ssam_notifier_unregister(struct ssam_controller *ctrl, + struct ssam_event_notifier *n) +{ + return __ssam_notifier_unregister(ctrl, n, true); +} int ssam_controller_event_enable(struct ssam_controller *ctrl, struct ssam_event_registry reg, diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 6df7c8d4e50e..c418f7f2732d 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -483,4 +483,70 @@ static inline void ssam_remove_clients(struct device *dev) {} sdev->uid.instance, ret); \ } + +/* -- Helpers for client-device notifiers. ---------------------------------- */ + +/** + * ssam_device_notifier_register() - Register an event notifier for the + * specified client device. + * @sdev: The device the notifier should be registered on. + * @n: The event notifier to register. + * + * Register an event notifier. Increment the usage counter of the associated + * SAM event if the notifier is not marked as an observer. If the event is not + * marked as an observer and is currently not enabled, it will be enabled + * during this call. If the notifier is marked as an observer, no attempt will + * be made at enabling any event and no reference count will be modified. + * + * Notifiers marked as observers do not need to be associated with one specific + * event, i.e. as long as no event matching is performed, only the event target + * category needs to be set. + * + * Return: Returns zero on success, %-ENOSPC if there have already been + * %INT_MAX notifiers for the event ID/type associated with the notifier block + * registered, %-ENOMEM if the corresponding event entry could not be + * allocated, %-ENODEV if the device is marked as hot-removed. If this is the + * first time that a notifier block is registered for the specific associated + * event, returns the status of the event-enable EC-command. + */ +static inline int ssam_device_notifier_register(struct ssam_device *sdev, + struct ssam_event_notifier *n) +{ + /* + * Note that this check does not provide any guarantees whatsoever as + * hot-removal could happen at any point and we can't protect against + * it. Nevertheless, if we can detect hot-removal, bail early to avoid + * communication timeouts. + */ + if (ssam_device_is_hot_removed(sdev)) + return -ENODEV; + + return ssam_notifier_register(sdev->ctrl, n); +} + +/** + * ssam_device_notifier_unregister() - Unregister an event notifier for the + * specified client device. + * @sdev: The device the notifier has been registered on. + * @n: The event notifier to unregister. + * + * Unregister an event notifier. Decrement the usage counter of the associated + * SAM event if the notifier is not marked as an observer. If the usage counter + * reaches zero, the event will be disabled. + * + * In case the device has been marked as hot-removed, the event will not be + * disabled on the EC, as in those cases any attempt at doing so may time out. + * + * Return: Returns zero on success, %-ENOENT if the given notifier block has + * not been registered on the controller. If the given notifier block was the + * last one associated with its specific event, returns the status of the + * event-disable EC-command. + */ +static inline int ssam_device_notifier_unregister(struct ssam_device *sdev, + struct ssam_event_notifier *n) +{ + return __ssam_notifier_unregister(sdev->ctrl, n, + !ssam_device_is_hot_removed(sdev)); +} + #endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */ -- cgit v1.2.3 From 25e2ca7301bd3ca5a63a6be41d729eb42202bc21 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:43 +0200 Subject: platform/surface: aggregator: Add comment for KIP subsystem category The KIP subsystem (full name unknown, abbreviation has been obtained through reverse engineering) handles detachable peripherals such as the keyboard cover on the Surface Pro X and Surface Pro 8. It is currently not entirely clear what this subsystem entails, but at the very least it provides event notifications for when the keyboard cover on the Surface Pro X and Surface Pro 8 have been detached or re-attached, as well as the state that the keyboard cover is currently in (e.g. folded-back, folded laptop-like, closed, etc.). Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-9-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- include/linux/surface_aggregator/serial_hub.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h index c3de43edcffa..26b95ec12733 100644 --- a/include/linux/surface_aggregator/serial_hub.h +++ b/include/linux/surface_aggregator/serial_hub.h @@ -306,7 +306,7 @@ enum ssam_ssh_tc { SSAM_SSH_TC_LPC = 0x0b, SSAM_SSH_TC_TCL = 0x0c, SSAM_SSH_TC_SFL = 0x0d, - SSAM_SSH_TC_KIP = 0x0e, + SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */ SSAM_SSH_TC_EXT = 0x0f, SSAM_SSH_TC_BLD = 0x10, SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */ -- cgit v1.2.3 From 546093206ba16623c18e344630dbfdd71a4327e0 Mon Sep 17 00:00:00 2001 From: Xiu Jianfeng Date: Sat, 11 Jun 2022 17:23:04 +0800 Subject: audit: make is_audit_feature_set() static Currently nobody use is_audit_feature_set() outside this file, so make it static. Signed-off-by: Xiu Jianfeng Signed-off-by: Paul Moore --- include/linux/audit.h | 2 -- kernel/audit.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/audit.h b/include/linux/audit.h index cece70231138..00f7a80f1a3e 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -119,8 +119,6 @@ enum audit_nfcfgop { AUDIT_NFT_OP_INVALID, }; -extern int is_audit_feature_set(int which); - extern int __init audit_register_class(int class, unsigned *list); extern int audit_classify_syscall(int abi, unsigned syscall); extern int audit_classify_arch(int arch); diff --git a/kernel/audit.c b/kernel/audit.c index 0749211d5552..a75978ae38ad 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1100,7 +1100,7 @@ static inline void audit_log_user_recv_msg(struct audit_buffer **ab, audit_log_common_recv_msg(NULL, ab, msg_type); } -int is_audit_feature_set(int i) +static int is_audit_feature_set(int i) { return af.features & AUDIT_FEATURE_TO_MASK(i); } -- cgit v1.2.3 From 795e10b450a88b2943a241a5eaa6e86ae4f47694 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Tue, 7 Jun 2022 15:47:43 +0300 Subject: net/mlx5: Introduce header-modify-pattern ICM properties Added new fields for device memory capabilities, in order to support creation of ICM memory for modify header patterns. Signed-off-by: Erez Shitrit Signed-off-by: Yevgeny Kliteynik Signed-off-by: Leon Romanovsky Acked-by: Saeed Mahameed Signed-off-by: Saeed Mahameed --- include/linux/mlx5/mlx5_ifc.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index fd7d083a34d3..789d64400744 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1086,11 +1086,14 @@ struct mlx5_ifc_device_mem_cap_bits { u8 log_sw_icm_alloc_granularity[0x6]; u8 log_steering_sw_icm_size[0x8]; - u8 reserved_at_120[0x20]; + u8 reserved_at_120[0x18]; + u8 log_header_modify_pattern_sw_icm_size[0x8]; u8 header_modify_sw_icm_start_address[0x40]; - u8 reserved_at_180[0x80]; + u8 reserved_at_180[0x40]; + + u8 header_modify_pattern_sw_icm_start_address[0x40]; u8 memic_operations[0x20]; -- cgit v1.2.3 From 667658364b2056f344a2769280b939a5e45610be Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Tue, 7 Jun 2022 15:47:44 +0300 Subject: net/mlx5: Manage ICM of type modify-header pattern Added support for managing new type of ICM for devices that support sw_owner_v2. Signed-off-by: Erez Shitrit Signed-off-by: Yevgeny Kliteynik Signed-off-by: Leon Romanovsky Acked-by: Saeed Mahameed Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c | 42 ++++++++++++++++++++++++ include/linux/mlx5/driver.h | 1 + 2 files changed, 43 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c index 3d5e57ff558c..7e02cbe8c3b9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c @@ -12,13 +12,16 @@ struct mlx5_dm { spinlock_t lock; unsigned long *steering_sw_icm_alloc_blocks; unsigned long *header_modify_sw_icm_alloc_blocks; + unsigned long *header_modify_pattern_sw_icm_alloc_blocks; }; struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev) { + u64 header_modify_pattern_icm_blocks = 0; u64 header_modify_icm_blocks = 0; u64 steering_icm_blocks = 0; struct mlx5_dm *dm; + bool support_v2; if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM)) return NULL; @@ -53,8 +56,27 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev) goto err_modify_hdr; } + support_v2 = MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) && + MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2) && + MLX5_CAP64_DEV_MEM(dev, header_modify_pattern_sw_icm_start_address); + + if (support_v2) { + header_modify_pattern_icm_blocks = + BIT(MLX5_CAP_DEV_MEM(dev, log_header_modify_pattern_sw_icm_size) - + MLX5_LOG_SW_ICM_BLOCK_SIZE(dev)); + + dm->header_modify_pattern_sw_icm_alloc_blocks = + kcalloc(BITS_TO_LONGS(header_modify_pattern_icm_blocks), + sizeof(unsigned long), GFP_KERNEL); + if (!dm->header_modify_pattern_sw_icm_alloc_blocks) + goto err_pattern; + } + return dm; +err_pattern: + kfree(dm->header_modify_sw_icm_alloc_blocks); + err_modify_hdr: kfree(dm->steering_sw_icm_alloc_blocks); @@ -86,6 +108,14 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev) kfree(dm->header_modify_sw_icm_alloc_blocks); } + if (dm->header_modify_pattern_sw_icm_alloc_blocks) { + WARN_ON(!bitmap_empty(dm->header_modify_pattern_sw_icm_alloc_blocks, + BIT(MLX5_CAP_DEV_MEM(dev, + log_header_modify_pattern_sw_icm_size) - + MLX5_LOG_SW_ICM_BLOCK_SIZE(dev)))); + kfree(dm->header_modify_pattern_sw_icm_alloc_blocks); + } + kfree(dm); } @@ -130,6 +160,13 @@ int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type, log_header_modify_sw_icm_size); block_map = dm->header_modify_sw_icm_alloc_blocks; break; + case MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN: + icm_start_addr = MLX5_CAP64_DEV_MEM(dev, + header_modify_pattern_sw_icm_start_address); + log_icm_size = MLX5_CAP_DEV_MEM(dev, + log_header_modify_pattern_sw_icm_size); + block_map = dm->header_modify_pattern_sw_icm_alloc_blocks; + break; default: return -EINVAL; } @@ -203,6 +240,11 @@ int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address); block_map = dm->header_modify_sw_icm_alloc_blocks; break; + case MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN: + icm_start_addr = MLX5_CAP64_DEV_MEM(dev, + header_modify_pattern_sw_icm_start_address); + block_map = dm->header_modify_pattern_sw_icm_alloc_blocks; + break; default: return -EINVAL; } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 5040cd774c5a..76d7661e3e63 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -676,6 +676,7 @@ struct mlx5e_resources { enum mlx5_sw_icm_type { MLX5_SW_ICM_TYPE_STEERING, MLX5_SW_ICM_TYPE_HEADER_MODIFY, + MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN, }; #define MLX5_MAX_RESERVED_GIDS 8 -- cgit v1.2.3 From a6492af3805ae3d9fe872545aa4797971b4e2a33 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Tue, 7 Jun 2022 15:47:45 +0300 Subject: RDMA/mlx5: Support handling of modify-header pattern ICM area Add support for allocate/deallocate and registering MR of the new type of ICM area. Support exists only for devices that support sw_owner_v2. Signed-off-by: Yevgeny Kliteynik Signed-off-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/dm.c | 53 ++++++++++++++++++++----------- drivers/infiniband/hw/mlx5/mr.c | 1 + include/uapi/rdma/mlx5_user_ioctl_verbs.h | 1 + 3 files changed, 37 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/hw/mlx5/dm.c b/drivers/infiniband/hw/mlx5/dm.c index 001d766cf291..3669c90b2dad 100644 --- a/drivers/infiniband/hw/mlx5/dm.c +++ b/drivers/infiniband/hw/mlx5/dm.c @@ -336,9 +336,15 @@ err_copy: static enum mlx5_sw_icm_type get_icm_type(int uapi_type) { - return uapi_type == MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM ? - MLX5_SW_ICM_TYPE_STEERING : - MLX5_SW_ICM_TYPE_HEADER_MODIFY; + switch (uapi_type) { + case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: + return MLX5_SW_ICM_TYPE_HEADER_MODIFY; + case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM: + return MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN; + case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: + default: + return MLX5_SW_ICM_TYPE_STEERING; + } } static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx, @@ -347,11 +353,32 @@ static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx, int type) { struct mlx5_core_dev *dev = to_mdev(ctx->device)->mdev; - enum mlx5_sw_icm_type icm_type = get_icm_type(type); + enum mlx5_sw_icm_type icm_type; struct mlx5_ib_dm_icm *dm; u64 act_size; int err; + if (!capable(CAP_SYS_RAWIO) || !capable(CAP_NET_RAW)) + return ERR_PTR(-EPERM); + + switch (type) { + case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: + case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: + if (!(MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner) || + MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner) || + MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) || + MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2))) + return ERR_PTR(-EOPNOTSUPP); + break; + case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM: + if (!MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) || + !MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2)) + return ERR_PTR(-EOPNOTSUPP); + break; + default: + return ERR_PTR(-EOPNOTSUPP); + } + dm = kzalloc(sizeof(*dm), GFP_KERNEL); if (!dm) return ERR_PTR(-ENOMEM); @@ -359,19 +386,6 @@ static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx, dm->base.type = type; dm->base.ibdm.device = ctx->device; - if (!capable(CAP_SYS_RAWIO) || !capable(CAP_NET_RAW)) { - err = -EPERM; - goto free; - } - - if (!(MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner) || - MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner) || - MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) || - MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2))) { - err = -EOPNOTSUPP; - goto free; - } - /* Allocation size must a multiple of the basic block size * and a power of 2. */ @@ -379,6 +393,8 @@ static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx, act_size = roundup_pow_of_two(act_size); dm->base.size = act_size; + icm_type = get_icm_type(type); + err = mlx5_dm_sw_icm_alloc(dev, icm_type, act_size, attr->alignment, to_mucontext(ctx)->devx_uid, &dm->base.dev_addr, &dm->obj_id); @@ -420,8 +436,8 @@ struct ib_dm *mlx5_ib_alloc_dm(struct ib_device *ibdev, case MLX5_IB_UAPI_DM_TYPE_MEMIC: return handle_alloc_dm_memic(context, attr, attrs); case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: - return handle_alloc_dm_sw_icm(context, attr, attrs, type); case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: + case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM: return handle_alloc_dm_sw_icm(context, attr, attrs, type); default: return ERR_PTR(-EOPNOTSUPP); @@ -474,6 +490,7 @@ static int mlx5_ib_dealloc_dm(struct ib_dm *ibdm, return 0; case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: + case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM: return mlx5_dm_icm_dealloc(ctx, to_icm(ibdm)); default: return -EOPNOTSUPP; diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 1e7653c997b5..aedfd7ff4846 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1083,6 +1083,7 @@ struct ib_mr *mlx5_ib_reg_dm_mr(struct ib_pd *pd, struct ib_dm *dm, break; case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM: case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM: + case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM: if (attr->access_flags & ~MLX5_IB_DM_SW_ICM_ALLOWED_ACCESS) return ERR_PTR(-EINVAL); diff --git a/include/uapi/rdma/mlx5_user_ioctl_verbs.h b/include/uapi/rdma/mlx5_user_ioctl_verbs.h index a21ca8ece8db..7af9e09ea556 100644 --- a/include/uapi/rdma/mlx5_user_ioctl_verbs.h +++ b/include/uapi/rdma/mlx5_user_ioctl_verbs.h @@ -63,6 +63,7 @@ enum mlx5_ib_uapi_dm_type { MLX5_IB_UAPI_DM_TYPE_MEMIC, MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM, MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM, + MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM, }; enum mlx5_ib_uapi_devx_create_event_channel_flags { -- cgit v1.2.3 From f5d23ee137e51b4e5cd5d263b144d5e6719f6e52 Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Wed, 8 Jun 2022 13:04:47 -0700 Subject: net/mlx5: Add IFC bits and enums for flow meter Add/extend structure layouts and defines for flow meter. Signed-off-by: Jianbo Liu Reviewed-by: Ariel Levkovich Signed-off-by: Saeed Mahameed --- include/linux/mlx5/device.h | 1 + include/linux/mlx5/mlx5_ifc.h | 114 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 111 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 604b85dd770a..15ac02eeed4f 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -455,6 +455,7 @@ enum { MLX5_OPCODE_UMR = 0x25, + MLX5_OPCODE_ACCESS_ASO = 0x2d, }; enum { diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 789d64400744..91872afb2bfe 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -442,7 +442,9 @@ struct mlx5_ifc_flow_table_prop_layout_bits { u8 max_modify_header_actions[0x8]; u8 max_ft_level[0x8]; - u8 reserved_at_40[0x20]; + u8 reserved_at_40[0x6]; + u8 execute_aso[0x1]; + u8 reserved_at_47[0x19]; u8 reserved_at_60[0x2]; u8 reformat_insert[0x1]; @@ -940,7 +942,17 @@ struct mlx5_ifc_qos_cap_bits { u8 max_tsar_bw_share[0x20]; - u8 reserved_at_100[0x700]; + u8 reserved_at_100[0x20]; + + u8 reserved_at_120[0x3]; + u8 log_meter_aso_granularity[0x5]; + u8 reserved_at_128[0x3]; + u8 log_meter_aso_max_alloc[0x5]; + u8 reserved_at_130[0x3]; + u8 log_max_num_meter_aso[0x5]; + u8 reserved_at_138[0x8]; + + u8 reserved_at_140[0x6c0]; }; struct mlx5_ifc_debug_cap_bits { @@ -3280,6 +3292,7 @@ enum { MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2 = 0x800, MLX5_FLOW_CONTEXT_ACTION_IPSEC_DECRYPT = 0x1000, MLX5_FLOW_CONTEXT_ACTION_IPSEC_ENCRYPT = 0x2000, + MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO = 0x4000, }; enum { @@ -3295,6 +3308,38 @@ struct mlx5_ifc_vlan_bits { u8 vid[0xc]; }; +enum { + MLX5_FLOW_METER_COLOR_RED = 0x0, + MLX5_FLOW_METER_COLOR_YELLOW = 0x1, + MLX5_FLOW_METER_COLOR_GREEN = 0x2, + MLX5_FLOW_METER_COLOR_UNDEFINED = 0x3, +}; + +enum { + MLX5_EXE_ASO_FLOW_METER = 0x2, +}; + +struct mlx5_ifc_exe_aso_ctrl_flow_meter_bits { + u8 return_reg_id[0x4]; + u8 aso_type[0x4]; + u8 reserved_at_8[0x14]; + u8 action[0x1]; + u8 init_color[0x2]; + u8 meter_id[0x1]; +}; + +union mlx5_ifc_exe_aso_ctrl { + struct mlx5_ifc_exe_aso_ctrl_flow_meter_bits exe_aso_ctrl_flow_meter; +}; + +struct mlx5_ifc_execute_aso_bits { + u8 valid[0x1]; + u8 reserved_at_1[0x7]; + u8 aso_object_id[0x18]; + + union mlx5_ifc_exe_aso_ctrl exe_aso_ctrl; +}; + struct mlx5_ifc_flow_context_bits { struct mlx5_ifc_vlan_bits push_vlan; @@ -3326,7 +3371,9 @@ struct mlx5_ifc_flow_context_bits { struct mlx5_ifc_fte_match_param_bits match_value; - u8 reserved_at_1200[0x600]; + struct mlx5_ifc_execute_aso_bits execute_aso[4]; + + u8 reserved_at_1300[0x500]; union mlx5_ifc_dest_format_struct_flow_counter_list_auto_bits destination[]; }; @@ -5973,7 +6020,9 @@ struct mlx5_ifc_general_obj_in_cmd_hdr_bits { u8 obj_id[0x20]; - u8 reserved_at_60[0x20]; + u8 reserved_at_60[0x3]; + u8 log_obj_range[0x5]; + u8 reserved_at_68[0x18]; }; struct mlx5_ifc_general_obj_out_cmd_hdr_bits { @@ -11373,12 +11422,14 @@ enum { MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY = BIT_ULL(0xc), MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC = BIT_ULL(0x13), MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_SAMPLER = BIT_ULL(0x20), + MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_FLOW_METER_ASO = BIT_ULL(0x24), }; enum { MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY = 0xc, MLX5_GENERAL_OBJECT_TYPES_IPSEC = 0x13, MLX5_GENERAL_OBJECT_TYPES_SAMPLER = 0x20, + MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO = 0x24, }; enum { @@ -11451,6 +11502,61 @@ struct mlx5_ifc_create_encryption_key_in_bits { struct mlx5_ifc_encryption_key_obj_bits encryption_key_object; }; +enum { + MLX5_FLOW_METER_MODE_BYTES_IP_LENGTH = 0x0, + MLX5_FLOW_METER_MODE_BYTES_CALC_WITH_L2 = 0x1, + MLX5_FLOW_METER_MODE_BYTES_CALC_WITH_L2_IPG = 0x2, + MLX5_FLOW_METER_MODE_NUM_PACKETS = 0x3, +}; + +struct mlx5_ifc_flow_meter_parameters_bits { + u8 valid[0x1]; + u8 bucket_overflow[0x1]; + u8 start_color[0x2]; + u8 both_buckets_on_green[0x1]; + u8 reserved_at_5[0x1]; + u8 meter_mode[0x2]; + u8 reserved_at_8[0x18]; + + u8 reserved_at_20[0x20]; + + u8 reserved_at_40[0x3]; + u8 cbs_exponent[0x5]; + u8 cbs_mantissa[0x8]; + u8 reserved_at_50[0x3]; + u8 cir_exponent[0x5]; + u8 cir_mantissa[0x8]; + + u8 reserved_at_60[0x20]; + + u8 reserved_at_80[0x3]; + u8 ebs_exponent[0x5]; + u8 ebs_mantissa[0x8]; + u8 reserved_at_90[0x3]; + u8 eir_exponent[0x5]; + u8 eir_mantissa[0x8]; + + u8 reserved_at_a0[0x60]; +}; + +struct mlx5_ifc_flow_meter_aso_obj_bits { + u8 modify_field_select[0x40]; + + u8 reserved_at_40[0x40]; + + u8 reserved_at_80[0x8]; + u8 meter_aso_access_pd[0x18]; + + u8 reserved_at_a0[0x160]; + + struct mlx5_ifc_flow_meter_parameters_bits flow_meter_parameters[2]; +}; + +struct mlx5_ifc_create_flow_meter_aso_obj_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; + struct mlx5_ifc_flow_meter_aso_obj_bits flow_meter_aso_obj; +}; + struct mlx5_ifc_sampler_obj_bits { u8 modify_field_select[0x40]; -- cgit v1.2.3 From 3e94e61bd44d90070dcda53b647fdc826097ef26 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Wed, 8 Jun 2022 13:04:48 -0700 Subject: net/mlx5: Add HW definitions of vport debug counters total_q_under_processor_handle - number of queues in error state due to an async error or errored command. send_queue_priority_update_flow - number of QP/SQ priority/SL update events. cq_overrun - number of times CQ entered an error state due to an overflow. async_eq_overrun -number of time an EQ mapped to async events was overrun. comp_eq_overrun - number of time an EQ mapped to completion events was overrun. quota_exceeded_command - number of commands issued and failed due to quota exceeded. invalid_command - number of commands issued and failed dues to any reason other than quota exceeded. Signed-off-by: Saeed Mahameed Signed-off-by: Michael Guralnik Signed-off-by: Saeed Mahameed --- include/linux/mlx5/mlx5_ifc.h | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 91872afb2bfe..f678ad88a7d5 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1441,7 +1441,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 reserved_at_120[0xa]; u8 log_max_ra_req_dc[0x6]; - u8 reserved_at_130[0xa]; + u8 reserved_at_130[0x9]; + u8 vnic_env_cq_overrun[0x1]; u8 log_max_ra_res_dc[0x6]; u8 reserved_at_140[0x5]; @@ -1636,7 +1637,11 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 nic_receive_steering_discard[0x1]; u8 receive_discard_vport_down[0x1]; u8 transmit_discard_vport_down[0x1]; - u8 reserved_at_343[0x5]; + u8 eq_overrun_count[0x1]; + u8 reserved_at_344[0x1]; + u8 invalid_command_count[0x1]; + u8 quota_exceeded_count[0x1]; + u8 reserved_at_347[0x1]; u8 log_max_flow_counter_bulk[0x8]; u8 max_flow_counter_15_0[0x10]; @@ -3441,11 +3446,21 @@ struct mlx5_ifc_vnic_diagnostic_statistics_bits { u8 transmit_discard_vport_down[0x40]; - u8 reserved_at_140[0xa0]; + u8 async_eq_overrun[0x20]; + + u8 comp_eq_overrun[0x20]; + + u8 reserved_at_180[0x20]; + + u8 invalid_command[0x20]; + + u8 quota_exceeded_command[0x20]; u8 internal_rq_out_of_buffer[0x20]; - u8 reserved_at_200[0xe00]; + u8 cq_overrun[0x20]; + + u8 reserved_at_220[0xde0]; }; struct mlx5_ifc_traffic_counter_bits { -- cgit v1.2.3 From 91707779a481aab9c7f1d7a5ea3033ce87dc4fd6 Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Wed, 8 Jun 2022 13:04:49 -0700 Subject: net/mlx5: Add support EXECUTE_ASO action for flow entry Attach flow meter to FTE with object id and index. Use metadata register C5 to store the packet color meter result. Signed-off-by: Jianbo Liu Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 33 ++++++++++++++++++++++++ include/linux/mlx5/fs.h | 14 ++++++++++ 2 files changed, 47 insertions(+) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 2ccf7bef9b05..735dc805dad7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -479,6 +479,30 @@ static int mlx5_set_extended_dest(struct mlx5_core_dev *dev, return 0; } + +static void +mlx5_cmd_set_fte_flow_meter(struct fs_fte *fte, void *in_flow_context) +{ + void *exe_aso_ctrl; + void *execute_aso; + + execute_aso = MLX5_ADDR_OF(flow_context, in_flow_context, + execute_aso[0]); + MLX5_SET(execute_aso, execute_aso, valid, 1); + MLX5_SET(execute_aso, execute_aso, aso_object_id, + fte->action.exe_aso.object_id); + + exe_aso_ctrl = MLX5_ADDR_OF(execute_aso, execute_aso, exe_aso_ctrl); + MLX5_SET(exe_aso_ctrl_flow_meter, exe_aso_ctrl, return_reg_id, + fte->action.exe_aso.return_reg_id); + MLX5_SET(exe_aso_ctrl_flow_meter, exe_aso_ctrl, aso_type, + fte->action.exe_aso.type); + MLX5_SET(exe_aso_ctrl_flow_meter, exe_aso_ctrl, init_color, + fte->action.exe_aso.flow_meter.init_color); + MLX5_SET(exe_aso_ctrl_flow_meter, exe_aso_ctrl, meter_id, + fte->action.exe_aso.flow_meter.meter_idx); +} + static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev, int opmod, int modify_mask, struct mlx5_flow_table *ft, @@ -663,6 +687,15 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev, list_size); } + if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) { + if (fte->action.exe_aso.type == MLX5_EXE_ASO_FLOW_METER) { + mlx5_cmd_set_fte_flow_meter(fte, in_flow_context); + } else { + err = -EOPNOTSUPP; + goto err_out; + } + } + err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); err_out: kvfree(in); diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 8135713b0d2d..ece3e35622d7 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -212,6 +212,19 @@ struct mlx5_flow_group * mlx5_create_flow_group(struct mlx5_flow_table *ft, u32 *in); void mlx5_destroy_flow_group(struct mlx5_flow_group *fg); +struct mlx5_exe_aso { + u32 object_id; + u8 type; + u8 return_reg_id; + union { + u32 ctrl_data; + struct { + u8 meter_idx; + u8 init_color; + } flow_meter; + }; +}; + struct mlx5_fs_vlan { u16 ethtype; u16 vid; @@ -237,6 +250,7 @@ struct mlx5_flow_act { struct mlx5_fs_vlan vlan[MLX5_FS_VLAN_DEPTH]; struct ib_counters *counters; struct mlx5_flow_group *fg; + struct mlx5_exe_aso exe_aso; }; #define MLX5_DECLARE_FLOW_ACT(name) \ -- cgit v1.2.3 From d107ba1f7c067b08eb4b8ca7c51187fb7c4d97f2 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Wed, 8 Jun 2022 13:04:51 -0700 Subject: net/mlx5: Remove not used MLX5_CAP_BITS_RW_MASK Remove not used MLX5_CAP_BITS_RW_MASK. While at it, remove CAP_MASK, MLX5_CAP_OFF_CMDIF_CSUM and MLX5_DEV_CAP_FLAG_*, since MLX5_CAP_BITS_RW_MASK was their only user. Signed-off-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 7 ------- include/linux/mlx5/device.h | 19 ------------------- 2 files changed, 26 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index c9b4e50a593e..2078d9f03a5f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -314,13 +314,6 @@ struct mlx5_reg_host_endianness { u8 rsvd[15]; }; -#define CAP_MASK(pos, size) ((u64)((1 << (size)) - 1) << (pos)) - -enum { - MLX5_CAP_BITS_RW_MASK = CAP_MASK(MLX5_CAP_OFF_CMDIF_CSUM, 2) | - MLX5_DEV_CAP_FLAG_DCT, -}; - static u16 to_fw_pkey_sz(struct mlx5_core_dev *dev, u32 size) { switch (size) { diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 15ac02eeed4f..95a4fa0fd40a 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -386,21 +386,6 @@ enum { MLX5_PORT_CHANGE_SUBTYPE_CLIENT_REREG = 9, }; -enum { - MLX5_DEV_CAP_FLAG_XRC = 1LL << 3, - MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1LL << 8, - MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL << 9, - MLX5_DEV_CAP_FLAG_APM = 1LL << 17, - MLX5_DEV_CAP_FLAG_ATOMIC = 1LL << 18, - MLX5_DEV_CAP_FLAG_BLOCK_MCAST = 1LL << 23, - MLX5_DEV_CAP_FLAG_ON_DMND_PG = 1LL << 24, - MLX5_DEV_CAP_FLAG_CQ_MODER = 1LL << 29, - MLX5_DEV_CAP_FLAG_RESIZE_CQ = 1LL << 30, - MLX5_DEV_CAP_FLAG_DCT = 1LL << 37, - MLX5_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40, - MLX5_DEV_CAP_FLAG_CMDIF_CSUM = 3LL << 46, -}; - enum { MLX5_ROCE_VERSION_1 = 0, MLX5_ROCE_VERSION_2 = 2, @@ -496,10 +481,6 @@ enum { MLX5_MAX_PAGE_SHIFT = 31 }; -enum { - MLX5_CAP_OFF_CMDIF_CSUM = 46, -}; - enum { /* * Max wqe size for rdma read is 512 bytes, so this -- cgit v1.2.3 From cdcdce948d64139aea1c6dfea4b04f5c8ad2784e Mon Sep 17 00:00:00 2001 From: Ofer Levi Date: Wed, 8 Jun 2022 13:04:52 -0700 Subject: net/mlx5: Add bits and fields to support enhanced CQE compression Expose ifc bits and add needed structure fields and methods to support enhanced CQE compression feature. The enhanced CQE compression feature improves cpu utiliziation with better packet latency from nic to host. Signed-off-by: Ofer Levi Signed-off-by: Saeed Mahameed --- include/linux/mlx5/device.h | 16 +++++++++++++++- include/linux/mlx5/mlx5_ifc.h | 7 +++++-- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 95a4fa0fd40a..b5f58fd37a0f 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -822,7 +822,10 @@ struct mlx5_cqe64 { __be32 timestamp_l; __be32 sop_drop_qpn; __be16 wqe_counter; - u8 signature; + union { + u8 signature; + u8 validity_iteration_count; + }; u8 op_own; }; @@ -854,6 +857,11 @@ enum { MLX5_CQE_FORMAT_CSUM_STRIDX = 0x3, }; +enum { + MLX5_CQE_COMPRESS_LAYOUT_BASIC = 0, + MLX5_CQE_COMPRESS_LAYOUT_ENHANCED = 1, +}; + #define MLX5_MINI_CQE_ARRAY_SIZE 8 static inline u8 mlx5_get_cqe_format(struct mlx5_cqe64 *cqe) @@ -866,6 +874,12 @@ static inline u8 get_cqe_opcode(struct mlx5_cqe64 *cqe) return cqe->op_own >> 4; } +static inline u8 get_cqe_enhanced_num_mini_cqes(struct mlx5_cqe64 *cqe) +{ + /* num_of_mini_cqes is zero based */ + return get_cqe_opcode(cqe) + 1; +} + static inline u8 get_cqe_lro_tcppsh(struct mlx5_cqe64 *cqe) { return (cqe->lro.tcppsh_abort_dupack >> 6) & 1; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index f678ad88a7d5..8e87eb47f9dc 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1739,7 +1739,9 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 log_max_dci_errored_streams[0x5]; u8 reserved_at_598[0x8]; - u8 reserved_at_5a0[0x13]; + u8 reserved_at_5a0[0x10]; + u8 enhanced_cqe_compression[0x1]; + u8 reserved_at_5b1[0x2]; u8 log_max_dek[0x5]; u8 reserved_at_5b8[0x4]; u8 mini_cqe_resp_stride_index[0x1]; @@ -4139,7 +4141,8 @@ struct mlx5_ifc_cqc_bits { u8 cqe_comp_en[0x1]; u8 mini_cqe_res_format[0x2]; u8 st[0x4]; - u8 reserved_at_18[0x8]; + u8 reserved_at_18[0x6]; + u8 cqe_compression_layout[0x2]; u8 reserved_at_20[0x20]; -- cgit v1.2.3 From 6554400d6f66b9494a0c0f07712ab0a9d307eb01 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 3 Jun 2022 20:05:19 +0900 Subject: scsi: ufs: core: Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS Add UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS for host controllers which do not support 64-bit addressing. Link: https://lore.kernel.org/r/20220603110524.1997825-3-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Yoshihiro Shimoda Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 2 ++ include/ufs/ufshcd.h | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 01fb4bad86be..88e567c3ba0b 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2216,6 +2216,8 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) int err; hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES); + if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) + hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT; /* nutrs and nutmrs are 0 based values */ hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1; diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index a92271421718..795c8951341d 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -577,6 +577,12 @@ enum ufshcd_quirks { * support physical host configuration. */ UFSHCD_QUIRK_SKIP_PH_CONFIGURATION = 1 << 16, + + /* + * This quirk needs to be enabled if the host controller has + * 64-bit addressing supported capability but it doesn't work. + */ + UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS = 1 << 17, }; enum ufshcd_caps { -- cgit v1.2.3 From 2f11bbc2c7f37e3a6151ac548b1c0679cc90ea83 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 3 Jun 2022 20:05:20 +0900 Subject: scsi: ufs: core: Add UFSHCD_QUIRK_HIBERN_FASTAUTO Add UFSHCD_QUIRK_HIBERN_FASTAUTO quirk for host controllers which supports auto-hibernate the capability but only FASTAUTO mode. Link: https://lore.kernel.org/r/20220603110524.1997825-4-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Yoshihiro Shimoda Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 9 +++++++-- include/ufs/ufshcd.h | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 88e567c3ba0b..bb6cbd514a69 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4260,8 +4260,13 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) if (hba->max_pwr_info.is_valid) return 0; - pwr_info->pwr_tx = FAST_MODE; - pwr_info->pwr_rx = FAST_MODE; + if (hba->quirks & UFSHCD_QUIRK_HIBERN_FASTAUTO) { + pwr_info->pwr_tx = FASTAUTO_MODE; + pwr_info->pwr_rx = FASTAUTO_MODE; + } else { + pwr_info->pwr_tx = FAST_MODE; + pwr_info->pwr_rx = FAST_MODE; + } pwr_info->hs_rate = PA_HS_MODE_B; /* Get the connected lane count */ diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 795c8951341d..991aea081ec7 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -583,6 +583,12 @@ enum ufshcd_quirks { * 64-bit addressing supported capability but it doesn't work. */ UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS = 1 << 17, + + /* + * This quirk needs to be enabled if the host controller has + * auto-hibernate capability but it's FASTAUTO only. + */ + UFSHCD_QUIRK_HIBERN_FASTAUTO = 1 << 18, }; enum ufshcd_caps { -- cgit v1.2.3 From 689614ce48b0310b50d8d6c9a64f8a98cfc6f195 Mon Sep 17 00:00:00 2001 From: Ajit Kumar Pandey Date: Tue, 14 Jun 2022 10:52:51 +0300 Subject: ASoC: SOF: topology: add code to parse config params for ACPDMIC dai MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add sof_ipc_dai_acpdmic_params and tokens to parse dmic channels and rate params from topology file Signed-off-by: Ajit Kumar Pandey Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20220614075251.21499-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/dai-amd.h | 7 +++++++ include/sound/sof/dai.h | 2 +- include/uapi/sound/sof/tokens.h | 4 ++++ sound/soc/sof/ipc3-pcm.c | 8 ++++---- sound/soc/sof/ipc3-topology.c | 25 +++++++++++++++++++------ sound/soc/sof/sof-audio.h | 1 + sound/soc/sof/topology.c | 4 ++++ 7 files changed, 40 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h index 90d09dbdd709..92f45c180b7c 100644 --- a/include/sound/sof/dai-amd.h +++ b/include/sound/sof/dai-amd.h @@ -18,4 +18,11 @@ struct sof_ipc_dai_acp_params { uint32_t fsync_rate; /* FSYNC frequency in Hz */ uint32_t tdm_slots; } __packed; + +/* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */ +struct sof_ipc_dai_acpdmic_params { + uint32_t pdm_rate; + uint32_t pdm_ch; +} __packed; + #endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index a818a0f0a226..21d98f31a9ca 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -111,7 +111,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_sai_params sai; struct sof_ipc_dai_acp_params acpbt; struct sof_ipc_dai_acp_params acpsp; - struct sof_ipc_dai_acp_params acpdmic; + struct sof_ipc_dai_acpdmic_params acpdmic; struct sof_ipc_dai_mtk_afe_params afe; }; } __packed; diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index f7b2019065ad..5caf75cadaf8 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -157,6 +157,10 @@ /* MIXER */ #define SOF_TKN_MIXER_TYPE 1700 +/* ACPDMIC */ +#define SOF_TKN_AMD_ACPDMIC_RATE 1800 +#define SOF_TKN_AMD_ACPDMIC_CH 1801 + /* CAVS AUDIO FORMAT */ #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE 1900 #define SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH 1901 diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index c8774a891d6f..b97e63d3724a 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -344,10 +344,10 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min, channels->max); break; case SOF_DAI_AMD_DMIC: - rate->min = private->dai_config->acpdmic.fsync_rate; - rate->max = private->dai_config->acpdmic.fsync_rate; - channels->min = private->dai_config->acpdmic.tdm_slots; - channels->max = private->dai_config->acpdmic.tdm_slots; + rate->min = private->dai_config->acpdmic.pdm_rate; + rate->max = private->dai_config->acpdmic.pdm_rate; + channels->min = private->dai_config->acpdmic.pdm_ch; + channels->max = private->dai_config->acpdmic.pdm_ch; dev_dbg(component->dev, "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max); diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index a91d7df3f07e..5ee1537f9c2d 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -266,6 +266,16 @@ static const struct sof_topology_token afe_tokens[] = { offsetof(struct sof_ipc_dai_mtk_afe_params, format)}, }; +/* ACPDMIC */ +static const struct sof_topology_token acpdmic_tokens[] = { + {SOF_TKN_AMD_ACPDMIC_RATE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acpdmic_params, pdm_rate)}, + {SOF_TKN_AMD_ACPDMIC_CH, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)}, +}; + /* Core tokens */ static const struct sof_topology_token core_tokens[] = { {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -300,6 +310,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)}, [SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)}, [SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)}, + [SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)}, }; /** @@ -1120,20 +1131,22 @@ static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_so struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs; struct sof_dai_private_data *private = dai->private; u32 size = sizeof(*config); + int ret; /* handle master/slave and inverted clocks */ sof_dai_set_format(hw_config, config); - /* init IPC */ - memset(&config->acpdmic, 0, sizeof(config->acpdmic)); config->hdr.size = size; - config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + /* parse the required set of ACPDMIC tokens based on num_hw_cfgs */ + ret = sof_update_ipc_object(scomp, &config->acpdmic, SOF_ACPDMIC_TOKENS, slink->tuples, + slink->num_tuples, size, slink->num_hw_configs); + if (ret < 0) + return ret; dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n", - config->dai_index, config->acpdmic.tdm_slots, - config->acpdmic.fsync_rate); + config->dai_index, config->acpdmic.pdm_ch, + config->acpdmic.pdm_rate); dai->number_configs = 1; dai->current_config = 0; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 79486266081f..4284ea2f3a1f 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -236,6 +236,7 @@ enum sof_tokens { SOF_AUDIO_FMT_NUM_TOKENS, SOF_COPIER_FORMAT_TOKENS, SOF_GAIN_TOKENS, + SOF_ACPDMIC_TOKENS, /* this should be the last */ SOF_TOKEN_COUNT, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 1893c590f2f0..7e54eb1bf77b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1739,6 +1739,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ token_id = SOF_AFE_TOKENS; num_tuples += token_list[SOF_AFE_TOKENS].count; break; + case SOF_DAI_AMD_DMIC: + token_id = SOF_ACPDMIC_TOKENS; + num_tuples += token_list[SOF_ACPDMIC_TOKENS].count; + break; default: break; } -- cgit v1.2.3 From 9822bb87cee12a9d1e3321b652ba537af1f174aa Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 20 Feb 2022 16:33:27 +0000 Subject: iio: core: drop iio_get_time_res() This function was introduced with the ability to pick a clock. There are no upstream users so presumably it isn't as obviously useful as it seemed at the time. Hence drop it. Signed-off-by: Jonathan Cameron Link: https://lore.kernel.org/r/20220220163327.424696-1-jic23@kernel.org --- drivers/iio/industrialio-core.c | 23 ----------------------- include/linux/iio/iio.h | 1 - 2 files changed, 24 deletions(-) (limited to 'include') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 7517deec501e..dd42df854a57 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -334,29 +334,6 @@ s64 iio_get_time_ns(const struct iio_dev *indio_dev) } 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; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 233d2e6b7721..f6ea2ed99457 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -313,7 +313,6 @@ static inline bool iio_channel_has_available(const struct iio_chan_spec *chan, } 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 -- cgit v1.2.3 From 12c4efe3509b8018e76ea3ebda8227cb53bf5887 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 8 May 2022 18:55:41 +0100 Subject: iio: core: Fix IIO_ALIGN and rename as it was not sufficiently large MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discussion of the series: https://lore.kernel.org/all/20220405135758.774016-1-catalin.marinas@arm.com/ mm, arm64: Reduce ARCH_KMALLOC_MINALIGN brought to my attention that our current IIO usage of L1CACHE_ALIGN is insufficient as their are Arm platforms out their with non coherent DMA and larger cache lines at at higher levels of their cache hierarchy. Rename the define to make it's purpose more explicit. It will be used much more widely going forwards (to replace incorrect ____cacheline_aligned markings. Note this patch will greatly reduce the padding on some architectures that have smaller requirements for DMA safe buffers. The history of changing values of ARCH_KMALLOC_MINALIGN via ARCH_DMA_MINALIGN on arm64 is rather complex. I'm not tagging this as fixing a particular patch from that route as it's not clear what to tag. Most recently a change to bring them back inline was reverted because of some Qualcomm Kryo cores with an L2 cache with 128-byte lines sitting above the point of coherency. c1132702c71f Revert "arm64: cache: Lower ARCH_DMA_MINALIGN to 64 (L1_CACHE_BYTES)" That reverts: 65688d2a05de arm64: cache: Lower ARCH_DMA_MINALIGN to 64 (L1_CACHE_BYTES) which refers to the change originally being motivated by Thunder x1 performance rather than correctness. Fixes: 6f7c8ee585e9d ("staging:iio: Add ability to allocate private data space to iio_allocate_device") Signed-off-by: Jonathan Cameron Acked-by: Nuno Sá Link: https://lore.kernel.org/r/20220508175712.647246-2-jic23@kernel.org --- drivers/iio/accel/bma400_core.c | 2 +- drivers/iio/adc/adi-axi-adc.c | 7 ++++--- drivers/iio/industrialio-core.c | 4 ++-- include/linux/iio/iio.h | 10 ++++++++-- 4 files changed, 15 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index 517920400df1..c31bdd9b168e 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -93,7 +93,7 @@ struct bma400_data { __le16 buff[3]; u8 temperature; s64 ts __aligned(8); - } buffer __aligned(IIO_ALIGN); + } buffer __aligned(IIO_DMA_MINALIGN); __le16 status; __be16 duration; }; diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index cf07d522925e..bd6fd0dd04b9 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -84,7 +84,8 @@ void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv) { struct adi_axi_adc_client *cl = conv_to_client(conv); - return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client), IIO_ALIGN); + return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client), + IIO_DMA_MINALIGN); } EXPORT_SYMBOL_NS_GPL(adi_axi_adc_conv_priv, IIO_ADI_AXI); @@ -169,9 +170,9 @@ static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev, struct adi_axi_adc_client *cl; size_t alloc_size; - alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_ALIGN); + alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_DMA_MINALIGN); if (sizeof_priv) - alloc_size += ALIGN(sizeof_priv, IIO_ALIGN); + alloc_size += ALIGN(sizeof_priv, IIO_DMA_MINALIGN); cl = kzalloc(alloc_size, GFP_KERNEL); if (!cl) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index dd42df854a57..0703c8c7c180 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1630,7 +1630,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) alloc_size = sizeof(struct iio_dev_opaque); if (sizeof_priv) { - alloc_size = ALIGN(alloc_size, IIO_ALIGN); + alloc_size = ALIGN(alloc_size, IIO_DMA_MINALIGN); alloc_size += sizeof_priv; } @@ -1640,7 +1640,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) indio_dev = &iio_dev_opaque->indio_dev; indio_dev->priv = (char *)iio_dev_opaque + - ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN); + ALIGN(sizeof(struct iio_dev_opaque), IIO_DMA_MINALIGN); indio_dev->dev.parent = parent; indio_dev->dev.type = &iio_device_type; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index f6ea2ed99457..4e21a82b3756 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -9,6 +9,7 @@ #include #include +#include #include #include /* IIO TODO LIST */ @@ -708,8 +709,13 @@ static inline void *iio_device_get_drvdata(const struct iio_dev *indio_dev) return dev_get_drvdata(&indio_dev->dev); } -/* Can we make this smaller? */ -#define IIO_ALIGN L1_CACHE_BYTES +/* + * Used to ensure the iio_priv() structure is aligned to allow that structure + * to in turn include IIO_DMA_MINALIGN'd elements such as buffers which + * must not share cachelines with the rest of the structure, thus making + * them safe for use with non-coherent DMA. + */ +#define IIO_DMA_MINALIGN ARCH_KMALLOC_MINALIGN struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv); /* The information at the returned address is guaranteed to be cacheline aligned */ -- cgit v1.2.3 From 0da11bf0cab9029db8b85e48d962ff05c00a4faa Mon Sep 17 00:00:00 2001 From: Eiichi Tsukata Date: Fri, 27 May 2022 00:53:45 +0000 Subject: cpuidle: haltpoll: Add trace points for guest_halt_poll_ns grow/shrink Add trace points as are implemented in KVM host halt polling. This helps tune guest halt polling params. Signed-off-by: Eiichi Tsukata Acked-by: Marcelo Tosatti Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/haltpoll.c | 3 +++ include/trace/events/power.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'include') diff --git a/drivers/cpuidle/governors/haltpoll.c b/drivers/cpuidle/governors/haltpoll.c index cb2a96eafc02..1dff3a52917d 100644 --- a/drivers/cpuidle/governors/haltpoll.c +++ b/drivers/cpuidle/governors/haltpoll.c @@ -19,6 +19,7 @@ #include #include #include +#include static unsigned int guest_halt_poll_ns __read_mostly = 200000; module_param(guest_halt_poll_ns, uint, 0644); @@ -90,6 +91,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns) if (val > guest_halt_poll_ns) val = guest_halt_poll_ns; + trace_guest_halt_poll_ns_grow(val, dev->poll_limit_ns); dev->poll_limit_ns = val; } else if (block_ns > guest_halt_poll_ns && guest_halt_poll_allow_shrink) { @@ -100,6 +102,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns) val = 0; else val /= shrink; + trace_guest_halt_poll_ns_shrink(val, dev->poll_limit_ns); dev->poll_limit_ns = val; } } diff --git a/include/trace/events/power.h b/include/trace/events/power.h index af5018aa9517..c708521e4ed5 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -500,6 +500,35 @@ DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_remove_request, TP_ARGS(name, type, new_value) ); + +TRACE_EVENT(guest_halt_poll_ns, + + TP_PROTO(bool grow, unsigned int new, unsigned int old), + + TP_ARGS(grow, new, old), + + TP_STRUCT__entry( + __field(bool, grow) + __field(unsigned int, new) + __field(unsigned int, old) + ), + + TP_fast_assign( + __entry->grow = grow; + __entry->new = new; + __entry->old = old; + ), + + TP_printk("halt_poll_ns %u (%s %u)", + __entry->new, + __entry->grow ? "grow" : "shrink", + __entry->old) +); + +#define trace_guest_halt_poll_ns_grow(new, old) \ + trace_guest_halt_poll_ns(true, new, old) +#define trace_guest_halt_poll_ns_shrink(new, old) \ + trace_guest_halt_poll_ns(false, new, old) #endif /* _TRACE_POWER_H */ /* This part must be outside protection */ -- cgit v1.2.3 From 6dbdc9f35360d4ef4704462c265f63b32fcb5354 Mon Sep 17 00:00:00 2001 From: Hongyi Lu Date: Mon, 13 Jun 2022 21:16:33 +0000 Subject: bpf: Fix spelling in bpf_verifier.h Minor spelling fix spotted in bpf_verifier.h. Spelling is no big deal, but it is still an improvement when reading through the code. Signed-off-by: Hongyi Lu Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20220613211633.58647-1-jwnhy0@gmail.com --- include/linux/bpf_verifier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index e8439f6cbe57..3930c963fa67 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -299,7 +299,7 @@ struct bpf_verifier_state { * If is_state_visited() sees a state with branches > 0 it means * there is a loop. If such state is exactly equal to the current state * it's an infinite loop. Note states_equal() checks for states - * equvalency, so two states being 'states_equal' does not mean + * equivalency, so two states being 'states_equal' does not mean * infinite loop. The exact comparison is provided by * states_maybe_looping() function. It's a stronger pre-check and * much faster than states_equal(). -- cgit v1.2.3 From 9731dd4cadc53251ef80b3655c8d841fed52fa3d Mon Sep 17 00:00:00 2001 From: Daniel Phillips Date: Mon, 30 May 2022 11:21:22 -0400 Subject: drm/amdkfd: Add available memory ioctl Add a new KFD ioctl to return the largest possible memory size that can be allocated as a buffer object using kfd_ioctl_alloc_memory_of_gpu. It attempts to use exactly the same accept/reject criteria as that function so that allocating a new buffer object of the size returned by this new ioctl is guaranteed to succeed, barring races with other allocating tasks. This IOCTL will be used by libhsakmt: https://www.mail-archive.com/amd-gfx@lists.freedesktop.org/msg75743.html Signed-off-by: Daniel Phillips Signed-off-by: David Yat Sin Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 38 +++++++++++++++++++++--- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 34 +++++++++++++++++++++ include/uapi/linux/kfd_ioctl.h | 14 +++++++-- 4 files changed, 81 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index ffb2b7d9b9a5..648c031942e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -268,6 +268,7 @@ int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct amdgpu_device *adev, void amdgpu_amdkfd_gpuvm_release_process_vm(struct amdgpu_device *adev, void *drm_priv); uint64_t amdgpu_amdkfd_gpuvm_get_process_page_dir(void *drm_priv); +size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev); int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( struct amdgpu_device *adev, uint64_t va, uint64_t size, void *drm_priv, struct kgd_mem **mem, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index f386b0d256d2..8805bd1eed37 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -38,6 +38,12 @@ */ #define AMDGPU_USERPTR_RESTORE_DELAY_MS 1 +/* + * Align VRAM allocations to 2MB to avoid fragmentation caused by 4K allocations in the tail 2MB + * BO chunk + */ +#define VRAM_ALLOCATION_ALIGN (1 << 21) + /* Impose limit on how much memory KFD can use */ static struct { uint64_t max_system_mem_limit; @@ -108,7 +114,7 @@ void amdgpu_amdkfd_reserve_system_mem(uint64_t size) * compromise that should work in most cases without reserving too * much memory for page tables unnecessarily (factor 16K, >> 14). */ -#define ESTIMATE_PT_SIZE(mem_size) ((mem_size) >> 14) +#define ESTIMATE_PT_SIZE(mem_size) max(((mem_size) >> 14), AMDGPU_VM_RESERVED_VRAM) static size_t amdgpu_amdkfd_acc_size(uint64_t size) { @@ -148,7 +154,13 @@ static int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, } else if (alloc_flag & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) { system_mem_needed = acc_size; ttm_mem_needed = acc_size; - vram_needed = size; + + /* + * Conservatively round up the allocation requirement to 2 MB + * to avoid fragmentation caused by 4K allocations in the tail + * 2M BO chunk. + */ + vram_needed = ALIGN(size, VRAM_ALLOCATION_ALIGN); } else if (alloc_flag & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) { system_mem_needed = acc_size + size; ttm_mem_needed = acc_size; @@ -173,7 +185,9 @@ static int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev, (kfd_mem_limit.ttm_mem_used + ttm_mem_needed > kfd_mem_limit.max_ttm_mem_limit) || (adev->kfd.vram_used + vram_needed > - adev->gmc.real_vram_size - reserved_for_pt)) { + adev->gmc.real_vram_size - + atomic64_read(&adev->vram_pin_size) - + reserved_for_pt)) { ret = -ENOMEM; goto release; } @@ -205,7 +219,7 @@ static void unreserve_mem_limit(struct amdgpu_device *adev, } else if (alloc_flag & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) { kfd_mem_limit.system_mem_used -= acc_size; kfd_mem_limit.ttm_mem_used -= acc_size; - adev->kfd.vram_used -= size; + adev->kfd.vram_used -= ALIGN(size, VRAM_ALLOCATION_ALIGN); } else if (alloc_flag & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) { kfd_mem_limit.system_mem_used -= (acc_size + size); kfd_mem_limit.ttm_mem_used -= acc_size; @@ -1633,6 +1647,22 @@ out_unlock: return ret; } +size_t amdgpu_amdkfd_get_available_memory(struct amdgpu_device *adev) +{ + uint64_t reserved_for_pt = + ESTIMATE_PT_SIZE(amdgpu_amdkfd_total_mem_size); + size_t available; + + spin_lock(&kfd_mem_limit.mem_limit_lock); + available = adev->gmc.real_vram_size + - adev->kfd.vram_used + - atomic64_read(&adev->vram_pin_size) + - reserved_for_pt; + spin_unlock(&kfd_mem_limit.mem_limit_lock); + + return ALIGN_DOWN(available, VRAM_ALLOCATION_ALIGN); +} + int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( struct amdgpu_device *adev, uint64_t va, uint64_t size, void *drm_priv, struct kgd_mem **mem, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 1c7016958d6d..3bcf9bf29acb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -65,6 +65,25 @@ static int kfd_char_dev_major = -1; static struct class *kfd_class; struct device *kfd_device; +static inline struct kfd_process_device *kfd_lock_pdd_by_id(struct kfd_process *p, __u32 gpu_id) +{ + struct kfd_process_device *pdd; + + mutex_lock(&p->mutex); + pdd = kfd_process_device_data_by_id(p, gpu_id); + + if (pdd) + return pdd; + + mutex_unlock(&p->mutex); + return NULL; +} + +static inline void kfd_unlock_pdd(struct kfd_process_device *pdd) +{ + mutex_unlock(&pdd->process->mutex); +} + int kfd_chardev_init(void) { int err = 0; @@ -958,6 +977,19 @@ bool kfd_dev_is_large_bar(struct kfd_dev *dev) return false; } +static int kfd_ioctl_get_available_memory(struct file *filep, + struct kfd_process *p, void *data) +{ + struct kfd_ioctl_get_available_memory_args *args = data; + struct kfd_process_device *pdd = kfd_lock_pdd_by_id(p, args->gpu_id); + + if (!pdd) + return -EINVAL; + args->available = amdgpu_amdkfd_get_available_memory(pdd->dev->adev); + kfd_unlock_pdd(pdd); + return 0; +} + static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep, struct kfd_process *p, void *data) { @@ -2648,6 +2680,8 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = { AMDKFD_IOCTL_DEF(AMDKFD_IOC_CRIU_OP, kfd_ioctl_criu, KFD_IOC_FLAG_CHECKPOINT_RESTORE), + AMDKFD_IOCTL_DEF(AMDKFD_IOC_AVAILABLE_MEMORY, + kfd_ioctl_get_available_memory, 0), }; #define AMDKFD_CORE_IOCTL_COUNT ARRAY_SIZE(amdkfd_ioctls) diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index 42975e940758..231eb010b823 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -34,9 +34,10 @@ * - 1.6 - Query clear flags in SVM get_attr API * - 1.7 - Checkpoint Restore (CRIU) API * - 1.8 - CRIU - Support for SDMA transfers with GTT BOs + * - 1.9 - Add available memory ioctl */ #define KFD_IOCTL_MAJOR_VERSION 1 -#define KFD_IOCTL_MINOR_VERSION 8 +#define KFD_IOCTL_MINOR_VERSION 9 struct kfd_ioctl_get_version_args { __u32 major_version; /* from KFD */ @@ -100,6 +101,12 @@ struct kfd_ioctl_get_queue_wave_state_args { __u32 pad; }; +struct kfd_ioctl_get_available_memory_args { + __u64 available; /* from KFD */ + __u32 gpu_id; /* to KFD */ + __u32 pad; +}; + /* For kfd_ioctl_set_memory_policy_args.default_policy and alternate_policy */ #define KFD_IOC_CACHE_POLICY_COHERENT 0 #define KFD_IOC_CACHE_POLICY_NONCOHERENT 1 @@ -826,7 +833,10 @@ struct kfd_ioctl_set_xnack_mode_args { #define AMDKFD_IOC_CRIU_OP \ AMDKFD_IOWR(0x22, struct kfd_ioctl_criu_args) +#define AMDKFD_IOC_AVAILABLE_MEMORY \ + AMDKFD_IOWR(0x23, struct kfd_ioctl_get_available_memory_args) + #define AMDKFD_COMMAND_START 0x01 -#define AMDKFD_COMMAND_END 0x23 +#define AMDKFD_COMMAND_END 0x24 #endif -- cgit v1.2.3 From c27e1efb61c545f36c450ef60862df9251d239a4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Jun 2022 08:45:37 +0200 Subject: ALSA: control: Use xarray for faster lookups The control elements are managed in a single linked list and we traverse the whole list for matching each numid or ctl id per every inquiry of a control element. This is OK-ish for a small number of elements but obviously it doesn't scale. Especially the matching with the ctl id takes time because it checks each field of the snd_ctl_id element, e.g. the name string is matched with strcmp(). This patch adds the hash tables with Xarray for improving the lookup speed of a control element. There are two xarray tables added to the card; one for numid and another for ctl id. For the numid, we use the numid as the index, while for the ctl id, we calculate a hash key. The lookup is done via a single xa_load() execution. As long as the given control element is found on the Xarray table, that's fine, we can give back a quick lookup result. The problem is when no entry hits on the table, and for this case, we have a slight optimization. Namely, the driver checks whether we had a collision on Xarray table, and do a fallback search (linear lookup of the full entries) only if a hash key collision happened beforehand. So, in theory, the inquiry for a non-existing element might take still time even with this patch in a worst case, but this must be pretty rare. The feature is enabled via CONFIG_SND_CTL_FAST_LOOKUP, which is turned on as default. For simplicity, the option can be turned off only when CONFIG_EXPERT is set ("You are expert? Then you manage 1000 knobs"). Link: https://lore.kernel.org/r/20211028130027.18764-1-tiwai@suse.de Link: https://lore.kernel.org/r/20220609180504.775-1-tiwai@suse.de Link: https://lore.kernel.org/all/cover.1653813866.git.quic_rbankapu@quicinc.com/ Link: https://lore.kernel.org/r/20220610064537.18660-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/core.h | 6 ++ sound/core/Kconfig | 10 +++ sound/core/control.c | 180 ++++++++++++++++++++++++++++++++++++++++++--------- sound/core/init.c | 4 ++ 4 files changed, 168 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/include/sound/core.h b/include/sound/core.h index 6d4cc49584c6..dd28de2343b8 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -14,6 +14,7 @@ #include /* pm_message_t */ #include #include +#include /* number of supported soundcards */ #ifdef CONFIG_SND_DYNAMIC_MINORS @@ -103,6 +104,11 @@ struct snd_card { size_t user_ctl_alloc_size; // current memory allocation by user controls. struct list_head controls; /* all controls for this card */ struct list_head ctl_files; /* active control files */ +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + struct xarray ctl_numids; /* hash table for numids */ + struct xarray ctl_hash; /* hash table for ctl id matching */ + bool ctl_hash_collision; /* ctl_hash collision seen? */ +#endif struct snd_info_entry *proc_root; /* root for soundcard specific files */ struct proc_dir_entry *proc_root_link; /* number link to real id */ diff --git a/sound/core/Kconfig b/sound/core/Kconfig index dd7b40734723..25b2434e4556 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -154,6 +154,16 @@ config SND_VERBOSE_PRINTK You don't need this unless you're debugging ALSA. +config SND_CTL_FAST_LOOKUP + bool "Fast lookup of control elements" if EXPERT + default y + select XARRAY_MULTI + help + This option enables the faster lookup of control elements. + It will consume more memory because of the additional Xarray. + If you want to choose the memory footprint over the performance + inevitably, turn this off. + config SND_DEBUG bool "Debug" help diff --git a/sound/core/control.c b/sound/core/control.c index a25c0d64d104..6a8fd9933f06 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -364,6 +364,93 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) return 0; } +/* check whether the given id is contained in the given kctl */ +static bool elem_id_matches(const struct snd_kcontrol *kctl, + const struct snd_ctl_elem_id *id) +{ + return kctl->id.iface == id->iface && + kctl->id.device == id->device && + kctl->id.subdevice == id->subdevice && + !strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)) && + kctl->id.index <= id->index && + kctl->id.index + kctl->count > id->index; +} + +#ifdef CONFIG_SND_CTL_FAST_LOOKUP +/* Compute a hash key for the corresponding ctl id + * It's for the name lookup, hence the numid is excluded. + * The hash key is bound in LONG_MAX to be used for Xarray key. + */ +#define MULTIPLIER 37 +static unsigned long get_ctl_id_hash(const struct snd_ctl_elem_id *id) +{ + unsigned long h; + const unsigned char *p; + + h = id->iface; + h = MULTIPLIER * h + id->device; + h = MULTIPLIER * h + id->subdevice; + for (p = id->name; *p; p++) + h = MULTIPLIER * h + *p; + h = MULTIPLIER * h + id->index; + h &= LONG_MAX; + return h; +} + +/* add hash entries to numid and ctl xarray tables */ +static void add_hash_entries(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ + struct snd_ctl_elem_id id = kcontrol->id; + int i; + + xa_store_range(&card->ctl_numids, kcontrol->id.numid, + kcontrol->id.numid + kcontrol->count - 1, + kcontrol, GFP_KERNEL); + + for (i = 0; i < kcontrol->count; i++) { + id.index = kcontrol->id.index + i; + if (xa_insert(&card->ctl_hash, get_ctl_id_hash(&id), + kcontrol, GFP_KERNEL)) { + /* skip hash for this entry, noting we had collision */ + card->ctl_hash_collision = true; + dev_dbg(card->dev, "ctl_hash collision %d:%s:%d\n", + id.iface, id.name, id.index); + } + } +} + +/* remove hash entries that have been added */ +static void remove_hash_entries(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ + struct snd_ctl_elem_id id = kcontrol->id; + struct snd_kcontrol *matched; + unsigned long h; + int i; + + for (i = 0; i < kcontrol->count; i++) { + xa_erase(&card->ctl_numids, id.numid); + h = get_ctl_id_hash(&id); + matched = xa_load(&card->ctl_hash, h); + if (matched && (matched == kcontrol || + elem_id_matches(matched, &id))) + xa_erase(&card->ctl_hash, h); + id.index++; + id.numid++; + } +} +#else /* CONFIG_SND_CTL_FAST_LOOKUP */ +static inline void add_hash_entries(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ +} +static inline void remove_hash_entries(struct snd_card *card, + struct snd_kcontrol *kcontrol) +{ +} +#endif /* CONFIG_SND_CTL_FAST_LOOKUP */ + enum snd_ctl_add_mode { CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE, }; @@ -408,6 +495,8 @@ static int __snd_ctl_add_replace(struct snd_card *card, kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; + add_hash_entries(card, kcontrol); + for (idx = 0; idx < kcontrol->count; idx++) snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_ADD, kcontrol, idx); @@ -479,6 +568,26 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL(snd_ctl_replace); +static int __snd_ctl_remove(struct snd_card *card, + struct snd_kcontrol *kcontrol, + bool remove_hash) +{ + unsigned int idx; + + if (snd_BUG_ON(!card || !kcontrol)) + return -EINVAL; + list_del(&kcontrol->list); + + if (remove_hash) + remove_hash_entries(card, kcontrol); + + card->controls_count -= kcontrol->count; + for (idx = 0; idx < kcontrol->count; idx++) + snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx); + snd_ctl_free_one(kcontrol); + return 0; +} + /** * snd_ctl_remove - remove the control from the card and release it * @card: the card instance @@ -492,16 +601,7 @@ EXPORT_SYMBOL(snd_ctl_replace); */ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { - unsigned int idx; - - if (snd_BUG_ON(!card || !kcontrol)) - return -EINVAL; - list_del(&kcontrol->list); - card->controls_count -= kcontrol->count; - for (idx = 0; idx < kcontrol->count; idx++) - snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx); - snd_ctl_free_one(kcontrol); - return 0; + return __snd_ctl_remove(card, kcontrol, true); } EXPORT_SYMBOL(snd_ctl_remove); @@ -642,14 +742,30 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, up_write(&card->controls_rwsem); return -ENOENT; } + remove_hash_entries(card, kctl); kctl->id = *dst_id; kctl->id.numid = card->last_numid + 1; card->last_numid += kctl->count; + add_hash_entries(card, kctl); up_write(&card->controls_rwsem); return 0; } EXPORT_SYMBOL(snd_ctl_rename_id); +#ifndef CONFIG_SND_CTL_FAST_LOOKUP +static struct snd_kcontrol * +snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid) +{ + struct snd_kcontrol *kctl; + + list_for_each_entry(kctl, &card->controls, list) { + if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) + return kctl; + } + return NULL; +} +#endif /* !CONFIG_SND_CTL_FAST_LOOKUP */ + /** * snd_ctl_find_numid - find the control instance with the given number-id * @card: the card instance @@ -665,15 +781,13 @@ EXPORT_SYMBOL(snd_ctl_rename_id); */ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) { - struct snd_kcontrol *kctl; - if (snd_BUG_ON(!card || !numid)) return NULL; - list_for_each_entry(kctl, &card->controls, list) { - if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) - return kctl; - } - return NULL; +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + return xa_load(&card->ctl_numids, numid); +#else + return snd_ctl_find_numid_slow(card, numid); +#endif } EXPORT_SYMBOL(snd_ctl_find_numid); @@ -699,21 +813,18 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, return NULL; if (id->numid != 0) return snd_ctl_find_numid(card, id->numid); - list_for_each_entry(kctl, &card->controls, list) { - if (kctl->id.iface != id->iface) - continue; - if (kctl->id.device != id->device) - continue; - if (kctl->id.subdevice != id->subdevice) - continue; - if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name))) - continue; - if (kctl->id.index > id->index) - continue; - if (kctl->id.index + kctl->count <= id->index) - continue; +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id)); + if (kctl && elem_id_matches(kctl, id)) return kctl; - } + if (!card->ctl_hash_collision) + return NULL; /* we can rely on only hash table */ +#endif + /* no matching in hash table - try all as the last resort */ + list_for_each_entry(kctl, &card->controls, list) + if (elem_id_matches(kctl, id)) + return kctl; + return NULL; } EXPORT_SYMBOL(snd_ctl_find_id); @@ -2195,8 +2306,13 @@ static int snd_ctl_dev_free(struct snd_device *device) down_write(&card->controls_rwsem); while (!list_empty(&card->controls)) { control = snd_kcontrol(card->controls.next); - snd_ctl_remove(card, control); + __snd_ctl_remove(card, control, false); } + +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + xa_destroy(&card->ctl_numids); + xa_destroy(&card->ctl_hash); +#endif up_write(&card->controls_rwsem); put_device(&card->ctl_dev); return 0; diff --git a/sound/core/init.c b/sound/core/init.c index 726a8353201f..1870aee7b64f 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -310,6 +310,10 @@ static int snd_card_init(struct snd_card *card, struct device *parent, rwlock_init(&card->ctl_files_rwlock); INIT_LIST_HEAD(&card->controls); INIT_LIST_HEAD(&card->ctl_files); +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + xa_init(&card->ctl_numids); + xa_init(&card->ctl_hash); +#endif spin_lock_init(&card->files_lock); INIT_LIST_HEAD(&card->files_list); mutex_init(&card->memory_mutex); -- cgit v1.2.3 From 1b7ec5143c34f167266fa21245d99bacb4db4aa6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Jun 2022 14:02:17 +0200 Subject: ALSA: control: Rename CONFIG_SND_CTL_VALIDATION to CONFIG_SND_CTL_DEBUG The purpose of CONFIG_SND_CTL_VALIDATION is rather to enable the debugging feature for the control API. The validation is only a part of it. Let's rename it to be more explicit and intuitive. While we're at it, let's advertise, give more comment to recommend this feature for development in the kconfig help text. Link: https://lore.kernel.org/r/20220609120219.3937-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/control.h | 2 +- sound/core/Kconfig | 17 +++++++++++------ sound/core/control.c | 4 ++-- 3 files changed, 14 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/sound/control.h b/include/sound/control.h index 985c51a8fb74..fcd3cce673ec 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -23,7 +23,7 @@ typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol, unsigned int __user *tlv); /* internal flag for skipping validations */ -#ifdef CONFIG_SND_CTL_VALIDATION +#ifdef CONFIG_SND_CTL_DEBUG #define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK (1 << 24) #define snd_ctl_skip_validation(info) \ ((info)->access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK) diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 25b2434e4556..5289bb29131b 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -188,14 +188,19 @@ config SND_PCM_XRUN_DEBUG sound clicking when system is loaded, it may help to determine the process or driver which causes the scheduling gaps. -config SND_CTL_VALIDATION - bool "Perform sanity-checks for each control element access" +config SND_CTL_DEBUG + bool "Enable debugging feature for control API" depends on SND_DEBUG help - Say Y to enable the additional validation of each control element - access, including sanity-checks like whether the values returned - from the driver are in the proper ranges or the check of the invalid - access at out-of-array areas. + Say Y to enable the debugging feature for ALSA control API. + It performs the additional sanity-checks for each control element + read access, such as whether the values returned from the driver + are in the proper ranges or the check of the invalid access at + out-of-array areas. The error is printed when the driver gives + such unexpected values. + When you develop a driver that deals with control elements, it's + strongly recommended to try this one once and verify whether you see + any relevant errors or not. config SND_JACK_INJECTION_DEBUG bool "Sound jack injection interface via debugfs" diff --git a/sound/core/control.c b/sound/core/control.c index 6a8fd9933f06..1401522ce552 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -966,7 +966,7 @@ static const unsigned int value_sizes[] = { [SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long), }; -#ifdef CONFIG_SND_CTL_VALIDATION +#ifdef CONFIG_SND_CTL_DEBUG /* fill the remaining snd_ctl_elem_value data with the given pattern */ static void fill_remaining_elem_value(struct snd_ctl_elem_value *control, struct snd_ctl_elem_info *info, @@ -1188,7 +1188,7 @@ static int snd_ctl_elem_read(struct snd_card *card, snd_ctl_build_ioff(&control->id, kctl, index_offset); -#ifdef CONFIG_SND_CTL_VALIDATION +#ifdef CONFIG_SND_CTL_DEBUG /* info is needed only for validation */ memset(&info, 0, sizeof(info)); info.id = control->id; -- cgit v1.2.3 From 064520e8aeaa2569f6504a50a37ac801b73656bc Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 15 Jun 2022 16:43:48 +0800 Subject: ASoC: SOF: Intel: Add support for MeteorLake (MTL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add platform abstraction for the Meteor Lake platform. This platform has significant differences compared to the TGL/ADL generation: it relies on new hardware using the code name 'ACE' and only supports the INTEL_IPC4 protocol and firmware architecture based on the Zephyr RTOS Co-developed-by: Ranjani Sridharan Signed-off-by: Ranjani Sridharan Signed-off-by: Bard Liao Reviewed-by: Péter Ujfalusi Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20220615084348.3489-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- include/linux/soundwire/sdw_intel.h | 2 + sound/soc/sof/intel/Kconfig | 16 + sound/soc/sof/intel/Makefile | 4 +- sound/soc/sof/intel/hda.h | 3 + sound/soc/sof/intel/mtl.c | 800 ++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/mtl.h | 76 ++++ sound/soc/sof/intel/pci-mtl.c | 71 ++++ sound/soc/sof/intel/shim.h | 1 + 8 files changed, 972 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sof/intel/mtl.c create mode 100644 sound/soc/sof/intel/mtl.h create mode 100644 sound/soc/sof/intel/pci-mtl.c (limited to 'include') diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 67e0d3e750b5..b5b489ea1aef 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -9,6 +9,8 @@ #define SDW_SHIM_BASE 0x2C000 #define SDW_ALH_BASE 0x2C800 +#define SDW_SHIM_BASE_ACE 0x38000 +#define SDW_ALH_BASE_ACE 0x24000 #define SDW_LINK_BASE 0x30000 #define SDW_LINK_SIZE 0x10000 diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 80cdc3788bbe..3f54678e810b 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -221,6 +221,22 @@ config SND_SOC_SOF_ALDERLAKE Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_INTEL_MTL + tristate + select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + select SND_SOC_SOF_INTEL_IPC4 + +config SND_SOC_SOF_METEORLAKE + tristate "SOF support for Meteorlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_MTL + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Meteorlake processors. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index b9d51dc39ffa..a079159bb2f0 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -6,7 +6,7 @@ snd-sof-acpi-intel-bdw-objs := bdw.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-bus.o \ - apl.o cnl.o tgl.o icl.o hda-common-ops.o + apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o snd-sof-intel-hda-objs := hda-codec.o @@ -24,9 +24,11 @@ snd-sof-pci-intel-apl-objs := pci-apl.o snd-sof-pci-intel-cnl-objs := pci-cnl.o snd-sof-pci-intel-icl-objs := pci-icl.o snd-sof-pci-intel-tgl-objs := pci-tgl.o +snd-sof-pci-intel-mtl-objs := pci-mtl.o obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o obj-$(CONFIG_SND_SOC_SOF_INTEL_APL) += snd-sof-pci-intel-apl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 8b7f3c07d478..a3118499e34f 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -714,6 +714,8 @@ extern struct snd_sof_dsp_ops sof_tgl_ops; int sof_tgl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_icl_ops; int sof_icl_ops_init(struct snd_sof_dev *sdev); +extern struct snd_sof_dsp_ops sof_mtl_ops; +int sof_mtl_ops_init(struct snd_sof_dev *sdev); extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; @@ -723,6 +725,7 @@ extern const struct sof_intel_dsp_desc tglh_chip_info; extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info; +extern const struct sof_intel_dsp_desc mtl_chip_info; /* Probes support */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c new file mode 100644 index 000000000000..37be77beb415 --- /dev/null +++ b/sound/soc/sof/intel/mtl.c @@ -0,0 +1,800 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2022 Intel Corporation. All rights reserved. +// +// Authors: Ranjani Sridharan +// + +/* + * Hardware interface for audio DSP on Meteorlake. + */ + +#include +#include +#include "../ipc4-priv.h" +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" +#include "mtl.h" + +static const struct snd_sof_debugfs_map mtl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +static void mtl_ipc_host_done(struct snd_sof_dev *sdev) +{ + /* + * clear busy interrupt to tell dsp controller this interrupt has been accepted, + * not trigger it again + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR, + MTL_DSP_REG_HFIPCXTDR_BUSY, MTL_DSP_REG_HFIPCXTDR_BUSY); + /* + * clear busy bit to ack dsp the msg has been processed and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA, + MTL_DSP_REG_HFIPCXTDA_BUSY, 0); +} + +static void mtl_ipc_dsp_done(struct snd_sof_dev *sdev) +{ + /* + * set DONE bit - tell DSP we have received the reply msg from DSP, and processed it, + * don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA, + MTL_DSP_REG_HFIPCXIDA_DONE, MTL_DSP_REG_HFIPCXIDA_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL, + MTL_DSP_REG_HFIPCXCTL_DONE, MTL_DSP_REG_HFIPCXCTL_DONE); +} + +/* Check if an IPC IRQ occurred */ +static bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev) +{ + u32 irq_status; + u32 hfintipptr; + + /* read Interrupt IP Pointer */ + hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS); + + dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); + + if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_IPC)) + return true; + + return false; +} + +/* Check if an SDW IRQ occurred */ +static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +{ + u32 irq_status; + u32 hfintipptr; + + /* read Interrupt IP Pointer */ + hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS); + + if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_SDW)) + return true; + + return false; +} + +static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct sof_ipc4_msg *msg_data = msg->msg_data; + + /* send the message via mailbox */ + if (msg_data->data_size) + sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr, + msg_data->data_size); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDDY, + msg_data->extension); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR, + msg_data->primary | MTL_DSP_REG_HFIPCXIDR_BUSY); + + return 0; +} + +static void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* enable IPC DONE and BUSY interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, + MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE); +} + +static void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* disable IPC DONE and BUSY interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0); +} + +static int mtl_enable_interrupts(struct snd_sof_dev *sdev) +{ + u32 hfintipptr; + u32 irqinten; + u32 host_ipc; + u32 hipcie; + int ret; + + /* read Interrupt IP Pointer */ + hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + + /* Enable Host IPC and SOUNDWIRE */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, + MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, + MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK); + + /* check if operation was successful */ + host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; + irqinten = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, + (irqinten & host_ipc) == host_ipc, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable Host IPC and/or SOUNDWIRE\n"); + return ret; + } + + /* Set Host IPC interrupt enable */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, + MTL_DSP_REG_HfHIPCIE_IE_MASK, MTL_DSP_REG_HfHIPCIE_IE_MASK); + + /* check if operation was successful */ + host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, + (hipcie & host_ipc) == host_ipc, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "failed to set Host IPC interrupt enable\n"); + return ret; + } + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, + MTL_DSP_REG_HfSNDWIE_IE_MASK, MTL_DSP_REG_HfSNDWIE_IE_MASK); + host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, + (hipcie & host_ipc) == host_ipc, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "failed to set SoundWire IPC interrupt enable\n"); + + return ret; +} + +static int mtl_disable_interrupts(struct snd_sof_dev *sdev) +{ + u32 hfintipptr; + u32 irqinten; + u32 host_ipc; + u32 hipcie; + int ret1; + int ret; + + /* read Interrupt IP Pointer */ + hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK; + + /* Disable Host IPC and SOUNDWIRE */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr, + MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, 0); + + /* check if operation was successful */ + host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK; + irqinten = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten, + (irqinten & host_ipc) == 0, + HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + /* Continue to disable other interrupts when error happens */ + if (ret < 0) + dev_err(sdev->dev, "failed to disable Host IPC and SoundWire\n"); + + /* Set Host IPC interrupt disable */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, + MTL_DSP_REG_HfHIPCIE_IE_MASK, 0); + + /* check if operation was successful */ + host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK; + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE); + ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie, + (hipcie & host_ipc) == 0, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret1 < 0) { + dev_err(sdev->dev, "failed to set Host IPC interrupt disable\n"); + if (!ret) + ret = ret1; + } + + /* Set SoundWire IPC interrupt disable */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, + MTL_DSP_REG_HfSNDWIE_IE_MASK, 0); + host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK; + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE); + ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie, + (hipcie & host_ipc) == 0, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret1 < 0) { + dev_err(sdev->dev, "failed to set SoundWire IPC interrupt disable\n"); + if (!ret) + ret = ret1; + } + + return ret; +} + +/* pre fw run operations */ +static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + u32 dsphfpwrsts; + u32 dsphfdsscs; + u32 cpa; + u32 pgs; + int ret; + + /* Set the DSP subsystem power on */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS, + MTL_HFDSSCS_SPA_MASK, MTL_HFDSSCS_SPA_MASK); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + cpa = MTL_HFDSSCS_CPA_MASK; + dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs, + (dsphfdsscs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "failed to enable DSP subsystem\n"); + return ret; + } + + /* Power up gated-DSP-0 domain in order to access the DSP shim register block. */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL, + MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG); + + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK; + dsphfpwrsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFPWRSTS); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFPWRSTS, dsphfpwrsts, + (dsphfpwrsts & pgs) == pgs, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "failed to power up gated DSP domain\n"); + + /* make sure SoundWire is not power-gated */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, MTL_HFPWRCTL, + MTL_HfPWRCTL_WPIOXPG(1), MTL_HfPWRCTL_WPIOXPG(1)); + return ret; +} + +static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + int ret; + + if (sdev->first_boot) { + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; + + ret = hda_sdw_startup(sdev); + if (ret < 0) { + dev_err(sdev->dev, "could not startup SoundWire links\n"); + return ret; + } + + /* Check if IMR boot is usable */ + if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) + hdev->imrboot_supported = true; + } + + hda_sdw_int_enable(sdev, true); + return 0; +} + +static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +{ + char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR; + u32 romdbgsts; + u32 romdbgerr; + u32 fwsts; + u32 fwlec; + + fwsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_STS); + fwlec = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_ERROR); + romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY); + romdbgerr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY_ERROR); + + dev_err(sdev->dev, "ROM status: %#x, ROM error: %#x\n", fwsts, fwlec); + dev_err(sdev->dev, "ROM debug status: %#x, ROM debug error: %#x\n", romdbgsts, + romdbgerr); + romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY + 0x8 * 3); + dev_printk(level, sdev->dev, "ROM feature bit%s enabled\n", + romdbgsts & BIT(24) ? "" : " not"); +} + +static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev) +{ + int val; + + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE); + if (val != U32_MAX && val & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) + return true; + + return false; +} + +static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core) +{ + unsigned int cpa; + u32 dspcxctl; + int ret; + + /* Only the primary core can be powered up by the host */ + if (core != SOF_DSP_PRIMARY_CORE || mtl_dsp_primary_core_is_enabled(sdev)) + return 0; + + /* Program the owner of the IP & shim registers (10: Host CPU) */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, + MTL_DSP2CXCTL_PRIMARY_CORE_OSEL, + 0x2 << MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT); + + /* enable SPA bit */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, + MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, + MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + cpa = MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK; + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl, + (dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n", + __func__); + return ret; + } + + /* did core power up ? */ + dspcxctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE); + if ((dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) + != MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) { + dev_err(sdev->dev, "power up core failed core %d adspcs %#x\n", + core, dspcxctl); + ret = -EIO; + } + + return ret; +} + +static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core) +{ + u32 dspcxctl; + int ret; + + /* Only the primary core can be powered down by the host */ + if (core != SOF_DSP_PRIMARY_CORE || !mtl_dsp_primary_core_is_enabled(sdev)) + return 0; + + /* disable SPA bit */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, + MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl, + !(dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); + if (ret < 0) + dev_err(sdev->dev, "failed to power down primary core\n"); + + return ret; +} + +static int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + unsigned int status; + u32 ipc_hdr; + int ret; + + /* step 1: purge FW request */ + ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL; + if (!imr_boot) + ipc_hdr |= HDA_DSP_ROM_IPC_PURGE_FW | ((stream_tag - 1) << 9); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr); + + /* step 2: power up primary core */ + ret = mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE); + if (ret < 0) { + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, "dsp core 0/1 power up failed\n"); + goto err; + } + + dev_dbg(sdev->dev, "Primary core power up successful\n"); + + /* step 3: wait for IPC DONE bit from ROM */ + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->ipc_ack, status, + ((status & chip->ipc_ack_mask) == chip->ipc_ack_mask), + HDA_DSP_REG_POLL_INTERVAL_US, MTL_DSP_PURGE_TIMEOUT_US); + if (ret < 0) { + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, "timeout waiting for purge IPC done\n"); + goto err; + } + + /* set DONE bit to clear the reply IPC message */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, chip->ipc_ack, chip->ipc_ack_mask, + chip->ipc_ack_mask); + + /* step 4: enable interrupts */ + ret = mtl_enable_interrupts(sdev); + if (ret < 0) { + if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) + dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__); + goto err; + } + + mtl_enable_ipc_interrupts(sdev); + + /* + * ACE workaround: don't wait for ROM INIT. + * The platform cannot catch ROM_INIT_DONE because of a very short + * timing window. Follow the recommendations and skip this part. + */ + + return 0; + +err: + snd_sof_dsp_dbg_dump(sdev, "MTL DSP init fail", 0); + mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE); + return ret; +} + +static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) +{ + struct sof_ipc4_msg notification_data = {{ 0 }}; + struct snd_sof_dev *sdev = context; + bool ipc_irq = false; + u32 hipcida; + u32 hipctdr; + + hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA); + + /* reply message from DSP */ + if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) { + /* DSP received the message */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL, + MTL_DSP_REG_HFIPCXCTL_DONE, 0); + + mtl_ipc_dsp_done(sdev); + + ipc_irq = true; + } + + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR); + if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) { + /* Message from DSP (reply or notification) */ + u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY); + u32 primary = hipctdr & MTL_DSP_REG_HFIPCXTDR_MSG_MASK; + + /* + * ACE fw sends a new fw ipc message to host to + * notify the status of the last host ipc message + */ + if (primary & SOF_IPC4_MSG_DIR_MASK) { + /* Reply received */ + struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; + + data->primary = primary; + data->extension = extension; + + spin_lock_irq(&sdev->ipc_lock); + + snd_sof_ipc_get_reply(sdev); + snd_sof_ipc_reply(sdev, data->primary); + + spin_unlock_irq(&sdev->ipc_lock); + } else { + /* Notification received */ + notification_data.primary = primary; + notification_data.extension = extension; + + sdev->ipc->msg.rx_data = ¬ification_data; + snd_sof_ipc_msgs_rx(sdev); + sdev->ipc->msg.rx_data = NULL; + } + + mtl_ipc_host_done(sdev); + + ipc_irq = true; + } + + if (!ipc_irq) { + /* This interrupt is not shared so no need to return IRQ_NONE. */ + dev_dbg_ratelimited(sdev->dev, "%s nothing to do in IPC IRQ thread\n", + __func__); + } + + return IRQ_HANDLED; +} + +static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MTL_DSP_MBOX_UPLINK_OFFSET; +} + +static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MTL_SRAM_WINDOW_OFFSET(id); +} + +static int mtl_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); +#endif + u32 dsphfdsscs; + u32 cpa; + int ret; + int i; + + mtl_disable_ipc_interrupts(sdev); + ret = mtl_disable_interrupts(sdev); + if (ret) + return ret; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + hda_codec_jack_wake_enable(sdev, runtime_suspend); + /* power down all hda link */ + snd_hdac_ext_bus_link_power_down_all(bus); +#endif + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL, + MTL_HFPWRCTL_WPDSPHPXPG, 0); + + /* Set the DSP subsystem power down */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS, + MTL_HFDSSCS_SPA_MASK, 0); + + /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */ + usleep_range(1000, 1010); + + /* poll with timeout to check if operation successful */ + cpa = MTL_HFDSSCS_CPA_MASK; + dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs, + (dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "failed to disable DSP subsystem\n"); + + /* reset ref counts for all cores */ + for (i = 0; i < chip->cores_num; i++) + sdev->dsp_core_ref_count[i] = 0; + + /* TODO: need to reset controller? */ + + /* display codec can be powered off after link reset */ + hda_codec_i915_display_power(sdev, false); + + return 0; +} + +static int mtl_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = target_state, + .substate = target_state == SOF_DSP_PM_D0 ? + SOF_HDA_DSP_PM_D0I3 : 0, + }; + int ret; + + ret = mtl_suspend(sdev, false); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int mtl_dsp_runtime_suspend(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D3, + }; + int ret; + + ret = mtl_suspend(sdev, true); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static int mtl_resume(struct snd_sof_dev *sdev, bool runtime_resume) +{ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_link *hlink = NULL; +#endif + + /* display codec must be powered before link reset */ + hda_codec_i915_display_power(sdev, true); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* check jack status */ + if (runtime_resume) { + hda_codec_jack_wake_enable(sdev, false); + if (sdev->system_suspend_target == SOF_SUSPEND_NONE) + hda_codec_jack_check(sdev); + } + + /* turn off the links that were off before suspend */ + list_for_each_entry(hlink, &bus->hlink_list, list) { + if (!hlink->ref_count) + snd_hdac_ext_bus_link_power_down(hlink); + } + + /* check dma status and clean up CORB/RIRB buffers */ + if (!bus->cmd_dma_state) + snd_hdac_bus_stop_cmd_io(bus); +#endif + + return 0; +} + +static int mtl_dsp_resume(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D0, + .substate = SOF_HDA_DSP_PM_D0I0, + }; + int ret; + + ret = mtl_resume(sdev, false); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static int mtl_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D0, + }; + int ret; + + ret = mtl_resume(sdev, true); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static void mtl_ipc_dump(struct snd_sof_dev *sdev) +{ + u32 hipcctl; + u32 hipcida; + u32 hipctdr; + + /* read IPC status */ + hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL); + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR); + + /* dump the IPC regs */ + /* TODO: parse the raw msg */ + dev_err(sdev->dev, + "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", + hipcida, hipctdr, hipcctl); +} + +/* Meteorlake ops */ +struct snd_sof_dsp_ops sof_mtl_ops; +EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +int sof_mtl_ops_init(struct snd_sof_dev *sdev) +{ + struct sof_ipc4_fw_data *ipc4_data; + + /* common defaults */ + memcpy(&sof_mtl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + + /* shutdown */ + sof_mtl_ops.shutdown = hda_dsp_shutdown; + + /* doorbell */ + sof_mtl_ops.irq_thread = mtl_ipc_irq_thread; + + /* ipc */ + sof_mtl_ops.send_msg = mtl_ipc_send_msg; + sof_mtl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; + sof_mtl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset; + + /* debug */ + sof_mtl_ops.debug_map = mtl_dsp_debugfs; + sof_mtl_ops.debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs); + sof_mtl_ops.dbg_dump = mtl_dsp_dump; + sof_mtl_ops.ipc_dump = mtl_ipc_dump; + + /* pre/post fw run */ + sof_mtl_ops.pre_fw_run = mtl_dsp_pre_fw_run; + sof_mtl_ops.post_fw_run = mtl_dsp_post_fw_run; + + /* parse platform specific extended manifest */ + sof_mtl_ops.parse_platform_ext_manifest = NULL; + + /* dsp core get/put */ + /* TODO: add core_get and core_put */ + + /* PM */ + sof_mtl_ops.suspend = mtl_dsp_suspend; + sof_mtl_ops.resume = mtl_dsp_resume; + sof_mtl_ops.runtime_suspend = mtl_dsp_runtime_suspend; + sof_mtl_ops.runtime_resume = mtl_dsp_runtime_resume; + + sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); + if (!sdev->private) + return -ENOMEM; + + ipc4_data = sdev->private; + ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; + + /* set DAI ops */ + hda_set_dai_drv_ops(sdev, &sof_mtl_ops); + + return 0; +}; +EXPORT_SYMBOL_NS(sof_mtl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); + +const struct sof_intel_dsp_desc mtl_chip_info = { + .cores_num = 3, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = MTL_DSP_ROM_STS, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, + .sdw_shim_base = SDW_SHIM_BASE_ACE, + .sdw_alh_base = SDW_ALH_BASE_ACE, + .check_sdw_irq = mtl_dsp_check_sdw_irq, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .cl_init = mtl_dsp_cl_init, + .hw_ip_version = SOF_INTEL_ACE_1_0, +}; +EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h new file mode 100644 index 000000000000..788bf0e3ea87 --- /dev/null +++ b/sound/soc/sof/intel/mtl.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2020-2022 Intel Corporation. All rights reserved. + */ + +/* DSP Registers */ +#define MTL_HFDSSCS 0x1000 +#define MTL_HFDSSCS_SPA_MASK BIT(16) +#define MTL_HFDSSCS_CPA_MASK BIT(24) +#define MTL_HFSNDWIE 0x114C +#define MTL_HFPWRCTL 0x1D18 +#define MTL_HfPWRCTL_WPIOXPG(x) BIT((x) + 8) +#define MTL_HFPWRCTL_WPDSPHPXPG BIT(0) +#define MTL_HFPWRSTS 0x1D1C +#define MTL_HFPWRSTS_DSPHPXPGS_MASK BIT(0) +#define MTL_HFINTIPPTR 0x1108 +#define MTL_IRQ_INTEN_L_HOST_IPC_MASK BIT(0) +#define MTL_IRQ_INTEN_L_SOUNDWIRE_MASK BIT(6) +#define MTL_HFINTIPPTR_PTR_MASK GENMASK(20, 0) + +#define MTL_DSP2CXCAP_PRIMARY_CORE 0x178D00 +#define MTL_DSP2CXCTL_PRIMARY_CORE 0x178D04 +#define MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK BIT(0) +#define MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK BIT(8) +#define MTL_DSP2CXCTL_PRIMARY_CORE_OSEL GENMASK(25, 24) +#define MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT 24 + +/* IPC Registers */ +#define MTL_DSP_REG_HFIPCXTDR 0x73200 +#define MTL_DSP_REG_HFIPCXTDR_BUSY BIT(31) +#define MTL_DSP_REG_HFIPCXTDR_MSG_MASK GENMASK(30, 0) +#define MTL_DSP_REG_HFIPCXTDA 0x73204 +#define MTL_DSP_REG_HFIPCXTDA_BUSY BIT(31) +#define MTL_DSP_REG_HFIPCXIDR 0x73210 +#define MTL_DSP_REG_HFIPCXIDR_BUSY BIT(31) +#define MTL_DSP_REG_HFIPCXIDR_MSG_MASK GENMASK(30, 0) +#define MTL_DSP_REG_HFIPCXIDA 0x73214 +#define MTL_DSP_REG_HFIPCXIDA_DONE BIT(31) +#define MTL_DSP_REG_HFIPCXIDA_MSG_MASK GENMASK(30, 0) +#define MTL_DSP_REG_HFIPCXCTL 0x73228 +#define MTL_DSP_REG_HFIPCXCTL_BUSY BIT(0) +#define MTL_DSP_REG_HFIPCXCTL_DONE BIT(1) +#define MTL_DSP_REG_HFIPCXTDDY 0x73300 +#define MTL_DSP_REG_HFIPCXIDDY 0x73380 +#define MTL_DSP_REG_HfHIPCIE 0x1140 +#define MTL_DSP_REG_HfHIPCIE_IE_MASK BIT(0) +#define MTL_DSP_REG_HfSNDWIE 0x114C +#define MTL_DSP_REG_HfSNDWIE_IE_MASK GENMASK(3, 0) + +#define MTL_DSP_IRQSTS 0x20 +#define MTL_DSP_IRQSTS_IPC BIT(0) +#define MTL_DSP_IRQSTS_SDW BIT(6) + +#define MTL_DSP_PURGE_TIMEOUT_US 20000000 /* 20s */ +#define MTL_DSP_REG_POLL_INTERVAL_US 10 /* 10 us */ + +/* Memory windows */ +#define MTL_SRAM_WINDOW_OFFSET(x) (0x180000 + 0x8000 * (x)) + +#define MTL_DSP_MBOX_UPLINK_OFFSET (MTL_SRAM_WINDOW_OFFSET(0) + 0x1000) +#define MTL_DSP_MBOX_UPLINK_SIZE 0x1000 +#define MTL_DSP_MBOX_DOWNLINK_OFFSET MTL_SRAM_WINDOW_OFFSET(1) +#define MTL_DSP_MBOX_DOWNLINK_SIZE 0x1000 + +/* FW registers */ +#define MTL_DSP_ROM_STS MTL_SRAM_WINDOW_OFFSET(0) /* ROM status */ +#define MTL_DSP_ROM_ERROR (MTL_SRAM_WINDOW_OFFSET(0) + 0x4) /* ROM error code */ + +#define MTL_DSP_REG_HFFLGPXQWY 0x163200 /* ROM debug status */ +#define MTL_DSP_REG_HFFLGPXQWY_ERROR 0x163204 /* ROM debug error code */ +#define MTL_DSP_REG_HfIMRIS1 0x162088 +#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0) + diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c new file mode 100644 index 000000000000..899b00d53d64 --- /dev/null +++ b/sound/soc/sof/intel/pci-mtl.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018-2022 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan +// + +#include +#include +#include +#include +#include +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" +#include "mtl.h" + +static const struct sof_dev_desc mtl_desc = { + .use_acpi_target_states = true, + .machines = snd_soc_acpi_intel_mtl_machines, + .alt_machines = snd_soc_acpi_intel_mtl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .chip_info = &mtl_chip_info, + .ipc_supported_mask = BIT(SOF_INTEL_IPC4), + .ipc_default = SOF_INTEL_IPC4, + .default_fw_path = { + [SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl", + }, + .default_tplg_path = { + [SOF_INTEL_IPC4] = "intel/sof-ace-tplg", + }, + .default_fw_filename = { + [SOF_INTEL_IPC4] = "dsp_basefw.bin", + }, + .nocodec_tplg_filename = "sof-mtl-nocodec.tplg", + .ops = &sof_mtl_ops, + .ops_init = sof_mtl_ops_init, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE(0x8086, 0x7E28), /* MTL */ + .driver_data = (unsigned long)&mtl_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_mtl_driver = { + .name = "sof-audio-pci-intel-mtl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_mtl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 371991fa474f..638159bee864 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -20,6 +20,7 @@ enum sof_intel_hw_ip_version { SOF_INTEL_CAVS_1_8, /* CannonLake, CometLake, CoffeeLake */ SOF_INTEL_CAVS_2_0, /* IceLake, JasperLake */ SOF_INTEL_CAVS_2_5, /* TigerLake, AlderLake */ + SOF_INTEL_ACE_1_0, /* MeteorLake */ }; /* -- cgit v1.2.3 From 6365a1935c5151455812e96d8de434c551dc0d98 Mon Sep 17 00:00:00 2001 From: Ma Wupeng Date: Tue, 14 Jun 2022 17:21:52 +0800 Subject: efi: Make code to find mirrored memory ranges generic Commit b05b9f5f9dcf ("x86, mirror: x86 enabling - find mirrored memory ranges") introduce the efi_find_mirror() function on x86. In order to reuse the API we make it public. Arm64 can support mirrored memory too, so function efi_find_mirror() is added to efi_init() to this support for arm64. Since efi_init() is shared by ARM, arm64 and riscv, this patch will bring mirror memory support for these architectures, but this support is only tested in arm64. Signed-off-by: Ma Wupeng Link: https://lore.kernel.org/r/20220614092156.1972846-2-mawupeng1@huawei.com [ardb: fix subject to better reflect the payload] Acked-by: Mike Rapoport Signed-off-by: Ard Biesheuvel --- arch/x86/include/asm/efi.h | 4 ---- arch/x86/platform/efi/efi.c | 23 ----------------------- drivers/firmware/efi/efi-init.c | 1 + drivers/firmware/efi/efi.c | 23 +++++++++++++++++++++++ include/linux/efi.h | 3 +++ 5 files changed, 27 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 71943dce691e..eb90206eae80 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -383,7 +383,6 @@ static inline bool efi_is_64bit(void) extern bool efi_reboot_required(void); extern bool efi_is_table_address(unsigned long phys_addr); -extern void efi_find_mirror(void); extern void efi_reserve_boot_services(void); #else static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} @@ -395,9 +394,6 @@ static inline bool efi_is_table_address(unsigned long phys_addr) { return false; } -static inline void efi_find_mirror(void) -{ -} static inline void efi_reserve_boot_services(void) { } diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 1591d67e0bcd..6e598bd78eef 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -108,29 +108,6 @@ static int __init setup_add_efi_memmap(char *arg) } early_param("add_efi_memmap", setup_add_efi_memmap); -void __init efi_find_mirror(void) -{ - efi_memory_desc_t *md; - u64 mirror_size = 0, total_size = 0; - - if (!efi_enabled(EFI_MEMMAP)) - return; - - for_each_efi_memory_desc(md) { - unsigned long long start = md->phys_addr; - unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; - - total_size += size; - if (md->attribute & EFI_MEMORY_MORE_RELIABLE) { - memblock_mark_mirror(start, size); - mirror_size += size; - } - } - if (mirror_size) - pr_info("Memory: %lldM/%lldM mirrored memory\n", - mirror_size>>20, total_size>>20); -} - /* * Tell the kernel about the EFI memory map. This might include * more than the max 128 entries that can fit in the passed in e820 diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c index b2c829e95bd1..3928dbff76d0 100644 --- a/drivers/firmware/efi/efi-init.c +++ b/drivers/firmware/efi/efi-init.c @@ -240,6 +240,7 @@ void __init efi_init(void) * And now, memblock is fully populated, it is time to do capping. */ early_init_dt_check_for_usable_mem_range(); + efi_find_mirror(); efi_esrt_init(); efi_mokvar_table_init(); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 860534bcfdac..79c232e07de7 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -446,6 +446,29 @@ err_put: subsys_initcall(efisubsys_init); +void __init efi_find_mirror(void) +{ + efi_memory_desc_t *md; + u64 mirror_size = 0, total_size = 0; + + if (!efi_enabled(EFI_MEMMAP)) + return; + + for_each_efi_memory_desc(md) { + unsigned long long start = md->phys_addr; + unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; + + total_size += size; + if (md->attribute & EFI_MEMORY_MORE_RELIABLE) { + memblock_mark_mirror(start, size); + mirror_size += size; + } + } + if (mirror_size) + pr_info("Memory: %lldM/%lldM mirrored memory\n", + mirror_size>>20, total_size>>20); +} + /* * Find the efi memory descriptor for a given physical address. Given a * physical address, determine if it exists within an EFI Memory Map entry, diff --git a/include/linux/efi.h b/include/linux/efi.h index 7d9b0bb47eb3..53f64c14a525 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -872,6 +872,7 @@ static inline bool efi_rt_services_supported(unsigned int mask) { return (efi.runtime_supported_mask & mask) == mask; } +extern void efi_find_mirror(void); #else static inline bool efi_enabled(int feature) { @@ -889,6 +890,8 @@ static inline bool efi_rt_services_supported(unsigned int mask) { return false; } + +static inline void efi_find_mirror(void) {} #endif extern int efi_status_to_err(efi_status_t status); -- cgit v1.2.3 From f67be8b7ee90c292948c3ec6395673963cccaee6 Mon Sep 17 00:00:00 2001 From: Li Chen Date: Sun, 22 May 2022 20:26:58 -0700 Subject: regmap: provide regmap_field helpers for simple bit operations We have set/clear/test operations for regmap, but not for regmap_field yet. So let's introduce regmap_field helpers too. In many instances regmap_field_update_bits() is used for simple bit setting and clearing. In these cases the last argument is redundant and we can hide it with a static inline function. This adds three new helpers for simple bit operations: set_bits, clear_bits and test_bits (the last one defined as a regular function). Signed-off-by: Li Chen Link: https://lore.kernel.org/r/180eef422c3.deae9cd960729.8518395646822099769@zohomail.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 22 ++++++++++++++++++++++ include/linux/regmap.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) (limited to 'include') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 2221d9863831..cb0be5e7b100 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2220,6 +2220,28 @@ int regmap_field_update_bits_base(struct regmap_field *field, } EXPORT_SYMBOL_GPL(regmap_field_update_bits_base); +/** + * regmap_field_test_bits() - Check if all specified bits are set in a + * register field. + * + * @field: Register field to operate on + * @bits: Bits to test + * + * Returns -1 if the underlying regmap_field_read() fails, 0 if at least one of the + * tested bits is not set and 1 if all tested bits are set. + */ +int regmap_field_test_bits(struct regmap_field *field, unsigned int bits) +{ + unsigned int val, ret; + + ret = regmap_field_read(field, &val); + if (ret) + return ret; + + return (val & bits) == bits; +} +EXPORT_SYMBOL_GPL(regmap_field_test_bits); + /** * regmap_fields_update_bits_base() - Perform a read/modify/write cycle a * register field with port ID diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 8952fa3d0d59..d5b08f4f0dc0 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -1336,6 +1336,22 @@ static inline int regmap_field_update_bits(struct regmap_field *field, NULL, false, false); } +static inline int regmap_field_set_bits(struct regmap_field *field, + unsigned int bits) +{ + return regmap_field_update_bits_base(field, bits, bits, NULL, false, + false); +} + +static inline int regmap_field_clear_bits(struct regmap_field *field, + unsigned int bits) +{ + return regmap_field_update_bits_base(field, bits, 0, NULL, false, + false); +} + +int regmap_field_test_bits(struct regmap_field *field, unsigned int bits); + static inline int regmap_field_force_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val) @@ -1769,6 +1785,27 @@ regmap_field_force_update_bits(struct regmap_field *field, return -EINVAL; } +static inline int regmap_field_set_bits(struct regmap_field *field, + unsigned int bits) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + +static inline int regmap_field_clear_bits(struct regmap_field *field, + unsigned int bits) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + +static inline int regmap_field_test_bits(struct regmap_field *field, + unsigned int bits) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_fields_write(struct regmap_field *field, unsigned int id, unsigned int val) { -- cgit v1.2.3 From 003cbe046171596809c2f37dc07e69df1b4d9f95 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Wed, 1 Jun 2022 20:58:55 +0530 Subject: pinctrl: Add pingroup and define PINCTRL_PINGROUP Add 'struct pingroup' to represent pingroup and 'PINCTRL_PINGROUP' macro for inline use. Both are used to manage and represent larger number of pingroups. Signed-off-by: Basavaraj Natikar Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220601152900.1012813-2-Basavaraj.Natikar@amd.com Signed-off-by: Linus Walleij --- include/linux/pinctrl/pinctrl.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'include') diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 70b45d28e7a9..487117ccb1bc 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -26,6 +26,26 @@ struct pin_config_item; struct gpio_chip; struct device_node; +/** + * struct pingroup - provides information on pingroup + * @name: a name for pingroup + * @pins: an array of pins in the pingroup + * @npins: number of pins in the pingroup + */ +struct pingroup { + const char *name; + const unsigned int *pins; + size_t npins; +}; + +/* Convenience macro to define a single named or anonymous pingroup */ +#define PINCTRL_PINGROUP(_name, _pins, _npins) \ +(struct pingroup){ \ + .name = _name, \ + .pins = _pins, \ + .npins = _npins, \ +} + /** * struct pinctrl_pin_desc - boards/machines provide information on their * pins, pads or other muxable units in this struct -- cgit v1.2.3 From f2c5092190f21e02d384f750bcc473554f3aa3f8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 14 Jun 2022 20:18:14 +0200 Subject: arch/*: Disable softirq stacks on PREEMPT_RT. PREEMPT_RT preempts softirqs and the current implementation avoids do_softirq_own_stack() and only uses __do_softirq(). Disable the unused softirqs stacks on PREEMPT_RT to save some memory and ensure that do_softirq_own_stack() is not used bwcause it is not expected. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Arnd Bergmann --- arch/arm/kernel/irq.c | 3 ++- arch/parisc/kernel/irq.c | 2 ++ arch/powerpc/kernel/irq.c | 4 ++++ arch/s390/include/asm/softirq_stack.h | 3 ++- arch/sh/kernel/irq.c | 2 ++ arch/sparc/kernel/irq_64.c | 2 ++ include/asm-generic/softirq_stack.h | 2 +- 7 files changed, 15 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 5c6f8d11a3ce..034cb48c9eeb 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -70,6 +70,7 @@ static void __init init_irq_stacks(void) } } +#ifndef CONFIG_PREEMPT_RT static void ____do_softirq(void *arg) { __do_softirq(); @@ -80,7 +81,7 @@ void do_softirq_own_stack(void) call_with_stack(____do_softirq, NULL, __this_cpu_read(irq_stack_ptr)); } - +#endif #endif int arch_show_interrupts(struct seq_file *p, int prec) diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 0fe2d79fb123..eba193bcdab1 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -480,10 +480,12 @@ static void execute_on_irq_stack(void *func, unsigned long param1) *irq_stack_in_use = 1; } +#ifndef CONFIG_PREEMPT_RT void do_softirq_own_stack(void) { execute_on_irq_stack(__do_softirq, 0); } +#endif #endif /* CONFIG_IRQSTACKS */ /* ONLY called from entry.S:intr_extint() */ diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index dd09919c3c66..0822a274a549 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -611,6 +611,7 @@ static inline void check_stack_overflow(void) } } +#ifndef CONFIG_PREEMPT_RT static __always_inline void call_do_softirq(const void *sp) { /* Temporarily switch r1 to sp, call __do_softirq() then restore r1. */ @@ -629,6 +630,7 @@ static __always_inline void call_do_softirq(const void *sp) "r11", "r12" ); } +#endif static __always_inline void call_do_irq(struct pt_regs *regs, void *sp) { @@ -747,10 +749,12 @@ void *mcheckirq_ctx[NR_CPUS] __read_mostly; void *softirq_ctx[NR_CPUS] __read_mostly; void *hardirq_ctx[NR_CPUS] __read_mostly; +#ifndef CONFIG_PREEMPT_RT void do_softirq_own_stack(void) { call_do_softirq(softirq_ctx[smp_processor_id()]); } +#endif irq_hw_number_t virq_to_hw(unsigned int virq) { diff --git a/arch/s390/include/asm/softirq_stack.h b/arch/s390/include/asm/softirq_stack.h index fd17f25704bd..af68d6c1d584 100644 --- a/arch/s390/include/asm/softirq_stack.h +++ b/arch/s390/include/asm/softirq_stack.h @@ -5,9 +5,10 @@ #include #include +#ifndef CONFIG_PREEMPT_RT static inline void do_softirq_own_stack(void) { call_on_stack(0, S390_lowcore.async_stack, void, __do_softirq); } - +#endif #endif /* __ASM_S390_SOFTIRQ_STACK_H */ diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index ef0f0827cf57..2d3eca8fee01 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -149,6 +149,7 @@ void irq_ctx_exit(int cpu) hardirq_ctx[cpu] = NULL; } +#ifndef CONFIG_PREEMPT_RT void do_softirq_own_stack(void) { struct thread_info *curctx; @@ -176,6 +177,7 @@ void do_softirq_own_stack(void) "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" ); } +#endif #else static inline void handle_one_irq(unsigned int irq) { diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index c8848bb681a1..41fa1be980a3 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -855,6 +855,7 @@ void __irq_entry handler_irq(int pil, struct pt_regs *regs) set_irq_regs(old_regs); } +#ifndef CONFIG_PREEMPT_RT void do_softirq_own_stack(void) { void *orig_sp, *sp = softirq_stack[smp_processor_id()]; @@ -869,6 +870,7 @@ void do_softirq_own_stack(void) __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); } +#endif #ifdef CONFIG_HOTPLUG_CPU void fixup_irqs(void) diff --git a/include/asm-generic/softirq_stack.h b/include/asm-generic/softirq_stack.h index eceeecf6a5bd..d3e2d81656e0 100644 --- a/include/asm-generic/softirq_stack.h +++ b/include/asm-generic/softirq_stack.h @@ -2,7 +2,7 @@ #ifndef __ASM_GENERIC_SOFTIRQ_STACK_H #define __ASM_GENERIC_SOFTIRQ_STACK_H -#ifdef CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK +#if defined(CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK) && !defined(CONFIG_PREEMPT_RT) void do_softirq_own_stack(void); #else static inline void do_softirq_own_stack(void) -- cgit v1.2.3 From d593d64f043add170d8ea9cf698449637917dcf9 Mon Sep 17 00:00:00 2001 From: Prasad Sodagudi Date: Wed, 18 May 2022 22:14:14 +0530 Subject: lib: Add register read/write tracing support Generic MMIO read/write i.e., __raw_{read,write}{b,l,w,q} accessors are typically used to read/write from/to memory mapped registers and can cause hangs or some undefined behaviour in following few cases, * If the access to the register space is unclocked, for example: if there is an access to multimedia(MM) block registers without MM clocks. * If the register space is protected and not set to be accessible from non-secure world, for example: only EL3 (EL: Exception level) access is allowed and any EL2/EL1 access is forbidden. * If xPU(memory/register protection units) is controlling access to certain memory/register space for specific clients. and more... Such cases usually results in instant reboot/SErrors/NOC or interconnect hangs and tracing these register accesses can be very helpful to debug such issues during initial development stages and also in later stages. So use ftrace trace events to log such MMIO register accesses which provides rich feature set such as early enablement of trace events, filtering capability, dumping ftrace logs on console and many more. Sample output: rwmmio_write: __qcom_geni_serial_console_write+0x160/0x1e0 width=32 val=0xa0d5d addr=0xfffffbfffdbff700 rwmmio_post_write: __qcom_geni_serial_console_write+0x160/0x1e0 width=32 val=0xa0d5d addr=0xfffffbfffdbff700 rwmmio_read: qcom_geni_serial_poll_bit+0x94/0x138 width=32 addr=0xfffffbfffdbff610 rwmmio_post_read: qcom_geni_serial_poll_bit+0x94/0x138 width=32 val=0x0 addr=0xfffffbfffdbff610 Co-developed-by: Sai Prakash Ranjan Signed-off-by: Prasad Sodagudi Signed-off-by: Sai Prakash Ranjan Acked-by: Steven Rostedt (Google) Signed-off-by: Arnd Bergmann --- arch/Kconfig | 3 ++ arch/arm64/Kconfig | 1 + include/trace/events/rwmmio.h | 97 +++++++++++++++++++++++++++++++++++++++++++ lib/Kconfig | 7 ++++ lib/Makefile | 2 + lib/trace_readwrite.c | 47 +++++++++++++++++++++ 6 files changed, 157 insertions(+) create mode 100644 include/trace/events/rwmmio.h create mode 100644 lib/trace_readwrite.c (limited to 'include') diff --git a/arch/Kconfig b/arch/Kconfig index fcf9a41a4ef5..47899446483b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1396,6 +1396,9 @@ config ARCH_HAS_ELFCORE_COMPAT config ARCH_HAS_PARANOID_L1D_FLUSH bool +config ARCH_HAVE_TRACE_MMIO_ACCESS + bool + config DYNAMIC_SIGFRAME bool diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1652a9800ebe..fbf21e01f0b6 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -49,6 +49,7 @@ config ARM64 select ARCH_HAS_ZONE_DMA_SET if EXPERT select ARCH_HAVE_ELF_PROT select ARCH_HAVE_NMI_SAFE_CMPXCHG + select ARCH_HAVE_TRACE_MMIO_ACCESS select ARCH_INLINE_READ_LOCK if !PREEMPTION select ARCH_INLINE_READ_LOCK_BH if !PREEMPTION select ARCH_INLINE_READ_LOCK_IRQ if !PREEMPTION diff --git a/include/trace/events/rwmmio.h b/include/trace/events/rwmmio.h new file mode 100644 index 000000000000..de41159216c1 --- /dev/null +++ b/include/trace/events/rwmmio.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rwmmio + +#if !defined(_TRACE_RWMMIO_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_RWMMIO_H + +#include + +DECLARE_EVENT_CLASS(rwmmio_rw_template, + + TP_PROTO(unsigned long caller, u64 val, u8 width, volatile void __iomem *addr), + + TP_ARGS(caller, val, width, addr), + + TP_STRUCT__entry( + __field(unsigned long, caller) + __field(unsigned long, addr) + __field(u64, val) + __field(u8, width) + ), + + TP_fast_assign( + __entry->caller = caller; + __entry->val = val; + __entry->addr = (unsigned long)addr; + __entry->width = width; + ), + + TP_printk("%pS width=%d val=%#llx addr=%#lx", + (void *)__entry->caller, __entry->width, + __entry->val, __entry->addr) +); + +DEFINE_EVENT(rwmmio_rw_template, rwmmio_write, + TP_PROTO(unsigned long caller, u64 val, u8 width, volatile void __iomem *addr), + TP_ARGS(caller, val, width, addr) +); + +DEFINE_EVENT(rwmmio_rw_template, rwmmio_post_write, + TP_PROTO(unsigned long caller, u64 val, u8 width, volatile void __iomem *addr), + TP_ARGS(caller, val, width, addr) +); + +TRACE_EVENT(rwmmio_read, + + TP_PROTO(unsigned long caller, u8 width, const volatile void __iomem *addr), + + TP_ARGS(caller, width, addr), + + TP_STRUCT__entry( + __field(unsigned long, caller) + __field(unsigned long, addr) + __field(u8, width) + ), + + TP_fast_assign( + __entry->caller = caller; + __entry->addr = (unsigned long)addr; + __entry->width = width; + ), + + TP_printk("%pS width=%d addr=%#lx", + (void *)__entry->caller, __entry->width, __entry->addr) +); + +TRACE_EVENT(rwmmio_post_read, + + TP_PROTO(unsigned long caller, u64 val, u8 width, const volatile void __iomem *addr), + + TP_ARGS(caller, val, width, addr), + + TP_STRUCT__entry( + __field(unsigned long, caller) + __field(unsigned long, addr) + __field(u64, val) + __field(u8, width) + ), + + TP_fast_assign( + __entry->caller = caller; + __entry->val = val; + __entry->addr = (unsigned long)addr; + __entry->width = width; + ), + + TP_printk("%pS width=%d val=%#llx addr=%#lx", + (void *)__entry->caller, __entry->width, + __entry->val, __entry->addr) +); + +#endif /* _TRACE_RWMMIO_H */ + +#include diff --git a/lib/Kconfig b/lib/Kconfig index 6a843639814f..80aeceee88ed 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -118,6 +118,13 @@ config INDIRECT_IOMEM_FALLBACK mmio accesses when the IO memory address is not a registered emulated region. +config TRACE_MMIO_ACCESS + bool "Register read/write tracing" + depends on TRACING && ARCH_HAVE_TRACE_MMIO_ACCESS + help + Create tracepoints for MMIO read/write operations. These trace events + can be used for logging all MMIO read/write operations. + source "lib/crypto/Kconfig" config CRC_CCITT diff --git a/lib/Makefile b/lib/Makefile index ea54294d73bf..07917a40c91f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -151,6 +151,8 @@ lib-y += logic_pio.o lib-$(CONFIG_INDIRECT_IOMEM) += logic_iomem.o +obj-$(CONFIG_TRACE_MMIO_ACCESS) += trace_readwrite.o + obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o obj-$(CONFIG_BTREE) += btree.o diff --git a/lib/trace_readwrite.c b/lib/trace_readwrite.c new file mode 100644 index 000000000000..88637038b30c --- /dev/null +++ b/lib/trace_readwrite.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Register read and write tracepoints + * + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +#ifdef CONFIG_TRACE_MMIO_ACCESS +void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr, + unsigned long caller_addr) +{ + trace_rwmmio_write(caller_addr, val, width, addr); +} +EXPORT_SYMBOL_GPL(log_write_mmio); +EXPORT_TRACEPOINT_SYMBOL_GPL(rwmmio_write); + +void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr, + unsigned long caller_addr) +{ + trace_rwmmio_post_write(caller_addr, val, width, addr); +} +EXPORT_SYMBOL_GPL(log_post_write_mmio); +EXPORT_TRACEPOINT_SYMBOL_GPL(rwmmio_post_write); + +void log_read_mmio(u8 width, const volatile void __iomem *addr, + unsigned long caller_addr) +{ + trace_rwmmio_read(caller_addr, width, addr); +} +EXPORT_SYMBOL_GPL(log_read_mmio); +EXPORT_TRACEPOINT_SYMBOL_GPL(rwmmio_read); + +void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr, + unsigned long caller_addr) +{ + trace_rwmmio_post_read(caller_addr, val, width, addr); +} +EXPORT_SYMBOL_GPL(log_post_read_mmio); +EXPORT_TRACEPOINT_SYMBOL_GPL(rwmmio_post_read); +#endif /* CONFIG_TRACE_MMIO_ACCESS */ -- cgit v1.2.3 From 210031971cdd25a2a2b70c190de98c237db0731f Mon Sep 17 00:00:00 2001 From: Sai Prakash Ranjan Date: Wed, 18 May 2022 22:14:16 +0530 Subject: asm-generic/io: Add logging support for MMIO accessors Add logging support for MMIO high level accessors such as read{b,w,l,q} and their relaxed versions to aid in debugging unexpected crashes/hangs caused by the corresponding MMIO operation. Signed-off-by: Sai Prakash Ranjan Signed-off-by: Arnd Bergmann --- include/asm-generic/io.h | 91 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 7ce93aaf69f8..9c5114335a2d 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h @@ -10,6 +10,7 @@ #include /* I/O is all done through memory accesses */ #include /* for memset() and memcpy() */ #include +#include #ifdef CONFIG_GENERIC_IOMAP #include @@ -61,6 +62,44 @@ #define __io_par(v) __io_ar(v) #endif +/* + * "__DISABLE_TRACE_MMIO__" flag can be used to disable MMIO tracing for + * specific kernel drivers in case of excessive/unwanted logging. + * + * Usage: Add a #define flag at the beginning of the driver file. + * Ex: #define __DISABLE_TRACE_MMIO__ + * #include <...> + * ... + */ +#if IS_ENABLED(CONFIG_TRACE_MMIO_ACCESS) && !(defined(__DISABLE_TRACE_MMIO__)) +#include + +DECLARE_TRACEPOINT(rwmmio_write); +DECLARE_TRACEPOINT(rwmmio_post_write); +DECLARE_TRACEPOINT(rwmmio_read); +DECLARE_TRACEPOINT(rwmmio_post_read); + +void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr, + unsigned long caller_addr); +void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr, + unsigned long caller_addr); +void log_read_mmio(u8 width, const volatile void __iomem *addr, + unsigned long caller_addr); +void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr, + unsigned long caller_addr); + +#else + +static inline void log_write_mmio(u64 val, u8 width, volatile void __iomem *addr, + unsigned long caller_addr) {} +static inline void log_post_write_mmio(u64 val, u8 width, volatile void __iomem *addr, + unsigned long caller_addr) {} +static inline void log_read_mmio(u8 width, const volatile void __iomem *addr, + unsigned long caller_addr) {} +static inline void log_post_read_mmio(u64 val, u8 width, const volatile void __iomem *addr, + unsigned long caller_addr) {} + +#endif /* CONFIG_TRACE_MMIO_ACCESS */ /* * __raw_{read,write}{b,w,l,q}() access memory in native endianness. @@ -149,9 +188,11 @@ static inline u8 readb(const volatile void __iomem *addr) { u8 val; + log_read_mmio(8, addr, _THIS_IP_); __io_br(); val = __raw_readb(addr); __io_ar(val); + log_post_read_mmio(val, 8, addr, _THIS_IP_); return val; } #endif @@ -162,9 +203,11 @@ static inline u16 readw(const volatile void __iomem *addr) { u16 val; + log_read_mmio(16, addr, _THIS_IP_); __io_br(); val = __le16_to_cpu((__le16 __force)__raw_readw(addr)); __io_ar(val); + log_post_read_mmio(val, 16, addr, _THIS_IP_); return val; } #endif @@ -175,9 +218,11 @@ static inline u32 readl(const volatile void __iomem *addr) { u32 val; + log_read_mmio(32, addr, _THIS_IP_); __io_br(); val = __le32_to_cpu((__le32 __force)__raw_readl(addr)); __io_ar(val); + log_post_read_mmio(val, 32, addr, _THIS_IP_); return val; } #endif @@ -189,9 +234,11 @@ static inline u64 readq(const volatile void __iomem *addr) { u64 val; + log_read_mmio(64, addr, _THIS_IP_); __io_br(); val = __le64_to_cpu(__raw_readq(addr)); __io_ar(val); + log_post_read_mmio(val, 64, addr, _THIS_IP_); return val; } #endif @@ -201,9 +248,11 @@ static inline u64 readq(const volatile void __iomem *addr) #define writeb writeb static inline void writeb(u8 value, volatile void __iomem *addr) { + log_write_mmio(value, 8, addr, _THIS_IP_); __io_bw(); __raw_writeb(value, addr); __io_aw(); + log_post_write_mmio(value, 8, addr, _THIS_IP_); } #endif @@ -211,9 +260,11 @@ static inline void writeb(u8 value, volatile void __iomem *addr) #define writew writew static inline void writew(u16 value, volatile void __iomem *addr) { + log_write_mmio(value, 16, addr, _THIS_IP_); __io_bw(); __raw_writew((u16 __force)cpu_to_le16(value), addr); __io_aw(); + log_post_write_mmio(value, 16, addr, _THIS_IP_); } #endif @@ -221,9 +272,11 @@ static inline void writew(u16 value, volatile void __iomem *addr) #define writel writel static inline void writel(u32 value, volatile void __iomem *addr) { + log_write_mmio(value, 32, addr, _THIS_IP_); __io_bw(); __raw_writel((u32 __force)__cpu_to_le32(value), addr); __io_aw(); + log_post_write_mmio(value, 32, addr, _THIS_IP_); } #endif @@ -232,9 +285,11 @@ static inline void writel(u32 value, volatile void __iomem *addr) #define writeq writeq static inline void writeq(u64 value, volatile void __iomem *addr) { + log_write_mmio(value, 64, addr, _THIS_IP_); __io_bw(); __raw_writeq(__cpu_to_le64(value), addr); __io_aw(); + log_post_write_mmio(value, 64, addr, _THIS_IP_); } #endif #endif /* CONFIG_64BIT */ @@ -248,7 +303,12 @@ static inline void writeq(u64 value, volatile void __iomem *addr) #define readb_relaxed readb_relaxed static inline u8 readb_relaxed(const volatile void __iomem *addr) { - return __raw_readb(addr); + u8 val; + + log_read_mmio(8, addr, _THIS_IP_); + val = __raw_readb(addr); + log_post_read_mmio(val, 8, addr, _THIS_IP_); + return val; } #endif @@ -256,7 +316,12 @@ static inline u8 readb_relaxed(const volatile void __iomem *addr) #define readw_relaxed readw_relaxed static inline u16 readw_relaxed(const volatile void __iomem *addr) { - return __le16_to_cpu(__raw_readw(addr)); + u16 val; + + log_read_mmio(16, addr, _THIS_IP_); + val = __le16_to_cpu(__raw_readw(addr)); + log_post_read_mmio(val, 16, addr, _THIS_IP_); + return val; } #endif @@ -264,7 +329,12 @@ static inline u16 readw_relaxed(const volatile void __iomem *addr) #define readl_relaxed readl_relaxed static inline u32 readl_relaxed(const volatile void __iomem *addr) { - return __le32_to_cpu(__raw_readl(addr)); + u32 val; + + log_read_mmio(32, addr, _THIS_IP_); + val = __le32_to_cpu(__raw_readl(addr)); + log_post_read_mmio(val, 32, addr, _THIS_IP_); + return val; } #endif @@ -272,7 +342,12 @@ static inline u32 readl_relaxed(const volatile void __iomem *addr) #define readq_relaxed readq_relaxed static inline u64 readq_relaxed(const volatile void __iomem *addr) { - return __le64_to_cpu(__raw_readq(addr)); + u64 val; + + log_read_mmio(64, addr, _THIS_IP_); + val = __le64_to_cpu(__raw_readq(addr)); + log_post_read_mmio(val, 64, addr, _THIS_IP_); + return val; } #endif @@ -280,7 +355,9 @@ static inline u64 readq_relaxed(const volatile void __iomem *addr) #define writeb_relaxed writeb_relaxed static inline void writeb_relaxed(u8 value, volatile void __iomem *addr) { + log_write_mmio(value, 8, addr, _THIS_IP_); __raw_writeb(value, addr); + log_post_write_mmio(value, 8, addr, _THIS_IP_); } #endif @@ -288,7 +365,9 @@ static inline void writeb_relaxed(u8 value, volatile void __iomem *addr) #define writew_relaxed writew_relaxed static inline void writew_relaxed(u16 value, volatile void __iomem *addr) { + log_write_mmio(value, 16, addr, _THIS_IP_); __raw_writew(cpu_to_le16(value), addr); + log_post_write_mmio(value, 16, addr, _THIS_IP_); } #endif @@ -296,7 +375,9 @@ static inline void writew_relaxed(u16 value, volatile void __iomem *addr) #define writel_relaxed writel_relaxed static inline void writel_relaxed(u32 value, volatile void __iomem *addr) { + log_write_mmio(value, 32, addr, _THIS_IP_); __raw_writel(__cpu_to_le32(value), addr); + log_post_write_mmio(value, 32, addr, _THIS_IP_); } #endif @@ -304,7 +385,9 @@ static inline void writel_relaxed(u32 value, volatile void __iomem *addr) #define writeq_relaxed writeq_relaxed static inline void writeq_relaxed(u64 value, volatile void __iomem *addr) { + log_write_mmio(value, 64, addr, _THIS_IP_); __raw_writeq(__cpu_to_le64(value), addr); + log_post_write_mmio(value, 64, addr, _THIS_IP_); } #endif -- cgit v1.2.3 From 10f09307199da274584b8170a41228ca6dfed6d3 Mon Sep 17 00:00:00 2001 From: Nuno Sá Date: Fri, 10 Jun 2022 10:45:30 +0200 Subject: iio: core: drop of.h from iio.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no reason to include OF as we only need to forward declare 'of_phandle_args'. Previously, some drivers were actually relying on this for some headers (those were already fixed). Signed-off-by: Nuno Sá Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220610084545.547700-20-nuno.sa@analog.com Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 4e21a82b3756..d9b4a9ca9a0f 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -11,13 +11,14 @@ #include #include #include -#include /* IIO TODO LIST */ /* * Provide means of adjusting timer accuracy. * Currently assumes nano seconds. */ +struct of_phandle_args; + enum iio_shared_by { IIO_SEPARATE, IIO_SHARED_BY_TYPE, -- cgit v1.2.3 From fb91526b5fb04133799bc708661b467226caa032 Mon Sep 17 00:00:00 2001 From: Rex-BC Chen Date: Mon, 23 May 2022 17:33:40 +0800 Subject: dt-bindings: reset: mediatek: Add infra_ao reset index for MT8192/MT8195 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support reset of infra_ao, add the index of infra_ao reset of thermal/svs/pcei for MT8192 and thermal/svs for MT8195. Signed-off-by: Rex-BC Chen Acked-by: Krzysztof Kozlowski Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Nícolas F. R. A. Prado [Nícolas: Test for MT8192] Tested-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20220523093346.28493-14-rex-bc.chen@mediatek.com Signed-off-by: Stephen Boyd --- include/dt-bindings/reset/mt8192-resets.h | 8 ++++++++ include/dt-bindings/reset/mt8195-resets.h | 6 ++++++ 2 files changed, 14 insertions(+) (limited to 'include') diff --git a/include/dt-bindings/reset/mt8192-resets.h b/include/dt-bindings/reset/mt8192-resets.h index 764ca9910fa9..12e2087c90a3 100644 --- a/include/dt-bindings/reset/mt8192-resets.h +++ b/include/dt-bindings/reset/mt8192-resets.h @@ -7,6 +7,7 @@ #ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8192 #define _DT_BINDINGS_RESET_CONTROLLER_MT8192 +/* TOPRGU resets */ #define MT8192_TOPRGU_MM_SW_RST 1 #define MT8192_TOPRGU_MFG_SW_RST 2 #define MT8192_TOPRGU_VENC_SW_RST 3 @@ -30,4 +31,11 @@ /* MMSYS resets */ #define MT8192_MMSYS_SW0_RST_B_DISP_DSI0 15 +/* INFRA resets */ +#define MT8192_INFRA_RST0_THERM_CTRL_SWRST 0 +#define MT8192_INFRA_RST2_PEXTP_PHY_SWRST 1 +#define MT8192_INFRA_RST3_THERM_CTRL_PTP_SWRST 2 +#define MT8192_INFRA_RST4_PCIE_TOP_SWRST 3 +#define MT8192_INFRA_RST4_THERM_CTRL_MCU_SWRST 4 + #endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8192 */ diff --git a/include/dt-bindings/reset/mt8195-resets.h b/include/dt-bindings/reset/mt8195-resets.h index a26bccc8b957..0b1937f14b36 100644 --- a/include/dt-bindings/reset/mt8195-resets.h +++ b/include/dt-bindings/reset/mt8195-resets.h @@ -7,6 +7,7 @@ #ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8195 #define _DT_BINDINGS_RESET_CONTROLLER_MT8195 +/* TOPRGU resets */ #define MT8195_TOPRGU_CONN_MCU_SW_RST 0 #define MT8195_TOPRGU_INFRA_GRST_SW_RST 1 #define MT8195_TOPRGU_APU_SW_RST 2 @@ -26,4 +27,9 @@ #define MT8195_TOPRGU_SW_RST_NUM 16 +/* INFRA resets */ +#define MT8195_INFRA_RST0_THERM_CTRL_SWRST 0 +#define MT8195_INFRA_RST3_THERM_CTRL_PTP_SWRST 1 +#define MT8195_INFRA_RST4_THERM_CTRL_MCU_SWRST 2 + #endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8195 */ -- cgit v1.2.3 From 5ea61b478f30c7083fc9048934220f20a3089782 Mon Sep 17 00:00:00 2001 From: Rex-BC Chen Date: Mon, 23 May 2022 17:33:44 +0800 Subject: dt-bindings: reset: mediatek: Add infra_ao reset index for MT8186 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support reset of infra_ao, add the index of infra_ao reset of thermal/svs for MT8186. Signed-off-by: Rex-BC Chen Acked-by: Rob Herring Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220523093346.28493-18-rex-bc.chen@mediatek.com Signed-off-by: Stephen Boyd --- include/dt-bindings/reset/mt8186-resets.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/dt-bindings/reset/mt8186-resets.h b/include/dt-bindings/reset/mt8186-resets.h index 5f850370c42c..2e9029c22f38 100644 --- a/include/dt-bindings/reset/mt8186-resets.h +++ b/include/dt-bindings/reset/mt8186-resets.h @@ -7,6 +7,7 @@ #ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8186 #define _DT_BINDINGS_RESET_CONTROLLER_MT8186 +/* TOPRGU resets */ #define MT8186_TOPRGU_INFRA_SW_RST 0 #define MT8186_TOPRGU_MM_SW_RST 1 #define MT8186_TOPRGU_MFG_SW_RST 2 @@ -33,4 +34,8 @@ /* MMSYS resets */ #define MT8186_MMSYS_SW0_RST_B_DISP_DSI0 19 +/* INFRA resets */ +#define MT8186_INFRA_THERMAL_CTRL_RST 0 +#define MT8186_INFRA_PTP_CTRL_RST 1 + #endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8186 */ -- cgit v1.2.3 From af89cd45603483135bdd238fcb3fa871155a0ae1 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 20 May 2022 09:57:34 +0200 Subject: clk: Improve documentation for devm_clk_get() and its optional variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make use of "Context:" and "Return:". Mention that the clk is not to be expected to be prepared, previously only not being enabled was mentioned which probably dates from the times when the concept of clk preparation wasn't invented yet. Also describe devm_clk_get_optional() fully instead of just referencing devm_clk_get(). Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220520075737.758761-2-u.kleine-koenig@pengutronix.de Reviewed-by: Russell King (Oracle) Signed-off-by: Stephen Boyd --- include/linux/clk.h | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/clk.h b/include/linux/clk.h index 39faa54efe88..c8fc398d2ad7 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -443,15 +443,16 @@ int __must_check devm_clk_bulk_get_all(struct device *dev, * @dev: device for clock "consumer" * @id: clock consumer ID * - * Returns a struct clk corresponding to the clock producer, or + * Context: May sleep. + * + * Return: a struct clk corresponding to the clock producer, or * valid IS_ERR() condition containing errno. The implementation * uses @dev and @id to determine the clock consumer, and thereby * the clock producer. (IOW, @id may be identical strings, but * clk_get may return different clock producers depending on @dev.) * - * Drivers must assume that the clock source is not enabled. - * - * devm_clk_get should not be called from within interrupt context. + * Drivers must assume that the clock source is neither prepared nor + * enabled. * * The clock will automatically be freed when the device is unbound * from the bus. @@ -464,8 +465,20 @@ struct clk *devm_clk_get(struct device *dev, const char *id); * @dev: device for clock "consumer" * @id: clock consumer ID * - * Behaves the same as devm_clk_get() except where there is no clock producer. - * In this case, instead of returning -ENOENT, the function returns NULL. + * Context: May sleep. + * + * Return: a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. The implementation + * uses @dev and @id to determine the clock consumer, and thereby + * the clock producer. If no such clk is found, it returns NULL + * which serves as a dummy clk. That's the only difference compared + * to devm_clk_get(). + * + * Drivers must assume that the clock source is neither prepared nor + * enabled. + * + * The clock will automatically be freed when the device is unbound + * from the bus. */ struct clk *devm_clk_get_optional(struct device *dev, const char *id); -- cgit v1.2.3 From 7ef9651e9792b08eb310c6beb202cbc947f43cab Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 20 May 2022 09:57:36 +0200 Subject: clk: Provide new devm_clk helpers for prepared and enabled clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a driver keeps a clock prepared (or enabled) during the whole lifetime of the driver, these helpers allow to simplify the drivers. Reviewed-by: Jonathan Cameron Reviewed-by: Alexandru Ardelean Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20220520075737.758761-4-u.kleine-koenig@pengutronix.de Signed-off-by: Stephen Boyd --- drivers/clk/clk-devres.c | 27 ++++++++++++ include/linux/clk.h | 109 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) (limited to 'include') diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index c822f4ef1584..43ccd20e0298 100644 --- a/drivers/clk/clk-devres.c +++ b/drivers/clk/clk-devres.c @@ -66,12 +66,39 @@ struct clk *devm_clk_get(struct device *dev, const char *id) } EXPORT_SYMBOL(devm_clk_get); +struct clk *devm_clk_get_prepared(struct device *dev, const char *id) +{ + return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare); +} +EXPORT_SYMBOL_GPL(devm_clk_get_prepared); + +struct clk *devm_clk_get_enabled(struct device *dev, const char *id) +{ + return __devm_clk_get(dev, id, clk_get, + clk_prepare_enable, clk_disable_unprepare); +} +EXPORT_SYMBOL_GPL(devm_clk_get_enabled); + struct clk *devm_clk_get_optional(struct device *dev, const char *id) { return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL); } EXPORT_SYMBOL(devm_clk_get_optional); +struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id) +{ + return __devm_clk_get(dev, id, clk_get_optional, + clk_prepare, clk_unprepare); +} +EXPORT_SYMBOL_GPL(devm_clk_get_optional_prepared); + +struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id) +{ + return __devm_clk_get(dev, id, clk_get_optional, + clk_prepare_enable, clk_disable_unprepare); +} +EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled); + struct clk_bulk_devres { struct clk_bulk_data *clks; int num_clks; diff --git a/include/linux/clk.h b/include/linux/clk.h index c8fc398d2ad7..c13061cabdfc 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -459,6 +459,47 @@ int __must_check devm_clk_bulk_get_all(struct device *dev, */ struct clk *devm_clk_get(struct device *dev, const char *id); +/** + * devm_clk_get_prepared - devm_clk_get() + clk_prepare() + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Context: May sleep. + * + * Return: a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. The implementation + * uses @dev and @id to determine the clock consumer, and thereby + * the clock producer. (IOW, @id may be identical strings, but + * clk_get may return different clock producers depending on @dev.) + * + * The returned clk (if valid) is prepared. Drivers must however assume + * that the clock is not enabled. + * + * The clock will automatically be unprepared and freed when the device + * is unbound from the bus. + */ +struct clk *devm_clk_get_prepared(struct device *dev, const char *id); + +/** + * devm_clk_get_enabled - devm_clk_get() + clk_prepare_enable() + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Context: May sleep. + * + * Return: a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. The implementation + * uses @dev and @id to determine the clock consumer, and thereby + * the clock producer. (IOW, @id may be identical strings, but + * clk_get may return different clock producers depending on @dev.) + * + * The returned clk (if valid) is prepared and enabled. + * + * The clock will automatically be disabled, unprepared and freed + * when the device is unbound from the bus. + */ +struct clk *devm_clk_get_enabled(struct device *dev, const char *id); + /** * devm_clk_get_optional - lookup and obtain a managed reference to an optional * clock producer. @@ -482,6 +523,50 @@ struct clk *devm_clk_get(struct device *dev, const char *id); */ struct clk *devm_clk_get_optional(struct device *dev, const char *id); +/** + * devm_clk_get_optional_prepared - devm_clk_get_optional() + clk_prepare() + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Context: May sleep. + * + * Return: a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. The implementation + * uses @dev and @id to determine the clock consumer, and thereby + * the clock producer. If no such clk is found, it returns NULL + * which serves as a dummy clk. That's the only difference compared + * to devm_clk_get_prepared(). + * + * The returned clk (if valid) is prepared. Drivers must however + * assume that the clock is not enabled. + * + * The clock will automatically be unprepared and freed when the + * device is unbound from the bus. + */ +struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id); + +/** + * devm_clk_get_optional_enabled - devm_clk_get_optional() + + * clk_prepare_enable() + * @dev: device for clock "consumer" + * @id: clock consumer ID + * + * Context: May sleep. + * + * Return: a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. The implementation + * uses @dev and @id to determine the clock consumer, and thereby + * the clock producer. If no such clk is found, it returns NULL + * which serves as a dummy clk. That's the only difference compared + * to devm_clk_get_enabled(). + * + * The returned clk (if valid) is prepared and enabled. + * + * The clock will automatically be disabled, unprepared and freed + * when the device is unbound from the bus. + */ +struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id); + /** * devm_get_clk_from_child - lookup and obtain a managed reference to a * clock producer from child node. @@ -826,12 +911,36 @@ static inline struct clk *devm_clk_get(struct device *dev, const char *id) return NULL; } +static inline struct clk *devm_clk_get_prepared(struct device *dev, + const char *id) +{ + return NULL; +} + +static inline struct clk *devm_clk_get_enabled(struct device *dev, + const char *id) +{ + return NULL; +} + static inline struct clk *devm_clk_get_optional(struct device *dev, const char *id) { return NULL; } +static inline struct clk *devm_clk_get_optional_prepared(struct device *dev, + const char *id) +{ + return NULL; +} + +static inline struct clk *devm_clk_get_optional_enabled(struct device *dev, + const char *id) +{ + return NULL; +} + static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { -- cgit v1.2.3 From 925d046e7e52c71c3531199ce137e141807ef740 Mon Sep 17 00:00:00 2001 From: Patrisious Haddad Date: Tue, 7 Jun 2022 14:32:44 +0300 Subject: RDMA/core: Add a netevent notifier to cma Add a netevent callback for cma, mainly to catch NETEVENT_NEIGH_UPDATE. Previously, when a system with failover MAC mechanism change its MAC address during a CM connection attempt, the RDMA-CM would take a lot of time till it disconnects and timesout due to the incorrect MAC address. Now when we get a NETEVENT_NEIGH_UPDATE we check if it is due to a failover MAC change and if so, we instantly destroy the CM and notify the user in order to spare the unnecessary waiting for the timeout. Link: https://lore.kernel.org/r/bb255c9e301cd50b905663b8e73f7f5133d0e4c5.1654601342.git.leonro@nvidia.com Signed-off-by: Patrisious Haddad Reviewed-by: Mark Zhang Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/cma.c | 81 +++++++++++++++++++++++++++++++++++++++++++ include/rdma/rdma_cm.h | 1 + 2 files changed, 82 insertions(+) (limited to 'include') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 0a17b1bb9547..46d06678dfbe 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -5047,10 +5048,87 @@ out: return ret; } +static void cma_netevent_work_handler(struct work_struct *_work) +{ + struct rdma_id_private *id_priv = + container_of(_work, struct rdma_id_private, id.net_work); + struct rdma_cm_event event = {}; + + mutex_lock(&id_priv->handler_mutex); + + if (READ_ONCE(id_priv->state) == RDMA_CM_DESTROYING || + READ_ONCE(id_priv->state) == RDMA_CM_DEVICE_REMOVAL) + goto out_unlock; + + event.event = RDMA_CM_EVENT_UNREACHABLE; + event.status = -ETIMEDOUT; + + if (cma_cm_event_handler(id_priv, &event)) { + __acquire(&id_priv->handler_mutex); + id_priv->cm_id.ib = NULL; + cma_id_put(id_priv); + destroy_id_handler_unlock(id_priv); + return; + } + +out_unlock: + mutex_unlock(&id_priv->handler_mutex); + cma_id_put(id_priv); +} + +static int cma_netevent_callback(struct notifier_block *self, + unsigned long event, void *ctx) +{ + struct id_table_entry *ips_node = NULL; + struct rdma_id_private *current_id; + struct neighbour *neigh = ctx; + unsigned long flags; + + if (event != NETEVENT_NEIGH_UPDATE) + return NOTIFY_DONE; + + spin_lock_irqsave(&id_table_lock, flags); + if (neigh->tbl->family == AF_INET6) { + struct sockaddr_in6 neigh_sock_6; + + neigh_sock_6.sin6_family = AF_INET6; + neigh_sock_6.sin6_addr = *(struct in6_addr *)neigh->primary_key; + ips_node = node_from_ndev_ip(&id_table, neigh->dev->ifindex, + (struct sockaddr *)&neigh_sock_6); + } else if (neigh->tbl->family == AF_INET) { + struct sockaddr_in neigh_sock_4; + + neigh_sock_4.sin_family = AF_INET; + neigh_sock_4.sin_addr.s_addr = *(__be32 *)(neigh->primary_key); + ips_node = node_from_ndev_ip(&id_table, neigh->dev->ifindex, + (struct sockaddr *)&neigh_sock_4); + } else + goto out; + + if (!ips_node) + goto out; + + list_for_each_entry(current_id, &ips_node->id_list, id_list_entry) { + if (!memcmp(current_id->id.route.addr.dev_addr.dst_dev_addr, + neigh->ha, ETH_ALEN)) + continue; + INIT_WORK(¤t_id->id.net_work, cma_netevent_work_handler); + cma_id_get(current_id); + queue_work(cma_wq, ¤t_id->id.net_work); + } +out: + spin_unlock_irqrestore(&id_table_lock, flags); + return NOTIFY_DONE; +} + static struct notifier_block cma_nb = { .notifier_call = cma_netdev_callback }; +static struct notifier_block cma_netevent_cb = { + .notifier_call = cma_netevent_callback +}; + static void cma_send_device_removal_put(struct rdma_id_private *id_priv) { struct rdma_cm_event event = { .event = RDMA_CM_EVENT_DEVICE_REMOVAL }; @@ -5273,6 +5351,7 @@ static int __init cma_init(void) ib_sa_register_client(&sa_client); register_netdevice_notifier(&cma_nb); + register_netevent_notifier(&cma_netevent_cb); ret = ib_register_client(&cma_client); if (ret) @@ -5287,6 +5366,7 @@ static int __init cma_init(void) err_ib: ib_unregister_client(&cma_client); err: + unregister_netevent_notifier(&cma_netevent_cb); unregister_netdevice_notifier(&cma_nb); ib_sa_unregister_client(&sa_client); unregister_pernet_subsys(&cma_pernet_operations); @@ -5299,6 +5379,7 @@ static void __exit cma_cleanup(void) { cma_configfs_exit(); ib_unregister_client(&cma_client); + unregister_netevent_notifier(&cma_netevent_cb); unregister_netdevice_notifier(&cma_nb); ib_sa_unregister_client(&sa_client); unregister_pernet_subsys(&cma_pernet_operations); diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index d989f030fae0..5b18e2e36ee6 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -108,6 +108,7 @@ struct rdma_cm_id { enum rdma_ucm_port_space ps; enum ib_qp_type qp_type; u32 port_num; + struct work_struct net_work; }; struct rdma_cm_id * -- cgit v1.2.3 From 5a0e4529d9aee8ce348f628ad476c9ddb6cf457d Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 24 May 2022 10:21:52 -0500 Subject: dmaengine: dw-edma: Remove unused irq field in struct dw_edma_chip The "irq" field of struct dw_edma_chip was never used. Remove it. Link: https://lore.kernel.org/r/20220524152159.2370739-2-Frank.Li@nxp.com Tested-by: Serge Semin Tested-by: Manivannan Sadhasivam Signed-off-by: Frank Li Signed-off-by: Bjorn Helgaas Reviewed-by: Serge Semin Reviewed-by: Manivannan Sadhasivam Acked-By: Vinod Koul --- drivers/dma/dw-edma/dw-edma-pcie.c | 1 - include/linux/dma/edma.h | 2 -- 2 files changed, 3 deletions(-) (limited to 'include') diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c index cee7aa231d7b..bc07923c3bc0 100644 --- a/drivers/dma/dw-edma/dw-edma-pcie.c +++ b/drivers/dma/dw-edma/dw-edma-pcie.c @@ -214,7 +214,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev, chip->dw = dw; chip->dev = dev; chip->id = pdev->devfn; - chip->irq = pdev->irq; dw->mf = vsec_data.mf; dw->nr_irqs = nr_irqs; diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h index cab6e18773da..d4333e721588 100644 --- a/include/linux/dma/edma.h +++ b/include/linux/dma/edma.h @@ -18,13 +18,11 @@ struct dw_edma; * struct dw_edma_chip - representation of DesignWare eDMA controller hardware * @dev: struct device of the eDMA controller * @id: instance ID - * @irq: irq line * @dw: struct dw_edma that is filed by dw_edma_probe() */ struct dw_edma_chip { struct device *dev; int id; - int irq; struct dw_edma *dw; }; -- cgit v1.2.3 From ee774c40fa32e3b2642bb2533bc54662ea8445c2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 15 Jun 2022 23:07:19 +0200 Subject: dt-bindings: efm32: remove bindings for deleted platform Commit cc6111375cec ("ARM: drop efm32 platform") removed the platform, so no need to still carry the bindings. Signed-off-by: Wolfram Sang Acked-by: Mark Brown Acked-by: Stephen Boyd Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220615210720.6363-1-wsa@kernel.org --- .../devicetree/bindings/clock/efm32-clock.txt | 11 ------ .../devicetree/bindings/i2c/i2c-efm32.txt | 33 ----------------- .../devicetree/bindings/serial/efm32-uart.txt | 20 ---------- .../devicetree/bindings/spi/efm32-spi.txt | 39 -------------------- include/dt-bindings/clock/efm32-cmu.h | 43 ---------------------- 5 files changed, 146 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/efm32-clock.txt delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-efm32.txt delete mode 100644 Documentation/devicetree/bindings/serial/efm32-uart.txt delete mode 100644 Documentation/devicetree/bindings/spi/efm32-spi.txt delete mode 100644 include/dt-bindings/clock/efm32-cmu.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/efm32-clock.txt b/Documentation/devicetree/bindings/clock/efm32-clock.txt deleted file mode 100644 index 263d293f6a10..000000000000 --- a/Documentation/devicetree/bindings/clock/efm32-clock.txt +++ /dev/null @@ -1,11 +0,0 @@ -* Clock bindings for Energy Micro efm32 Giant Gecko's Clock Management Unit - -Required properties: -- compatible: Should be "efm32gg,cmu" -- reg: Base address and length of the register set -- interrupts: Interrupt used by the CMU -- #clock-cells: Should be <1> - -The clock consumer should specify the desired clock by having the clock ID in -its "clocks" phandle cell. The header efm32-clk.h contains a list of available -IDs. diff --git a/Documentation/devicetree/bindings/i2c/i2c-efm32.txt b/Documentation/devicetree/bindings/i2c/i2c-efm32.txt deleted file mode 100644 index 3b30e54ae3c7..000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c-efm32.txt +++ /dev/null @@ -1,33 +0,0 @@ -* Energymicro efm32 i2c controller - -Required properties : - - - reg : Offset and length of the register set for the device - - compatible : should be "energymicro,efm32-i2c" - - interrupts : the interrupt number - - clocks : reference to the module clock - -Recommended properties : - - - clock-frequency : maximal I2C bus clock frequency in Hz. - - energymicro,location : Decides the location of the USART I/O pins. - Allowed range : [0 .. 6] - -Example: - i2c0: i2c@4000a000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "energymicro,efm32-i2c"; - reg = <0x4000a000 0x400>; - interrupts = <9>; - clocks = <&cmu clk_HFPERCLKI2C0>; - clock-frequency = <100000>; - energymicro,location = <3>; - - eeprom@50 { - compatible = "microchip,24c02"; - reg = <0x50>; - pagesize = <16>; - }; - }; - diff --git a/Documentation/devicetree/bindings/serial/efm32-uart.txt b/Documentation/devicetree/bindings/serial/efm32-uart.txt deleted file mode 100644 index 4f8d8fde0c1c..000000000000 --- a/Documentation/devicetree/bindings/serial/efm32-uart.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Energymicro efm32 UART - -Required properties: -- compatible : Should be "energymicro,efm32-uart" -- reg : Address and length of the register set -- interrupts : Should contain uart interrupt - -Optional properties: -- energymicro,location : Decides the location of the USART I/O pins. - Allowed range : [0 .. 5] - Default: 0 - -Example: - -uart@4000c400 { - compatible = "energymicro,efm32-uart"; - reg = <0x4000c400 0x400>; - interrupts = <15>; - energymicro,location = <0>; -}; diff --git a/Documentation/devicetree/bindings/spi/efm32-spi.txt b/Documentation/devicetree/bindings/spi/efm32-spi.txt deleted file mode 100644 index e0fa61a1be0c..000000000000 --- a/Documentation/devicetree/bindings/spi/efm32-spi.txt +++ /dev/null @@ -1,39 +0,0 @@ -* Energy Micro EFM32 SPI - -Required properties: -- #address-cells: see spi-bus.txt -- #size-cells: see spi-bus.txt -- compatible: should be "energymicro,efm32-spi" -- reg: Offset and length of the register set for the controller -- interrupts: pair specifying rx and tx irq -- clocks: phandle to the spi clock -- cs-gpios: see spi-bus.txt - -Recommended properties : -- energymicro,location: Value to write to the ROUTE register's LOCATION - bitfield to configure the pinmux for the device, see - datasheet for values. - If this property is not provided, keeping what is - already configured in the hardware, so its either the - reset default 0 or whatever the bootloader did. - -Example: - -spi1: spi@4000c400 { /* USART1 */ - #address-cells = <1>; - #size-cells = <0>; - compatible = "energymicro,efm32-spi"; - reg = <0x4000c400 0x400>; - interrupts = <15 16>; - clocks = <&cmu 20>; - cs-gpios = <&gpio 51 1>; // D3 - energymicro,location = <1>; - - ks8851@0 { - compatible = "ks8851"; - spi-max-frequency = <6000000>; - reg = <0>; - interrupt-parent = <&boardfpga>; - interrupts = <4>; - }; -}; diff --git a/include/dt-bindings/clock/efm32-cmu.h b/include/dt-bindings/clock/efm32-cmu.h deleted file mode 100644 index 4b48d15fe194..000000000000 --- a/include/dt-bindings/clock/efm32-cmu.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __DT_BINDINGS_CLOCK_EFM32_CMU_H -#define __DT_BINDINGS_CLOCK_EFM32_CMU_H - -#define clk_HFXO 0 -#define clk_HFRCO 1 -#define clk_LFXO 2 -#define clk_LFRCO 3 -#define clk_ULFRCO 4 -#define clk_AUXHFRCO 5 -#define clk_HFCLKNODIV 6 -#define clk_HFCLK 7 -#define clk_HFPERCLK 8 -#define clk_HFCORECLK 9 -#define clk_LFACLK 10 -#define clk_LFBCLK 11 -#define clk_WDOGCLK 12 -#define clk_HFCORECLKDMA 13 -#define clk_HFCORECLKAES 14 -#define clk_HFCORECLKUSBC 15 -#define clk_HFCORECLKUSB 16 -#define clk_HFCORECLKLE 17 -#define clk_HFCORECLKEBI 18 -#define clk_HFPERCLKUSART0 19 -#define clk_HFPERCLKUSART1 20 -#define clk_HFPERCLKUSART2 21 -#define clk_HFPERCLKUART0 22 -#define clk_HFPERCLKUART1 23 -#define clk_HFPERCLKTIMER0 24 -#define clk_HFPERCLKTIMER1 25 -#define clk_HFPERCLKTIMER2 26 -#define clk_HFPERCLKTIMER3 27 -#define clk_HFPERCLKACMP0 28 -#define clk_HFPERCLKACMP1 29 -#define clk_HFPERCLKI2C0 30 -#define clk_HFPERCLKI2C1 31 -#define clk_HFPERCLKGPIO 32 -#define clk_HFPERCLKVCMP 33 -#define clk_HFPERCLKPRS 34 -#define clk_HFPERCLKADC0 35 -#define clk_HFPERCLKDAC0 36 - -#endif /* __DT_BINDINGS_CLOCK_EFM32_CMU_H */ -- cgit v1.2.3 From e4a8864f74e9e9e4a7eb93952a4cfa35c165c930 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 10 Jun 2022 16:21:30 -0700 Subject: iosys-map: Fix typo in documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's one argument, vaddr_iomem, not 2 (vaddr and _iomem). Signed-off-by: Lucas De Marchi Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20220610232130.2865479-3-lucas.demarchi@intel.com --- include/linux/iosys-map.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h index e69a002d5aa4..4b8406ee8bc4 100644 --- a/include/linux/iosys-map.h +++ b/include/linux/iosys-map.h @@ -23,7 +23,7 @@ * memcpy(vaddr, src, len); * * void *vaddr_iomem = ...; // pointer to I/O memory - * memcpy_toio(vaddr, _iomem, src, len); + * memcpy_toio(vaddr_iomem, src, len); * * The user of such pointer may not have information about the mapping of that * region or may want to have a single code path to handle operations on that -- cgit v1.2.3 From cb2bf7c6e544d2df3a683d6012ac15a5276ef911 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Wed, 15 Jun 2022 17:42:03 +0530 Subject: scsi: ufs: host: ufs-exynos: Use already existing definition UFS core already uses RX_MIN_ACTIVATETIME_CAPABILITY macro, let's use the same in driver as well instead of having a different macro name for the same offset. Link: https://lore.kernel.org/r/20220615121204.16642-2-alim.akhtar@samsung.com Reviewed-by: Chanho Park Signed-off-by: Alim Akhtar Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-exynos.c | 5 +++-- include/ufs/unipro.h | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index 04728b5da040..f971569bafc7 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -651,8 +651,9 @@ static void exynos_ufs_config_phy_cap_attr(struct exynos_ufs *ufs) if (attr->rx_min_actv_time_cap) ufshcd_dme_set(hba, - UIC_ARG_MIB_SEL(RX_MIN_ACTIVATETIME_CAP, - i), attr->rx_min_actv_time_cap); + UIC_ARG_MIB_SEL( + RX_MIN_ACTIVATETIME_CAPABILITY, i), + attr->rx_min_actv_time_cap); if (attr->rx_hibern8_time_cap) ufshcd_dme_set(hba, diff --git a/include/ufs/unipro.h b/include/ufs/unipro.h index 0521f887e3ac..ade92e8d3676 100644 --- a/include/ufs/unipro.h +++ b/include/ufs/unipro.h @@ -69,7 +69,6 @@ #define RX_HS_G2_PREP_LENGTH_CAP 0x0096 #define RX_HS_G3_PREP_LENGTH_CAP 0x0097 #define RX_ADV_GRANULARITY_CAP 0x0098 -#define RX_MIN_ACTIVATETIME_CAP 0x008F #define RX_HIBERN8TIME_CAP 0x0092 #define RX_ADV_HIBERN8TIME_CAP 0x0099 #define RX_ADV_MIN_ACTIVATETIME_CAP 0x009A -- cgit v1.2.3 From c0d93b12f31c31748ca5d3349777c70f1e2a8228 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Wed, 15 Jun 2022 17:42:04 +0530 Subject: scsi: ufs: Rearrange addresses in increasing order Rearrange all the unipro and mphy addresses in their increasing order. Link: https://lore.kernel.org/r/20220615121204.16642-3-alim.akhtar@samsung.com Reviewed-by: Chanho Park Signed-off-by: Alim Akhtar Signed-off-by: Martin K. Petersen --- include/ufs/unipro.h | 102 +++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) (limited to 'include') diff --git a/include/ufs/unipro.h b/include/ufs/unipro.h index ade92e8d3676..4cbfe9272787 100644 --- a/include/ufs/unipro.h +++ b/include/ufs/unipro.h @@ -38,6 +38,18 @@ /* * M-RX Configuration Attributes */ +#define RX_HS_G1_SYNC_LENGTH_CAP 0x008B +#define RX_HS_G1_PREP_LENGTH_CAP 0x008C +#define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F +#define RX_HIBERN8TIME_CAPABILITY 0x0092 +#define RX_HS_G2_SYNC_LENGTH_CAP 0x0094 +#define RX_HS_G3_SYNC_LENGTH_CAP 0x0095 +#define RX_HS_G2_PREP_LENGTH_CAP 0x0096 +#define RX_HS_G3_PREP_LENGTH_CAP 0x0097 +#define RX_ADV_GRANULARITY_CAP 0x0098 +#define RX_HIBERN8TIME_CAP 0x0092 +#define RX_ADV_HIBERN8TIME_CAP 0x0099 +#define RX_ADV_MIN_ACTIVATETIME_CAP 0x009A #define RX_MODE 0x00A1 #define RX_HSRATE_SERIES 0x00A2 #define RX_HSGEAR 0x00A3 @@ -47,31 +59,19 @@ #define RX_ENTER_HIBERN8 0x00A7 #define RX_BYPASS_8B10B_ENABLE 0x00A8 #define RX_TERMINATION_FORCE_ENABLE 0x00A9 -#define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F -#define RX_HIBERN8TIME_CAPABILITY 0x0092 +#define RXCALCTRL 0x00B4 +#define RXSQCTRL 0x00B5 +#define CFGRXCDR8 0x00BA +#define CFGRXOVR8 0x00BD +#define CFGRXOVR6 0x00BF +#define RXDIRECTCTRL2 0x00C7 +#define CFGRXOVR4 0x00E9 #define RX_REFCLKFREQ 0x00EB #define RX_CFGCLKFREQVAL 0x00EC #define CFGWIDEINLN 0x00F0 -#define CFGRXCDR8 0x00BA #define ENARXDIRECTCFG4 0x00F2 -#define CFGRXOVR8 0x00BD -#define RXDIRECTCTRL2 0x00C7 #define ENARXDIRECTCFG3 0x00F3 -#define RXCALCTRL 0x00B4 #define ENARXDIRECTCFG2 0x00F4 -#define CFGRXOVR4 0x00E9 -#define RXSQCTRL 0x00B5 -#define CFGRXOVR6 0x00BF -#define RX_HS_G1_SYNC_LENGTH_CAP 0x008B -#define RX_HS_G1_PREP_LENGTH_CAP 0x008C -#define RX_HS_G2_SYNC_LENGTH_CAP 0x0094 -#define RX_HS_G3_SYNC_LENGTH_CAP 0x0095 -#define RX_HS_G2_PREP_LENGTH_CAP 0x0096 -#define RX_HS_G3_PREP_LENGTH_CAP 0x0097 -#define RX_ADV_GRANULARITY_CAP 0x0098 -#define RX_HIBERN8TIME_CAP 0x0092 -#define RX_ADV_HIBERN8TIME_CAP 0x0099 -#define RX_ADV_MIN_ACTIVATETIME_CAP 0x009A #define is_mphy_tx_attr(attr) (attr < RX_MODE) @@ -102,47 +102,50 @@ /* * PHY Adapter attributes */ -#define PA_ACTIVETXDATALANES 0x1560 -#define PA_ACTIVERXDATALANES 0x1580 -#define PA_TXTRAILINGCLOCKS 0x1564 #define PA_PHY_TYPE 0x1500 #define PA_AVAILTXDATALANES 0x1520 -#define PA_AVAILRXDATALANES 0x1540 -#define PA_MINRXTRAILINGCLOCKS 0x1543 -#define PA_TXPWRSTATUS 0x1567 -#define PA_RXPWRSTATUS 0x1582 -#define PA_TXFORCECLOCK 0x1562 -#define PA_TXPWRMODE 0x1563 -#define PA_LEGACYDPHYESCDL 0x1570 #define PA_MAXTXSPEEDFAST 0x1521 #define PA_MAXTXSPEEDSLOW 0x1522 #define PA_MAXRXSPEEDFAST 0x1541 #define PA_MAXRXSPEEDSLOW 0x1542 #define PA_TXLINKSTARTUPHS 0x1544 +#define PA_AVAILRXDATALANES 0x1540 +#define PA_MINRXTRAILINGCLOCKS 0x1543 #define PA_LOCAL_TX_LCC_ENABLE 0x155E +#define PA_ACTIVETXDATALANES 0x1560 +#define PA_CONNECTEDTXDATALANES 0x1561 +#define PA_TXFORCECLOCK 0x1562 +#define PA_TXPWRMODE 0x1563 +#define PA_TXTRAILINGCLOCKS 0x1564 #define PA_TXSPEEDFAST 0x1565 #define PA_TXSPEEDSLOW 0x1566 -#define PA_REMOTEVERINFO 0x15A0 +#define PA_TXPWRSTATUS 0x1567 #define PA_TXGEAR 0x1568 #define PA_TXTERMINATION 0x1569 #define PA_HSSERIES 0x156A +#define PA_LEGACYDPHYESCDL 0x1570 #define PA_PWRMODE 0x1571 +#define PA_ACTIVERXDATALANES 0x1580 +#define PA_CONNECTEDRXDATALANES 0x1581 +#define PA_RXPWRSTATUS 0x1582 #define PA_RXGEAR 0x1583 #define PA_RXTERMINATION 0x1584 #define PA_MAXRXPWMGEAR 0x1586 #define PA_MAXRXHSGEAR 0x1587 +#define PA_PACPREQTIMEOUT 0x1590 +#define PA_PACPREQEOBTIMEOUT 0x1591 +#define PA_REMOTEVERINFO 0x15A0 +#define PA_LOGICALLANEMAP 0x15A1 +#define PA_SLEEPNOCONFIGTIME 0x15A2 +#define PA_STALLNOCONFIGTIME 0x15A3 +#define PA_SAVECONFIGTIME 0x15A4 #define PA_RXHSUNTERMCAP 0x15A5 #define PA_RXLSTERMCAP 0x15A6 #define PA_GRANULARITY 0x15AA -#define PA_PACPREQTIMEOUT 0x1590 -#define PA_PACPREQEOBTIMEOUT 0x1591 #define PA_HIBERN8TIME 0x15A7 #define PA_LOCALVERINFO 0x15A9 #define PA_GRANULARITY 0x15AA #define PA_TACTIVATE 0x15A8 -#define PA_PACPFRAMECOUNT 0x15C0 -#define PA_PACPERRORCOUNT 0x15C1 -#define PA_PHYTESTCONTROL 0x15C2 #define PA_PWRMODEUSERDATA0 0x15B0 #define PA_PWRMODEUSERDATA1 0x15B1 #define PA_PWRMODEUSERDATA2 0x15B2 @@ -155,12 +158,9 @@ #define PA_PWRMODEUSERDATA9 0x15B9 #define PA_PWRMODEUSERDATA10 0x15BA #define PA_PWRMODEUSERDATA11 0x15BB -#define PA_CONNECTEDTXDATALANES 0x1561 -#define PA_CONNECTEDRXDATALANES 0x1581 -#define PA_LOGICALLANEMAP 0x15A1 -#define PA_SLEEPNOCONFIGTIME 0x15A2 -#define PA_STALLNOCONFIGTIME 0x15A3 -#define PA_SAVECONFIGTIME 0x15A4 +#define PA_PACPFRAMECOUNT 0x15C0 +#define PA_PACPERRORCOUNT 0x15C1 +#define PA_PHYTESTCONTROL 0x15C2 #define PA_TXHSADAPTTYPE 0x15D4 /* Adpat type for PA_TXHSADAPTTYPE attribute */ @@ -172,9 +172,9 @@ #define PA_HIBERN8_TIME_UNIT_US 100 /*Other attributes*/ +#define VS_POWERSTATE 0xD083 #define VS_MPHYCFGUPDT 0xD085 #define VS_DEBUGOMC 0xD09E -#define VS_POWERSTATE 0xD083 #define PA_GRANULARITY_MIN_VAL 1 #define PA_GRANULARITY_MAX_VAL 6 @@ -245,27 +245,27 @@ enum ufs_unipro_ver { /* * Data Link Layer Attributes */ +#define DL_TXPREEMPTIONCAP 0x2000 +#define DL_TC0TXMAXSDUSIZE 0x2001 +#define DL_TC0RXINITCREDITVAL 0x2002 +#define DL_TC1TXMAXSDUSIZE 0x2003 +#define DL_TC1RXINITCREDITVAL 0x2004 +#define DL_TC0TXBUFFERSIZE 0x2005 +#define DL_TC1TXBUFFERSIZE 0x2006 #define DL_TC0TXFCTHRESHOLD 0x2040 #define DL_FC0PROTTIMEOUTVAL 0x2041 #define DL_TC0REPLAYTIMEOUTVAL 0x2042 #define DL_AFC0REQTIMEOUTVAL 0x2043 #define DL_AFC0CREDITTHRESHOLD 0x2044 #define DL_TC0OUTACKTHRESHOLD 0x2045 +#define DL_PEERTC0PRESENT 0x2046 +#define DL_PEERTC0RXINITCREVAL 0x2047 #define DL_TC1TXFCTHRESHOLD 0x2060 #define DL_FC1PROTTIMEOUTVAL 0x2061 #define DL_TC1REPLAYTIMEOUTVAL 0x2062 #define DL_AFC1REQTIMEOUTVAL 0x2063 #define DL_AFC1CREDITTHRESHOLD 0x2064 #define DL_TC1OUTACKTHRESHOLD 0x2065 -#define DL_TXPREEMPTIONCAP 0x2000 -#define DL_TC0TXMAXSDUSIZE 0x2001 -#define DL_TC0RXINITCREDITVAL 0x2002 -#define DL_TC0TXBUFFERSIZE 0x2005 -#define DL_PEERTC0PRESENT 0x2046 -#define DL_PEERTC0RXINITCREVAL 0x2047 -#define DL_TC1TXMAXSDUSIZE 0x2003 -#define DL_TC1RXINITCREDITVAL 0x2004 -#define DL_TC1TXBUFFERSIZE 0x2006 #define DL_PEERTC1PRESENT 0x2066 #define DL_PEERTC1RXINITCREVAL 0x2067 -- cgit v1.2.3 From fc53683b45b053d94a660c417fd3d63cabc43b6f Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Thu, 16 Jun 2022 13:37:15 +0800 Subject: scsi: ufs: Export ufshcd_uic_change_pwr_mode() Export ufshcd_uic_change_pwr_mode() to allow vendors to use it for SoC-specific power mode change design limitations. Link: https://lore.kernel.org/r/20220616053725.5681-2-stanley.chu@mediatek.com Reviewed-by: Bart Van Assche Signed-off-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 3 ++- include/ufs/ufshcd.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index bb6cbd514a69..f484ba61472a 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4093,7 +4093,7 @@ out_unlock: * * Returns 0 on success, non-zero value on failure */ -static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) +int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) { struct uic_command uic_cmd = {0}; int ret; @@ -4118,6 +4118,7 @@ static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) out: return ret; } +EXPORT_SYMBOL_GPL(ufshcd_uic_change_pwr_mode); int ufshcd_link_recovery(struct ufs_hba *hba) { diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 991aea081ec7..cb66304bda3d 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1099,6 +1099,7 @@ extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, u32 *mib_val, u8 peer); extern int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode); +extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode); /* UIC command interfaces for DME primitives */ #define DME_LOCAL 0 -- cgit v1.2.3 From 3f9b6cec12e2d2b3bdf69d47979b7877985c55e0 Mon Sep 17 00:00:00 2001 From: CC Chou Date: Thu, 16 Jun 2022 13:37:17 +0800 Subject: scsi: ufs: ufs-mediatek: Introduce workaround for power mode change Some MediaTek SoC chips need special flow for power mode change, especially for chips supporting HS-G5. Enable the workaround by setting the host-specific capability. Link: https://lore.kernel.org/r/20220616053725.5681-4-stanley.chu@mediatek.com Reviewed-by: Stanley Chu Signed-off-by: CC Chou Signed-off-by: Eddie Huang Signed-off-by: Dennis Yu Signed-off-by: Peter Wang Signed-off-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-mediatek.c | 60 +++++++++++++++++++++++++++++++++++++++-- drivers/ufs/host/ufs-mediatek.h | 1 + include/ufs/unipro.h | 1 + 3 files changed, 60 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index beabc3ccd30b..2931fd21e38a 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -82,6 +82,13 @@ static bool ufs_mtk_is_broken_vcc(struct ufs_hba *hba) return !!(host->caps & UFS_MTK_CAP_BROKEN_VCC); } +static bool ufs_mtk_is_pmc_via_fastauto(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + return (host->caps & UFS_MTK_CAP_PMC_VIA_FASTAUTO); +} + static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) { u32 tmp; @@ -579,6 +586,9 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba) if (of_property_read_bool(np, "mediatek,ufs-broken-vcc")) host->caps |= UFS_MTK_CAP_BROKEN_VCC; + if (of_property_read_bool(np, "mediatek,ufs-pmc-via-fastauto")) + host->caps |= UFS_MTK_CAP_PMC_VIA_FASTAUTO; + dev_info(hba->dev, "caps: 0x%x", host->caps); } @@ -754,6 +764,26 @@ out: return err; } +static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba, + struct ufs_pa_layer_attr *dev_req_params) +{ + if (!ufs_mtk_is_pmc_via_fastauto(hba)) + return false; + + if (dev_req_params->hs_rate == hba->pwr_info.hs_rate) + return false; + + if (dev_req_params->pwr_tx != FAST_MODE && + dev_req_params->gear_tx < UFS_HS_G4) + return false; + + if (dev_req_params->pwr_rx != FAST_MODE && + dev_req_params->gear_rx < UFS_HS_G4) + return false; + + return true; +} + static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) @@ -763,8 +793,8 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, int ret; ufshcd_init_pwr_dev_param(&host_cap); - host_cap.hs_rx_gear = UFS_HS_G4; - host_cap.hs_tx_gear = UFS_HS_G4; + host_cap.hs_rx_gear = UFS_HS_G5; + host_cap.hs_tx_gear = UFS_HS_G5; ret = ufshcd_get_pwr_dev_param(&host_cap, dev_max_params, @@ -774,6 +804,32 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, __func__); } + if (ufs_mtk_pmc_via_fastauto(hba, dev_req_params)) { + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), true); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), UFS_HS_G1); + + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), true); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), UFS_HS_G1); + + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), + dev_req_params->lane_tx); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), + dev_req_params->lane_rx); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), + dev_req_params->hs_rate); + + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE), + PA_NO_ADAPT); + + ret = ufshcd_uic_change_pwr_mode(hba, + FASTAUTO_MODE << 4 | FASTAUTO_MODE); + + if (ret) { + dev_err(hba->dev, "%s: HSG1B FASTAUTO failed ret=%d\n", + __func__, ret); + } + } + if (host->hw_ver.major >= 3) { ret = ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx, diff --git a/drivers/ufs/host/ufs-mediatek.h b/drivers/ufs/host/ufs-mediatek.h index 414dca86c09f..7e1913769671 100644 --- a/drivers/ufs/host/ufs-mediatek.h +++ b/drivers/ufs/host/ufs-mediatek.h @@ -108,6 +108,7 @@ enum ufs_mtk_host_caps { UFS_MTK_CAP_VA09_PWR_CTRL = 1 << 1, UFS_MTK_CAP_DISABLE_AH8 = 1 << 2, UFS_MTK_CAP_BROKEN_VCC = 1 << 3, + UFS_MTK_CAP_PMC_VIA_FASTAUTO = 1 << 6, }; struct ufs_mtk_crypt_cfg { diff --git a/include/ufs/unipro.h b/include/ufs/unipro.h index 4cbfe9272787..6c553f98fe57 100644 --- a/include/ufs/unipro.h +++ b/include/ufs/unipro.h @@ -228,6 +228,7 @@ enum ufs_hs_gear_tag { UFS_HS_G2, /* HS Gear 2 */ UFS_HS_G3, /* HS Gear 3 */ UFS_HS_G4, /* HS Gear 4 */ + UFS_HS_G5 /* HS Gear 5 */ }; enum ufs_unipro_ver { -- cgit v1.2.3 From 1d6f9decb60a23cde2e0fbe0f89d5fc6d462ddd5 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Thu, 16 Jun 2022 13:37:23 +0800 Subject: scsi: ufs: Export regulator functions Export below regulator functions to allow vendors to customize regulator configuration in their own platforms. int ufshcd_populate_vreg(struct device *dev, const char *name, struct ufs_vreg **out_vreg); int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg); Link: https://lore.kernel.org/r/20220616053725.5681-10-stanley.chu@mediatek.com Signed-off-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 3 ++- drivers/ufs/host/ufshcd-pltfrm.c | 5 +++-- drivers/ufs/host/ufshcd-pltfrm.h | 2 ++ include/ufs/ufshcd.h | 2 ++ 4 files changed, 9 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 295a900d39a3..cdea7edeb14d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8415,7 +8415,7 @@ static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on) return ufshcd_toggle_vreg(hba->dev, info->vdd_hba, on); } -static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg) +int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg) { int ret = 0; @@ -8431,6 +8431,7 @@ static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg) out: return ret; } +EXPORT_SYMBOL_GPL(ufshcd_get_vreg); static int ufshcd_init_vreg(struct ufs_hba *hba) { diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index e7332cc65b1f..2dd9c660531b 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -109,8 +109,8 @@ out: } #define MAX_PROP_SIZE 32 -static int ufshcd_populate_vreg(struct device *dev, const char *name, - struct ufs_vreg **out_vreg) +int ufshcd_populate_vreg(struct device *dev, const char *name, + struct ufs_vreg **out_vreg) { char prop_name[MAX_PROP_SIZE]; struct ufs_vreg *vreg = NULL; @@ -145,6 +145,7 @@ out: *out_vreg = vreg; return 0; } +EXPORT_SYMBOL_GPL(ufshcd_populate_vreg); /** * ufshcd_parse_regulator_info - get regulator info from device tree diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h index 43c2e412bd99..5130c9471dc2 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.h +++ b/drivers/ufs/host/ufshcd-pltfrm.h @@ -32,5 +32,7 @@ void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param); int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops); void ufshcd_pltfrm_shutdown(struct platform_device *pdev); +int ufshcd_populate_vreg(struct device *dev, const char *name, + struct ufs_vreg **out_vreg); #endif /* UFSHCD_PLTFRM_H_ */ diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index cb66304bda3d..b5c9064a11d9 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1199,6 +1199,8 @@ void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); +int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg); + int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd); int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, -- cgit v1.2.3 From 6a33ed506416a74aea3071a72192fb06a3cc82df Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Thu, 16 Jun 2022 11:02:10 +0300 Subject: scsi: iscsi: Make iscsi_unregister_transport() return void This function always returns 0. We can make it return void to simplify the code. Also, no caller ever checks the return value of this function. Link: https://lore.kernel.org/r/20220616080210.18531-1-mgurtovoy@nvidia.com Reviewed-by: Mike Christie Signed-off-by: Max Gurtovoy Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_iscsi.c | 4 +--- include/scsi/scsi_transport_iscsi.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 2578db4c095d..360e73ee29d5 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -4807,7 +4807,7 @@ free_priv: } EXPORT_SYMBOL_GPL(iscsi_register_transport); -int iscsi_unregister_transport(struct iscsi_transport *tt) +void iscsi_unregister_transport(struct iscsi_transport *tt) { struct iscsi_internal *priv; unsigned long flags; @@ -4830,8 +4830,6 @@ int iscsi_unregister_transport(struct iscsi_transport *tt) sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group); device_unregister(&priv->dev); mutex_unlock(&rx_queue_mutex); - - return 0; } EXPORT_SYMBOL_GPL(iscsi_unregister_transport); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 9acb8422f680..695396a5f607 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -162,7 +162,7 @@ struct iscsi_transport { * transport registration upcalls */ extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt); -extern int iscsi_unregister_transport(struct iscsi_transport *tt); +extern void iscsi_unregister_transport(struct iscsi_transport *tt); /* * control plane upcalls -- cgit v1.2.3 From d687f621c518d791b5fffde8add3112d869b0b1b Mon Sep 17 00:00:00 2001 From: Delyan Kratunov Date: Tue, 14 Jun 2022 23:10:42 +0000 Subject: bpf: move bpf_prog to bpf.h In order to add a version of bpf_prog_run_array which accesses the bpf_prog->aux member, bpf_prog needs to be more than a forward declaration inside bpf.h. Given that filter.h already includes bpf.h, this merely reorders the type declarations for filter.h users. bpf.h users now have access to bpf_prog internals. Signed-off-by: Delyan Kratunov Link: https://lore.kernel.org/r/3ed7824e3948f22d84583649ccac0ff0d38b6b58.1655248076.git.delyank@fb.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 36 ++++++++++++++++++++++++++++++++++++ include/linux/filter.h | 34 ---------------------------------- 2 files changed, 36 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8e6092d0ea95..69106ae46464 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -5,6 +5,7 @@ #define _LINUX_BPF_H 1 #include +#include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -1084,6 +1086,40 @@ struct bpf_prog_aux { }; }; +struct bpf_prog { + u16 pages; /* Number of allocated pages */ + u16 jited:1, /* Is our filter JIT'ed? */ + jit_requested:1,/* archs need to JIT the prog */ + gpl_compatible:1, /* Is filter GPL compatible? */ + cb_access:1, /* Is control block accessed? */ + dst_needed:1, /* Do we need dst entry? */ + blinding_requested:1, /* needs constant blinding */ + blinded:1, /* Was blinded */ + is_func:1, /* program is a bpf function */ + kprobe_override:1, /* Do we override a kprobe? */ + has_callchain_buf:1, /* callchain buffer allocated? */ + enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */ + call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */ + call_get_func_ip:1, /* Do we call get_func_ip() */ + tstamp_type_access:1; /* Accessed __sk_buff->tstamp_type */ + enum bpf_prog_type type; /* Type of BPF program */ + enum bpf_attach_type expected_attach_type; /* For some prog types */ + u32 len; /* Number of filter blocks */ + u32 jited_len; /* Size of jited insns in bytes */ + u8 tag[BPF_TAG_SIZE]; + struct bpf_prog_stats __percpu *stats; + int __percpu *active; + unsigned int (*bpf_func)(const void *ctx, + const struct bpf_insn *insn); + struct bpf_prog_aux *aux; /* Auxiliary fields */ + struct sock_fprog_kern *orig_prog; /* Original BPF program */ + /* Instructions for interpreter */ + union { + DECLARE_FLEX_ARRAY(struct sock_filter, insns); + DECLARE_FLEX_ARRAY(struct bpf_insn, insnsi); + }; +}; + struct bpf_array_aux { /* Programs with direct jumps into programs part of this array. */ struct list_head poke_progs; diff --git a/include/linux/filter.h b/include/linux/filter.h index ed0c0ff42ad5..d0cbb31b1b4d 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -559,40 +559,6 @@ struct bpf_prog_stats { struct u64_stats_sync syncp; } __aligned(2 * sizeof(u64)); -struct bpf_prog { - u16 pages; /* Number of allocated pages */ - u16 jited:1, /* Is our filter JIT'ed? */ - jit_requested:1,/* archs need to JIT the prog */ - gpl_compatible:1, /* Is filter GPL compatible? */ - cb_access:1, /* Is control block accessed? */ - dst_needed:1, /* Do we need dst entry? */ - blinding_requested:1, /* needs constant blinding */ - blinded:1, /* Was blinded */ - is_func:1, /* program is a bpf function */ - kprobe_override:1, /* Do we override a kprobe? */ - has_callchain_buf:1, /* callchain buffer allocated? */ - enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */ - call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */ - call_get_func_ip:1, /* Do we call get_func_ip() */ - tstamp_type_access:1; /* Accessed __sk_buff->tstamp_type */ - enum bpf_prog_type type; /* Type of BPF program */ - enum bpf_attach_type expected_attach_type; /* For some prog types */ - u32 len; /* Number of filter blocks */ - u32 jited_len; /* Size of jited insns in bytes */ - u8 tag[BPF_TAG_SIZE]; - struct bpf_prog_stats __percpu *stats; - int __percpu *active; - unsigned int (*bpf_func)(const void *ctx, - const struct bpf_insn *insn); - struct bpf_prog_aux *aux; /* Auxiliary fields */ - struct sock_fprog_kern *orig_prog; /* Original BPF program */ - /* Instructions for interpreter */ - union { - DECLARE_FLEX_ARRAY(struct sock_filter, insns); - DECLARE_FLEX_ARRAY(struct bpf_insn, insnsi); - }; -}; - struct sk_filter { refcount_t refcnt; struct rcu_head rcu; -- cgit v1.2.3 From 8c7dcb84e3b744b2b70baa7a44a9b1881c33a9c9 Mon Sep 17 00:00:00 2001 From: Delyan Kratunov Date: Tue, 14 Jun 2022 23:10:46 +0000 Subject: bpf: implement sleepable uprobes by chaining gps uprobes work by raising a trap, setting a task flag from within the interrupt handler, and processing the actual work for the uprobe on the way back to userspace. As a result, uprobe handlers already execute in a might_fault/_sleep context. The primary obstacle to sleepable bpf uprobe programs is therefore on the bpf side. Namely, the bpf_prog_array attached to the uprobe is protected by normal rcu. In order for uprobe bpf programs to become sleepable, it has to be protected by the tasks_trace rcu flavor instead (and kfree() called after a corresponding grace period). Therefore, the free path for bpf_prog_array now chains a tasks_trace and normal grace periods one after the other. Users who iterate under tasks_trace read section would be safe, as would users who iterate under normal read sections (from non-sleepable locations). The downside is that the tasks_trace latency affects all perf_event-attached bpf programs (and not just uprobe ones). This is deemed safe given the possible attach rates for kprobe/uprobe/tp programs. Separately, non-sleepable programs need access to dynamically sized rcu-protected maps, so bpf_run_prog_array_sleepables now conditionally takes an rcu read section, in addition to the overarching tasks_trace section. Signed-off-by: Delyan Kratunov Link: https://lore.kernel.org/r/ce844d62a2fd0443b08c5ab02e95bc7149f9aeb1.1655248076.git.delyank@fb.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 52 +++++++++++++++++++++++++++++++++++++++++++++ kernel/bpf/core.c | 15 +++++++++++++ kernel/trace/bpf_trace.c | 4 ++-- kernel/trace/trace_uprobe.c | 5 ++--- 4 files changed, 71 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 69106ae46464..f3e88afdaffe 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -26,6 +26,7 @@ #include #include #include +#include struct bpf_verifier_env; struct bpf_verifier_log; @@ -1372,6 +1373,8 @@ extern struct bpf_empty_prog_array bpf_empty_prog_array; struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); void bpf_prog_array_free(struct bpf_prog_array *progs); +/* Use when traversal over the bpf_prog_array uses tasks_trace rcu */ +void bpf_prog_array_free_sleepable(struct bpf_prog_array *progs); int bpf_prog_array_length(struct bpf_prog_array *progs); bool bpf_prog_array_is_empty(struct bpf_prog_array *array); int bpf_prog_array_copy_to_user(struct bpf_prog_array *progs, @@ -1463,6 +1466,55 @@ bpf_prog_run_array(const struct bpf_prog_array *array, return ret; } +/* Notes on RCU design for bpf_prog_arrays containing sleepable programs: + * + * We use the tasks_trace rcu flavor read section to protect the bpf_prog_array + * overall. As a result, we must use the bpf_prog_array_free_sleepable + * in order to use the tasks_trace rcu grace period. + * + * When a non-sleepable program is inside the array, we take the rcu read + * section and disable preemption for that program alone, so it can access + * rcu-protected dynamically sized maps. + */ +static __always_inline u32 +bpf_prog_run_array_sleepable(const struct bpf_prog_array __rcu *array_rcu, + const void *ctx, bpf_prog_run_fn run_prog) +{ + const struct bpf_prog_array_item *item; + const struct bpf_prog *prog; + const struct bpf_prog_array *array; + struct bpf_run_ctx *old_run_ctx; + struct bpf_trace_run_ctx run_ctx; + u32 ret = 1; + + might_fault(); + + rcu_read_lock_trace(); + migrate_disable(); + + array = rcu_dereference_check(array_rcu, rcu_read_lock_trace_held()); + if (unlikely(!array)) + goto out; + old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx); + item = &array->items[0]; + while ((prog = READ_ONCE(item->prog))) { + if (!prog->aux->sleepable) + rcu_read_lock(); + + run_ctx.bpf_cookie = item->bpf_cookie; + ret &= run_prog(prog, ctx); + item++; + + if (!prog->aux->sleepable) + rcu_read_unlock(); + } + bpf_reset_run_ctx(old_run_ctx); +out: + migrate_enable(); + rcu_read_unlock_trace(); + return ret; +} + #ifdef CONFIG_BPF_SYSCALL DECLARE_PER_CPU(int, bpf_prog_active); extern struct mutex bpf_stats_enabled_mutex; diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index e78cc5eea4a5..b5ffebcce6cc 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2279,6 +2279,21 @@ void bpf_prog_array_free(struct bpf_prog_array *progs) kfree_rcu(progs, rcu); } +static void __bpf_prog_array_free_sleepable_cb(struct rcu_head *rcu) +{ + struct bpf_prog_array *progs; + + progs = container_of(rcu, struct bpf_prog_array, rcu); + kfree_rcu(progs, rcu); +} + +void bpf_prog_array_free_sleepable(struct bpf_prog_array *progs) +{ + if (!progs || progs == &bpf_empty_prog_array.hdr) + return; + call_rcu_tasks_trace(&progs->rcu, __bpf_prog_array_free_sleepable_cb); +} + int bpf_prog_array_length(struct bpf_prog_array *array) { struct bpf_prog_array_item *item; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 10b157a6d73e..d1c22594dbf9 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1936,7 +1936,7 @@ int perf_event_attach_bpf_prog(struct perf_event *event, event->prog = prog; event->bpf_cookie = bpf_cookie; rcu_assign_pointer(event->tp_event->prog_array, new_array); - bpf_prog_array_free(old_array); + bpf_prog_array_free_sleepable(old_array); unlock: mutex_unlock(&bpf_event_mutex); @@ -1962,7 +1962,7 @@ void perf_event_detach_bpf_prog(struct perf_event *event) bpf_prog_array_delete_safe(old_array, event->prog); } else { rcu_assign_pointer(event->tp_event->prog_array, new_array); - bpf_prog_array_free(old_array); + bpf_prog_array_free_sleepable(old_array); } bpf_prog_put(event->prog); diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 9711589273cd..0282c119b1b2 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "trace_dynevent.h" #include "trace_probe.h" @@ -1346,9 +1347,7 @@ static void __uprobe_perf_func(struct trace_uprobe *tu, if (bpf_prog_array_valid(call)) { u32 ret; - preempt_disable(); - ret = trace_call_bpf(call, regs); - preempt_enable(); + ret = bpf_prog_run_array_sleepable(call->prog_array, regs, bpf_prog_run); if (!ret) return; } -- cgit v1.2.3 From d92725256b4f22d084b813b37ddc394da79aacab Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Mon, 30 May 2022 14:34:50 -0400 Subject: mm: avoid unnecessary page fault retires on shared memory types I observed that for each of the shared file-backed page faults, we're very likely to retry one more time for the 1st write fault upon no page. It's because we'll need to release the mmap lock for dirty rate limit purpose with balance_dirty_pages_ratelimited() (in fault_dirty_shared_page()). Then after that throttling we return VM_FAULT_RETRY. We did that probably because VM_FAULT_RETRY is the only way we can return to the fault handler at that time telling it we've released the mmap lock. However that's not ideal because it's very likely the fault does not need to be retried at all since the pgtable was well installed before the throttling, so the next continuous fault (including taking mmap read lock, walk the pgtable, etc.) could be in most cases unnecessary. It's not only slowing down page faults for shared file-backed, but also add more mmap lock contention which is in most cases not needed at all. To observe this, one could try to write to some shmem page and look at "pgfault" value in /proc/vmstat, then we should expect 2 counts for each shmem write simply because we retried, and vm event "pgfault" will capture that. To make it more efficient, add a new VM_FAULT_COMPLETED return code just to show that we've completed the whole fault and released the lock. It's also a hint that we should very possibly not need another fault immediately on this page because we've just completed it. This patch provides a ~12% perf boost on my aarch64 test VM with a simple program sequentially dirtying 400MB shmem file being mmap()ed and these are the time it needs: Before: 650.980 ms (+-1.94%) After: 569.396 ms (+-1.38%) I believe it could help more than that. We need some special care on GUP and the s390 pgfault handler (for gmap code before returning from pgfault), the rest changes in the page fault handlers should be relatively straightforward. Another thing to mention is that mm_account_fault() does take this new fault as a generic fault to be accounted, unlike VM_FAULT_RETRY. I explicitly didn't touch hmm_vma_fault() and break_ksm() because they do not handle VM_FAULT_RETRY even with existing code, so I'm literally keeping them as-is. Link: https://lkml.kernel.org/r/20220530183450.42886-1-peterx@redhat.com Signed-off-by: Peter Xu Acked-by: Geert Uytterhoeven Acked-by: Peter Zijlstra (Intel) Acked-by: Johannes Weiner Acked-by: Vineet Gupta Acked-by: Guo Ren Acked-by: Max Filippov Acked-by: Christian Borntraeger Acked-by: Michael Ellerman (powerpc) Acked-by: Catalin Marinas Reviewed-by: Alistair Popple Reviewed-by: Ingo Molnar Acked-by: Russell King (Oracle) [arm part] Acked-by: Heiko Carstens Cc: Vasily Gorbik Cc: Stafford Horne Cc: David S. Miller Cc: Johannes Berg Cc: Brian Cain Cc: Richard Henderson Cc: Richard Weinberger Cc: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Janosch Frank Cc: Albert Ou Cc: Anton Ivanov Cc: Dave Hansen Cc: Borislav Petkov Cc: Sven Schnelle Cc: Andrea Arcangeli Cc: James Bottomley Cc: Al Viro Cc: Alexander Gordeev Cc: Jonas Bonn Cc: Will Deacon Cc: Vlastimil Babka Cc: Michal Simek Cc: Matt Turner Cc: Paul Mackerras Cc: David Hildenbrand Cc: Nicholas Piggin Cc: Palmer Dabbelt Cc: Stefan Kristiansson Cc: Paul Walmsley Cc: Ivan Kokshaysky Cc: Chris Zankel Cc: Hugh Dickins Cc: Dinh Nguyen Cc: Rich Felker Cc: H. Peter Anvin Cc: Andy Lutomirski Cc: Thomas Bogendoerfer Cc: Helge Deller Cc: Yoshinori Sato Signed-off-by: Andrew Morton --- arch/alpha/mm/fault.c | 4 ++++ arch/arc/mm/fault.c | 4 ++++ arch/arm/mm/fault.c | 4 ++++ arch/arm64/mm/fault.c | 4 ++++ arch/csky/mm/fault.c | 4 ++++ arch/hexagon/mm/vm_fault.c | 4 ++++ arch/ia64/mm/fault.c | 4 ++++ arch/m68k/mm/fault.c | 4 ++++ arch/microblaze/mm/fault.c | 4 ++++ arch/mips/mm/fault.c | 4 ++++ arch/nios2/mm/fault.c | 4 ++++ arch/openrisc/mm/fault.c | 4 ++++ arch/parisc/mm/fault.c | 4 ++++ arch/powerpc/mm/copro_fault.c | 5 +++++ arch/powerpc/mm/fault.c | 5 +++++ arch/riscv/mm/fault.c | 4 ++++ arch/s390/mm/fault.c | 12 ++++++++++++ arch/sh/mm/fault.c | 4 ++++ arch/sparc/mm/fault_32.c | 4 ++++ arch/sparc/mm/fault_64.c | 5 +++++ arch/um/kernel/trap.c | 4 ++++ arch/x86/mm/fault.c | 4 ++++ arch/xtensa/mm/fault.c | 4 ++++ include/linux/mm_types.h | 2 ++ mm/gup.c | 34 +++++++++++++++++++++++++++++++++- mm/memory.c | 2 +- 26 files changed, 139 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index ec20c1004abf..ef427a6bdd1a 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -155,6 +155,10 @@ retry: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c index dad27e4d69ff..5ca59a482632 100644 --- a/arch/arc/mm/fault.c +++ b/arch/arc/mm/fault.c @@ -146,6 +146,10 @@ retry: return; } + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + /* * Fault retry nuances, mmap_lock already relinquished by core mm */ diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index a062e07516dd..46cccd6bf705 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -322,6 +322,10 @@ retry: return 0; } + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return 0; + if (!(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_RETRY) { flags |= FAULT_FLAG_TRIED; diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index c5e11768e5c1..de166cdeb89a 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -608,6 +608,10 @@ retry: return 0; } + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return 0; + if (fault & VM_FAULT_RETRY) { mm_flags |= FAULT_FLAG_TRIED; goto retry; diff --git a/arch/csky/mm/fault.c b/arch/csky/mm/fault.c index 7215a46b6b8e..e15f736cca4b 100644 --- a/arch/csky/mm/fault.c +++ b/arch/csky/mm/fault.c @@ -285,6 +285,10 @@ good_area: return; } + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely((fault & VM_FAULT_RETRY) && (flags & FAULT_FLAG_ALLOW_RETRY))) { flags |= FAULT_FLAG_TRIED; diff --git a/arch/hexagon/mm/vm_fault.c b/arch/hexagon/mm/vm_fault.c index 4fac4b9eb316..f73c7cbfe326 100644 --- a/arch/hexagon/mm/vm_fault.c +++ b/arch/hexagon/mm/vm_fault.c @@ -96,6 +96,10 @@ good_area: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + /* The most common case -- we are done. */ if (likely(!(fault & VM_FAULT_ERROR))) { if (fault & VM_FAULT_RETRY) { diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 07379d1a227f..ef78c2d66cdd 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -139,6 +139,10 @@ retry: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { /* * We ran out of memory, or some other thing happened diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 71aa9f6315dc..4d2837eb3e2a 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -141,6 +141,10 @@ good_area: if (fault_signal_pending(fault, regs)) return 0; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return 0; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index a9626e6a68af..5c40c3ebe52f 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c @@ -222,6 +222,10 @@ good_area: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index b08bc556d30d..a27045f5a556 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -162,6 +162,10 @@ good_area: return; } + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/nios2/mm/fault.c b/arch/nios2/mm/fault.c index a32f14cd72f2..edaca0a6c1c1 100644 --- a/arch/nios2/mm/fault.c +++ b/arch/nios2/mm/fault.c @@ -139,6 +139,10 @@ good_area: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/openrisc/mm/fault.c b/arch/openrisc/mm/fault.c index 53b760af3bb7..b4762d66e9ef 100644 --- a/arch/openrisc/mm/fault.c +++ b/arch/openrisc/mm/fault.c @@ -165,6 +165,10 @@ good_area: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 84bc437be5cd..9ad80d4d3389 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -311,6 +311,10 @@ good_area: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { /* * We hit a shared mapping outside of the file, or some diff --git a/arch/powerpc/mm/copro_fault.c b/arch/powerpc/mm/copro_fault.c index c1cb21a00884..7c507fb48182 100644 --- a/arch/powerpc/mm/copro_fault.c +++ b/arch/powerpc/mm/copro_fault.c @@ -65,6 +65,11 @@ int copro_handle_mm_fault(struct mm_struct *mm, unsigned long ea, ret = 0; *flt = handle_mm_fault(vma, ea, is_write ? FAULT_FLAG_WRITE : 0, NULL); + + /* The fault is fully completed (including releasing mmap lock) */ + if (*flt & VM_FAULT_COMPLETED) + return 0; + if (unlikely(*flt & VM_FAULT_ERROR)) { if (*flt & VM_FAULT_OOM) { ret = -ENOMEM; diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index d53fed4eccbd..014005428687 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -511,6 +511,10 @@ retry: if (fault_signal_pending(fault, regs)) return user_mode(regs) ? 0 : SIGBUS; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + goto out; + /* * Handle the retry right now, the mmap_lock has been released in that * case. @@ -525,6 +529,7 @@ retry: if (unlikely(fault & VM_FAULT_ERROR)) return mm_fault_error(regs, address, fault); +out: /* * Major/minor page fault accounting. */ diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c index 40694f0cab9e..f2fbd1400b7c 100644 --- a/arch/riscv/mm/fault.c +++ b/arch/riscv/mm/fault.c @@ -326,6 +326,10 @@ good_area: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_RETRY)) { flags |= FAULT_FLAG_TRIED; diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index e173b6187ad5..973dcd05c293 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -433,6 +433,17 @@ retry: goto out_up; goto out; } + + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) { + if (gmap) { + mmap_read_lock(mm); + goto out_gmap; + } + fault = 0; + goto out; + } + if (unlikely(fault & VM_FAULT_ERROR)) goto out_up; @@ -452,6 +463,7 @@ retry: mmap_read_lock(mm); goto retry; } +out_gmap: if (IS_ENABLED(CONFIG_PGSTE) && gmap) { address = __gmap_link(gmap, current->thread.gmap_addr, address); diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index e175667b1363..acd2f5e50bfc 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -485,6 +485,10 @@ good_area: if (mm_fault_error(regs, error_code, address, fault)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (fault & VM_FAULT_RETRY) { flags |= FAULT_FLAG_TRIED; diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index ad569d9bd124..91259f291c54 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -190,6 +190,10 @@ good_area: if (fault_signal_pending(fault, regs)) return; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 253e07043298..4acc12eafbf5 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -427,6 +427,10 @@ good_area: if (fault_signal_pending(fault, regs)) goto exit_exception; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + goto lock_released; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -449,6 +453,7 @@ good_area: } mmap_read_unlock(mm); +lock_released: mm_rss = get_mm_rss(mm); #if defined(CONFIG_TRANSPARENT_HUGEPAGE) mm_rss -= (mm->context.thp_pte_count * (HPAGE_SIZE / PAGE_SIZE)); diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index d1d5d0be0308..d3ce21c4ca32 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -76,6 +76,10 @@ good_area: if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) goto out_nosemaphore; + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return 0; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) { goto out_of_memory; diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index fad8faa29d04..fe10c6d76bac 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1408,6 +1408,10 @@ good_area: return; } + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + /* * If we need to retry the mmap_lock has already been released, * and if there is a fatal signal pending there is no guarantee diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c index 16f0a5ff5799..8c781b05c0bd 100644 --- a/arch/xtensa/mm/fault.c +++ b/arch/xtensa/mm/fault.c @@ -172,6 +172,10 @@ good_area: return; } + /* The fault is fully completed (including releasing mmap lock) */ + if (fault & VM_FAULT_COMPLETED) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index c29ab4c0cd5c..6b961a29bf26 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -729,6 +729,7 @@ typedef __bitwise unsigned int vm_fault_t; * @VM_FAULT_NEEDDSYNC: ->fault did not modify page tables and needs * fsync() to complete (for synchronous page faults * in DAX) + * @VM_FAULT_COMPLETED: ->fault completed, meanwhile mmap lock released * @VM_FAULT_HINDEX_MASK: mask HINDEX value * */ @@ -746,6 +747,7 @@ enum vm_fault_reason { VM_FAULT_FALLBACK = (__force vm_fault_t)0x000800, VM_FAULT_DONE_COW = (__force vm_fault_t)0x001000, VM_FAULT_NEEDDSYNC = (__force vm_fault_t)0x002000, + VM_FAULT_COMPLETED = (__force vm_fault_t)0x004000, VM_FAULT_HINDEX_MASK = (__force vm_fault_t)0x0f0000, }; diff --git a/mm/gup.c b/mm/gup.c index 551264407624..407a81d5ca03 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -951,6 +951,25 @@ static int faultin_page(struct vm_area_struct *vma, } ret = handle_mm_fault(vma, address, fault_flags, NULL); + + if (ret & VM_FAULT_COMPLETED) { + /* + * With FAULT_FLAG_RETRY_NOWAIT we'll never release the + * mmap lock in the page fault handler. Sanity check this. + */ + WARN_ON_ONCE(fault_flags & FAULT_FLAG_RETRY_NOWAIT); + if (locked) + *locked = 0; + /* + * We should do the same as VM_FAULT_RETRY, but let's not + * return -EBUSY since that's not reflecting the reality of + * what has happened - we've just fully completed a page + * fault, with the mmap lock released. Use -EAGAIN to show + * that we want to take the mmap lock _again_. + */ + return -EAGAIN; + } + if (ret & VM_FAULT_ERROR) { int err = vm_fault_to_errno(ret, *flags); @@ -1177,6 +1196,7 @@ retry: case 0: goto retry; case -EBUSY: + case -EAGAIN: ret = 0; fallthrough; case -EFAULT: @@ -1303,6 +1323,18 @@ retry: return -EINTR; ret = handle_mm_fault(vma, address, fault_flags, NULL); + + if (ret & VM_FAULT_COMPLETED) { + /* + * NOTE: it's a pity that we need to retake the lock here + * to pair with the unlock() in the callers. Ideally we + * could tell the callers so they do not need to unlock. + */ + mmap_read_lock(mm); + *unlocked = true; + return 0; + } + if (ret & VM_FAULT_ERROR) { int err = vm_fault_to_errno(ret, 0); @@ -1368,7 +1400,7 @@ static __always_inline long __get_user_pages_locked(struct mm_struct *mm, /* VM_FAULT_RETRY couldn't trigger, bypass */ return ret; - /* VM_FAULT_RETRY cannot return errors */ + /* VM_FAULT_RETRY or VM_FAULT_COMPLETED cannot return errors */ if (!*locked) { BUG_ON(ret < 0); BUG_ON(ret >= nr_pages); diff --git a/mm/memory.c b/mm/memory.c index 7a089145cad4..580c62febe42 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3020,7 +3020,7 @@ static vm_fault_t fault_dirty_shared_page(struct vm_fault *vmf) balance_dirty_pages_ratelimited(mapping); if (fpin) { fput(fpin); - return VM_FAULT_RETRY; + return VM_FAULT_COMPLETED; } } -- cgit v1.2.3 From bcc728eb4f446073e0160671d7d0059a4e9aa300 Mon Sep 17 00:00:00 2001 From: Chengming Zhou Date: Tue, 31 May 2022 10:04:21 +0800 Subject: mm/damon: remove obsolete comments of kdamond_stop Since commit 0f91d13366a4 ("mm/damon: simplify stop mechanism") delete kdamond_stop and change to use kthread stop mechanism, these obsolete comments should be removed accordingly. Link: https://lkml.kernel.org/r/20220531020421.46849-1-zhouchengming@bytedance.com Signed-off-by: Chengming Zhou Reviewed-by: SeongJae Park Signed-off-by: Andrew Morton --- include/linux/damon.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/linux/damon.h b/include/linux/damon.h index 7c62da31ce4b..2765c7d99beb 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -397,7 +397,6 @@ struct damon_callback { * detail. * * @kdamond: Kernel thread who does the monitoring. - * @kdamond_stop: Notifies whether kdamond should stop. * @kdamond_lock: Mutex for the synchronizations with @kdamond. * * For each monitoring context, one kernel thread for the monitoring is @@ -406,14 +405,14 @@ struct damon_callback { * Once started, the monitoring thread runs until explicitly required to be * terminated or every monitoring target is invalid. The validity of the * targets is checked via the &damon_operations.target_valid of @ops. The - * termination can also be explicitly requested by writing non-zero to - * @kdamond_stop. The thread sets @kdamond to NULL when it terminates. - * Therefore, users can know whether the monitoring is ongoing or terminated by - * reading @kdamond. Reads and writes to @kdamond and @kdamond_stop from - * outside of the monitoring thread must be protected by @kdamond_lock. - * - * Note that the monitoring thread protects only @kdamond and @kdamond_stop via - * @kdamond_lock. Accesses to other fields must be protected by themselves. + * termination can also be explicitly requested by calling damon_stop(). + * The thread sets @kdamond to NULL when it terminates. Therefore, users can + * know whether the monitoring is ongoing or terminated by reading @kdamond. + * Reads and writes to @kdamond from outside of the monitoring thread must + * be protected by @kdamond_lock. + * + * Note that the monitoring thread protects only @kdamond via @kdamond_lock. + * Accesses to other fields must be protected by themselves. * * @ops: Set of monitoring operations for given use cases. * @callback: Set of callbacks for monitoring events notifications. -- cgit v1.2.3 From 9384d79249d04b03572abb7e551a35d99c9268c0 Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Mon, 6 Jun 2022 16:15:33 +0200 Subject: mm/highmem: delete memmove_page() Matthew Wilcox reported that, while he was looking at memmove_page(), he realized that it can't actually work. The reasons are hidden in its implementation, which makes use of memmove() on logical addresses provided by kmap_local_page(). memmove() does the wrong thing when it tests "if (dest <= src)". Therefore, delete memmove_page(). No need to change any other code because we have no call sites of memmove_page() across the whole kernel. Link: https://lkml.kernel.org/r/20220606141533.555-1-fmdefrancesco@gmail.com Signed-off-by: Fabio M. De Francesco Reported-by: Matthew Wilcox Reviewed-by: Baoquan He Reviewed-by: Ira Weiny Cc: Sebastian Andrzej Siewior Signed-off-by: Andrew Morton --- include/linux/highmem.h | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'include') diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 3af34de54330..fee9835e3793 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -336,19 +336,6 @@ static inline void memcpy_page(struct page *dst_page, size_t dst_off, kunmap_local(dst); } -static inline void memmove_page(struct page *dst_page, size_t dst_off, - struct page *src_page, size_t src_off, - size_t len) -{ - char *dst = kmap_local_page(dst_page); - char *src = kmap_local_page(src_page); - - VM_BUG_ON(dst_off + len > PAGE_SIZE || src_off + len > PAGE_SIZE); - memmove(dst + dst_off, src + src_off, len); - kunmap_local(src); - kunmap_local(dst); -} - static inline void memset_page(struct page *page, size_t offset, int val, size_t len) { -- cgit v1.2.3 From c200d90049dbe08fa8b016f74b713fddefca0479 Mon Sep 17 00:00:00 2001 From: Patrick Wang Date: Sat, 11 Jun 2022 11:55:48 +0800 Subject: mm: kmemleak: remove kmemleak_not_leak_phys() and the min_count argument to kmemleak_alloc_phys() Patch series "mm: kmemleak: store objects allocated with physical address separately and check when scan", v4. The kmemleak_*_phys() interface uses "min_low_pfn" and "max_low_pfn" to check address. But on some architectures, kmemleak_*_phys() is called before those two variables initialized. The following steps will be taken: 1) Add OBJECT_PHYS flag and rbtree for the objects allocated with physical address 2) Store physical address in objects if allocated with OBJECT_PHYS 3) Check the boundary when scan instead of in kmemleak_*_phys() This patch set will solve: https://lore.kernel.org/r/20220527032504.30341-1-yee.lee@mediatek.com https://lore.kernel.org/r/9dd08bb5-f39e-53d8-f88d-bec598a08c93@gmail.com v3: https://lore.kernel.org/r/20220609124950.1694394-1-patrick.wang.shcn@gmail.com v2: https://lore.kernel.org/r/20220603035415.1243913-1-patrick.wang.shcn@gmail.com v1: https://lore.kernel.org/r/20220531150823.1004101-1-patrick.wang.shcn@gmail.com This patch (of 4): Remove the unused kmemleak_not_leak_phys() function. And remove the min_count argument to kmemleak_alloc_phys() function, assume it's 0. Link: https://lkml.kernel.org/r/20220611035551.1823303-1-patrick.wang.shcn@gmail.com Link: https://lkml.kernel.org/r/20220611035551.1823303-2-patrick.wang.shcn@gmail.com Signed-off-by: Patrick Wang Suggested-by: Catalin Marinas Reviewed-by: Catalin Marinas Cc: Yee Lee Signed-off-by: Andrew Morton --- Documentation/dev-tools/kmemleak.rst | 1 - drivers/of/fdt.c | 2 +- include/linux/kmemleak.h | 8 ++------ mm/kmemleak.c | 20 +++----------------- mm/memblock.c | 14 +++++++------- tools/testing/memblock/linux/kmemleak.h | 2 +- 6 files changed, 14 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/Documentation/dev-tools/kmemleak.rst b/Documentation/dev-tools/kmemleak.rst index 1c935f41cd3a..5483fd39ef29 100644 --- a/Documentation/dev-tools/kmemleak.rst +++ b/Documentation/dev-tools/kmemleak.rst @@ -174,7 +174,6 @@ mapping: - ``kmemleak_alloc_phys`` - ``kmemleak_free_part_phys`` -- ``kmemleak_not_leak_phys`` - ``kmemleak_ignore_phys`` Dealing with false positives/negatives diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index a8f5b6532165..2c677e84c3f5 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -529,7 +529,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n", uname, &base, (unsigned long)(size / SZ_1M)); if (!nomap) - kmemleak_alloc_phys(base, size, 0, 0); + kmemleak_alloc_phys(base, size, 0); } else pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h index 34684b2026ab..6a3cd1bf4680 100644 --- a/include/linux/kmemleak.h +++ b/include/linux/kmemleak.h @@ -29,10 +29,9 @@ extern void kmemleak_not_leak(const void *ptr) __ref; extern void kmemleak_ignore(const void *ptr) __ref; extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref; extern void kmemleak_no_scan(const void *ptr) __ref; -extern void kmemleak_alloc_phys(phys_addr_t phys, size_t size, int min_count, +extern void kmemleak_alloc_phys(phys_addr_t phys, size_t size, gfp_t gfp) __ref; extern void kmemleak_free_part_phys(phys_addr_t phys, size_t size) __ref; -extern void kmemleak_not_leak_phys(phys_addr_t phys) __ref; extern void kmemleak_ignore_phys(phys_addr_t phys) __ref; static inline void kmemleak_alloc_recursive(const void *ptr, size_t size, @@ -107,15 +106,12 @@ static inline void kmemleak_no_scan(const void *ptr) { } static inline void kmemleak_alloc_phys(phys_addr_t phys, size_t size, - int min_count, gfp_t gfp) + gfp_t gfp) { } static inline void kmemleak_free_part_phys(phys_addr_t phys, size_t size) { } -static inline void kmemleak_not_leak_phys(phys_addr_t phys) -{ -} static inline void kmemleak_ignore_phys(phys_addr_t phys) { } diff --git a/mm/kmemleak.c b/mm/kmemleak.c index a182f5ddaf68..156eafafa182 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1125,15 +1125,13 @@ EXPORT_SYMBOL(kmemleak_no_scan); * address argument * @phys: physical address of the object * @size: size of the object - * @min_count: minimum number of references to this object. - * See kmemleak_alloc() * @gfp: kmalloc() flags used for kmemleak internal memory allocations */ -void __ref kmemleak_alloc_phys(phys_addr_t phys, size_t size, int min_count, - gfp_t gfp) +void __ref kmemleak_alloc_phys(phys_addr_t phys, size_t size, gfp_t gfp) { if (PHYS_PFN(phys) >= min_low_pfn && PHYS_PFN(phys) < max_low_pfn) - kmemleak_alloc(__va(phys), size, min_count, gfp); + /* assume min_count 0 */ + kmemleak_alloc(__va(phys), size, 0, gfp); } EXPORT_SYMBOL(kmemleak_alloc_phys); @@ -1151,18 +1149,6 @@ void __ref kmemleak_free_part_phys(phys_addr_t phys, size_t size) } EXPORT_SYMBOL(kmemleak_free_part_phys); -/** - * kmemleak_not_leak_phys - similar to kmemleak_not_leak but taking a physical - * address argument - * @phys: physical address of the object - */ -void __ref kmemleak_not_leak_phys(phys_addr_t phys) -{ - if (PHYS_PFN(phys) >= min_low_pfn && PHYS_PFN(phys) < max_low_pfn) - kmemleak_not_leak(__va(phys)); -} -EXPORT_SYMBOL(kmemleak_not_leak_phys); - /** * kmemleak_ignore_phys - similar to kmemleak_ignore but taking a physical * address argument diff --git a/mm/memblock.c b/mm/memblock.c index e4f03a6e8e56..749abd2685c4 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1345,8 +1345,8 @@ __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone, * from the regions with mirroring enabled and then retried from any * memory region. * - * In addition, function sets the min_count to 0 using kmemleak_alloc_phys for - * allocated boot memory block, so that it is never reported as leaks. + * In addition, function using kmemleak_alloc_phys for allocated boot + * memory block, it is never reported as leaks. * * Return: * Physical address of allocated memory block on success, %0 on failure. @@ -1398,12 +1398,12 @@ done: */ if (end != MEMBLOCK_ALLOC_NOLEAKTRACE) /* - * The min_count is set to 0 so that memblock allocated - * blocks are never reported as leaks. This is because many - * of these blocks are only referred via the physical - * address which is not looked up by kmemleak. + * Memblock allocated blocks are never reported as + * leaks. This is because many of these blocks are + * only referred via the physical address which is + * not looked up by kmemleak. */ - kmemleak_alloc_phys(found, size, 0, 0); + kmemleak_alloc_phys(found, size, 0); return found; } diff --git a/tools/testing/memblock/linux/kmemleak.h b/tools/testing/memblock/linux/kmemleak.h index 462f8c5e8aa0..5fed13bb9ec4 100644 --- a/tools/testing/memblock/linux/kmemleak.h +++ b/tools/testing/memblock/linux/kmemleak.h @@ -7,7 +7,7 @@ static inline void kmemleak_free_part_phys(phys_addr_t phys, size_t size) } static inline void kmemleak_alloc_phys(phys_addr_t phys, size_t size, - int min_count, gfp_t gfp) + gfp_t gfp) { } -- cgit v1.2.3 From fc4db90fe71e640e3fe88df346f7cf653b75315d Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 10 Jun 2022 11:03:10 -0700 Subject: mm: kmem: make mem_cgroup_from_obj() vmalloc()-safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently mem_cgroup_from_obj() is not working properly with objects allocated using vmalloc(). It creates problems in some cases, when it's called for static objects belonging to modules or generally allocated using vmalloc(). This patch makes mem_cgroup_from_obj() safe to be called on objects allocated using vmalloc(). It also introduces mem_cgroup_from_slab_obj(), which is a faster version to use in places when we know the object is either a slab object or a generic slab page (e.g. when adding an object to a lru list). Link: https://lkml.kernel.org/r/20220610180310.1725111-1-roman.gushchin@linux.dev Suggested-by: Kefeng Wang Signed-off-by: Roman Gushchin Tested-by: Linux Kernel Functional Testing Acked-by: Shakeel Butt Tested-by: Vasily Averin Acked-by: Michal Hocko Acked-by: Muchun Song Cc: Johannes Weiner Cc: Naresh Kamboju Cc: Qian Cai Cc: Kefeng Wang Cc: David S. Miller Cc: Eric Dumazet Cc: Florian Westphal Cc: Jakub Kicinski Cc: Michal Koutný Cc: Paolo Abeni Cc: Vlastimil Babka Signed-off-by: Andrew Morton --- include/linux/memcontrol.h | 6 ++++ mm/list_lru.c | 2 +- mm/memcontrol.c | 71 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 57 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 9ecead1042b9..3ce96ce5fe3e 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -1740,6 +1740,7 @@ static inline int memcg_kmem_id(struct mem_cgroup *memcg) } struct mem_cgroup *mem_cgroup_from_obj(void *p); +struct mem_cgroup *mem_cgroup_from_slab_obj(void *p); static inline void count_objcg_event(struct obj_cgroup *objcg, enum vm_event_item idx) @@ -1801,6 +1802,11 @@ static inline struct mem_cgroup *mem_cgroup_from_obj(void *p) return NULL; } +static inline struct mem_cgroup *mem_cgroup_from_slab_obj(void *p) +{ + return NULL; +} + static inline void count_objcg_event(struct obj_cgroup *objcg, enum vm_event_item idx) { diff --git a/mm/list_lru.c b/mm/list_lru.c index ba76428ceece..a05e5bef3b40 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -71,7 +71,7 @@ list_lru_from_kmem(struct list_lru *lru, int nid, void *ptr, if (!list_lru_memcg_aware(lru)) goto out; - memcg = mem_cgroup_from_obj(ptr); + memcg = mem_cgroup_from_slab_obj(ptr); if (!memcg) goto out; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 28c1532cc91f..c1ae9b3f8d35 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -783,7 +783,7 @@ void __mod_lruvec_kmem_state(void *p, enum node_stat_item idx, int val) struct lruvec *lruvec; rcu_read_lock(); - memcg = mem_cgroup_from_obj(p); + memcg = mem_cgroup_from_slab_obj(p); /* * Untracked pages have no memcg, no lruvec. Update only the @@ -2841,27 +2841,9 @@ int memcg_alloc_slab_cgroups(struct slab *slab, struct kmem_cache *s, return 0; } -/* - * Returns a pointer to the memory cgroup to which the kernel object is charged. - * - * A passed kernel object can be a slab object or a generic kernel page, so - * different mechanisms for getting the memory cgroup pointer should be used. - * In certain cases (e.g. kernel stacks or large kmallocs with SLUB) the caller - * can not know for sure how the kernel object is implemented. - * mem_cgroup_from_obj() can be safely used in such cases. - * - * The caller must ensure the memcg lifetime, e.g. by taking rcu_read_lock(), - * cgroup_mutex, etc. - */ -struct mem_cgroup *mem_cgroup_from_obj(void *p) +static __always_inline +struct mem_cgroup *mem_cgroup_from_obj_folio(struct folio *folio, void *p) { - struct folio *folio; - - if (mem_cgroup_disabled()) - return NULL; - - folio = virt_to_folio(p); - /* * Slab objects are accounted individually, not per-page. * Memcg membership data for each individual object is saved in @@ -2894,6 +2876,53 @@ struct mem_cgroup *mem_cgroup_from_obj(void *p) return page_memcg_check(folio_page(folio, 0)); } +/* + * Returns a pointer to the memory cgroup to which the kernel object is charged. + * + * A passed kernel object can be a slab object, vmalloc object or a generic + * kernel page, so different mechanisms for getting the memory cgroup pointer + * should be used. + * + * In certain cases (e.g. kernel stacks or large kmallocs with SLUB) the caller + * can not know for sure how the kernel object is implemented. + * mem_cgroup_from_obj() can be safely used in such cases. + * + * The caller must ensure the memcg lifetime, e.g. by taking rcu_read_lock(), + * cgroup_mutex, etc. + */ +struct mem_cgroup *mem_cgroup_from_obj(void *p) +{ + struct folio *folio; + + if (mem_cgroup_disabled()) + return NULL; + + if (unlikely(is_vmalloc_addr(p))) + folio = page_folio(vmalloc_to_page(p)); + else + folio = virt_to_folio(p); + + return mem_cgroup_from_obj_folio(folio, p); +} + +/* + * Returns a pointer to the memory cgroup to which the kernel object is charged. + * Similar to mem_cgroup_from_obj(), but faster and not suitable for objects, + * allocated using vmalloc(). + * + * A passed kernel object must be a slab object or a generic kernel page. + * + * The caller must ensure the memcg lifetime, e.g. by taking rcu_read_lock(), + * cgroup_mutex, etc. + */ +struct mem_cgroup *mem_cgroup_from_slab_obj(void *p) +{ + if (mem_cgroup_disabled()) + return NULL; + + return mem_cgroup_from_obj_folio(virt_to_folio(p), p); +} + static struct obj_cgroup *__get_obj_cgroup_from_memcg(struct mem_cgroup *memcg) { struct obj_cgroup *objcg = NULL; -- cgit v1.2.3 From 1d0403d20f6c281cb3d14c5f1db5317caeec48e9 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Fri, 3 Jun 2022 07:19:43 +0300 Subject: net: set proper memcg for net_init hooks allocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __register_pernet_operations() executes init hook of registered pernet_operation structure in all existing net namespaces. Typically, these hooks are called by a process associated with the specified net namespace, and all __GFP_ACCOUNT marked allocation are accounted for corresponding container/memcg. However __register_pernet_operations() calls the hooks in the same context, and as a result all marked allocations are accounted to one memcg for all processed net namespaces. This patch adjusts active memcg for each net namespace and helps to account memory allocated inside ops_init() into the proper memcg. Link: https://lkml.kernel.org/r/f9394752-e272-9bf9-645f-a18c56d1c4ec@openvz.org Signed-off-by: Vasily Averin Acked-by: Roman Gushchin Acked-by: Shakeel Butt Cc: Michal Koutný Cc: Vlastimil Babka Cc: Michal Hocko Cc: Florian Westphal Cc: David S. Miller Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Eric Dumazet Cc: Johannes Weiner Cc: Kefeng Wang Cc: Linux Kernel Functional Testing Cc: Muchun Song Cc: Naresh Kamboju Cc: Qian Cai Signed-off-by: Andrew Morton --- include/linux/memcontrol.h | 47 +++++++++++++++++++++++++++++++++++++++++++++- net/core/net_namespace.c | 7 +++++++ 2 files changed, 53 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 3ce96ce5fe3e..04f2f33607e9 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -1756,6 +1756,42 @@ static inline void count_objcg_event(struct obj_cgroup *objcg, rcu_read_unlock(); } +/** + * get_mem_cgroup_from_obj - get a memcg associated with passed kernel object. + * @p: pointer to object from which memcg should be extracted. It can be NULL. + * + * Retrieves the memory group into which the memory of the pointed kernel + * object is accounted. If memcg is found, its reference is taken. + * If a passed kernel object is uncharged, or if proper memcg cannot be found, + * as well as if mem_cgroup is disabled, NULL is returned. + * + * Return: valid memcg pointer with taken reference or NULL. + */ +static inline struct mem_cgroup *get_mem_cgroup_from_obj(void *p) +{ + struct mem_cgroup *memcg; + + rcu_read_lock(); + do { + memcg = mem_cgroup_from_obj(p); + } while (memcg && !css_tryget(&memcg->css)); + rcu_read_unlock(); + return memcg; +} + +/** + * mem_cgroup_or_root - always returns a pointer to a valid memory cgroup. + * @memcg: pointer to a valid memory cgroup or NULL. + * + * If passed argument is not NULL, returns it without any additional checks + * and changes. Otherwise, root_mem_cgroup is returned. + * + * NOTE: root_mem_cgroup can be NULL during early boot. + */ +static inline struct mem_cgroup *mem_cgroup_or_root(struct mem_cgroup *memcg) +{ + return memcg ? memcg : root_mem_cgroup; +} #else static inline bool mem_cgroup_kmem_disabled(void) { @@ -1799,7 +1835,7 @@ static inline int memcg_kmem_id(struct mem_cgroup *memcg) static inline struct mem_cgroup *mem_cgroup_from_obj(void *p) { - return NULL; + return NULL; } static inline struct mem_cgroup *mem_cgroup_from_slab_obj(void *p) @@ -1812,6 +1848,15 @@ static inline void count_objcg_event(struct obj_cgroup *objcg, { } +static inline struct mem_cgroup *get_mem_cgroup_from_obj(void *p) +{ + return NULL; +} + +static inline struct mem_cgroup *mem_cgroup_or_root(struct mem_cgroup *memcg) +{ + return NULL; +} #endif /* CONFIG_MEMCG_KMEM */ #if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_ZSWAP) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 0ec2f5906a27..6b9f19122ec1 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1143,7 +1144,13 @@ static int __register_pernet_operations(struct list_head *list, * setup_net() and cleanup_net() are not possible. */ for_each_net(net) { + struct mem_cgroup *old, *memcg; + + memcg = mem_cgroup_or_root(get_mem_cgroup_from_obj(net)); + old = set_active_memcg(memcg); error = ops_init(ops, net); + set_active_memcg(old); + mem_cgroup_put(memcg); if (error) goto out_undo; list_add_tail(&net->exit_list, &net_exit_list); -- cgit v1.2.3 From 4815a36009044ba69a9b8d781943ec6505c451a2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Jun 2022 20:10:12 +0300 Subject: include/linux/rbtree.h: replace kernel.h with the necessary inclusions When kernel.h is used in the headers it adds a lot into dependency hell, especially when there are circular dependencies are involved. Replace kernel.h inclusion with the list of what is really being used. Link: https://lkml.kernel.org/r/20220603171012.48880-1-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Cc: Matthew Wilcox Signed-off-by: Andrew Morton --- include/linux/rbtree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index 235047d7a1b5..f7edca369eda 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h @@ -17,9 +17,9 @@ #ifndef _LINUX_RBTREE_H #define _LINUX_RBTREE_H +#include #include -#include #include #include -- cgit v1.2.3 From d30dfd490f7dc4cb6a7c11a647bd1ff7a22139e7 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Wed, 8 Jun 2022 15:35:39 -0700 Subject: include/uapi/linux/swab.h: move explicit cast outside ternary A cast inside __builtin_constant_p doesn't do anything since it should evaluate as constant at compile time irrespective of this cast. Instead, I moved this cast outside the ternary to ensure the return type is as expected. Additionally, if __HAVE_BUILTIN_BSWAP16__ was not defined then __swab16 is actually returning an `int` not a `u16` due to integer promotion. As Al Viro notes: You *can't* get smaller-than-int out of ? :, same as you can't get it out of addition, etc. This also fixes some clang -Wformat warnings involving default argument promotion. Link: https://github.com/ClangBuiltLinux/linux/issues/378 Link: https://lkml.kernel.org/r/20220608223539.470472-1-justinstitt@google.com Signed-off-by: Justin Stitt Suggested-by: Al Viro Suggested-by: Nathan Chancellor Reviewed-by: Nathan Chancellor Suggested-by: Nick Desaulniers Signed-off-by: Andrew Morton --- include/uapi/linux/swab.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/swab.h b/include/uapi/linux/swab.h index 7272f85d6d6a..0723a9cce747 100644 --- a/include/uapi/linux/swab.h +++ b/include/uapi/linux/swab.h @@ -102,7 +102,7 @@ static inline __attribute_const__ __u32 __fswahb32(__u32 val) #define __swab16(x) (__u16)__builtin_bswap16((__u16)(x)) #else #define __swab16(x) \ - (__builtin_constant_p((__u16)(x)) ? \ + (__u16)(__builtin_constant_p(x) ? \ ___constant_swab16(x) : \ __fswab16(x)) #endif @@ -115,7 +115,7 @@ static inline __attribute_const__ __u32 __fswahb32(__u32 val) #define __swab32(x) (__u32)__builtin_bswap32((__u32)(x)) #else #define __swab32(x) \ - (__builtin_constant_p((__u32)(x)) ? \ + (__u32)(__builtin_constant_p(x) ? \ ___constant_swab32(x) : \ __fswab32(x)) #endif @@ -128,7 +128,7 @@ static inline __attribute_const__ __u32 __fswahb32(__u32 val) #define __swab64(x) (__u64)__builtin_bswap64((__u64)(x)) #else #define __swab64(x) \ - (__builtin_constant_p((__u64)(x)) ? \ + (__u64)(__builtin_constant_p(x) ? \ ___constant_swab64(x) : \ __fswab64(x)) #endif -- cgit v1.2.3 From dabba87229411a5e9d20ac03ffc36463c53ae672 Mon Sep 17 00:00:00 2001 From: Pasha Tatashin Date: Fri, 27 May 2022 02:55:34 +0000 Subject: fs/kernel_read_file: allow to read files up-to ssize_t Patch series "Allow to kexec with initramfs larger than 2G", v2. Currently, the largest initramfs that is supported by kexec_file_load() syscall is 2G. This is because kernel_read_file() returns int, and is limited to INT_MAX or 2G. On the other hand, there are kexec based boot loaders (i.e. u-root), that may need to boot netboot images that might be larger than 2G. The first patch changes the return type from int to ssize_t in kernel_read_file* functions. The second patch increases the maximum initramfs file size to 4G. Tested: verified that can kexec_file_load() works with 4G initramfs on x86_64. This patch (of 2): Currently, the maximum file size that is supported is 2G. This may be too small in some cases. For example, kexec_file_load() system call loads initramfs. In some netboot cases initramfs can be rather large. Allow to use up-to ssize_t bytes. The callers still can limit the maximum file size via buf_size. Link: https://lkml.kernel.org/r/20220527025535.3953665-1-pasha.tatashin@soleen.com Link: https://lkml.kernel.org/r/20220527025535.3953665-2-pasha.tatashin@soleen.com Signed-off-by: Pasha Tatashin Cc: Al Viro Cc: Baoquan He Cc: "Eric W. Biederman" Cc: Greg Thelen Cc: Sasha Levin Signed-off-by: Andrew Morton --- fs/kernel_read_file.c | 38 +++++++++++++++++++------------------- include/linux/kernel_read_file.h | 32 ++++++++++++++++---------------- include/linux/limits.h | 1 + 3 files changed, 36 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/fs/kernel_read_file.c b/fs/kernel_read_file.c index 1b07550485b9..5d826274570c 100644 --- a/fs/kernel_read_file.c +++ b/fs/kernel_read_file.c @@ -29,15 +29,15 @@ * change between calls to kernel_read_file(). * * Returns number of bytes read (no single read will be bigger - * than INT_MAX), or negative on error. + * than SSIZE_MAX), or negative on error. * */ -int kernel_read_file(struct file *file, loff_t offset, void **buf, - size_t buf_size, size_t *file_size, - enum kernel_read_file_id id) +ssize_t kernel_read_file(struct file *file, loff_t offset, void **buf, + size_t buf_size, size_t *file_size, + enum kernel_read_file_id id) { loff_t i_size, pos; - size_t copied; + ssize_t copied; void *allocated = NULL; bool whole_file; int ret; @@ -58,7 +58,7 @@ int kernel_read_file(struct file *file, loff_t offset, void **buf, goto out; } /* The file is too big for sane activities. */ - if (i_size > INT_MAX) { + if (i_size > SSIZE_MAX) { ret = -EFBIG; goto out; } @@ -124,12 +124,12 @@ out: } EXPORT_SYMBOL_GPL(kernel_read_file); -int kernel_read_file_from_path(const char *path, loff_t offset, void **buf, - size_t buf_size, size_t *file_size, - enum kernel_read_file_id id) +ssize_t kernel_read_file_from_path(const char *path, loff_t offset, void **buf, + size_t buf_size, size_t *file_size, + enum kernel_read_file_id id) { struct file *file; - int ret; + ssize_t ret; if (!path || !*path) return -EINVAL; @@ -144,14 +144,14 @@ int kernel_read_file_from_path(const char *path, loff_t offset, void **buf, } EXPORT_SYMBOL_GPL(kernel_read_file_from_path); -int kernel_read_file_from_path_initns(const char *path, loff_t offset, - void **buf, size_t buf_size, - size_t *file_size, - enum kernel_read_file_id id) +ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset, + void **buf, size_t buf_size, + size_t *file_size, + enum kernel_read_file_id id) { struct file *file; struct path root; - int ret; + ssize_t ret; if (!path || !*path) return -EINVAL; @@ -171,12 +171,12 @@ int kernel_read_file_from_path_initns(const char *path, loff_t offset, } EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns); -int kernel_read_file_from_fd(int fd, loff_t offset, void **buf, - size_t buf_size, size_t *file_size, - enum kernel_read_file_id id) +ssize_t kernel_read_file_from_fd(int fd, loff_t offset, void **buf, + size_t buf_size, size_t *file_size, + enum kernel_read_file_id id) { struct fd f = fdget(fd); - int ret = -EBADF; + ssize_t ret = -EBADF; if (!f.file || !(f.file->f_mode & FMODE_READ)) goto out; diff --git a/include/linux/kernel_read_file.h b/include/linux/kernel_read_file.h index 575ffa1031d3..90451e2e12bd 100644 --- a/include/linux/kernel_read_file.h +++ b/include/linux/kernel_read_file.h @@ -35,21 +35,21 @@ static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) return kernel_read_file_str[id]; } -int kernel_read_file(struct file *file, loff_t offset, - void **buf, size_t buf_size, - size_t *file_size, - enum kernel_read_file_id id); -int kernel_read_file_from_path(const char *path, loff_t offset, - void **buf, size_t buf_size, - size_t *file_size, - enum kernel_read_file_id id); -int kernel_read_file_from_path_initns(const char *path, loff_t offset, - void **buf, size_t buf_size, - size_t *file_size, - enum kernel_read_file_id id); -int kernel_read_file_from_fd(int fd, loff_t offset, - void **buf, size_t buf_size, - size_t *file_size, - enum kernel_read_file_id id); +ssize_t kernel_read_file(struct file *file, loff_t offset, + void **buf, size_t buf_size, + size_t *file_size, + enum kernel_read_file_id id); +ssize_t kernel_read_file_from_path(const char *path, loff_t offset, + void **buf, size_t buf_size, + size_t *file_size, + enum kernel_read_file_id id); +ssize_t kernel_read_file_from_path_initns(const char *path, loff_t offset, + void **buf, size_t buf_size, + size_t *file_size, + enum kernel_read_file_id id); +ssize_t kernel_read_file_from_fd(int fd, loff_t offset, + void **buf, size_t buf_size, + size_t *file_size, + enum kernel_read_file_id id); #endif /* _LINUX_KERNEL_READ_FILE_H */ diff --git a/include/linux/limits.h b/include/linux/limits.h index b568b9c30bbf..f6bcc9369010 100644 --- a/include/linux/limits.h +++ b/include/linux/limits.h @@ -7,6 +7,7 @@ #include #define SIZE_MAX (~(size_t)0) +#define SSIZE_MAX ((ssize_t)(SIZE_MAX >> 1)) #define PHYS_ADDR_MAX (~(phys_addr_t)0) #define U8_MAX ((u8)~0U) -- cgit v1.2.3 From a793679827a87b01f9d973ea30b923cd5a3ff2c5 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 14 Jun 2022 10:46:11 +0200 Subject: linux/phy.h: add phydev_err_probe() wrapper for dev_err_probe() The dev_err_probe() function is quite useful to avoid boilerplate related to -EPROBE_DEFER handling. Add a phydev_err_probe() helper to simplify making use of that from phy drivers which otherwise use the phydev_* helpers. Signed-off-by: Rasmus Villemoes Signed-off-by: Jakub Kicinski --- include/linux/phy.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/phy.h b/include/linux/phy.h index 508f1149665b..bed9a347481b 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1539,6 +1539,9 @@ static inline void phy_device_reset(struct phy_device *phydev, int value) #define phydev_err(_phydev, format, args...) \ dev_err(&_phydev->mdio.dev, format, ##args) +#define phydev_err_probe(_phydev, err, format, args...) \ + dev_err_probe(&_phydev->mdio.dev, err, format, ##args) + #define phydev_info(_phydev, format, args...) \ dev_info(&_phydev->mdio.dev, format, ##args) -- cgit v1.2.3 From ac80287a6af9fc3f3d189d6d1f523889a0a9e1bc Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Wed, 15 Jun 2022 16:48:42 +0300 Subject: bpf: Fix documentation of th_len in bpf_tcp_{gen,check}_syncookie bpf_tcp_gen_syncookie expects the full length of the TCP header (with all options), and bpf_tcp_check_syncookie accepts lengths bigger than sizeof(struct tcphdr). Fix the documentation that says these lengths should be exactly sizeof(struct tcphdr). While at it, fix a typo in the name of struct ipv6hdr. Signed-off-by: Maxim Mikityanskiy Reviewed-by: Tariq Toukan Link: https://lore.kernel.org/r/20220615134847.3753567-2-maximmi@nvidia.com Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 10 ++++++---- tools/include/uapi/linux/bpf.h | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index f4009dbdf62d..f545e39df72a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -3597,10 +3597,11 @@ union bpf_attr { * * *iph* points to the start of the IPv4 or IPv6 header, while * *iph_len* contains **sizeof**\ (**struct iphdr**) or - * **sizeof**\ (**struct ip6hdr**). + * **sizeof**\ (**struct ipv6hdr**). * * *th* points to the start of the TCP header, while *th_len* - * contains **sizeof**\ (**struct tcphdr**). + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). * Return * 0 if *iph* and *th* are a valid SYN cookie ACK, or a negative * error otherwise. @@ -3783,10 +3784,11 @@ union bpf_attr { * * *iph* points to the start of the IPv4 or IPv6 header, while * *iph_len* contains **sizeof**\ (**struct iphdr**) or - * **sizeof**\ (**struct ip6hdr**). + * **sizeof**\ (**struct ipv6hdr**). * * *th* points to the start of the TCP header, while *th_len* - * contains the length of the TCP header. + * contains the length of the TCP header with options (at least + * **sizeof**\ (**struct tcphdr**)). * Return * On success, lower 32 bits hold the generated SYN cookie in * followed by 16 bits which hold the MSS value for that cookie, diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f4009dbdf62d..f545e39df72a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -3597,10 +3597,11 @@ union bpf_attr { * * *iph* points to the start of the IPv4 or IPv6 header, while * *iph_len* contains **sizeof**\ (**struct iphdr**) or - * **sizeof**\ (**struct ip6hdr**). + * **sizeof**\ (**struct ipv6hdr**). * * *th* points to the start of the TCP header, while *th_len* - * contains **sizeof**\ (**struct tcphdr**). + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). * Return * 0 if *iph* and *th* are a valid SYN cookie ACK, or a negative * error otherwise. @@ -3783,10 +3784,11 @@ union bpf_attr { * * *iph* points to the start of the IPv4 or IPv6 header, while * *iph_len* contains **sizeof**\ (**struct iphdr**) or - * **sizeof**\ (**struct ip6hdr**). + * **sizeof**\ (**struct ipv6hdr**). * * *th* points to the start of the TCP header, while *th_len* - * contains the length of the TCP header. + * contains the length of the TCP header with options (at least + * **sizeof**\ (**struct tcphdr**)). * Return * On success, lower 32 bits hold the generated SYN cookie in * followed by 16 bits which hold the MSS value for that cookie, -- cgit v1.2.3 From 508362ac66b0478affb4e52cb8da98478312d72d Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Wed, 15 Jun 2022 16:48:43 +0300 Subject: bpf: Allow helpers to accept pointers with a fixed size Before this commit, the BPF verifier required ARG_PTR_TO_MEM arguments to be followed by ARG_CONST_SIZE holding the size of the memory region. The helpers had to check that size in runtime. There are cases where the size expected by a helper is a compile-time constant. Checking it in runtime is an unnecessary overhead and waste of BPF registers. This commit allows helpers to accept pointers to memory without the corresponding ARG_CONST_SIZE, given that they define the memory region size in struct bpf_func_proto and use ARG_PTR_TO_FIXED_SIZE_MEM type. arg_size is unionized with arg_btf_id to reduce the kernel image size, and it's valid because they are used by different argument types. Signed-off-by: Maxim Mikityanskiy Reviewed-by: Tariq Toukan Link: https://lore.kernel.org/r/20220615134847.3753567-3-maximmi@nvidia.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 13 +++++++++++++ kernel/bpf/verifier.c | 43 ++++++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index f3e88afdaffe..a94531971a7a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -401,6 +401,9 @@ enum bpf_type_flag { /* DYNPTR points to a ringbuf record. */ DYNPTR_TYPE_RINGBUF = BIT(9 + BPF_BASE_TYPE_BITS), + /* Size is known at compile time. */ + MEM_FIXED_SIZE = BIT(10 + BPF_BASE_TYPE_BITS), + __BPF_TYPE_FLAG_MAX, __BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1, }; @@ -464,6 +467,8 @@ enum bpf_arg_type { * all bytes or clear them in error case. */ ARG_PTR_TO_UNINIT_MEM = MEM_UNINIT | ARG_PTR_TO_MEM, + /* Pointer to valid memory of size known at compile time. */ + ARG_PTR_TO_FIXED_SIZE_MEM = MEM_FIXED_SIZE | ARG_PTR_TO_MEM, /* This must be the last entry. Its purpose is to ensure the enum is * wide enough to hold the higher bits reserved for bpf_type_flag. @@ -529,6 +534,14 @@ struct bpf_func_proto { u32 *arg5_btf_id; }; u32 *arg_btf_id[5]; + struct { + size_t arg1_size; + size_t arg2_size; + size_t arg3_size; + size_t arg4_size; + size_t arg5_size; + }; + size_t arg_size[5]; }; int *ret_btf_id; /* return value btf_id */ bool (*allowed)(const struct bpf_prog *prog); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index eadc23a8452c..2859901ffbe3 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5848,6 +5848,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; enum bpf_arg_type arg_type = fn->arg_type[arg]; enum bpf_reg_type type = reg->type; + u32 *arg_btf_id = NULL; int err = 0; if (arg_type == ARG_DONTCARE) @@ -5884,7 +5885,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, */ goto skip_type_check; - err = check_reg_type(env, regno, arg_type, fn->arg_btf_id[arg], meta); + /* arg_btf_id and arg_size are in a union. */ + if (base_type(arg_type) == ARG_PTR_TO_BTF_ID) + arg_btf_id = fn->arg_btf_id[arg]; + + err = check_reg_type(env, regno, arg_type, arg_btf_id, meta); if (err) return err; @@ -6011,6 +6016,11 @@ skip_type_check: * next is_mem_size argument below. */ meta->raw_mode = arg_type & MEM_UNINIT; + if (arg_type & MEM_FIXED_SIZE) { + err = check_helper_mem_access(env, regno, + fn->arg_size[arg], false, + meta); + } } else if (arg_type_is_mem_size(arg_type)) { bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO); @@ -6400,11 +6410,19 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn) return count <= 1; } -static bool check_args_pair_invalid(enum bpf_arg_type arg_curr, - enum bpf_arg_type arg_next) +static bool check_args_pair_invalid(const struct bpf_func_proto *fn, int arg) { - return (base_type(arg_curr) == ARG_PTR_TO_MEM) != - arg_type_is_mem_size(arg_next); + bool is_fixed = fn->arg_type[arg] & MEM_FIXED_SIZE; + bool has_size = fn->arg_size[arg] != 0; + bool is_next_size = false; + + if (arg + 1 < ARRAY_SIZE(fn->arg_type)) + is_next_size = arg_type_is_mem_size(fn->arg_type[arg + 1]); + + if (base_type(fn->arg_type[arg]) != ARG_PTR_TO_MEM) + return is_next_size; + + return has_size == is_next_size || is_next_size == is_fixed; } static bool check_arg_pair_ok(const struct bpf_func_proto *fn) @@ -6415,11 +6433,11 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn) * helper function specification. */ if (arg_type_is_mem_size(fn->arg1_type) || - base_type(fn->arg5_type) == ARG_PTR_TO_MEM || - check_args_pair_invalid(fn->arg1_type, fn->arg2_type) || - check_args_pair_invalid(fn->arg2_type, fn->arg3_type) || - check_args_pair_invalid(fn->arg3_type, fn->arg4_type) || - check_args_pair_invalid(fn->arg4_type, fn->arg5_type)) + check_args_pair_invalid(fn, 0) || + check_args_pair_invalid(fn, 1) || + check_args_pair_invalid(fn, 2) || + check_args_pair_invalid(fn, 3) || + check_args_pair_invalid(fn, 4)) return false; return true; @@ -6460,7 +6478,10 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn) if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID && !fn->arg_btf_id[i]) return false; - if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i]) + if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i] && + /* arg_btf_id and arg_size are in a union. */ + (base_type(fn->arg_type[i]) != ARG_PTR_TO_MEM || + !(fn->arg_type[i] & MEM_FIXED_SIZE))) return false; } -- cgit v1.2.3 From 33bf9885040c399cf6a95bd33216644126728e14 Mon Sep 17 00:00:00 2001 From: Maxim Mikityanskiy Date: Wed, 15 Jun 2022 16:48:44 +0300 Subject: bpf: Add helpers to issue and check SYN cookies in XDP The new helpers bpf_tcp_raw_{gen,check}_syncookie_ipv{4,6} allow an XDP program to generate SYN cookies in response to TCP SYN packets and to check those cookies upon receiving the first ACK packet (the final packet of the TCP handshake). Unlike bpf_tcp_{gen,check}_syncookie these new helpers don't need a listening socket on the local machine, which allows to use them together with synproxy to accelerate SYN cookie generation. Signed-off-by: Maxim Mikityanskiy Reviewed-by: Tariq Toukan Link: https://lore.kernel.org/r/20220615134847.3753567-4-maximmi@nvidia.com Signed-off-by: Alexei Starovoitov --- include/net/tcp.h | 1 + include/uapi/linux/bpf.h | 78 +++++++++++++++++++++++++++ net/core/filter.c | 118 +++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_input.c | 3 +- scripts/bpf_doc.py | 4 ++ tools/include/uapi/linux/bpf.h | 78 +++++++++++++++++++++++++++ 6 files changed, 281 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index 1e99f5c61f84..9a1efe23fab7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -432,6 +432,7 @@ u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph, struct tcphdr *th, u32 *cookie); u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph, struct tcphdr *th, u32 *cookie); +u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss); u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops, const struct tcp_request_sock_ops *af_ops, struct sock *sk, struct tcphdr *th); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index f545e39df72a..e81362891596 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5251,6 +5251,80 @@ union bpf_attr { * Pointer to the underlying dynptr data, NULL if the dynptr is * read-only, if the dynptr is invalid, or if the offset and length * is out of bounds. + * + * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IPv4/TCP headers, *iph* and *th*, without depending on a + * listening socket. + * + * *iph* points to the IPv4 header. + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** if *th_len* is invalid. + * + * s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IPv6/TCP headers, *iph* and *th*, without depending on a + * listening socket. + * + * *iph* points to the IPv6 header. + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** if *th_len* is invalid. + * + * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. + * + * long bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK + * without depending on a listening socket. + * + * *iph* points to the IPv4 header. + * + * *th* points to the TCP header. + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK. + * + * On failure, the returned value is one of the following: + * + * **-EACCES** if the SYN cookie is not valid. + * + * long bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK + * without depending on a listening socket. + * + * *iph* points to the IPv6 header. + * + * *th* points to the TCP header. + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK. + * + * On failure, the returned value is one of the following: + * + * **-EACCES** if the SYN cookie is not valid. + * + * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5457,6 +5531,10 @@ union bpf_attr { FN(dynptr_read), \ FN(dynptr_write), \ FN(dynptr_data), \ + FN(tcp_raw_gen_syncookie_ipv4), \ + FN(tcp_raw_gen_syncookie_ipv6), \ + FN(tcp_raw_check_syncookie_ipv4), \ + FN(tcp_raw_check_syncookie_ipv6), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/net/core/filter.c b/net/core/filter.c index 5af58eb48587..b62d4126a561 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -7444,6 +7444,114 @@ static const struct bpf_func_proto bpf_skb_set_tstamp_proto = { .arg3_type = ARG_ANYTHING, }; +#ifdef CONFIG_SYN_COOKIES +BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv4, struct iphdr *, iph, + struct tcphdr *, th, u32, th_len) +{ + u32 cookie; + u16 mss; + + if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4)) + return -EINVAL; + + mss = tcp_parse_mss_option(th, 0) ?: TCP_MSS_DEFAULT; + cookie = __cookie_v4_init_sequence(iph, th, &mss); + + return cookie | ((u64)mss << 32); +} + +static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv4_proto = { + .func = bpf_tcp_raw_gen_syncookie_ipv4, + .gpl_only = true, /* __cookie_v4_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg1_size = sizeof(struct iphdr), + .arg2_type = ARG_PTR_TO_MEM, + .arg3_type = ARG_CONST_SIZE, +}; + +BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv6, struct ipv6hdr *, iph, + struct tcphdr *, th, u32, th_len) +{ +#if IS_BUILTIN(CONFIG_IPV6) + const u16 mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - + sizeof(struct ipv6hdr); + u32 cookie; + u16 mss; + + if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4)) + return -EINVAL; + + mss = tcp_parse_mss_option(th, 0) ?: mss_clamp; + cookie = __cookie_v6_init_sequence(iph, th, &mss); + + return cookie | ((u64)mss << 32); +#else + return -EPROTONOSUPPORT; +#endif +} + +static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = { + .func = bpf_tcp_raw_gen_syncookie_ipv6, + .gpl_only = true, /* __cookie_v6_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg1_size = sizeof(struct ipv6hdr), + .arg2_type = ARG_PTR_TO_MEM, + .arg3_type = ARG_CONST_SIZE, +}; + +BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv4, struct iphdr *, iph, + struct tcphdr *, th) +{ + u32 cookie = ntohl(th->ack_seq) - 1; + + if (__cookie_v4_check(iph, th, cookie) > 0) + return 0; + + return -EACCES; +} + +static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv4_proto = { + .func = bpf_tcp_raw_check_syncookie_ipv4, + .gpl_only = true, /* __cookie_v4_check is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg1_size = sizeof(struct iphdr), + .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg2_size = sizeof(struct tcphdr), +}; + +BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv6, struct ipv6hdr *, iph, + struct tcphdr *, th) +{ +#if IS_BUILTIN(CONFIG_IPV6) + u32 cookie = ntohl(th->ack_seq) - 1; + + if (__cookie_v6_check(iph, th, cookie) > 0) + return 0; + + return -EACCES; +#else + return -EPROTONOSUPPORT; +#endif +} + +static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = { + .func = bpf_tcp_raw_check_syncookie_ipv6, + .gpl_only = true, /* __cookie_v6_check is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg1_size = sizeof(struct ipv6hdr), + .arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM, + .arg2_size = sizeof(struct tcphdr), +}; +#endif /* CONFIG_SYN_COOKIES */ + #endif /* CONFIG_INET */ bool bpf_helper_changes_pkt_data(void *func) @@ -7856,6 +7964,16 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_tcp_check_syncookie_proto; case BPF_FUNC_tcp_gen_syncookie: return &bpf_tcp_gen_syncookie_proto; +#ifdef CONFIG_SYN_COOKIES + case BPF_FUNC_tcp_raw_gen_syncookie_ipv4: + return &bpf_tcp_raw_gen_syncookie_ipv4_proto; + case BPF_FUNC_tcp_raw_gen_syncookie_ipv6: + return &bpf_tcp_raw_gen_syncookie_ipv6_proto; + case BPF_FUNC_tcp_raw_check_syncookie_ipv4: + return &bpf_tcp_raw_check_syncookie_ipv4_proto; + case BPF_FUNC_tcp_raw_check_syncookie_ipv6: + return &bpf_tcp_raw_check_syncookie_ipv6_proto; +#endif #endif default: return bpf_sk_base_func_proto(func_id); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2e2a9ece9af2..6426f6a2e744 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3967,7 +3967,7 @@ static bool smc_parse_options(const struct tcphdr *th, /* Try to parse the MSS option from the TCP header. Return 0 on failure, clamped * value on success. */ -static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss) +u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss) { const unsigned char *ptr = (const unsigned char *)(th + 1); int length = (th->doff * 4) - sizeof(struct tcphdr); @@ -4006,6 +4006,7 @@ static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss) } return mss; } +EXPORT_SYMBOL_GPL(tcp_parse_mss_option); /* Look for tcp options. Normally only called on SYN and SYNACK packets. * But, this can also be called on packets in the established flow when diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index 855b937e7585..a0ec321469bd 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -635,6 +635,8 @@ class PrinterHelpers(Printer): 'struct bpf_timer', 'struct mptcp_sock', 'struct bpf_dynptr', + 'struct iphdr', + 'struct ipv6hdr', ] known_types = { '...', @@ -686,6 +688,8 @@ class PrinterHelpers(Printer): 'struct bpf_timer', 'struct mptcp_sock', 'struct bpf_dynptr', + 'struct iphdr', + 'struct ipv6hdr', } mapped_types = { 'u8': '__u8', diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f545e39df72a..e81362891596 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5251,6 +5251,80 @@ union bpf_attr { * Pointer to the underlying dynptr data, NULL if the dynptr is * read-only, if the dynptr is invalid, or if the offset and length * is out of bounds. + * + * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IPv4/TCP headers, *iph* and *th*, without depending on a + * listening socket. + * + * *iph* points to the IPv4 header. + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** if *th_len* is invalid. + * + * s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IPv6/TCP headers, *iph* and *th*, without depending on a + * listening socket. + * + * *iph* points to the IPv6 header. + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header (at least + * **sizeof**\ (**struct tcphdr**)). + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** if *th_len* is invalid. + * + * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. + * + * long bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK + * without depending on a listening socket. + * + * *iph* points to the IPv4 header. + * + * *th* points to the TCP header. + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK. + * + * On failure, the returned value is one of the following: + * + * **-EACCES** if the SYN cookie is not valid. + * + * long bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK + * without depending on a listening socket. + * + * *iph* points to the IPv6 header. + * + * *th* points to the TCP header. + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK. + * + * On failure, the returned value is one of the following: + * + * **-EACCES** if the SYN cookie is not valid. + * + * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5457,6 +5531,10 @@ union bpf_attr { FN(dynptr_read), \ FN(dynptr_write), \ FN(dynptr_data), \ + FN(tcp_raw_gen_syncookie_ipv4), \ + FN(tcp_raw_gen_syncookie_ipv6), \ + FN(tcp_raw_check_syncookie_ipv4), \ + FN(tcp_raw_check_syncookie_ipv6), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper -- cgit v1.2.3 From f0a6d77b351c18c122fc1638ac9e58f5e0346f64 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Tue, 14 Jun 2022 22:51:47 +0300 Subject: ata: make transfer mode masks *unsigned int* The packed transfer mode masks and also the {pio|mwdma|udma}_mask fields of *struct*s ata_device and ata_port_info are declared as *unsigned long* (which is a 64-bit type on 64-bit architectures) but actually the packed masks occupy only 20 bits (7 PIO modes, 5 MWDMA modes, and 8 UDMA modes) and the PIO/MWDMA/UDMA masks easily fit into just 8 bits each, so we can safely use (always 32-bit) *unsigned int* variables instead. This saves 745 bytes of object code in libata-core.o alone, not to mention LLDDs... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- drivers/ata/libata-acpi.c | 8 +++---- drivers/ata/libata-core.c | 38 ++++++++++++++++---------------- drivers/ata/pata_acpi.c | 2 +- drivers/ata/pata_ali.c | 2 +- drivers/ata/pata_amd.c | 14 ++++++------ drivers/ata/pata_hpt366.c | 2 +- drivers/ata/pata_hpt37x.c | 6 +++--- drivers/ata/pata_hpt3x2n.c | 2 +- drivers/ata/pata_pdc2027x.c | 4 ++-- drivers/ata/pata_serverworks.c | 4 ++-- drivers/ata/pata_sis.c | 2 +- drivers/ata/pata_via.c | 2 +- include/linux/libata.h | 49 +++++++++++++++++++++--------------------- 13 files changed, 67 insertions(+), 68 deletions(-) (limited to 'include') diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 3d345d173556..61b4ccf88bf1 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -480,10 +480,10 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) * RETURNS: * Determined xfermask. */ -unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev, - const struct ata_acpi_gtm *gtm) +unsigned int ata_acpi_gtm_xfermask(struct ata_device *dev, + const struct ata_acpi_gtm *gtm) { - unsigned long xfer_mask = 0; + unsigned int xfer_mask = 0; unsigned int type; int unit; u8 mode; @@ -525,7 +525,7 @@ int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm) struct ata_device *dev; ata_for_each_dev(dev, &ap->link, ENABLED) { - unsigned long xfer_mask, udma_mask; + unsigned int xfer_mask, udma_mask; xfer_mask = ata_acpi_gtm_xfermask(dev, gtm); ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 980328a4b896..035092184c08 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -93,7 +93,7 @@ struct ata_force_param { const char *name; u8 cbl; u8 spd_limit; - unsigned long xfer_mask; + unsigned int xfer_mask; unsigned int horkage_on; unsigned int horkage_off; u16 lflags_on; @@ -425,7 +425,7 @@ static void ata_force_xfermask(struct ata_device *dev) for (i = ata_force_tbl_size - 1; i >= 0; i--) { const struct ata_force_ent *fe = &ata_force_tbl[i]; - unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned int pio_mask, mwdma_mask, udma_mask; if (fe->port != -1 && fe->port != dev->link->ap->print_id) continue; @@ -803,11 +803,11 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, * RETURNS: * Packed xfer_mask. */ -unsigned long ata_pack_xfermask(unsigned long pio_mask, - unsigned long mwdma_mask, - unsigned long udma_mask) +unsigned int ata_pack_xfermask(unsigned int pio_mask, + unsigned int mwdma_mask, + unsigned int udma_mask) { - return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) | + return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) | ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) | ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA); } @@ -823,8 +823,8 @@ EXPORT_SYMBOL_GPL(ata_pack_xfermask); * Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask. * Any NULL destination masks will be ignored. */ -void ata_unpack_xfermask(unsigned long xfer_mask, unsigned long *pio_mask, - unsigned long *mwdma_mask, unsigned long *udma_mask) +void ata_unpack_xfermask(unsigned int xfer_mask, unsigned int *pio_mask, + unsigned int *mwdma_mask, unsigned int *udma_mask) { if (pio_mask) *pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO; @@ -857,7 +857,7 @@ static const struct ata_xfer_ent { * RETURNS: * Matching XFER_* value, 0xff if no match found. */ -u8 ata_xfer_mask2mode(unsigned long xfer_mask) +u8 ata_xfer_mask2mode(unsigned int xfer_mask) { int highbit = fls(xfer_mask) - 1; const struct ata_xfer_ent *ent; @@ -881,7 +881,7 @@ EXPORT_SYMBOL_GPL(ata_xfer_mask2mode); * RETURNS: * Matching xfer_mask, 0 if no match found. */ -unsigned long ata_xfer_mode2mask(u8 xfer_mode) +unsigned int ata_xfer_mode2mask(u8 xfer_mode) { const struct ata_xfer_ent *ent; @@ -930,7 +930,7 @@ EXPORT_SYMBOL_GPL(ata_xfer_mode2shift); * Constant C string representing highest speed listed in * @mode_mask, or the constant C string "". */ -const char *ata_mode_string(unsigned long xfer_mask) +const char *ata_mode_string(unsigned int xfer_mask) { static const char * const xfer_mode_str[] = { "PIO0", @@ -1383,9 +1383,9 @@ static inline void ata_dump_id(struct ata_device *dev, const u16 *id) * RETURNS: * Computed xfermask */ -unsigned long ata_id_xfermask(const u16 *id) +unsigned int ata_id_xfermask(const u16 *id) { - unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned int pio_mask, mwdma_mask, udma_mask; /* Usual case. Word 53 indicates word 64 is valid */ if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { @@ -2534,7 +2534,7 @@ int ata_dev_configure(struct ata_device *dev) struct ata_port *ap = dev->link->ap; bool print_info = ata_dev_print_info(dev); const u16 *id = dev->id; - unsigned long xfer_mask; + unsigned int xfer_mask; unsigned int err_mask; char revbuf[7]; /* XYZ-99\0 */ char fwrevbuf[ATA_ID_FW_REV_LEN+1]; @@ -3202,8 +3202,8 @@ u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle) int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) { char buf[32]; - unsigned long orig_mask, xfer_mask; - unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned int orig_mask, xfer_mask; + unsigned int pio_mask, mwdma_mask, udma_mask; int quiet, highbit; quiet = !!(sel & ATA_DNXFER_QUIET); @@ -3381,7 +3381,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) /* step 1: calculate xfer_mask */ ata_for_each_dev(dev, link, ENABLED) { - unsigned long pio_mask, dma_mask; + unsigned int pio_mask, dma_mask; unsigned int mode_mask; mode_mask = ATA_DMA_MASK_ATA; @@ -4217,7 +4217,7 @@ static void ata_dev_xfermask(struct ata_device *dev) struct ata_link *link = dev->link; struct ata_port *ap = link->ap; struct ata_host *host = ap->host; - unsigned long xfer_mask; + unsigned int xfer_mask; /* controller modes available */ xfer_mask = ata_pack_xfermask(ap->pio_mask, @@ -5776,7 +5776,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) /* set cable, sata_spd_limit and report */ for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - unsigned long xfer_mask; + unsigned int xfer_mask; /* set SATA cable type if still unset */ if (ap->cbl == ATA_CBL_NONE && (ap->flags & ATA_FLAG_SATA)) diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index ade4c3eee230..f8706ee427d2 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -97,7 +97,7 @@ static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device * this case the list of discovered valid modes obtained by ACPI probing */ -static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask) +static unsigned int pacpi_mode_filter(struct ata_device *adev, unsigned int mask) { struct pata_acpi *acpi = adev->link->ap->private_data; return mask & acpi->mask[adev->devno]; diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 1b90cda27246..76ad0e73fe2a 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -115,7 +115,7 @@ static int ali_c2_cable_detect(struct ata_port *ap) * fix that later on. Also ensure we do not do UDMA on WDC drives */ -static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask) +static unsigned int ali_20_filter(struct ata_device *adev, unsigned int mask) { char model_num[ATA_ID_PROD_LEN + 1]; /* No DMA on anything but a disk for now */ diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 154748cfcc79..f216f9d7b9ec 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -264,8 +264,8 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) * cached during driver attach and are consulted to select transfer * mode. */ -static unsigned long nv_mode_filter(struct ata_device *dev, - unsigned long xfer_mask) +static unsigned int nv_mode_filter(struct ata_device *dev, + unsigned int xfer_mask) { static const unsigned int udma_mask_map[] = { ATA_UDMA2, ATA_UDMA1, ATA_UDMA0, 0, @@ -274,7 +274,7 @@ static unsigned long nv_mode_filter(struct ata_device *dev, char acpi_str[32] = ""; u32 saved_udma, udma; const struct ata_acpi_gtm *gtm; - unsigned long bios_limit = 0, acpi_limit = 0, limit; + unsigned int bios_limit = 0, acpi_limit = 0, limit; /* find out what BIOS configured */ udma = saved_udma = (unsigned long)ap->host->private_data; @@ -310,10 +310,10 @@ static unsigned long nv_mode_filter(struct ata_device *dev, cable detection result */ limit |= ata_pack_xfermask(ATA_PIO4, ATA_MWDMA2, ATA_UDMA2); - ata_port_dbg(ap, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, " - "BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n", - xfer_mask, limit, xfer_mask & limit, bios_limit, - saved_udma, acpi_limit, acpi_str); + ata_port_dbg(ap, + "nv_mode_filter: 0x%x&0x%x->0x%x, BIOS=0x%x (0x%x) ACPI=0x%x%s\n", + xfer_mask, limit, xfer_mask & limit, bios_limit, + saved_udma, acpi_limit, acpi_str); return xfer_mask & limit; } diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index c99e8f0708b3..7e441fb304d3 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -194,7 +194,7 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, * Block UDMA on devices that cause trouble with this controller. */ -static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask) +static unsigned int hpt366_filter(struct ata_device *adev, unsigned int mask) { if (adev->class == ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index d1a3d99d5d0a..ce3c5eaa7e76 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -278,7 +278,7 @@ static const char * const bad_ata100_5[] = { * Block UDMA on devices that cause trouble with this controller. */ -static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask) +static unsigned int hpt370_filter(struct ata_device *adev, unsigned int mask) { if (adev->class == ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33)) @@ -297,7 +297,7 @@ static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask) * Block UDMA on devices that cause trouble with this controller. */ -static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) +static unsigned int hpt370a_filter(struct ata_device *adev, unsigned int mask) { if (adev->class == ATA_DEV_ATA) { if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5)) @@ -314,7 +314,7 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask) * The Marvell bridge chips used on the HighPoint SATA cards do not seem * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... */ -static unsigned long hpt372_filter(struct ata_device *adev, unsigned long mask) +static unsigned int hpt372_filter(struct ata_device *adev, unsigned int mask) { if (ata_id_is_sata(adev->id)) mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA); diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index d1595e17dca2..617c95522f43 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -113,7 +113,7 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed) * The Marvell bridge chips used on the HighPoint SATA cards do not seem * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... */ -static unsigned long hpt372n_filter(struct ata_device *adev, unsigned long mask) +static unsigned int hpt372n_filter(struct ata_device *adev, unsigned int mask) { if (ata_id_is_sata(adev->id)) mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA); diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 4fbb3eed8b0b..4191aa61c8e4 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -57,7 +57,7 @@ static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline); static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev); static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc); -static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask); +static unsigned int pdc2027x_mode_filter(struct ata_device *adev, unsigned int mask); static int pdc2027x_cable_detect(struct ata_port *ap); static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed); @@ -251,7 +251,7 @@ static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline) * Block UDMA on devices that cause trouble with this controller. */ -static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask) +static unsigned int pdc2027x_mode_filter(struct ata_device *adev, unsigned int mask) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; struct ata_device *pair = ata_dev_pair(adev); diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index e410fe44177f..c0bc4af0d196 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -150,7 +150,7 @@ static u8 serverworks_is_csb(struct pci_dev *pdev) * bug we hit. */ -static unsigned long serverworks_osb4_filter(struct ata_device *adev, unsigned long mask) +static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned int mask) { if (adev->class == ATA_DEV_ATA) mask &= ~ATA_MASK_UDMA; @@ -166,7 +166,7 @@ static unsigned long serverworks_osb4_filter(struct ata_device *adev, unsigned l * Check the blacklist and disable UDMA5 if matched */ -static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned long mask) +static unsigned int serverworks_csb_filter(struct ata_device *adev, unsigned int mask) { const char *p; char model_num[ATA_ID_PROD_LEN + 1]; diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index b5b764e18adf..92e4cf05de2c 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -525,7 +525,7 @@ static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev) * Block UDMA6 on devices that do not support it. */ -static unsigned long sis_133_mode_filter(struct ata_device *adev, unsigned long mask) +static unsigned int sis_133_mode_filter(struct ata_device *adev, unsigned int mask) { struct ata_port *ap = adev->link->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 215c02d4056a..34f00f389932 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -352,7 +352,7 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev) * one breed of Transcend SSD. Return the updated mask. */ -static unsigned long via_mode_filter(struct ata_device *dev, unsigned long mask) +static unsigned int via_mode_filter(struct ata_device *dev, unsigned int mask) { struct ata_host *host = dev->link->ap->host; const struct via_isa_bridge *config = host->private_data; diff --git a/include/linux/libata.h b/include/linux/libata.h index 0f2a59c9c735..a8bc88b4fe07 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -275,7 +275,7 @@ enum { PORT_DISABLED = 2, /* encoding various smaller bitmaps into a single - * unsigned long bitmap + * unsigned int bitmap */ ATA_NR_PIO_MODES = 7, ATA_NR_MWDMA_MODES = 5, @@ -426,12 +426,9 @@ enum { }; enum ata_xfer_mask { - ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) - << ATA_SHIFT_PIO, - ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) - << ATA_SHIFT_MWDMA, - ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) - << ATA_SHIFT_UDMA, + ATA_MASK_PIO = ((1U << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1U << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1U << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, }; enum hsm_task_states { @@ -680,9 +677,9 @@ struct ata_device { unsigned int cdb_len; /* per-dev xfer mask */ - unsigned long pio_mask; - unsigned long mwdma_mask; - unsigned long udma_mask; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; /* for CHS addressing */ u16 cylinders; /* Number of cylinders */ @@ -885,7 +882,7 @@ struct ata_port_operations { * Configuration and exception handling */ int (*cable_detect)(struct ata_port *ap); - unsigned long (*mode_filter)(struct ata_device *dev, unsigned long xfer_mask); + unsigned int (*mode_filter)(struct ata_device *dev, unsigned int xfer_mask); void (*set_piomode)(struct ata_port *ap, struct ata_device *dev); void (*set_dmamode)(struct ata_port *ap, struct ata_device *dev); int (*set_mode)(struct ata_link *link, struct ata_device **r_failed_dev); @@ -981,9 +978,9 @@ struct ata_port_operations { struct ata_port_info { unsigned long flags; unsigned long link_flags; - unsigned long pio_mask; - unsigned long mwdma_mask; - unsigned long udma_mask; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; struct ata_port_operations *port_ops; void *private_data; }; @@ -1102,16 +1099,18 @@ extern void ata_msleep(struct ata_port *ap, unsigned int msecs); extern u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, unsigned long interval, unsigned long timeout); extern int atapi_cmd_type(u8 opcode); -extern unsigned long ata_pack_xfermask(unsigned long pio_mask, - unsigned long mwdma_mask, unsigned long udma_mask); -extern void ata_unpack_xfermask(unsigned long xfer_mask, - unsigned long *pio_mask, unsigned long *mwdma_mask, - unsigned long *udma_mask); -extern u8 ata_xfer_mask2mode(unsigned long xfer_mask); -extern unsigned long ata_xfer_mode2mask(u8 xfer_mode); +extern unsigned int ata_pack_xfermask(unsigned int pio_mask, + unsigned int mwdma_mask, + unsigned int udma_mask); +extern void ata_unpack_xfermask(unsigned int xfer_mask, + unsigned int *pio_mask, + unsigned int *mwdma_mask, + unsigned int *udma_mask); +extern u8 ata_xfer_mask2mode(unsigned int xfer_mask); +extern unsigned int ata_xfer_mode2mask(u8 xfer_mode); extern int ata_xfer_mode2shift(u8 xfer_mode); -extern const char *ata_mode_string(unsigned long xfer_mask); -extern unsigned long ata_id_xfermask(const u16 *id); +extern const char *ata_mode_string(unsigned int xfer_mask); +extern unsigned int ata_id_xfermask(const u16 *id); extern int ata_std_qc_defer(struct ata_queued_cmd *qc); extern enum ata_completion_errors ata_noop_qc_prep(struct ata_queued_cmd *qc); extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, @@ -1283,8 +1282,8 @@ static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap) } int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm); int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *stm); -unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev, - const struct ata_acpi_gtm *gtm); +unsigned int ata_acpi_gtm_xfermask(struct ata_device *dev, + const struct ata_acpi_gtm *gtm); int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm); #else static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap) -- cgit v1.2.3 From d64de9773c18409d2161228242968ff3ebe3707e Mon Sep 17 00:00:00 2001 From: Weili Qian Date: Thu, 9 Jun 2022 20:31:19 +0800 Subject: crypto: hisilicon/qm - modify event irq processing When the driver receives an event interrupt, the driver will enable the event interrupt after handling all completed tasks on the function, tasks on the function are parsed through only one thread. If the task's user callback takes time, other tasks on the function will be blocked. Therefore, the event irq processing is modified as follows: 1. Obtain the ID of the queue that completes the task. 2. Enable event interrupt. 3. Parse the completed tasks in the queue and call the user callback. Enabling event interrupt in advance can quickly report pending event interrupts and process tasks in multiple threads. Signed-off-by: Weili Qian Signed-off-by: Herbert Xu --- drivers/crypto/hisilicon/qm.c | 142 +++++++++++++++++++++++++++--------------- include/linux/hisi_acc_qm.h | 8 ++- 2 files changed, 99 insertions(+), 51 deletions(-) (limited to 'include') diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index f8d36b68494e..ad83c194d664 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -877,13 +877,6 @@ static void qm_pm_put_sync(struct hisi_qm *qm) pm_runtime_put_autosuspend(dev); } -static struct hisi_qp *qm_to_hisi_qp(struct hisi_qm *qm, struct qm_eqe *eqe) -{ - u16 cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK; - - return &qm->qp_array[cqn]; -} - static void qm_cq_head_update(struct hisi_qp *qp) { if (qp->qp_status.cq_head == QM_Q_DEPTH - 1) { @@ -894,47 +887,37 @@ static void qm_cq_head_update(struct hisi_qp *qp) } } -static void qm_poll_qp(struct hisi_qp *qp, struct hisi_qm *qm) +static void qm_poll_req_cb(struct hisi_qp *qp) { - if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP)) - return; - - if (qp->event_cb) { - qp->event_cb(qp); - return; - } - - if (qp->req_cb) { - struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head; - - while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) { - dma_rmb(); - qp->req_cb(qp, qp->sqe + qm->sqe_size * - le16_to_cpu(cqe->sq_head)); - qm_cq_head_update(qp); - cqe = qp->cqe + qp->qp_status.cq_head; - qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ, - qp->qp_status.cq_head, 0); - atomic_dec(&qp->qp_status.used); - } + struct qm_cqe *cqe = qp->cqe + qp->qp_status.cq_head; + struct hisi_qm *qm = qp->qm; - /* set c_flag */ + while (QM_CQE_PHASE(cqe) == qp->qp_status.cqc_phase) { + dma_rmb(); + qp->req_cb(qp, qp->sqe + qm->sqe_size * + le16_to_cpu(cqe->sq_head)); + qm_cq_head_update(qp); + cqe = qp->cqe + qp->qp_status.cq_head; qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ, - qp->qp_status.cq_head, 1); + qp->qp_status.cq_head, 0); + atomic_dec(&qp->qp_status.used); } + + /* set c_flag */ + qm_db(qm, qp->qp_id, QM_DOORBELL_CMD_CQ, qp->qp_status.cq_head, 1); } -static void qm_work_process(struct work_struct *work) +static int qm_get_complete_eqe_num(struct hisi_qm_poll_data *poll_data) { - struct hisi_qm *qm = container_of(work, struct hisi_qm, work); + struct hisi_qm *qm = poll_data->qm; struct qm_eqe *eqe = qm->eqe + qm->status.eq_head; - struct hisi_qp *qp; int eqe_num = 0; + u16 cqn; while (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) { + cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK; + poll_data->qp_finish_id[eqe_num] = cqn; eqe_num++; - qp = qm_to_hisi_qp(qm, eqe); - qm_poll_qp(qp, qm); if (qm->status.eq_head == QM_EQ_DEPTH - 1) { qm->status.eqc_phase = !qm->status.eqc_phase; @@ -945,34 +928,70 @@ static void qm_work_process(struct work_struct *work) qm->status.eq_head++; } - if (eqe_num == QM_EQ_DEPTH / 2 - 1) { - eqe_num = 0; - qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); - } + if (eqe_num == (QM_EQ_DEPTH >> 1) - 1) + break; } qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); + + return eqe_num; } -static irqreturn_t do_qm_irq(int irq, void *data) +static void qm_work_process(struct work_struct *work) { - struct hisi_qm *qm = (struct hisi_qm *)data; + struct hisi_qm_poll_data *poll_data = + container_of(work, struct hisi_qm_poll_data, work); + struct hisi_qm *qm = poll_data->qm; + struct hisi_qp *qp; + int eqe_num, i; - /* the workqueue created by device driver of QM */ - queue_work(qm->wq, &qm->work); + /* Get qp id of completed tasks and re-enable the interrupt. */ + eqe_num = qm_get_complete_eqe_num(poll_data); + for (i = eqe_num - 1; i >= 0; i--) { + qp = &qm->qp_array[poll_data->qp_finish_id[i]]; + if (unlikely(atomic_read(&qp->qp_status.flags) == QP_STOP)) + continue; - return IRQ_HANDLED; + if (qp->event_cb) { + qp->event_cb(qp); + continue; + } + + if (likely(qp->req_cb)) + qm_poll_req_cb(qp); + } +} + +static bool do_qm_irq(struct hisi_qm *qm) +{ + struct qm_eqe *eqe = qm->eqe + qm->status.eq_head; + struct hisi_qm_poll_data *poll_data; + u16 cqn; + + if (!readl(qm->io_base + QM_VF_EQ_INT_SOURCE)) + return false; + + if (QM_EQE_PHASE(eqe) == qm->status.eqc_phase) { + cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK; + poll_data = &qm->poll_data[cqn]; + queue_work(qm->wq, &poll_data->work); + + return true; + } + + return false; } static irqreturn_t qm_irq(int irq, void *data) { struct hisi_qm *qm = data; + bool ret; - if (readl(qm->io_base + QM_VF_EQ_INT_SOURCE)) - return do_qm_irq(irq, data); + ret = do_qm_irq(qm); + if (ret) + return IRQ_HANDLED; atomic64_inc(&qm->debug.dfx.err_irq_cnt); - dev_err(&qm->pdev->dev, "invalid int source\n"); qm_db(qm, 0, QM_DOORBELL_CMD_EQ, qm->status.eq_head, 0); return IRQ_NONE; @@ -3551,8 +3570,10 @@ static void hisi_qp_memory_uninit(struct hisi_qm *qm, int num) for (i = num - 1; i >= 0; i--) { qdma = &qm->qp_array[i].qdma; dma_free_coherent(dev, qdma->size, qdma->va, qdma->dma); + kfree(qm->poll_data[i].qp_finish_id); } + kfree(qm->poll_data); kfree(qm->qp_array); } @@ -3561,12 +3582,18 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id) struct device *dev = &qm->pdev->dev; size_t off = qm->sqe_size * QM_Q_DEPTH; struct hisi_qp *qp; + int ret = -ENOMEM; + + qm->poll_data[id].qp_finish_id = kcalloc(qm->qp_num, sizeof(u16), + GFP_KERNEL); + if (!qm->poll_data[id].qp_finish_id) + return -ENOMEM; qp = &qm->qp_array[id]; qp->qdma.va = dma_alloc_coherent(dev, dma_size, &qp->qdma.dma, GFP_KERNEL); if (!qp->qdma.va) - return -ENOMEM; + goto err_free_qp_finish_id; qp->sqe = qp->qdma.va; qp->sqe_dma = qp->qdma.dma; @@ -3577,6 +3604,10 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id) qp->qp_id = id; return 0; + +err_free_qp_finish_id: + kfree(qm->poll_data[id].qp_finish_id); + return ret; } static void hisi_qm_pre_init(struct hisi_qm *qm) @@ -6024,7 +6055,11 @@ err_disable_pcidev: static int hisi_qm_init_work(struct hisi_qm *qm) { - INIT_WORK(&qm->work, qm_work_process); + int i; + + for (i = 0; i < qm->qp_num; i++) + INIT_WORK(&qm->poll_data[i].work, qm_work_process); + if (qm->fun_type == QM_HW_PF) INIT_WORK(&qm->rst_work, hisi_qm_controller_reset); @@ -6052,11 +6087,18 @@ static int hisi_qp_alloc_memory(struct hisi_qm *qm) if (!qm->qp_array) return -ENOMEM; + qm->poll_data = kcalloc(qm->qp_num, sizeof(struct hisi_qm_poll_data), GFP_KERNEL); + if (!qm->poll_data) { + kfree(qm->qp_array); + return -ENOMEM; + } + /* one more page for device or qp statuses */ qp_dma_size = qm->sqe_size * QM_Q_DEPTH + sizeof(struct qm_cqe) * QM_Q_DEPTH; qp_dma_size = PAGE_ALIGN(qp_dma_size) + PAGE_SIZE; for (i = 0; i < qm->qp_num; i++) { + qm->poll_data[i].qm = qm; ret = hisi_qp_memory_init(qm, qp_dma_size, i); if (ret) goto err_init_qp_mem; diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index 6cabafffd0dd..116e8bd68c99 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -265,6 +265,12 @@ struct hisi_qm_list { void (*unregister_from_crypto)(struct hisi_qm *qm); }; +struct hisi_qm_poll_data { + struct hisi_qm *qm; + struct work_struct work; + u16 *qp_finish_id; +}; + struct hisi_qm { enum qm_hw_ver ver; enum qm_fun_type fun_type; @@ -302,6 +308,7 @@ struct hisi_qm { struct rw_semaphore qps_lock; struct idr qp_idr; struct hisi_qp *qp_array; + struct hisi_qm_poll_data *poll_data; struct mutex mailbox_lock; @@ -312,7 +319,6 @@ struct hisi_qm { u32 error_mask; struct workqueue_struct *wq; - struct work_struct work; struct work_struct rst_work; struct work_struct cmd_process; -- cgit v1.2.3 From fa9c562f9735d24c3253747eb21f3f0c0f6de48e Mon Sep 17 00:00:00 2001 From: Ong Boon Leong Date: Wed, 15 Jun 2022 16:39:04 +0800 Subject: net: make xpcs_do_config to accept advertising for pcs-xpcs and sja1105 xpcs_config() has 'advertising' input that is required for C37 1000BASE-X AN in later patch series. So, we prepare xpcs_do_config() for it. For sja1105, xpcs_do_config() is used for xpcs configuration without depending on advertising input, so set to NULL. Reported-by: kernel test robot Signed-off-by: Ong Boon Leong Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 2 +- drivers/net/pcs/pcs-xpcs.c | 6 +++--- include/linux/pcs/pcs-xpcs.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 72b6fc1932b5..b253e27bcfb4 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2330,7 +2330,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv, else mode = MLO_AN_PHY; - rc = xpcs_do_config(xpcs, priv->phy_mode[i], mode); + rc = xpcs_do_config(xpcs, priv->phy_mode[i], mode, NULL); if (rc < 0) goto out; diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 4cfd05c15aee..48d81c40aab7 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -795,7 +795,7 @@ static int xpcs_config_2500basex(struct dw_xpcs *xpcs) } int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, - unsigned int mode) + unsigned int mode, const unsigned long *advertising) { const struct xpcs_compat *compat; int ret; @@ -843,7 +843,7 @@ static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode, { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); - return xpcs_do_config(xpcs, interface, mode); + return xpcs_do_config(xpcs, interface, mode, advertising); } static int xpcs_get_state_c73(struct dw_xpcs *xpcs, @@ -864,7 +864,7 @@ static int xpcs_get_state_c73(struct dw_xpcs *xpcs, state->link = 0; - return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND); + return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND, NULL); } if (state->an_enabled && xpcs_aneg_done_c73(xpcs, state, compat)) { diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index 266eb26fb029..37eb97cc2283 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -30,7 +30,7 @@ int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface); void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode, phy_interface_t interface, int speed, int duplex); int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, - unsigned int mode); + unsigned int mode, const unsigned long *advertising); void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces); int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable); -- cgit v1.2.3 From b47aec885bcd672ebca2108a8b7e9ce3e3982775 Mon Sep 17 00:00:00 2001 From: Ong Boon Leong Date: Wed, 15 Jun 2022 16:39:06 +0800 Subject: net: pcs: xpcs: add CL37 1000BASE-X AN support For CL37 1000BASE-X AN, DW xPCS does not support C22 method but offers C45 vendor-specific MII MMD for programming. We also add the ability to disable Autoneg (through ethtool for certain network switch that supports 1000BASE-X (1000Mbps and Full-Duplex) but not Autoneg capability. v4: Fixes to comment from Russell King. Thanks! https://patchwork.kernel.org/comment/24894239/ Make xpcs_modify_changed() as private, change to use mdiodev_modify_changed() for cleaner code. v3: Fixes to issues spotted by Russell King. Thanks! https://patchwork.kernel.org/comment/24890210/ Use phylink_mii_c22_pcs_decode_state(), remove unnecessary interrupt clearing and skip speed & duplex setting if AN is enabled. v2: Fixes to issues spotted by Russell King in v1. Thanks! https://patchwork.kernel.org/comment/24826650/ Use phylink_mii_c22_pcs_encode_advertisement() and implement C45 MII ADV handling since IP only support C45 access. Tested-by: Emilio Riva Signed-off-by: Ong Boon Leong Reviewed-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 170 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/pcs/pcs-xpcs.h | 1 - include/linux/pcs/pcs-xpcs.h | 1 + 3 files changed, 171 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 48d81c40aab7..a5d520e34ea3 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -77,6 +77,14 @@ static const int xpcs_sgmii_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; +static const int xpcs_1000basex_features[] = { + ETHTOOL_LINK_MODE_Pause_BIT, + ETHTOOL_LINK_MODE_Asym_Pause_BIT, + ETHTOOL_LINK_MODE_Autoneg_BIT, + ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + __ETHTOOL_LINK_MODE_MASK_NBITS, +}; + static const int xpcs_2500basex_features[] = { ETHTOOL_LINK_MODE_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT, @@ -102,6 +110,10 @@ static const phy_interface_t xpcs_sgmii_interfaces[] = { PHY_INTERFACE_MODE_SGMII, }; +static const phy_interface_t xpcs_1000basex_interfaces[] = { + PHY_INTERFACE_MODE_1000BASEX, +}; + static const phy_interface_t xpcs_2500basex_interfaces[] = { PHY_INTERFACE_MODE_2500BASEX, PHY_INTERFACE_MODE_MAX, @@ -112,6 +124,7 @@ enum { DW_XPCS_10GKR, DW_XPCS_XLGMII, DW_XPCS_SGMII, + DW_XPCS_1000BASEX, DW_XPCS_2500BASEX, DW_XPCS_INTERFACE_MAX, }; @@ -189,6 +202,14 @@ int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val) return mdiobus_c45_write(bus, addr, dev, reg, val); } +static int xpcs_modify_changed(struct dw_xpcs *xpcs, int dev, u32 reg, + u16 mask, u16 set) +{ + u32 reg_addr = mdiobus_c45_addr(dev, reg); + + return mdiodev_modify_changed(xpcs->mdiodev, reg_addr, mask, set); +} + static int xpcs_read_vendor(struct dw_xpcs *xpcs, int dev, u32 reg) { return xpcs_read(xpcs, dev, DW_VENDOR | reg); @@ -237,6 +258,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs, break; case DW_AN_C37_SGMII: case DW_2500BASEX: + case DW_AN_C37_1000BASEX: dev = MDIO_MMD_VEND2; break; default: @@ -772,6 +794,68 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode) return ret; } +static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, unsigned int mode, + const unsigned long *advertising) +{ + phy_interface_t interface = PHY_INTERFACE_MODE_1000BASEX; + int ret, mdio_ctrl, adv; + bool changed = 0; + + /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must + * be disabled first:- + * 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b + * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 00b (1000BASE-X C37) + */ + mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL); + if (mdio_ctrl < 0) + return mdio_ctrl; + + if (mdio_ctrl & AN_CL37_EN) { + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, + mdio_ctrl & ~AN_CL37_EN); + if (ret < 0) + return ret; + } + + ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL); + if (ret < 0) + return ret; + + ret &= ~DW_VR_MII_PCS_MODE_MASK; + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret); + if (ret < 0) + return ret; + + /* Check for advertising changes and update the C45 MII ADV + * register accordingly. + */ + adv = phylink_mii_c22_pcs_encode_advertisement(interface, + advertising); + if (adv >= 0) { + ret = xpcs_modify_changed(xpcs, MDIO_MMD_VEND2, + MII_ADVERTISE, 0xffff, adv); + if (ret < 0) + return ret; + + changed = ret; + } + + /* Clear CL37 AN complete status */ + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0); + if (ret < 0) + return ret; + + if (phylink_autoneg_inband(mode) && + linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) { + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, + mdio_ctrl | AN_CL37_EN); + if (ret < 0) + return ret; + } + + return changed; +} + static int xpcs_config_2500basex(struct dw_xpcs *xpcs) { int ret; @@ -817,6 +901,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, if (ret) return ret; break; + case DW_AN_C37_1000BASEX: + ret = xpcs_config_aneg_c37_1000basex(xpcs, mode, + advertising); + if (ret) + return ret; + break; case DW_2500BASEX: ret = xpcs_config_2500basex(xpcs); if (ret) @@ -921,6 +1011,29 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, return 0; } +static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs, + struct phylink_link_state *state) +{ + int lpa, bmsr; + + if (state->an_enabled) { + /* Reset link state */ + state->link = false; + + lpa = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_LPA); + if (lpa < 0 || lpa & LPA_RFAULT) + return lpa; + + bmsr = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMSR); + if (bmsr < 0) + return bmsr; + + phylink_mii_c22_pcs_decode_state(state, bmsr, lpa); + } + + return 0; +} + static void xpcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state) { @@ -948,6 +1061,13 @@ static void xpcs_get_state(struct phylink_pcs *pcs, ERR_PTR(ret)); } break; + case DW_AN_C37_1000BASEX: + ret = xpcs_get_state_c37_1000basex(xpcs, state); + if (ret) { + pr_err("xpcs_get_state_c37_1000basex returned %pe\n", + ERR_PTR(ret)); + } + break; default: return; } @@ -983,6 +1103,35 @@ static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode, pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret)); } +static void xpcs_link_up_1000basex(struct dw_xpcs *xpcs, unsigned int mode, + int speed, int duplex) +{ + int val, ret; + + if (phylink_autoneg_inband(mode)) + return; + + switch (speed) { + case SPEED_1000: + val = BMCR_SPEED1000; + break; + case SPEED_100: + case SPEED_10: + default: + pr_err("%s: speed = %d\n", __func__, speed); + return; + } + + if (duplex == DUPLEX_FULL) + val |= BMCR_FULLDPLX; + else + pr_err("%s: half duplex not supported\n", __func__); + + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val); + if (ret) + pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret)); +} + void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode, phy_interface_t interface, int speed, int duplex) { @@ -992,9 +1141,23 @@ void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode, return xpcs_config_usxgmii(xpcs, speed); if (interface == PHY_INTERFACE_MODE_SGMII) return xpcs_link_up_sgmii(xpcs, mode, speed, duplex); + if (interface == PHY_INTERFACE_MODE_1000BASEX) + return xpcs_link_up_1000basex(xpcs, mode, speed, duplex); } EXPORT_SYMBOL_GPL(xpcs_link_up); +static void xpcs_an_restart(struct phylink_pcs *pcs) +{ + struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); + int ret; + + ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1); + if (ret >= 0) { + ret |= BMCR_ANRESTART; + xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret); + } +} + static u32 xpcs_get_id(struct dw_xpcs *xpcs) { int ret; @@ -1060,6 +1223,12 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, }, + [DW_XPCS_1000BASEX] = { + .supported = xpcs_1000basex_features, + .interface = xpcs_1000basex_interfaces, + .num_interfaces = ARRAY_SIZE(xpcs_1000basex_interfaces), + .an_mode = DW_AN_C37_1000BASEX, + }, [DW_XPCS_2500BASEX] = { .supported = xpcs_2500basex_features, .interface = xpcs_2500basex_interfaces, @@ -1115,6 +1284,7 @@ static const struct phylink_pcs_ops xpcs_phylink_ops = { .pcs_validate = xpcs_validate, .pcs_config = xpcs_config, .pcs_get_state = xpcs_get_state, + .pcs_an_restart = xpcs_an_restart, .pcs_link_up = xpcs_link_up, }; diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h index 35651d32a224..770df50323a0 100644 --- a/drivers/net/pcs/pcs-xpcs.h +++ b/drivers/net/pcs/pcs-xpcs.h @@ -109,7 +109,6 @@ int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg); int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val); - int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs); int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs); int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs); diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index 37eb97cc2283..d2da1e0b4a92 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -17,6 +17,7 @@ #define DW_AN_C73 1 #define DW_AN_C37_SGMII 2 #define DW_2500BASEX 3 +#define DW_AN_C37_1000BASEX 4 struct xpcs_id; -- cgit v1.2.3 From d0804085c5a7feb557bd3219777b51f5598dfdc6 Mon Sep 17 00:00:00 2001 From: Moudy Ho Date: Fri, 10 Jun 2022 14:34:18 +0800 Subject: soc: mediatek: mutex: add common interface for modules setting In order to allow multiple modules to operate MUTEX hardware through a common interfrace, two flexible indexes "mtk_mutex_mod_index" and "mtk_mutex_sof_index" need to be added to replace original component ID so that like DDP and MDP can add their own MOD table or SOF settings independently. In addition, 2 generic interface "mtk_mutex_write_mod" and "mtk_mutex_write_sof" have been added, which is expected to replace the "mtk_mutex_add_comp" and "mtk_mutex_remove_comp" pair originally dedicated to DDP in the future. Signed-off-by: Moudy Ho Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rex-BC Chen Reviewed-by: CK Hu Link: https://lore.kernel.org/r/20220610063424.7800-2-moudy.ho@mediatek.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-mutex.c | 53 ++++++++++++++++++++++++++++++++++ include/linux/soc/mediatek/mtk-mutex.h | 25 ++++++++++++++++ 2 files changed, 78 insertions(+) (limited to 'include') diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c index b8d5c4a62542..56987e2ff906 100644 --- a/drivers/soc/mediatek/mtk-mutex.c +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -199,6 +199,7 @@ struct mtk_mutex_data { const unsigned int *mutex_sof; const unsigned int mutex_mod_reg; const unsigned int mutex_sof_reg; + const unsigned int *mutex_table_mod; const bool no_clk; }; @@ -644,6 +645,58 @@ void mtk_mutex_release(struct mtk_mutex *mutex) } EXPORT_SYMBOL_GPL(mtk_mutex_release); +int mtk_mutex_write_mod(struct mtk_mutex *mutex, + enum mtk_mutex_mod_index idx, bool clear) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + unsigned int reg; + unsigned int offset; + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + if (idx < MUTEX_MOD_IDX_MDP_RDMA0 || + idx >= MUTEX_MOD_IDX_MAX) { + dev_err(mtx->dev, "Not supported MOD table index : %d", idx); + return -EINVAL; + } + + offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, + mutex->id); + reg = readl_relaxed(mtx->regs + offset); + + if (clear) + reg &= ~BIT(mtx->data->mutex_table_mod[idx]); + else + reg |= BIT(mtx->data->mutex_table_mod[idx]); + + writel_relaxed(reg, mtx->regs + offset); + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_mutex_write_mod); + +int mtk_mutex_write_sof(struct mtk_mutex *mutex, + enum mtk_mutex_sof_index idx) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + if (idx < MUTEX_SOF_IDX_SINGLE_MODE || + idx >= MUTEX_SOF_IDX_MAX) { + dev_err(mtx->dev, "Not supported SOF index : %d", idx); + return -EINVAL; + } + + writel_relaxed(idx, mtx->regs + + DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id)); + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_mutex_write_sof); + static int mtk_mutex_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; diff --git a/include/linux/soc/mediatek/mtk-mutex.h b/include/linux/soc/mediatek/mtk-mutex.h index 6fe4ffbde290..2ddab9d2b85d 100644 --- a/include/linux/soc/mediatek/mtk-mutex.h +++ b/include/linux/soc/mediatek/mtk-mutex.h @@ -10,6 +10,26 @@ struct regmap; struct device; struct mtk_mutex; +enum mtk_mutex_mod_index { + /* MDP table index */ + MUTEX_MOD_IDX_MDP_RDMA0, + MUTEX_MOD_IDX_MDP_RSZ0, + MUTEX_MOD_IDX_MDP_RSZ1, + MUTEX_MOD_IDX_MDP_TDSHP0, + MUTEX_MOD_IDX_MDP_WROT0, + MUTEX_MOD_IDX_MDP_WDMA, + MUTEX_MOD_IDX_MDP_AAL0, + MUTEX_MOD_IDX_MDP_CCORR0, + + MUTEX_MOD_IDX_MAX /* ALWAYS keep at the end */ +}; + +enum mtk_mutex_sof_index { + MUTEX_SOF_IDX_SINGLE_MODE, + + MUTEX_SOF_IDX_MAX /* ALWAYS keep at the end */ +}; + struct mtk_mutex *mtk_mutex_get(struct device *dev); int mtk_mutex_prepare(struct mtk_mutex *mutex); void mtk_mutex_add_comp(struct mtk_mutex *mutex, @@ -22,5 +42,10 @@ void mtk_mutex_unprepare(struct mtk_mutex *mutex); void mtk_mutex_put(struct mtk_mutex *mutex); void mtk_mutex_acquire(struct mtk_mutex *mutex); void mtk_mutex_release(struct mtk_mutex *mutex); +int mtk_mutex_write_mod(struct mtk_mutex *mutex, + enum mtk_mutex_mod_index idx, + bool clear); +int mtk_mutex_write_sof(struct mtk_mutex *mutex, + enum mtk_mutex_sof_index idx); #endif /* MTK_MUTEX_H */ -- cgit v1.2.3 From e5758850c2ea448dd750a280d128a3590d68b899 Mon Sep 17 00:00:00 2001 From: Moudy Ho Date: Fri, 10 Jun 2022 14:34:23 +0800 Subject: soc: mediatek: mutex: add functions that operate registers by CMDQ Due to HW limitations, MDP3 is necessary to enable MUTEX in each frame for SOF triggering and cooperate with CMDQ control to reduce the amount of interrupts generated(also, reduce frame latency). In response to the above situation, a new interface "mtk_mutex_enable_by_cmdq" has been added to achieve the purpose. Signed-off-by: Moudy Ho Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rex-BC Chen Reviewed-by: CK Hu Link: https://lore.kernel.org/r/20220610063424.7800-7-moudy.ho@mediatek.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-mutex.c | 45 +++++++++++++++++++++++++++++++++- include/linux/soc/mediatek/mtk-mutex.h | 2 ++ 2 files changed, 46 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c index a566f4cf6372..fa8e0ba38803 100644 --- a/drivers/soc/mediatek/mtk-mutex.c +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -7,10 +7,12 @@ #include #include #include +#include #include #include #include #include +#include #define MT2701_MUTEX0_MOD0 0x2c #define MT2701_MUTEX0_SOF0 0x30 @@ -218,6 +220,8 @@ struct mtk_mutex_ctx { void __iomem *regs; struct mtk_mutex mutex[10]; const struct mtk_mutex_data *data; + phys_addr_t addr; + struct cmdq_client_reg cmdq_reg; }; static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = { @@ -632,6 +636,30 @@ void mtk_mutex_enable(struct mtk_mutex *mutex) } EXPORT_SYMBOL_GPL(mtk_mutex_enable); +int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, void *pkt) +{ + struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, + mutex[mutex->id]); +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + struct cmdq_pkt *cmdq_pkt = (struct cmdq_pkt *)pkt; + + WARN_ON(&mtx->mutex[mutex->id] != mutex); + + if (!mtx->cmdq_reg.size) { + dev_err(mtx->dev, "mediatek,gce-client-reg hasn't been set"); + return -EINVAL; + } + + cmdq_pkt_write(cmdq_pkt, mtx->cmdq_reg.subsys, + mtx->addr + DISP_REG_MUTEX_EN(mutex->id), 1); + return 0; +#else + dev_err(mtx->dev, "Not support for enable MUTEX by CMDQ"); + return -ENODEV; +#endif +} +EXPORT_SYMBOL_GPL(mtk_mutex_enable_by_cmdq); + void mtk_mutex_disable(struct mtk_mutex *mutex) { struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, @@ -722,8 +750,11 @@ static int mtk_mutex_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_mutex_ctx *mtx; - struct resource *regs; + struct resource *regs, addr; int i; +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + int ret; +#endif mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL); if (!mtx) @@ -743,6 +774,18 @@ static int mtk_mutex_probe(struct platform_device *pdev) } } + if (of_address_to_resource(dev->of_node, 0, &addr) < 0) { + dev_err(dev, "Failed to get addr\n"); + return -EINVAL; + } + mtx->addr = addr.start; + +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + ret = cmdq_dev_get_client_reg(dev, &mtx->cmdq_reg, 0); + if (ret) + dev_dbg(dev, "No mediatek,gce-client-reg!\n"); +#endif + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); mtx->regs = devm_ioremap_resource(dev, regs); if (IS_ERR(mtx->regs)) { diff --git a/include/linux/soc/mediatek/mtk-mutex.h b/include/linux/soc/mediatek/mtk-mutex.h index 2ddab9d2b85d..a0f4f51a3b45 100644 --- a/include/linux/soc/mediatek/mtk-mutex.h +++ b/include/linux/soc/mediatek/mtk-mutex.h @@ -35,6 +35,8 @@ int mtk_mutex_prepare(struct mtk_mutex *mutex); void mtk_mutex_add_comp(struct mtk_mutex *mutex, enum mtk_ddp_comp_id id); void mtk_mutex_enable(struct mtk_mutex *mutex); +int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, + void *pkt); void mtk_mutex_disable(struct mtk_mutex *mutex); void mtk_mutex_remove_comp(struct mtk_mutex *mutex, enum mtk_ddp_comp_id id); -- cgit v1.2.3 From dc368e1c658e4f478a45e8d1d5b0c8392ca87506 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 16 Jun 2022 15:54:07 -0700 Subject: bpf: Fix non-static bpf_func_proto struct definitions This patch does two things: 1) Marks the dynptr bpf_func_proto structs that were added in [1] as static, as pointed out by the kernel test robot in [2]. 2) There are some bpf_func_proto structs marked as extern which can instead be statically defined. [1] https://lore.kernel.org/bpf/20220523210712.3641569-1-joannelkoong@gmail.com/ [2] https://lore.kernel.org/bpf/62ab89f2.Pko7sI08RAKdF8R6%25lkp@intel.com/ Reported-by: kernel test robot Signed-off-by: Joanne Koong Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20220616225407.1878436-1-joannelkoong@gmail.com --- include/linux/bpf.h | 3 --- kernel/bpf/helpers.c | 12 ++++++------ kernel/bpf/syscall.c | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index a94531971a7a..0edd7d2c0064 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2363,12 +2363,9 @@ extern const struct bpf_func_proto bpf_for_each_map_elem_proto; extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto; extern const struct bpf_func_proto bpf_sk_setsockopt_proto; extern const struct bpf_func_proto bpf_sk_getsockopt_proto; -extern const struct bpf_func_proto bpf_kallsyms_lookup_name_proto; extern const struct bpf_func_proto bpf_find_vma_proto; extern const struct bpf_func_proto bpf_loop_proto; -extern const struct bpf_func_proto bpf_strncmp_proto; extern const struct bpf_func_proto bpf_copy_from_user_task_proto; -extern const struct bpf_func_proto bpf_kptr_xchg_proto; const struct bpf_func_proto *tracing_prog_func_proto( enum bpf_func_id func_id, const struct bpf_prog *prog); diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 225806a02efb..a1c84d256f83 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -584,7 +584,7 @@ BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2) return strncmp(s1, s2, s1_sz); } -const struct bpf_func_proto bpf_strncmp_proto = { +static const struct bpf_func_proto bpf_strncmp_proto = { .func = bpf_strncmp, .gpl_only = false, .ret_type = RET_INTEGER, @@ -1402,7 +1402,7 @@ BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr) */ #define BPF_PTR_POISON ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA)) -const struct bpf_func_proto bpf_kptr_xchg_proto = { +static const struct bpf_func_proto bpf_kptr_xchg_proto = { .func = bpf_kptr_xchg, .gpl_only = false, .ret_type = RET_PTR_TO_BTF_ID_OR_NULL, @@ -1487,7 +1487,7 @@ error: return err; } -const struct bpf_func_proto bpf_dynptr_from_mem_proto = { +static const struct bpf_func_proto bpf_dynptr_from_mem_proto = { .func = bpf_dynptr_from_mem, .gpl_only = false, .ret_type = RET_INTEGER, @@ -1513,7 +1513,7 @@ BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src return 0; } -const struct bpf_func_proto bpf_dynptr_read_proto = { +static const struct bpf_func_proto bpf_dynptr_read_proto = { .func = bpf_dynptr_read, .gpl_only = false, .ret_type = RET_INTEGER, @@ -1539,7 +1539,7 @@ BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, return 0; } -const struct bpf_func_proto bpf_dynptr_write_proto = { +static const struct bpf_func_proto bpf_dynptr_write_proto = { .func = bpf_dynptr_write, .gpl_only = false, .ret_type = RET_INTEGER, @@ -1566,7 +1566,7 @@ BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len return (unsigned long)(ptr->data + ptr->offset + offset); } -const struct bpf_func_proto bpf_dynptr_data_proto = { +static const struct bpf_func_proto bpf_dynptr_data_proto = { .func = bpf_dynptr_data, .gpl_only = false, .ret_type = RET_PTR_TO_DYNPTR_MEM_OR_NULL, diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index aeb31137b2ed..7d5af5b99f0d 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -5131,7 +5131,7 @@ BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flag return *res ? 0 : -ENOENT; } -const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = { +static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = { .func = bpf_kallsyms_lookup_name, .gpl_only = false, .ret_type = RET_INTEGER, -- cgit v1.2.3 From 5994f58977e0123d5cb77617b3cc4676325028dd Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 10 Jun 2022 12:24:09 +0300 Subject: dt-bindings: reset: add sama7g5 definitions Add reset bindings for SAMA7G5. At the moment only USB PHYs are included. Signed-off-by: Claudiu Beznea Acked-by: Philipp Zabel Acked-by: Rob Herring Signed-off-by: Sebastian Reichel --- include/dt-bindings/reset/sama7g5-reset.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 include/dt-bindings/reset/sama7g5-reset.h (limited to 'include') diff --git a/include/dt-bindings/reset/sama7g5-reset.h b/include/dt-bindings/reset/sama7g5-reset.h new file mode 100644 index 000000000000..2116f41d04e0 --- /dev/null +++ b/include/dt-bindings/reset/sama7g5-reset.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef __DT_BINDINGS_RESET_SAMA7G5_H +#define __DT_BINDINGS_RESET_SAMA7G5_H + +#define SAMA7G5_RESET_USB_PHY1 4 +#define SAMA7G5_RESET_USB_PHY2 5 +#define SAMA7G5_RESET_USB_PHY3 6 + +#endif /* __DT_BINDINGS_RESET_SAMA7G5_H */ -- cgit v1.2.3 From 9a2139c2912ea64e288749c21452930dc752d4fd Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Fri, 29 Apr 2022 23:08:56 +0100 Subject: spmi: add a helper to look up an SPMI device from a device node The helper function spmi_device_from_of() takes a device node and returns the SPMI device associated with it. This is like of_find_device_by_node but for SPMI devices. Signed-off-by: Caleb Connolly Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20220429220904.137297-2-caleb.connolly@linaro.org Signed-off-by: Jonathan Cameron --- drivers/spmi/spmi.c | 17 +++++++++++++++++ include/linux/spmi.h | 3 +++ 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c index b37ead9e2fad..a456ce5141e1 100644 --- a/drivers/spmi/spmi.c +++ b/drivers/spmi/spmi.c @@ -386,6 +386,23 @@ static struct bus_type spmi_bus_type = { .uevent = spmi_drv_uevent, }; +/** + * spmi_device_from_of() - get the associated SPMI device from a device node + * + * @np: device node + * + * Returns the struct spmi_device associated with a device node or NULL. + */ +struct spmi_device *spmi_device_from_of(struct device_node *np) +{ + struct device *dev = bus_find_device_by_of_node(&spmi_bus_type, np); + + if (dev) + return to_spmi_device(dev); + return NULL; +} +EXPORT_SYMBOL_GPL(spmi_device_from_of); + /** * spmi_controller_alloc() - Allocate a new SPMI device * @ctrl: associated controller diff --git a/include/linux/spmi.h b/include/linux/spmi.h index 729bcbf9f5ad..eac1956a8727 100644 --- a/include/linux/spmi.h +++ b/include/linux/spmi.h @@ -164,6 +164,9 @@ static inline void spmi_driver_unregister(struct spmi_driver *sdrv) module_driver(__spmi_driver, spmi_driver_register, \ spmi_driver_unregister) +struct device_node; + +struct spmi_device *spmi_device_from_of(struct device_node *np); int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf); int spmi_ext_register_read(struct spmi_device *sdev, u8 addr, u8 *buf, size_t len); -- cgit v1.2.3 From e9c11c6e3a0e93903f5a13f8d2f97ae1bba512e1 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Fri, 29 Apr 2022 23:08:57 +0100 Subject: mfd: qcom-spmi-pmic: expose the PMIC revid information to clients Some PMIC functions such as the RRADC need to be aware of the PMIC chip revision information to implement errata or otherwise adjust behaviour, export the PMIC information to enable this. This is specifically required to enable the RRADC to adjust coefficients based on which chip fab the PMIC was produced in, this can vary per unique device and therefore has to be read at runtime. Signed-off-by: Caleb Connolly Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov Acked-by: Lee Jones Link: https://lore.kernel.org/r/20220429220904.137297-3-caleb.connolly@linaro.org Signed-off-by: Jonathan Cameron --- drivers/mfd/qcom-spmi-pmic.c | 265 +++++++++++++++++++++++++------------- include/soc/qcom/qcom-spmi-pmic.h | 60 +++++++++ 2 files changed, 235 insertions(+), 90 deletions(-) create mode 100644 include/soc/qcom/qcom-spmi-pmic.h (limited to 'include') diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index 1cacc00aa6c9..0f1f60e4daf7 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -3,11 +3,16 @@ * Copyright (c) 2014, The Linux Foundation. All rights reserved. */ +#include +#include +#include #include #include #include +#include #include #include +#include #define PMIC_REV2 0x101 #define PMIC_REV3 0x102 @@ -17,106 +22,140 @@ #define PMIC_TYPE_VALUE 0x51 -#define COMMON_SUBTYPE 0x00 -#define PM8941_SUBTYPE 0x01 -#define PM8841_SUBTYPE 0x02 -#define PM8019_SUBTYPE 0x03 -#define PM8226_SUBTYPE 0x04 -#define PM8110_SUBTYPE 0x05 -#define PMA8084_SUBTYPE 0x06 -#define PMI8962_SUBTYPE 0x07 -#define PMD9635_SUBTYPE 0x08 -#define PM8994_SUBTYPE 0x09 -#define PMI8994_SUBTYPE 0x0a -#define PM8916_SUBTYPE 0x0b -#define PM8004_SUBTYPE 0x0c -#define PM8909_SUBTYPE 0x0d -#define PM8028_SUBTYPE 0x0e -#define PM8901_SUBTYPE 0x0f -#define PM8950_SUBTYPE 0x10 -#define PMI8950_SUBTYPE 0x11 -#define PM8998_SUBTYPE 0x14 -#define PMI8998_SUBTYPE 0x15 -#define PM8005_SUBTYPE 0x18 -#define PM660L_SUBTYPE 0x1A -#define PM660_SUBTYPE 0x1B -#define PM8150_SUBTYPE 0x1E -#define PM8150L_SUBTYPE 0x1f -#define PM8150B_SUBTYPE 0x20 -#define PMK8002_SUBTYPE 0x21 -#define PM8009_SUBTYPE 0x24 -#define PM8150C_SUBTYPE 0x26 -#define SMB2351_SUBTYPE 0x29 +#define PMIC_REV4_V2 0x02 + +struct qcom_spmi_dev { + int num_usids; + struct qcom_spmi_pmic pmic; +}; + +#define N_USIDS(n) ((void *)n) static const struct of_device_id pmic_spmi_id_table[] = { - { .compatible = "qcom,pm660", .data = (void *)PM660_SUBTYPE }, - { .compatible = "qcom,pm660l", .data = (void *)PM660L_SUBTYPE }, - { .compatible = "qcom,pm8004", .data = (void *)PM8004_SUBTYPE }, - { .compatible = "qcom,pm8005", .data = (void *)PM8005_SUBTYPE }, - { .compatible = "qcom,pm8019", .data = (void *)PM8019_SUBTYPE }, - { .compatible = "qcom,pm8028", .data = (void *)PM8028_SUBTYPE }, - { .compatible = "qcom,pm8110", .data = (void *)PM8110_SUBTYPE }, - { .compatible = "qcom,pm8150", .data = (void *)PM8150_SUBTYPE }, - { .compatible = "qcom,pm8150b", .data = (void *)PM8150B_SUBTYPE }, - { .compatible = "qcom,pm8150c", .data = (void *)PM8150C_SUBTYPE }, - { .compatible = "qcom,pm8150l", .data = (void *)PM8150L_SUBTYPE }, - { .compatible = "qcom,pm8226", .data = (void *)PM8226_SUBTYPE }, - { .compatible = "qcom,pm8841", .data = (void *)PM8841_SUBTYPE }, - { .compatible = "qcom,pm8901", .data = (void *)PM8901_SUBTYPE }, - { .compatible = "qcom,pm8909", .data = (void *)PM8909_SUBTYPE }, - { .compatible = "qcom,pm8916", .data = (void *)PM8916_SUBTYPE }, - { .compatible = "qcom,pm8941", .data = (void *)PM8941_SUBTYPE }, - { .compatible = "qcom,pm8950", .data = (void *)PM8950_SUBTYPE }, - { .compatible = "qcom,pm8994", .data = (void *)PM8994_SUBTYPE }, - { .compatible = "qcom,pm8998", .data = (void *)PM8998_SUBTYPE }, - { .compatible = "qcom,pma8084", .data = (void *)PMA8084_SUBTYPE }, - { .compatible = "qcom,pmd9635", .data = (void *)PMD9635_SUBTYPE }, - { .compatible = "qcom,pmi8950", .data = (void *)PMI8950_SUBTYPE }, - { .compatible = "qcom,pmi8962", .data = (void *)PMI8962_SUBTYPE }, - { .compatible = "qcom,pmi8994", .data = (void *)PMI8994_SUBTYPE }, - { .compatible = "qcom,pmi8998", .data = (void *)PMI8998_SUBTYPE }, - { .compatible = "qcom,pmk8002", .data = (void *)PMK8002_SUBTYPE }, - { .compatible = "qcom,smb2351", .data = (void *)SMB2351_SUBTYPE }, - { .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE }, + { .compatible = "qcom,pm660", .data = N_USIDS(2) }, + { .compatible = "qcom,pm660l", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8004", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8005", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8019", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8028", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8110", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8150", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8150b", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8150c", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8150l", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8226", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8841", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8901", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8909", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8916", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8941", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8950", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8994", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8998", .data = N_USIDS(2) }, + { .compatible = "qcom,pma8084", .data = N_USIDS(2) }, + { .compatible = "qcom,pmd9635", .data = N_USIDS(2) }, + { .compatible = "qcom,pmi8950", .data = N_USIDS(2) }, + { .compatible = "qcom,pmi8962", .data = N_USIDS(2) }, + { .compatible = "qcom,pmi8994", .data = N_USIDS(2) }, + { .compatible = "qcom,pmi8998", .data = N_USIDS(2) }, + { .compatible = "qcom,pmk8002", .data = N_USIDS(2) }, + { .compatible = "qcom,smb2351", .data = N_USIDS(2) }, + { .compatible = "qcom,spmi-pmic", .data = N_USIDS(1) }, { } }; -static void pmic_spmi_show_revid(struct regmap *map, struct device *dev) +/* + * A PMIC can be represented by multiple SPMI devices, but + * only the base PMIC device will contain a reference to + * the revision information. + * + * This function takes a pointer to a pmic device and + * returns a pointer to the base PMIC device. + * + * This only supports PMICs with 1 or 2 USIDs. + */ +static struct spmi_device *qcom_pmic_get_base_usid(struct device *dev) { - unsigned int rev2, minor, major, type, subtype; - const char *name = "unknown"; - int ret, i; + struct spmi_device *sdev; + struct qcom_spmi_dev *ctx; + struct device_node *spmi_bus; + struct device_node *other_usid = NULL; + int function_parent_usid, ret; + u32 pmic_addr; - ret = regmap_read(map, PMIC_TYPE, &type); - if (ret < 0) - return; + sdev = to_spmi_device(dev); + ctx = dev_get_drvdata(&sdev->dev); + + /* + * Quick return if the function device is already in the base + * USID. This will always be hit for PMICs with only 1 USID. + */ + if (sdev->usid % ctx->num_usids == 0) + return sdev; - if (type != PMIC_TYPE_VALUE) - return; + function_parent_usid = sdev->usid; + + /* + * Walk through the list of PMICs until we find the sibling USID. + * The goal is to find the first USID which is less than the + * number of USIDs in the PMIC array, e.g. for a PMIC with 2 USIDs + * where the function device is under USID 3, we want to find the + * device for USID 2. + */ + spmi_bus = of_get_parent(sdev->dev.of_node); + do { + other_usid = of_get_next_child(spmi_bus, other_usid); + + ret = of_property_read_u32_index(other_usid, "reg", 0, &pmic_addr); + if (ret) + return ERR_PTR(ret); + + sdev = spmi_device_from_of(other_usid); + if (pmic_addr == function_parent_usid - (ctx->num_usids - 1)) { + if (!sdev) + /* + * If the base USID for this PMIC hasn't probed yet + * but the secondary USID has, then we need to defer + * the function driver so that it will attempt to + * probe again when the base USID is ready. + */ + return ERR_PTR(-EPROBE_DEFER); + return sdev; + } + } while (other_usid->sibling); + + return ERR_PTR(-ENODATA); +} + +static int pmic_spmi_load_revid(struct regmap *map, struct device *dev, + struct qcom_spmi_pmic *pmic) +{ + int ret; - ret = regmap_read(map, PMIC_SUBTYPE, &subtype); + ret = regmap_read(map, PMIC_TYPE, &pmic->type); if (ret < 0) - return; + return ret; - for (i = 0; i < ARRAY_SIZE(pmic_spmi_id_table); i++) { - if (subtype == (unsigned long)pmic_spmi_id_table[i].data) - break; - } + if (pmic->type != PMIC_TYPE_VALUE) + return ret; + + ret = regmap_read(map, PMIC_SUBTYPE, &pmic->subtype); + if (ret < 0) + return ret; - if (i != ARRAY_SIZE(pmic_spmi_id_table)) - name = pmic_spmi_id_table[i].compatible; + pmic->name = of_match_device(pmic_spmi_id_table, dev)->compatible; - ret = regmap_read(map, PMIC_REV2, &rev2); + ret = regmap_read(map, PMIC_REV2, &pmic->rev2); if (ret < 0) - return; + return ret; - ret = regmap_read(map, PMIC_REV3, &minor); + ret = regmap_read(map, PMIC_REV3, &pmic->minor); if (ret < 0) - return; + return ret; - ret = regmap_read(map, PMIC_REV4, &major); + ret = regmap_read(map, PMIC_REV4, &pmic->major); if (ret < 0) - return; + return ret; /* * In early versions of PM8941 and PM8226, the major revision number @@ -124,15 +163,49 @@ static void pmic_spmi_show_revid(struct regmap *map, struct device *dev) * Increment the major revision number here if the chip is an early * version of PM8941 or PM8226. */ - if ((subtype == PM8941_SUBTYPE || subtype == PM8226_SUBTYPE) && - major < 0x02) - major++; + if ((pmic->subtype == PM8941_SUBTYPE || pmic->subtype == PM8226_SUBTYPE) && + pmic->major < PMIC_REV4_V2) + pmic->major++; + + if (pmic->subtype == PM8110_SUBTYPE) + pmic->minor = pmic->rev2; + + dev_dbg(dev, "%x: %s v%d.%d\n", + pmic->subtype, pmic->name, pmic->major, pmic->minor); + + return 0; +} + +/** + * qcom_pmic_get() - Get a pointer to the base PMIC device + * + * This function takes a struct device for a driver which is a child of a PMIC. + * And locates the PMIC revision information for it. + * + * @dev: the pmic function device + * @return: the struct qcom_spmi_pmic* pointer associated with the function device + */ +const struct qcom_spmi_pmic *qcom_pmic_get(struct device *dev) +{ + struct spmi_device *sdev; + struct qcom_spmi_dev *spmi; + + /* + * Make sure the device is actually a child of a PMIC + */ + if (!of_match_device(pmic_spmi_id_table, dev->parent)) + return ERR_PTR(-EINVAL); + + sdev = qcom_pmic_get_base_usid(dev->parent); - if (subtype == PM8110_SUBTYPE) - minor = rev2; + if (IS_ERR(sdev)) + return ERR_CAST(sdev); - dev_dbg(dev, "%x: %s v%d.%d\n", subtype, name, major, minor); + spmi = dev_get_drvdata(&sdev->dev); + + return &spmi->pmic; } +EXPORT_SYMBOL(qcom_pmic_get); static const struct regmap_config spmi_regmap_config = { .reg_bits = 16, @@ -144,14 +217,26 @@ static const struct regmap_config spmi_regmap_config = { static int pmic_spmi_probe(struct spmi_device *sdev) { struct regmap *regmap; + struct qcom_spmi_dev *ctx; + int ret; regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); + ctx = devm_kzalloc(&sdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->num_usids = (uintptr_t)of_device_get_match_data(&sdev->dev); + /* Only the first slave id for a PMIC contains this information */ - if (sdev->usid % 2 == 0) - pmic_spmi_show_revid(regmap, &sdev->dev); + if (sdev->usid % ctx->num_usids == 0) { + ret = pmic_spmi_load_revid(regmap, &sdev->dev, &ctx->pmic); + if (ret < 0) + return ret; + } + spmi_device_set_drvdata(sdev, ctx); return devm_of_platform_populate(&sdev->dev); } diff --git a/include/soc/qcom/qcom-spmi-pmic.h b/include/soc/qcom/qcom-spmi-pmic.h new file mode 100644 index 000000000000..5894da3c7f6a --- /dev/null +++ b/include/soc/qcom/qcom-spmi-pmic.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2022 Linaro. All rights reserved. + * Author: Caleb Connolly + */ + +#ifndef __QCOM_SPMI_PMIC_H__ +#define __QCOM_SPMI_PMIC_H__ + +#include + +#define COMMON_SUBTYPE 0x00 +#define PM8941_SUBTYPE 0x01 +#define PM8841_SUBTYPE 0x02 +#define PM8019_SUBTYPE 0x03 +#define PM8226_SUBTYPE 0x04 +#define PM8110_SUBTYPE 0x05 +#define PMA8084_SUBTYPE 0x06 +#define PMI8962_SUBTYPE 0x07 +#define PMD9635_SUBTYPE 0x08 +#define PM8994_SUBTYPE 0x09 +#define PMI8994_SUBTYPE 0x0a +#define PM8916_SUBTYPE 0x0b +#define PM8004_SUBTYPE 0x0c +#define PM8909_SUBTYPE 0x0d +#define PM8028_SUBTYPE 0x0e +#define PM8901_SUBTYPE 0x0f +#define PM8950_SUBTYPE 0x10 +#define PMI8950_SUBTYPE 0x11 +#define PM8998_SUBTYPE 0x14 +#define PMI8998_SUBTYPE 0x15 +#define PM8005_SUBTYPE 0x18 +#define PM660L_SUBTYPE 0x1A +#define PM660_SUBTYPE 0x1B +#define PM8150_SUBTYPE 0x1E +#define PM8150L_SUBTYPE 0x1f +#define PM8150B_SUBTYPE 0x20 +#define PMK8002_SUBTYPE 0x21 +#define PM8009_SUBTYPE 0x24 +#define PM8150C_SUBTYPE 0x26 +#define SMB2351_SUBTYPE 0x29 + +#define PMI8998_FAB_ID_SMIC 0x11 +#define PMI8998_FAB_ID_GF 0x30 + +#define PM660_FAB_ID_GF 0x0 +#define PM660_FAB_ID_TSMC 0x2 +#define PM660_FAB_ID_MX 0x3 + +struct qcom_spmi_pmic { + unsigned int type; + unsigned int subtype; + unsigned int major; + unsigned int minor; + unsigned int rev2; + const char *name; +}; + +const struct qcom_spmi_pmic *qcom_pmic_get(struct device *dev); + +#endif /* __QCOM_SPMI_PMIC_H__ */ -- cgit v1.2.3 From d23c3c085a95fddae5143823b7d5a81419e6f497 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Fri, 29 Apr 2022 23:08:58 +0100 Subject: mfd: qcom-spmi-pmic: read fab id on supported PMICs The PMI8998 and PM660 expose the fab_id, this is needed by drivers like the RRADC to calibrate ADC values. Signed-off-by: Caleb Connolly Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov Acked-by: Lee Jones Link: https://lore.kernel.org/r/20220429220904.137297-4-caleb.connolly@linaro.org Signed-off-by: Jonathan Cameron --- drivers/mfd/qcom-spmi-pmic.c | 7 +++++++ include/soc/qcom/qcom-spmi-pmic.h | 1 + 2 files changed, 8 insertions(+) (limited to 'include') diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index 0f1f60e4daf7..00003a868d28 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -19,6 +19,7 @@ #define PMIC_REV4 0x103 #define PMIC_TYPE 0x104 #define PMIC_SUBTYPE 0x105 +#define PMIC_FAB_ID 0x1f2 #define PMIC_TYPE_VALUE 0x51 @@ -157,6 +158,12 @@ static int pmic_spmi_load_revid(struct regmap *map, struct device *dev, if (ret < 0) return ret; + if (pmic->subtype == PMI8998_SUBTYPE || pmic->subtype == PM660_SUBTYPE) { + ret = regmap_read(map, PMIC_FAB_ID, &pmic->fab_id); + if (ret < 0) + return ret; + } + /* * In early versions of PM8941 and PM8226, the major revision number * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0). diff --git a/include/soc/qcom/qcom-spmi-pmic.h b/include/soc/qcom/qcom-spmi-pmic.h index 5894da3c7f6a..72398ff44719 100644 --- a/include/soc/qcom/qcom-spmi-pmic.h +++ b/include/soc/qcom/qcom-spmi-pmic.h @@ -52,6 +52,7 @@ struct qcom_spmi_pmic { unsigned int major; unsigned int minor; unsigned int rev2; + unsigned int fab_id; const char *name; }; -- cgit v1.2.3 From 4a08069461ac9822855116d24fbf11d5fb223cd1 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Tue, 7 Jun 2022 18:39:18 +0000 Subject: iio: trigger: warn about non-registered iio trigger getting attempt As a part of patch series about wrong trigger register() and get() calls order in the some IIO drivers trigger initialization path: https://lore.kernel.org/all/20220524181150.9240-1-ddrokosov@sberdevices.ru/ runtime WARN_ONCE() is added to alarm IIO driver authors who make such a mistake. When an IIO driver allocates a new IIO trigger, it should register it before calling the get() operation. In other words, each IIO driver must abide by IIO trigger alloc()/register()/get() calls order. Signed-off-by: Dmitry Rokosov Link: https://lore.kernel.org/r/20220607183907.20017-1-ddrokosov@sberdevices.ru Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-trigger.c | 2 ++ include/linux/iio/trigger.h | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index d89bf90650d5..26d610d4cbb8 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -576,6 +576,8 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent, if (trig->name == NULL) goto free_descs; + INIT_LIST_HEAD(&trig->list); + trig->subirq_chip.name = trig->name; trig->subirq_chip.irq_mask = &iio_trig_subirqmask; trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask; diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 4c69b144677b..03b1d6863436 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -93,6 +93,11 @@ static inline void iio_trigger_put(struct iio_trigger *trig) static inline struct iio_trigger *iio_trigger_get(struct iio_trigger *trig) { get_device(&trig->dev); + + WARN_ONCE(list_empty(&trig->list), + "Getting non-registered iio trigger %s is prohibited\n", + trig->name); + __module_get(trig->owner); return trig; -- cgit v1.2.3 From 8670dc33f48bab4d7bb4b8d0232f17f4dae419ec Mon Sep 17 00:00:00 2001 From: Xiaoliang Yang Date: Fri, 17 Jun 2022 11:24:23 +0800 Subject: net: dsa: felix: update base time of time-aware shaper when adjusting PTP time When adjusting the PTP clock, the base time of the TAS configuration will become unreliable. We need reset the TAS configuration by using a new base time. For example, if the driver gets a base time 0 of Qbv configuration from user, and current time is 20000. The driver will set the TAS base time to be 20000. After the PTP clock adjustment, the current time becomes 10000. If the TAS base time is still 20000, it will be a future time, and TAS entry list will stop running. Another example, if the current time becomes to be 10000000 after PTP clock adjust, a large time offset can cause the hardware to hang. This patch introduces a tas_clock_adjust() function to reset the TAS module by using a new base time after the PTP clock adjustment. This can avoid issues above. Due to PTP clock adjustment can occur at any time, it may conflict with the TAS configuration. We introduce a new TAS lock to serialize the access to the TAS registers. Signed-off-by: Xiaoliang Yang Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 83 +++++++++++++++++++++++++++++++--- drivers/net/ethernet/mscc/ocelot.c | 1 + drivers/net/ethernet/mscc/ocelot_ptp.c | 8 ++++ include/soc/mscc/ocelot.h | 7 +++ 4 files changed, 93 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 570d0204b7be..dd9085ae0922 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1196,10 +1196,13 @@ static void vsc9959_tas_gcl_set(struct ocelot *ocelot, const u32 gcl_ix, static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, struct tc_taprio_qopt_offload *taprio) { + struct ocelot_port *ocelot_port = ocelot->ports[port]; struct timespec64 base_ts; int ret, i; u32 val; + mutex_lock(&ocelot->tas_lock); + if (!taprio->enable) { ocelot_rmw_rix(ocelot, QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF), @@ -1207,15 +1210,20 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, QSYS_TAG_CONFIG_INIT_GATE_STATE_M, QSYS_TAG_CONFIG, port); + mutex_unlock(&ocelot->tas_lock); return 0; } if (taprio->cycle_time > NSEC_PER_SEC || - taprio->cycle_time_extension >= NSEC_PER_SEC) - return -EINVAL; + taprio->cycle_time_extension >= NSEC_PER_SEC) { + ret = -EINVAL; + goto err; + } - if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX) - return -ERANGE; + if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX) { + ret = -ERANGE; + goto err; + } /* Enable guard band. The switch will schedule frames without taking * their length into account. Thus we'll always need to enable the @@ -1236,8 +1244,10 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, * config is pending, need reset the TAS module */ val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8); - if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) - return -EBUSY; + if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) { + ret = -EBUSY; + goto err; + } ocelot_rmw_rix(ocelot, QSYS_TAG_CONFIG_ENABLE | @@ -1248,6 +1258,8 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M, QSYS_TAG_CONFIG, port); + ocelot_port->base_time = taprio->base_time; + vsc9959_new_base_time(ocelot, taprio->base_time, taprio->cycle_time, &base_ts); ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1); @@ -1271,9 +1283,67 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, !(val & QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE), 10, 100000); +err: + mutex_unlock(&ocelot->tas_lock); + return ret; } +static void vsc9959_tas_clock_adjust(struct ocelot *ocelot) +{ + struct ocelot_port *ocelot_port; + struct timespec64 base_ts; + u64 cycletime; + int port; + u32 val; + + mutex_lock(&ocelot->tas_lock); + + for (port = 0; port < ocelot->num_phys_ports; port++) { + val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port); + if (!(val & QSYS_TAG_CONFIG_ENABLE)) + continue; + + ocelot_rmw(ocelot, + QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port), + QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M, + QSYS_TAS_PARAM_CFG_CTRL); + + ocelot_rmw_rix(ocelot, + QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF), + QSYS_TAG_CONFIG_ENABLE | + QSYS_TAG_CONFIG_INIT_GATE_STATE_M, + QSYS_TAG_CONFIG, port); + + cycletime = ocelot_read(ocelot, QSYS_PARAM_CFG_REG_4); + ocelot_port = ocelot->ports[port]; + + vsc9959_new_base_time(ocelot, ocelot_port->base_time, + cycletime, &base_ts); + + ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1); + ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), + QSYS_PARAM_CFG_REG_2); + val = upper_32_bits(base_ts.tv_sec); + ocelot_rmw(ocelot, + QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val), + QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M, + QSYS_PARAM_CFG_REG_3); + + ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, + QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE, + QSYS_TAS_PARAM_CFG_CTRL); + + ocelot_rmw_rix(ocelot, + QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF) | + QSYS_TAG_CONFIG_ENABLE, + QSYS_TAG_CONFIG_ENABLE | + QSYS_TAG_CONFIG_INIT_GATE_STATE_M, + QSYS_TAG_CONFIG, port); + } + mutex_unlock(&ocelot->tas_lock); +} + static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port, struct tc_cbs_qopt_offload *cbs_qopt) { @@ -2210,6 +2280,7 @@ static const struct ocelot_ops vsc9959_ops = { .psfp_filter_del = vsc9959_psfp_filter_del, .psfp_stats_get = vsc9959_psfp_stats_get, .cut_through_fwd = vsc9959_cut_through_fwd, + .tas_clock_adjust = vsc9959_tas_clock_adjust, }; static const struct felix_info felix_info_vsc9959 = { diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 8da7e25a47c9..d4649e4ee0e7 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -3367,6 +3367,7 @@ int ocelot_init(struct ocelot *ocelot) mutex_init(&ocelot->ptp_lock); mutex_init(&ocelot->mact_lock); mutex_init(&ocelot->fwd_domain_lock); + mutex_init(&ocelot->tas_lock); spin_lock_init(&ocelot->ptp_clock_lock); spin_lock_init(&ocelot->ts_id_lock); snprintf(queue_name, sizeof(queue_name), "%s-stats", diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c index 87ad2137ba06..09c703efe946 100644 --- a/drivers/net/ethernet/mscc/ocelot_ptp.c +++ b/drivers/net/ethernet/mscc/ocelot_ptp.c @@ -72,6 +72,10 @@ int ocelot_ptp_settime64(struct ptp_clock_info *ptp, ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + + if (ocelot->ops->tas_clock_adjust) + ocelot->ops->tas_clock_adjust(ocelot); + return 0; } EXPORT_SYMBOL(ocelot_ptp_settime64); @@ -105,6 +109,9 @@ int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN); spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); + + if (ocelot->ops->tas_clock_adjust) + ocelot->ops->tas_clock_adjust(ocelot); } else { /* Fall back using ocelot_ptp_settime64 which is not exact. */ struct timespec64 ts; @@ -117,6 +124,7 @@ int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ocelot_ptp_settime64(ptp, &ts); } + return 0; } EXPORT_SYMBOL(ocelot_ptp_adjtime); diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 5f88385a7748..3737570116c3 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -575,6 +575,7 @@ struct ocelot_ops { int (*psfp_stats_get)(struct ocelot *ocelot, struct flow_cls_offload *f, struct flow_stats *stats); void (*cut_through_fwd)(struct ocelot *ocelot); + void (*tas_clock_adjust)(struct ocelot *ocelot); }; struct ocelot_vcap_policer { @@ -691,6 +692,9 @@ struct ocelot_port { int bridge_num; int speed; + + /* Store the AdminBaseTime of EST fetched from userspace. */ + s64 base_time; }; struct ocelot { @@ -757,6 +761,9 @@ struct ocelot { /* Lock for serializing forwarding domain changes */ struct mutex fwd_domain_lock; + /* Lock for serializing Time-Aware Shaper changes */ + struct mutex tas_lock; + struct workqueue_struct *owq; u8 ptp:1; -- cgit v1.2.3 From ba44f8182ec299c5d1c8a72fc0fde4ec127b5a6d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 17 Jun 2022 20:47:04 -0700 Subject: raw: use more conventional iterators In order to prepare the following patch, I change raw v4 & v6 code to use more conventional iterators. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/raw.h | 5 +-- include/net/rawv6.h | 6 +-- net/ipv4/raw.c | 93 +++++++++++++++++----------------------------- net/ipv4/raw_diag.c | 33 ++++++++--------- net/ipv6/raw.c | 105 +++++++++++++++++++--------------------------------- 5 files changed, 92 insertions(+), 150 deletions(-) (limited to 'include') diff --git a/include/net/raw.h b/include/net/raw.h index 8ad8df594853..719d3556fc0a 100644 --- a/include/net/raw.h +++ b/include/net/raw.h @@ -20,9 +20,8 @@ extern struct proto raw_prot; extern struct raw_hashinfo raw_v4_hashinfo; -struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, - unsigned short num, __be32 raddr, - __be32 laddr, int dif, int sdif); +bool raw_v4_match(struct net *net, struct sock *sk, unsigned short num, + __be32 raddr, __be32 laddr, int dif, int sdif); int raw_abort(struct sock *sk, int err); void raw_icmp_error(struct sk_buff *, int, u32); diff --git a/include/net/rawv6.h b/include/net/rawv6.h index 53d86b6055e8..c48c1298699a 100644 --- a/include/net/rawv6.h +++ b/include/net/rawv6.h @@ -5,9 +5,9 @@ #include extern struct raw_hashinfo raw_v6_hashinfo; -struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, - unsigned short num, const struct in6_addr *loc_addr, - const struct in6_addr *rmt_addr, int dif, int sdif); +bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num, + const struct in6_addr *loc_addr, + const struct in6_addr *rmt_addr, int dif, int sdif); int raw_abort(struct sock *sk, int err); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index bbd717805b10..05e0de4a7c7f 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -117,24 +117,19 @@ void raw_unhash_sk(struct sock *sk) } EXPORT_SYMBOL_GPL(raw_unhash_sk); -struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, - unsigned short num, __be32 raddr, __be32 laddr, - int dif, int sdif) +bool raw_v4_match(struct net *net, struct sock *sk, unsigned short num, + __be32 raddr, __be32 laddr, int dif, int sdif) { - sk_for_each_from(sk) { - struct inet_sock *inet = inet_sk(sk); - - if (net_eq(sock_net(sk), net) && inet->inet_num == num && - !(inet->inet_daddr && inet->inet_daddr != raddr) && - !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && - raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) - goto found; /* gotcha */ - } - sk = NULL; -found: - return sk; + struct inet_sock *inet = inet_sk(sk); + + if (net_eq(sock_net(sk), net) && inet->inet_num == num && + !(inet->inet_daddr && inet->inet_daddr != raddr) && + !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && + raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) + return true; + return false; } -EXPORT_SYMBOL_GPL(__raw_v4_lookup); +EXPORT_SYMBOL_GPL(raw_v4_match); /* * 0 - deliver @@ -168,23 +163,21 @@ static int icmp_filter(const struct sock *sk, const struct sk_buff *skb) */ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) { + struct net *net = dev_net(skb->dev); int sdif = inet_sdif(skb); int dif = inet_iif(skb); - struct sock *sk; struct hlist_head *head; int delivered = 0; - struct net *net; + struct sock *sk; - read_lock(&raw_v4_hashinfo.lock); head = &raw_v4_hashinfo.ht[hash]; if (hlist_empty(head)) - goto out; - - net = dev_net(skb->dev); - sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol, - iph->saddr, iph->daddr, dif, sdif); - - while (sk) { + return 0; + read_lock(&raw_v4_hashinfo.lock); + sk_for_each(sk, head) { + if (!raw_v4_match(net, sk, iph->protocol, + iph->saddr, iph->daddr, dif, sdif)) + continue; delivered = 1; if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) && ip_mc_sf_allow(sk, iph->daddr, iph->saddr, @@ -195,31 +188,16 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) if (clone) raw_rcv(sk, clone); } - sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol, - iph->saddr, iph->daddr, - dif, sdif); } -out: read_unlock(&raw_v4_hashinfo.lock); return delivered; } int raw_local_deliver(struct sk_buff *skb, int protocol) { - int hash; - struct sock *raw_sk; - - hash = protocol & (RAW_HTABLE_SIZE - 1); - raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); - - /* If there maybe a raw socket we must check - if not we - * don't care less - */ - if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash)) - raw_sk = NULL; - - return raw_sk != NULL; + int hash = protocol & (RAW_HTABLE_SIZE - 1); + return raw_v4_input(skb, ip_hdr(skb), hash); } static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) @@ -286,29 +264,24 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) { - int hash; - struct sock *raw_sk; + struct net *net = dev_net(skb->dev);; + int dif = skb->dev->ifindex; + int sdif = inet_sdif(skb); + struct hlist_head *head; const struct iphdr *iph; - struct net *net; + struct sock *sk; + int hash; hash = protocol & (RAW_HTABLE_SIZE - 1); + head = &raw_v4_hashinfo.ht[hash]; read_lock(&raw_v4_hashinfo.lock); - raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); - if (raw_sk) { - int dif = skb->dev->ifindex; - int sdif = inet_sdif(skb); - + sk_for_each(sk, head) { iph = (const struct iphdr *)skb->data; - net = dev_net(skb->dev); - - while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, - iph->daddr, iph->saddr, - dif, sdif)) != NULL) { - raw_err(raw_sk, skb, info); - raw_sk = sk_next(raw_sk); - iph = (const struct iphdr *)skb->data; - } + if (!raw_v4_match(net, sk, iph->protocol, + iph->saddr, iph->daddr, dif, sdif)) + continue; + raw_err(sk, skb, info); } read_unlock(&raw_v4_hashinfo.lock); } diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c index ccacbde30a2c..b6d92dc7b051 100644 --- a/net/ipv4/raw_diag.c +++ b/net/ipv4/raw_diag.c @@ -34,31 +34,30 @@ raw_get_hashinfo(const struct inet_diag_req_v2 *r) * use helper to figure it out. */ -static struct sock *raw_lookup(struct net *net, struct sock *from, - const struct inet_diag_req_v2 *req) +static bool raw_lookup(struct net *net, struct sock *sk, + const struct inet_diag_req_v2 *req) { struct inet_diag_req_raw *r = (void *)req; - struct sock *sk = NULL; if (r->sdiag_family == AF_INET) - sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol, - r->id.idiag_dst[0], - r->id.idiag_src[0], - r->id.idiag_if, 0); + return raw_v4_match(net, sk, r->sdiag_raw_protocol, + r->id.idiag_dst[0], + r->id.idiag_src[0], + r->id.idiag_if, 0); #if IS_ENABLED(CONFIG_IPV6) else - sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol, - (const struct in6_addr *)r->id.idiag_src, - (const struct in6_addr *)r->id.idiag_dst, - r->id.idiag_if, 0); + return raw_v6_match(net, sk, r->sdiag_raw_protocol, + (const struct in6_addr *)r->id.idiag_src, + (const struct in6_addr *)r->id.idiag_dst, + r->id.idiag_if, 0); #endif - return sk; + return false; } static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r) { struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); - struct sock *sk = NULL, *s; + struct sock *sk; int slot; if (IS_ERR(hashinfo)) @@ -66,9 +65,8 @@ static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 read_lock(&hashinfo->lock); for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) { - sk_for_each(s, &hashinfo->ht[slot]) { - sk = raw_lookup(net, s, r); - if (sk) { + sk_for_each(sk, &hashinfo->ht[slot]) { + if (raw_lookup(net, sk, r)) { /* * Grab it and keep until we fill * diag meaage to be reported, so @@ -81,10 +79,11 @@ static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 } } } + sk = ERR_PTR(-ENOENT); out_unlock: read_unlock(&hashinfo->lock); - return sk ? sk : ERR_PTR(-ENOENT); + return sk; } static int raw_diag_dump_one(struct netlink_callback *cb, diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 3b7cbd522b54..c0f2e3475984 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -66,41 +66,27 @@ struct raw_hashinfo raw_v6_hashinfo = { }; EXPORT_SYMBOL_GPL(raw_v6_hashinfo); -struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, - unsigned short num, const struct in6_addr *loc_addr, - const struct in6_addr *rmt_addr, int dif, int sdif) +bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num, + const struct in6_addr *loc_addr, + const struct in6_addr *rmt_addr, int dif, int sdif) { - bool is_multicast = ipv6_addr_is_multicast(loc_addr); - - sk_for_each_from(sk) - if (inet_sk(sk)->inet_num == num) { - - if (!net_eq(sock_net(sk), net)) - continue; - - if (!ipv6_addr_any(&sk->sk_v6_daddr) && - !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) - continue; - - if (!raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, - dif, sdif)) - continue; - - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { - if (ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) - goto found; - if (is_multicast && - inet6_mc_check(sk, loc_addr, rmt_addr)) - goto found; - continue; - } - goto found; - } - sk = NULL; -found: - return sk; + if (inet_sk(sk)->inet_num != num || + !net_eq(sock_net(sk), net) || + (!ipv6_addr_any(&sk->sk_v6_daddr) && + !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) || + !raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, + dif, sdif)) + return false; + + if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) || + ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr) || + (ipv6_addr_is_multicast(loc_addr) && + inet6_mc_check(sk, loc_addr, rmt_addr))) + return true; + + return false; } -EXPORT_SYMBOL_GPL(__raw_v6_lookup); +EXPORT_SYMBOL_GPL(raw_v6_match); /* * 0 - deliver @@ -156,31 +142,28 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister); */ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { + struct net *net = dev_net(skb->dev); const struct in6_addr *saddr; const struct in6_addr *daddr; + struct hlist_head *head; struct sock *sk; bool delivered = false; __u8 hash; - struct net *net; saddr = &ipv6_hdr(skb)->saddr; daddr = saddr + 1; hash = nexthdr & (RAW_HTABLE_SIZE - 1); - + head = &raw_v6_hashinfo.ht[hash]; + if (hlist_empty(head)) + return false; read_lock(&raw_v6_hashinfo.lock); - sk = sk_head(&raw_v6_hashinfo.ht[hash]); - - if (!sk) - goto out; - - net = dev_net(skb->dev); - sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, - inet6_iif(skb), inet6_sdif(skb)); - - while (sk) { + sk_for_each(sk, head) { int filtered; + if (!raw_v6_match(net, sk, nexthdr, daddr, saddr, + inet6_iif(skb), inet6_sdif(skb))) + continue; delivered = true; switch (nexthdr) { case IPPROTO_ICMPV6: @@ -219,23 +202,14 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) rawv6_rcv(sk, clone); } } - sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr, - inet6_iif(skb), inet6_sdif(skb)); } -out: read_unlock(&raw_v6_hashinfo.lock); return delivered; } bool raw6_local_deliver(struct sk_buff *skb, int nexthdr) { - struct sock *raw_sk; - - raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (RAW_HTABLE_SIZE - 1)]); - if (raw_sk && !ipv6_raw_deliver(skb, nexthdr)) - raw_sk = NULL; - - return raw_sk != NULL; + return ipv6_raw_deliver(skb, nexthdr); } /* This cleans up af_inet6 a bit. -DaveM */ @@ -361,28 +335,25 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb, void raw6_icmp_error(struct sk_buff *skb, int nexthdr, u8 type, u8 code, int inner_offset, __be32 info) { + const struct in6_addr *saddr, *daddr; + struct net *net = dev_net(skb->dev); + struct hlist_head *head; struct sock *sk; int hash; - const struct in6_addr *saddr, *daddr; - struct net *net; hash = nexthdr & (RAW_HTABLE_SIZE - 1); - + head = &raw_v6_hashinfo.ht[hash]; read_lock(&raw_v6_hashinfo.lock); - sk = sk_head(&raw_v6_hashinfo.ht[hash]); - if (sk) { + sk_for_each(sk, head) { /* Note: ipv6_hdr(skb) != skb->data */ const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data; saddr = &ip6h->saddr; daddr = &ip6h->daddr; - net = dev_net(skb->dev); - while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, - inet6_iif(skb), inet6_iif(skb)))) { - rawv6_err(sk, skb, NULL, type, code, - inner_offset, info); - sk = sk_next(sk); - } + if (!raw_v6_match(net, sk, nexthdr, &ip6h->saddr, &ip6h->daddr, + inet6_iif(skb), inet6_iif(skb))) + continue; + rawv6_err(sk, skb, NULL, type, code, inner_offset, info); } read_unlock(&raw_v6_hashinfo.lock); } -- cgit v1.2.3 From 0daf07e527095e64ee8927ce297ab626643e9f51 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 17 Jun 2022 20:47:05 -0700 Subject: raw: convert raw sockets to RCU Using rwlock in networking code is extremely risky. writers can starve if enough readers are constantly grabing the rwlock. I thought rwlock were at fault and sent this patch: https://lkml.org/lkml/2022/6/17/272 But Peter and Linus essentially told me rwlock had to be unfair. We need to get rid of rwlock in networking code. Without this fix, following script triggers soft lockups: for i in {1..48} do ping -f -n -q 127.0.0.1 & sleep 0.1 done Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/raw.h | 11 ++++++- include/net/rawv6.h | 1 + net/ipv4/af_inet.c | 2 ++ net/ipv4/raw.c | 83 ++++++++++++++++++++++++----------------------------- net/ipv4/raw_diag.c | 22 ++++++++------ net/ipv6/af_inet6.c | 3 ++ net/ipv6/raw.c | 28 +++++++++--------- 7 files changed, 80 insertions(+), 70 deletions(-) (limited to 'include') diff --git a/include/net/raw.h b/include/net/raw.h index 719d3556fc0a..d81eeeb8f1e6 100644 --- a/include/net/raw.h +++ b/include/net/raw.h @@ -33,9 +33,18 @@ int raw_rcv(struct sock *, struct sk_buff *); struct raw_hashinfo { rwlock_t lock; - struct hlist_head ht[RAW_HTABLE_SIZE]; + struct hlist_nulls_head ht[RAW_HTABLE_SIZE]; }; +static inline void raw_hashinfo_init(struct raw_hashinfo *hashinfo) +{ + int i; + + rwlock_init(&hashinfo->lock); + for (i = 0; i < RAW_HTABLE_SIZE; i++) + INIT_HLIST_NULLS_HEAD(&hashinfo->ht[i], i); +} + #ifdef CONFIG_PROC_FS int raw_proc_init(void); void raw_proc_exit(void); diff --git a/include/net/rawv6.h b/include/net/rawv6.h index c48c1298699a..bc70909625f6 100644 --- a/include/net/rawv6.h +++ b/include/net/rawv6.h @@ -3,6 +3,7 @@ #define _NET_RAWV6_H #include +#include extern struct raw_hashinfo raw_v6_hashinfo; bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num, diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 30e0e8992085..da81f56fdd1c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1929,6 +1929,8 @@ static int __init inet_init(void) sock_skb_cb_check_size(sizeof(struct inet_skb_parm)); + raw_hashinfo_init(&raw_v4_hashinfo); + rc = proto_register(&tcp_prot, 1); if (rc) goto out; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 05e0de4a7c7f..d28bf0b901a2 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -85,20 +85,19 @@ struct raw_frag_vec { int hlen; }; -struct raw_hashinfo raw_v4_hashinfo = { - .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), -}; +struct raw_hashinfo raw_v4_hashinfo; EXPORT_SYMBOL_GPL(raw_v4_hashinfo); int raw_hash_sk(struct sock *sk) { struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; - struct hlist_head *head; + struct hlist_nulls_head *hlist; - head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)]; + hlist = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)]; write_lock_bh(&h->lock); - sk_add_node(sk, head); + hlist_nulls_add_head_rcu(&sk->sk_nulls_node, hlist); + sock_set_flag(sk, SOCK_RCU_FREE); write_unlock_bh(&h->lock); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); @@ -111,7 +110,7 @@ void raw_unhash_sk(struct sock *sk) struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; write_lock_bh(&h->lock); - if (sk_del_node_init(sk)) + if (__sk_nulls_del_node_init_rcu(sk)) sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); write_unlock_bh(&h->lock); } @@ -164,17 +163,16 @@ static int icmp_filter(const struct sock *sk, const struct sk_buff *skb) static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) { struct net *net = dev_net(skb->dev); + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; int sdif = inet_sdif(skb); int dif = inet_iif(skb); - struct hlist_head *head; int delivered = 0; struct sock *sk; - head = &raw_v4_hashinfo.ht[hash]; - if (hlist_empty(head)) - return 0; - read_lock(&raw_v4_hashinfo.lock); - sk_for_each(sk, head) { + hlist = &raw_v4_hashinfo.ht[hash]; + rcu_read_lock(); + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { if (!raw_v4_match(net, sk, iph->protocol, iph->saddr, iph->daddr, dif, sdif)) continue; @@ -189,7 +187,7 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) raw_rcv(sk, clone); } } - read_unlock(&raw_v4_hashinfo.lock); + rcu_read_unlock(); return delivered; } @@ -265,25 +263,26 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) { struct net *net = dev_net(skb->dev);; + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; int dif = skb->dev->ifindex; int sdif = inet_sdif(skb); - struct hlist_head *head; const struct iphdr *iph; struct sock *sk; int hash; hash = protocol & (RAW_HTABLE_SIZE - 1); - head = &raw_v4_hashinfo.ht[hash]; + hlist = &raw_v4_hashinfo.ht[hash]; - read_lock(&raw_v4_hashinfo.lock); - sk_for_each(sk, head) { + rcu_read_lock(); + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { iph = (const struct iphdr *)skb->data; if (!raw_v4_match(net, sk, iph->protocol, iph->saddr, iph->daddr, dif, sdif)) continue; raw_err(sk, skb, info); } - read_unlock(&raw_v4_hashinfo.lock); + rcu_read_unlock(); } static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) @@ -944,44 +943,41 @@ struct proto raw_prot = { }; #ifdef CONFIG_PROC_FS -static struct sock *raw_get_first(struct seq_file *seq) +static struct sock *raw_get_first(struct seq_file *seq, int bucket) { - struct sock *sk; struct raw_hashinfo *h = pde_data(file_inode(seq->file)); struct raw_iter_state *state = raw_seq_private(seq); + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; + struct sock *sk; - for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE; + for (state->bucket = bucket; state->bucket < RAW_HTABLE_SIZE; ++state->bucket) { - sk_for_each(sk, &h->ht[state->bucket]) + hlist = &h->ht[state->bucket]; + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { if (sock_net(sk) == seq_file_net(seq)) - goto found; + return sk; + } } - sk = NULL; -found: - return sk; + return NULL; } static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) { - struct raw_hashinfo *h = pde_data(file_inode(seq->file)); struct raw_iter_state *state = raw_seq_private(seq); do { - sk = sk_next(sk); -try_again: - ; + sk = sk_nulls_next(sk); } while (sk && sock_net(sk) != seq_file_net(seq)); - if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { - sk = sk_head(&h->ht[state->bucket]); - goto try_again; - } + if (!sk) + return raw_get_first(seq, state->bucket + 1); return sk; } static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos) { - struct sock *sk = raw_get_first(seq); + struct sock *sk = raw_get_first(seq, 0); if (sk) while (pos && (sk = raw_get_next(seq, sk)) != NULL) @@ -990,11 +986,9 @@ static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos) } void *raw_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(&h->lock) + __acquires(RCU) { - struct raw_hashinfo *h = pde_data(file_inode(seq->file)); - - read_lock(&h->lock); + rcu_read_lock(); return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; } EXPORT_SYMBOL_GPL(raw_seq_start); @@ -1004,7 +998,7 @@ void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos) struct sock *sk; if (v == SEQ_START_TOKEN) - sk = raw_get_first(seq); + sk = raw_get_first(seq, 0); else sk = raw_get_next(seq, v); ++*pos; @@ -1013,11 +1007,9 @@ void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos) EXPORT_SYMBOL_GPL(raw_seq_next); void raw_seq_stop(struct seq_file *seq, void *v) - __releases(&h->lock) + __releases(RCU) { - struct raw_hashinfo *h = pde_data(file_inode(seq->file)); - - read_unlock(&h->lock); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(raw_seq_stop); @@ -1079,6 +1071,7 @@ static __net_initdata struct pernet_operations raw_net_ops = { int __init raw_proc_init(void) { + return register_pernet_subsys(&raw_net_ops); } diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c index b6d92dc7b051..5f208e840d85 100644 --- a/net/ipv4/raw_diag.c +++ b/net/ipv4/raw_diag.c @@ -57,31 +57,32 @@ static bool raw_lookup(struct net *net, struct sock *sk, static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r) { struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; struct sock *sk; int slot; if (IS_ERR(hashinfo)) return ERR_CAST(hashinfo); - read_lock(&hashinfo->lock); + rcu_read_lock(); for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) { - sk_for_each(sk, &hashinfo->ht[slot]) { + hlist = &hashinfo->ht[slot]; + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { if (raw_lookup(net, sk, r)) { /* * Grab it and keep until we fill - * diag meaage to be reported, so + * diag message to be reported, so * caller should call sock_put then. - * We can do that because we're keeping - * hashinfo->lock here. */ - sock_hold(sk); - goto out_unlock; + if (refcount_inc_not_zero(&sk->sk_refcnt)) + goto out_unlock; } } } sk = ERR_PTR(-ENOENT); out_unlock: - read_unlock(&hashinfo->lock); + rcu_read_unlock(); return sk; } @@ -141,6 +142,8 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); struct net *net = sock_net(skb->sk); struct inet_diag_dump_data *cb_data; + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; int num, s_num, slot, s_slot; struct sock *sk = NULL; struct nlattr *bc; @@ -157,7 +160,8 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) { num = 0; - sk_for_each(sk, &hashinfo->ht[slot]) { + hlist = &hashinfo->ht[slot]; + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { struct inet_sock *inet = inet_sk(sk); if (!net_eq(sock_net(sk), net)) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 70564ddccc46..658823e91eca 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -1073,6 +1074,8 @@ static int __init inet6_init(void) goto out; } + raw_hashinfo_init(&raw_v6_hashinfo); + err = proto_register(&tcpv6_prot, 1); if (err) goto out; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index c0f2e3475984..f6119998700e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -61,9 +61,7 @@ #define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */ -struct raw_hashinfo raw_v6_hashinfo = { - .lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock), -}; +struct raw_hashinfo raw_v6_hashinfo; EXPORT_SYMBOL_GPL(raw_v6_hashinfo); bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num, @@ -143,9 +141,10 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister); static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) { struct net *net = dev_net(skb->dev); + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; const struct in6_addr *saddr; const struct in6_addr *daddr; - struct hlist_head *head; struct sock *sk; bool delivered = false; __u8 hash; @@ -154,11 +153,9 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) daddr = saddr + 1; hash = nexthdr & (RAW_HTABLE_SIZE - 1); - head = &raw_v6_hashinfo.ht[hash]; - if (hlist_empty(head)) - return false; - read_lock(&raw_v6_hashinfo.lock); - sk_for_each(sk, head) { + hlist = &raw_v6_hashinfo.ht[hash]; + rcu_read_lock(); + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { int filtered; if (!raw_v6_match(net, sk, nexthdr, daddr, saddr, @@ -203,7 +200,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) } } } - read_unlock(&raw_v6_hashinfo.lock); + rcu_read_unlock(); return delivered; } @@ -337,14 +334,15 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, { const struct in6_addr *saddr, *daddr; struct net *net = dev_net(skb->dev); - struct hlist_head *head; + struct hlist_nulls_head *hlist; + struct hlist_nulls_node *hnode; struct sock *sk; int hash; hash = nexthdr & (RAW_HTABLE_SIZE - 1); - head = &raw_v6_hashinfo.ht[hash]; - read_lock(&raw_v6_hashinfo.lock); - sk_for_each(sk, head) { + hlist = &raw_v6_hashinfo.ht[hash]; + rcu_read_lock(); + hlist_nulls_for_each_entry(sk, hnode, hlist, sk_nulls_node) { /* Note: ipv6_hdr(skb) != skb->data */ const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data; saddr = &ip6h->saddr; @@ -355,7 +353,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, continue; rawv6_err(sk, skb, NULL, type, code, inner_offset, info); } - read_unlock(&raw_v6_hashinfo.lock); + rcu_read_unlock(); } static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb) -- cgit v1.2.3 From bdb6cfe7512f7a214815a3092f0be50963dcacbc Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sat, 18 Jun 2022 11:28:32 +0100 Subject: net: mii: add mii_bmcr_encode_fixed() Add a function to encode a fixed speed/duplex to a BMCR value. Signed-off-by: Russell King (Oracle) Signed-off-by: David S. Miller --- include/linux/mii.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'include') diff --git a/include/linux/mii.h b/include/linux/mii.h index 5ee13083cec7..d5a959ce4877 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -545,4 +545,39 @@ static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv) return cap; } +/** + * mii_bmcr_encode_fixed - encode fixed speed/duplex settings to a BMCR value + * @speed: a SPEED_* value + * @duplex: a DUPLEX_* value + * + * Encode the speed and duplex to a BMCR value. 2500, 1000, 100 and 10 Mbps are + * supported. 2500Mbps is encoded to 1000Mbps. Other speeds are encoded as 10 + * Mbps. Unknown duplex values are encoded to half-duplex. + */ +static inline u16 mii_bmcr_encode_fixed(int speed, int duplex) +{ + u16 bmcr; + + switch (speed) { + case SPEED_2500: + case SPEED_1000: + bmcr = BMCR_SPEED1000; + break; + + case SPEED_100: + bmcr = BMCR_SPEED100; + break; + + case SPEED_10: + default: + bmcr = BMCR_SPEED10; + break; + } + + if (duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + + return bmcr; +} + #endif /* __LINUX_MII_H__ */ -- cgit v1.2.3 From 2e0aee8f0a22c60a1ae0876f7233e70ad9d026b8 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Thu, 16 Jun 2022 23:51:49 +0300 Subject: ata: make ata_port::fastdrain_cnt *unsigned int* *unsigned long* ata_port::fastdrain_cnt (64-bit value in a 64-bit kernel) is always assigned from the 32-bit *unsigned int* variables, thus could also be made just *unsigned int*... Signed-off-by: Sergey Shtylyov Signed-off-by: Damien Le Moal --- include/linux/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index a8bc88b4fe07..0269ff114f5a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -847,7 +847,7 @@ struct ata_port { enum ata_lpm_policy target_lpm_policy; struct timer_list fastdrain_timer; - unsigned long fastdrain_cnt; + unsigned int fastdrain_cnt; async_cookie_t cookie; -- cgit v1.2.3 From cd76175a2b204911a3cddef36b99e56945b6938c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Jun 2022 16:40:47 +0200 Subject: ALSA: rawmidi: Make internal functions local static __snd_rawmidi_transmit_peek() and __snd_rawmidi_transmit_ack() are never called from the outside. Let's make them local static and unexport them. Link: https://lore.kernel.org/r/20220617144051.18985-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 4 ---- sound/core/rawmidi.c | 13 ++++++------- 2 files changed, 6 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 7a08ed2acd60..9402c25ae9ba 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -156,10 +156,6 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count); -int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, - unsigned char *buffer, int count); -int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, - int count); int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream); /* main midi functions */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index befa9809ff00..82e8f656bbb2 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1258,7 +1258,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) } EXPORT_SYMBOL(snd_rawmidi_transmit_empty); -/** +/* * __snd_rawmidi_transmit_peek - copy data from the internal buffer * @substream: the rawmidi substream * @buffer: the buffer pointer @@ -1266,8 +1266,8 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_empty); * * This is a variant of snd_rawmidi_transmit_peek() without spinlock. */ -int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, - unsigned char *buffer, int count) +static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, + unsigned char *buffer, int count) { int result, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -1304,7 +1304,6 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, __skip: return result; } -EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); /** * snd_rawmidi_transmit_peek - copy data from the internal buffer @@ -1334,14 +1333,15 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, } EXPORT_SYMBOL(snd_rawmidi_transmit_peek); -/** +/* * __snd_rawmidi_transmit_ack - acknowledge the transmission * @substream: the rawmidi substream * @count: the transferred count * * This is a variant of __snd_rawmidi_transmit_ack() without spinlock. */ -int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) +static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, + int count) { struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -1361,7 +1361,6 @@ int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int coun } return count; } -EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); /** * snd_rawmidi_transmit_ack - acknowledge the transmission -- cgit v1.2.3 From f1d40433352e5d4babd59c0dd50b5f9414073ddb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Jun 2022 16:40:48 +0200 Subject: ALSA: rawmidi: Move lock to snd_rawmidi_substream Having a lock in snd_rawmidi_runtime can be a problem especially when a substream is accessed from the outside, as the runtime creation might be racy with the external calls. As a first step for hardening, move the spinlock from snd_rawmidi_runtime to snd_rawmidi_substream. This patch just replaces the lock calls, no real functional change is put yet. Link: https://lore.kernel.org/r/20220617144051.18985-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 2 +- sound/core/rawmidi.c | 131 +++++++++++++++++++++++------------------------- 2 files changed, 65 insertions(+), 68 deletions(-) (limited to 'include') diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 9402c25ae9ba..e1f59b2940af 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -63,7 +63,6 @@ struct snd_rawmidi_runtime { size_t xruns; /* over/underruns counter */ int buffer_ref; /* buffer reference count */ /* misc */ - spinlock_t lock; wait_queue_head_t sleep; /* event handler (new bytes, input only) */ void (*event)(struct snd_rawmidi_substream *substream); @@ -85,6 +84,7 @@ struct snd_rawmidi_substream { unsigned int clock_type; /* clock source to use for input framing */ int use_count; /* use counter (for output) */ size_t bytes; + spinlock_t lock; struct snd_rawmidi *rmidi; struct snd_rawmidi_str *pstr; char name[32]; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 82e8f656bbb2..0a00f37d8c42 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -102,13 +102,12 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime) static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream) { - struct snd_rawmidi_runtime *runtime = substream->runtime; unsigned long flags; bool ready; - spin_lock_irqsave(&runtime->lock, flags); - ready = __snd_rawmidi_ready(runtime); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); + ready = __snd_rawmidi_ready(substream->runtime); + spin_unlock_irqrestore(&substream->lock, flags); return ready; } @@ -130,7 +129,7 @@ static void snd_rawmidi_input_event_work(struct work_struct *work) runtime->event(runtime->substream); } -/* buffer refcount management: call with runtime->lock held */ +/* buffer refcount management: call with substream->lock held */ static inline void snd_rawmidi_buffer_ref(struct snd_rawmidi_runtime *runtime) { runtime->buffer_ref++; @@ -149,7 +148,6 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) if (!runtime) return -ENOMEM; runtime->substream = substream; - spin_lock_init(&runtime->lock); init_waitqueue_head(&runtime->sleep); INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); runtime->event = NULL; @@ -203,20 +201,20 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, runtime->avail = is_input ? 0 : runtime->buffer_size; } -static void reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, +static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream, bool is_input) { unsigned long flags; - spin_lock_irqsave(&runtime->lock, flags); - __reset_runtime_ptrs(runtime, is_input); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); + __reset_runtime_ptrs(substream->runtime, is_input); + spin_unlock_irqrestore(&substream->lock, flags); } int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) { snd_rawmidi_output_trigger(substream, 0); - reset_runtime_ptrs(substream->runtime, false); + reset_runtime_ptrs(substream, false); return 0; } EXPORT_SYMBOL(snd_rawmidi_drop_output); @@ -256,7 +254,7 @@ EXPORT_SYMBOL(snd_rawmidi_drain_output); int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) { snd_rawmidi_input_trigger(substream, 0); - reset_runtime_ptrs(substream->runtime, true); + reset_runtime_ptrs(substream, true); return 0; } EXPORT_SYMBOL(snd_rawmidi_drain_input); @@ -676,10 +674,11 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, return 0; } -static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, +static int resize_runtime_buffer(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params *params, bool is_input) { + struct snd_rawmidi_runtime *runtime = substream->runtime; char *newbuf, *oldbuf; unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; @@ -693,9 +692,9 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, newbuf = kvzalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); if (runtime->buffer_ref) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); kvfree(newbuf); return -EBUSY; } @@ -703,7 +702,7 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; __reset_runtime_ptrs(runtime, is_input); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); kvfree(oldbuf); } runtime->avail_min = params->avail_min; @@ -717,7 +716,7 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, return -EBUSY; snd_rawmidi_drain_output(substream); substream->active_sensing = !params->no_active_sensing; - return resize_runtime_buffer(substream->runtime, params, false); + return resize_runtime_buffer(substream, params, false); } EXPORT_SYMBOL(snd_rawmidi_output_params); @@ -735,7 +734,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) return -EINVAL; snd_rawmidi_drain_input(substream); - err = resize_runtime_buffer(substream->runtime, params, true); + err = resize_runtime_buffer(substream, params, true); if (err < 0) return err; @@ -752,9 +751,9 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); status->avail = runtime->avail; - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return 0; } @@ -765,11 +764,11 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_INPUT; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); status->avail = runtime->avail; status->xruns = runtime->xruns; runtime->xruns = 0; - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return 0; } @@ -1074,7 +1073,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, return -EINVAL; } - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { result = receive_with_tstamp_framing(substream, buffer, count, &ts64); } else if (count == 1) { /* special case, faster code */ @@ -1121,7 +1120,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, else if (__snd_rawmidi_ready(runtime)) wake_up(&runtime->sleep); } - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_receive); @@ -1136,7 +1135,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned long appl_ptr; int err = 0; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); snd_rawmidi_buffer_ref(runtime); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; @@ -1154,11 +1153,11 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, if (kernelbuf) memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (copy_to_user(userbuf + result, runtime->buffer + appl_ptr, count1)) err = -EFAULT; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (err) goto out; } @@ -1167,7 +1166,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, } out: snd_rawmidi_buffer_unref(runtime); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result > 0 ? result : err; } @@ -1196,31 +1195,31 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun snd_rawmidi_input_trigger(substream, 1); result = 0; while (count > 0) { - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); while (!__snd_rawmidi_ready(runtime)) { wait_queue_entry_t wait; if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EAGAIN; } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); schedule(); remove_wait_queue(&runtime->sleep, &wait); if (rfile->rmidi->card->shutdown) return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); if (!runtime->avail) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EIO; } } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); count1 = snd_rawmidi_kernel_read1(substream, (unsigned char __user *)buf, NULL/*kernelbuf*/, @@ -1251,9 +1250,9 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) "snd_rawmidi_transmit_empty: output is not active!!!\n"); return 1; } - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); result = runtime->avail >= runtime->buffer_size; - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit_empty); @@ -1322,13 +1321,12 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); result = __snd_rawmidi_transmit_peek(substream, buffer, count); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit_peek); @@ -1375,13 +1373,12 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, */ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); result = __snd_rawmidi_transmit_ack(substream, count); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit_ack); @@ -1399,11 +1396,10 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack); int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - struct snd_rawmidi_runtime *runtime = substream->runtime; int result; unsigned long flags; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (!substream->opened) result = -EBADFD; else { @@ -1413,7 +1409,7 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, else result = __snd_rawmidi_transmit_ack(substream, count); } - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit); @@ -1430,12 +1426,12 @@ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) unsigned long flags; int count = 0; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (runtime->avail < runtime->buffer_size) { count = runtime->buffer_size - runtime->avail; __snd_rawmidi_transmit_ack(substream, count); } - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return count; } EXPORT_SYMBOL(snd_rawmidi_proceed); @@ -1456,10 +1452,10 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, return -EINVAL; result = 0; - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); if (substream->append) { if ((long)runtime->avail < count) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); return -EAGAIN; } } @@ -1481,14 +1477,14 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); result = result > 0 ? result : -EFAULT; goto __end; } - spin_lock_irqsave(&runtime->lock, flags); + spin_lock_irqsave(&substream->lock, flags); } result += count1; count -= count1; @@ -1496,7 +1492,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, __end: count1 = runtime->avail < runtime->buffer_size; snd_rawmidi_buffer_unref(runtime); - spin_unlock_irqrestore(&runtime->lock, flags); + spin_unlock_irqrestore(&substream->lock, flags); if (count1) snd_rawmidi_output_trigger(substream, 1); return result; @@ -1526,31 +1522,31 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, return -EIO; result = 0; while (count > 0) { - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); while (!snd_rawmidi_ready_append(substream, count)) { wait_queue_entry_t wait; if (file->f_flags & O_NONBLOCK) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EAGAIN; } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); if (rfile->rmidi->card->shutdown) return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); if (!runtime->avail && !timeout) { - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); return result > 0 ? result : -EIO; } } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count); if (count1 < 0) return result > 0 ? result : count1; @@ -1561,7 +1557,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, count -= count1; } if (file->f_flags & O_DSYNC) { - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); while (runtime->avail != runtime->buffer_size) { wait_queue_entry_t wait; unsigned int last_avail = runtime->avail; @@ -1569,16 +1565,16 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (runtime->avail == last_avail && !timeout) return result > 0 ? result : -EIO; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); } - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); } return result; } @@ -1649,10 +1645,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); buffer_size = runtime->buffer_size; avail = runtime->avail; - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); snd_iprintf(buffer, " Mode : %s\n" " Buffer size : %lu\n" @@ -1676,11 +1672,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; - spin_lock_irq(&runtime->lock); + spin_lock_irq(&substream->lock); buffer_size = runtime->buffer_size; avail = runtime->avail; xruns = runtime->xruns; - spin_unlock_irq(&runtime->lock); + spin_unlock_irq(&substream->lock); snd_iprintf(buffer, " Buffer size : %lu\n" " Avail : %lu\n" @@ -1732,6 +1728,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, substream->number = idx; substream->rmidi = rmidi; substream->pstr = stream; + spin_lock_init(&substream->lock); list_add_tail(&substream->list, &stream->substreams); stream->substream_count++; } -- cgit v1.2.3 From 5a531791edb249e41e00cf1cc580dbb09e2157ae Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 May 2022 13:53:06 +0100 Subject: media: v4l2-tpg: add HDMI Video Guard Band test pattern This inserts 4 pixels of the RGB color 0xab55ab at the left hand side of the image. This is only done for 3 or 4 byte RGB pixel formats. The HDMI TMDS encoding of this pixel value equals the Video Guard Band value as defined by HDMI (see section 5.2.2.1 in the HDMI 1.3 Specification) that preceeds the first actual pixel of a video line. If an HDMI receiver doesn't handle this correctly, then it might keep skipping these Video Guard Band patterns and end up with a shorter video line. So this is a nice pattern to test with. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 38 +++++++++++++++++++++++++++ include/media/tpg/v4l2-tpg.h | 16 +++++++++++ 2 files changed, 54 insertions(+) (limited to 'include') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 7607b516a7c4..cb985de8ff72 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -2402,6 +2402,44 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg, ((params->sav_eav_f ^ vact) << 1) | (hact ^ vact ^ params->sav_eav_f); } + if (tpg->insert_hdmi_video_guard_band) { + unsigned int i; + + switch (tpg->fourcc) { + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB24: + for (i = 0; i < 3 * 4; i += 3) { + vbuf[i] = 0xab; + vbuf[i + 1] = 0x55; + vbuf[i + 2] = 0xab; + } + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_XRGB32: + case V4L2_PIX_FMT_BGRX32: + case V4L2_PIX_FMT_BGRA32: + for (i = 0; i < 4 * 4; i += 4) { + vbuf[i] = 0x00; + vbuf[i + 1] = 0xab; + vbuf[i + 2] = 0x55; + vbuf[i + 3] = 0xab; + } + break; + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_RGBA32: + for (i = 0; i < 4 * 4; i += 4) { + vbuf[i] = 0xab; + vbuf[i + 1] = 0x55; + vbuf[i + 2] = 0xab; + vbuf[i + 3] = 0x00; + } + break; + } + } } static void tpg_fill_plane_pattern(const struct tpg_data *tpg, diff --git a/include/media/tpg/v4l2-tpg.h b/include/media/tpg/v4l2-tpg.h index 181dcbe777f3..a55088921d1d 100644 --- a/include/media/tpg/v4l2-tpg.h +++ b/include/media/tpg/v4l2-tpg.h @@ -210,6 +210,7 @@ struct tpg_data { bool show_square; bool insert_sav; bool insert_eav; + bool insert_hdmi_video_guard_band; /* Test pattern movement */ enum tpg_move_mode mv_hor_mode; @@ -591,6 +592,21 @@ static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav) tpg->insert_eav = insert_eav; } +/* + * This inserts 4 pixels of the RGB color 0xab55ab at the left hand side of the + * image. This is only done for 3 or 4 byte RGB pixel formats. This pixel value + * equals the Video Guard Band value as defined by HDMI (see section 5.2.2.1 + * in the HDMI 1.3 Specification) that preceeds the first actual pixel. If the + * HDMI receiver doesn't handle this correctly, then it might keep skipping + * these Video Guard Band patterns and end up with a shorter video line. So this + * is a nice pattern to test with. + */ +static inline void tpg_s_insert_hdmi_video_guard_band(struct tpg_data *tpg, + bool insert_hdmi_video_guard_band) +{ + tpg->insert_hdmi_video_guard_band = insert_hdmi_video_guard_band; +} + void tpg_update_mv_step(struct tpg_data *tpg); static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg, -- cgit v1.2.3 From 5374d8fb75f313294c7d97e85c22bead34d63f2b Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 19 May 2022 08:11:46 +0100 Subject: media: Add P010 video format P010 is a YUV format with 10-bits per component with interleaved UV. Signed-off-by: Benjamin Gaignard Acked-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-yuv-planar.rst | 54 ++++++++++++++++++++++ drivers/media/v4l2-core/v4l2-common.c | 1 + drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/uapi/linux/videodev2.h | 1 + 4 files changed, 57 insertions(+) (limited to 'include') diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst index 8dff5906639b..a900ff66911a 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -109,6 +109,13 @@ All components are stored with the same number of bits per component. - Cb, Cr - No - 16x16 tiles + * - V4L2_PIX_FMT_P010 + - 'P010' + - 10 + - 4:2:0 + - Cb, Cr + - Yes + - Linear * - V4L2_PIX_FMT_NV16 - 'NV16' - 8 @@ -171,6 +178,7 @@ horizontally. .. _V4L2-PIX-FMT-NV21: .. _V4L2-PIX-FMT-NV12M: .. _V4L2-PIX-FMT-NV21M: +.. _V4L2-PIX-FMT-P010: NV12, NV21, NV12M and NV21M --------------------------- @@ -519,6 +527,52 @@ number of lines as the luma plane. - Cb\ :sub:`33` - Cr\ :sub:`33` +.. _V4L2_PIX_FMT_P010: + +P010 +---- + +Like NV12 with 10 bits per component, expanded to 16 bits. +Data in the 10 high bits, zeros in the 6 low bits, arranged in little endian order. + +.. flat-table:: Sample 4x4 P010 Image + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start + 8: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start + 16: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start + 24: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - start + 32: + - Cb\ :sub:`00` + - Cr\ :sub:`00` + - Cb\ :sub:`01` + - Cr\ :sub:`01` + * - start + 40: + - Cb\ :sub:`10` + - Cr\ :sub:`10` + - Cb\ :sub:`11` + - Cr\ :sub:`11` + +.. raw:: latex + + \endgroup Fully Planar YUV Formats ======================== diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index df34b2a283bc..1e38ad8906a2 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -266,6 +266,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) { .format = V4L2_PIX_FMT_NV61, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, { .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 21470de62d72..e2526701294e 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1306,6 +1306,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break; case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break; case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break; + case V4L2_PIX_FMT_P010: descr = "10-bit Y/CrCb 4:2:0"; break; case V4L2_PIX_FMT_NV12_4L4: descr = "Y/CbCr 4:2:0 (4x4 Linear)"; break; case V4L2_PIX_FMT_NV12_16L16: descr = "Y/CbCr 4:2:0 (16x16 Linear)"; break; case V4L2_PIX_FMT_NV12_32L32: descr = "Y/CbCr 4:2:0 (32x32 Linear)"; break; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 343b95107fce..5311ac4fde35 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -602,6 +602,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ #define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ #define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ +#define V4L2_PIX_FMT_P010 v4l2_fourcc('P', '0', '1', '0') /* 24 Y/CbCr 4:2:0 10-bit per component */ /* two non contiguous planes - one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ -- cgit v1.2.3 From 8e1c69149f27189cff93a0cfe9402e576d89ce29 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:10 +0000 Subject: KVM: Avoid pfn_to_page() and vice versa when releasing pages Invert the order of KVM's page/pfn release helpers so that the "inner" helper operates on a page instead of a pfn. As pointed out by Linus[*], converting between struct page and a pfn isn't necessarily cheap, and that's not even counting the overhead of is_error_noslot_pfn() and kvm_is_reserved_pfn(). Even if the checks were dirt cheap, there's no reason to convert from a page to a pfn and back to a page, just to mark the page dirty/accessed or to put a reference to the page. Opportunistically drop a stale declaration of kvm_set_page_accessed() from kvm_host.h (there was no implementation). No functional change intended. [*] https://lore.kernel.org/all/CAHk-=wifQimj2d6npq-wCi5onYPjzQg4vyO4tFcPJJZr268cRw@mail.gmail.com Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 1 - virt/kvm/kvm_main.c | 64 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index c20f2d55840c..af4b5c0bf04e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1139,7 +1139,6 @@ unsigned long gfn_to_hva_memslot_prot(struct kvm_memory_slot *slot, gfn_t gfn, bool *writable); void kvm_release_page_clean(struct page *page); void kvm_release_page_dirty(struct page *page); -void kvm_set_page_accessed(struct page *page); kvm_pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn); kvm_pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 351cbd121cf5..4732a99935f9 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2820,18 +2820,40 @@ struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn) } EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_page); +static bool kvm_is_ad_tracked_page(struct page *page) +{ + /* + * Per page-flags.h, pages tagged PG_reserved "should in general not be + * touched (e.g. set dirty) except by its owner". + */ + return !PageReserved(page); +} + +static void kvm_set_page_dirty(struct page *page) +{ + if (kvm_is_ad_tracked_page(page)) + SetPageDirty(page); +} + +static void kvm_set_page_accessed(struct page *page) +{ + if (kvm_is_ad_tracked_page(page)) + mark_page_accessed(page); +} + void kvm_release_page_clean(struct page *page) { WARN_ON(is_error_page(page)); - kvm_release_pfn_clean(page_to_pfn(page)); + kvm_set_page_accessed(page); + put_page(page); } EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(kvm_pfn_t pfn) { if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) - put_page(pfn_to_page(pfn)); + kvm_release_page_clean(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); @@ -2839,40 +2861,40 @@ void kvm_release_page_dirty(struct page *page) { WARN_ON(is_error_page(page)); - kvm_release_pfn_dirty(page_to_pfn(page)); + kvm_set_page_dirty(page); + kvm_release_page_clean(page); } EXPORT_SYMBOL_GPL(kvm_release_page_dirty); void kvm_release_pfn_dirty(kvm_pfn_t pfn) { - kvm_set_pfn_dirty(pfn); - kvm_release_pfn_clean(pfn); + if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) + kvm_release_page_dirty(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); -static bool kvm_is_ad_tracked_pfn(kvm_pfn_t pfn) -{ - if (!pfn_valid(pfn)) - return false; - - /* - * Per page-flags.h, pages tagged PG_reserved "should in general not be - * touched (e.g. set dirty) except by its owner". - */ - return !PageReserved(pfn_to_page(pfn)); -} - +/* + * Note, checking for an error/noslot pfn is the caller's responsibility when + * directly marking a page dirty/accessed. Unlike the "release" helpers, the + * "set" helpers are not to be used when the pfn might point at garbage. + */ void kvm_set_pfn_dirty(kvm_pfn_t pfn) { - if (kvm_is_ad_tracked_pfn(pfn)) - SetPageDirty(pfn_to_page(pfn)); + if (WARN_ON(is_error_noslot_pfn(pfn))) + return; + + if (pfn_valid(pfn)) + kvm_set_page_dirty(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty); void kvm_set_pfn_accessed(kvm_pfn_t pfn) { - if (kvm_is_ad_tracked_pfn(pfn)) - mark_page_accessed(pfn_to_page(pfn)); + if (WARN_ON(is_error_noslot_pfn(pfn))) + return; + + if (pfn_valid(pfn)) + kvm_set_page_accessed(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed); -- cgit v1.2.3 From b1624f99aa8fedafcabf1b92fa51ed88dde14acb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:13 +0000 Subject: KVM: Remove kvm_vcpu_gfn_to_page() and kvm_vcpu_gpa_to_page() Drop helpers to convert a gfn/gpa to a 'struct page' in the context of a vCPU. KVM doesn't require that guests be backed by 'struct page' memory, thus any use of helpers that assume 'struct page' is bound to be flawed, as was the case for the recently removed last user in x86's nested VMX. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 7 ------- virt/kvm/kvm_main.c | 31 +++++++++++-------------------- 2 files changed, 11 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index af4b5c0bf04e..4334789409c0 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1230,7 +1230,6 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn); kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn); int kvm_vcpu_map(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map); -struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn); void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty); unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn); unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable); @@ -1718,12 +1717,6 @@ static inline hpa_t pfn_to_hpa(kvm_pfn_t pfn) return (hpa_t)pfn << PAGE_SHIFT; } -static inline struct page *kvm_vcpu_gpa_to_page(struct kvm_vcpu *vcpu, - gpa_t gpa) -{ - return kvm_vcpu_gfn_to_page(vcpu, gpa_to_gfn(gpa)); -} - static inline bool kvm_is_error_gpa(struct kvm *kvm, gpa_t gpa) { unsigned long hva = gfn_to_hva(kvm, gpa_to_gfn(gpa)); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 78d280e119b3..7cd0e3d67f9f 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2720,8 +2720,18 @@ int gfn_to_page_many_atomic(struct kvm_memory_slot *slot, gfn_t gfn, } EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic); -static struct page *kvm_pfn_to_page(kvm_pfn_t pfn) +/* + * Do not use this helper unless you are absolutely certain the gfn _must_ be + * backed by 'struct page'. A valid example is if the backing memslot is + * controlled by KVM. Note, if the returned page is valid, it's refcount has + * been elevated by gfn_to_pfn(). + */ +struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) { + kvm_pfn_t pfn; + + pfn = gfn_to_pfn(kvm, gfn); + if (is_error_noslot_pfn(pfn)) return KVM_ERR_PTR_BAD_PAGE; @@ -2730,15 +2740,6 @@ static struct page *kvm_pfn_to_page(kvm_pfn_t pfn) return pfn_to_page(pfn); } - -struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) -{ - kvm_pfn_t pfn; - - pfn = gfn_to_pfn(kvm, gfn); - - return kvm_pfn_to_page(pfn); -} EXPORT_SYMBOL_GPL(gfn_to_page); void kvm_release_pfn(kvm_pfn_t pfn, bool dirty) @@ -2808,16 +2809,6 @@ void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty) } EXPORT_SYMBOL_GPL(kvm_vcpu_unmap); -struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn) -{ - kvm_pfn_t pfn; - - pfn = kvm_vcpu_gfn_to_pfn(vcpu, gfn); - - return kvm_pfn_to_page(pfn); -} -EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_page); - static bool kvm_is_ad_tracked_page(struct page *page) { /* -- cgit v1.2.3 From 284dc49307738d2a897fd375431f741213cd0f27 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:14 +0000 Subject: KVM: Take a 'struct page', not a pfn in kvm_is_zone_device_page() Operate on a 'struct page' instead of a pfn when checking if a page is a ZONE_DEVICE page, and rename the helper accordingly. Generally speaking, KVM doesn't actually care about ZONE_DEVICE memory, i.e. shouldn't do anything special for ZONE_DEVICE memory. Rather, KVM wants to treat ZONE_DEVICE memory like regular memory, and the need to identify ZONE_DEVICE memory only arises as an exception to PG_reserved pages. In other words, KVM should only ever check for ZONE_DEVICE memory after KVM has already verified that there is a struct page associated with the pfn. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-9-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 5 +++-- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 2dcedf04ef85..b209aaf096df 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2788,15 +2788,16 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep) static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, const struct kvm_memory_slot *slot) { + struct page *page = pfn_to_page(pfn); + int level = PG_LEVEL_4K; unsigned long hva; unsigned long flags; - int level = PG_LEVEL_4K; pgd_t pgd; p4d_t p4d; pud_t pud; pmd_t pmd; - if (!PageCompound(pfn_to_page(pfn)) && !kvm_is_zone_device_pfn(pfn)) + if (!PageCompound(page) && !kvm_is_zone_device_page(page)) return PG_LEVEL_4K; /* diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 4334789409c0..6fb433ac2ba1 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1571,7 +1571,7 @@ void kvm_arch_sync_events(struct kvm *kvm); int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); bool kvm_is_reserved_pfn(kvm_pfn_t pfn); -bool kvm_is_zone_device_pfn(kvm_pfn_t pfn); +bool kvm_is_zone_device_page(struct page *page); struct kvm_irq_ack_notifier { struct hlist_node link; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 7cd0e3d67f9f..aa1bcd5f140d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -168,7 +168,7 @@ __weak void kvm_arch_guest_memory_reclaimed(struct kvm *kvm) { } -bool kvm_is_zone_device_pfn(kvm_pfn_t pfn) +bool kvm_is_zone_device_page(struct page *page) { /* * The metadata used by is_zone_device_page() to determine whether or @@ -176,10 +176,10 @@ bool kvm_is_zone_device_pfn(kvm_pfn_t pfn) * the device has been pinned, e.g. by get_user_pages(). WARN if the * page_count() is zero to help detect bad usage of this helper. */ - if (!pfn_valid(pfn) || WARN_ON_ONCE(!page_count(pfn_to_page(pfn)))) + if (WARN_ON_ONCE(!page_count(page))) return false; - return is_zone_device_page(pfn_to_page(pfn)); + return is_zone_device_page(page); } bool kvm_is_reserved_pfn(kvm_pfn_t pfn) @@ -192,7 +192,7 @@ bool kvm_is_reserved_pfn(kvm_pfn_t pfn) if (pfn_valid(pfn)) return PageReserved(pfn_to_page(pfn)) && !is_zero_pfn(pfn) && - !kvm_is_zone_device_pfn(pfn); + !kvm_is_zone_device_page(pfn_to_page(pfn)); return true; } -- cgit v1.2.3 From b14b2690c50e02145bb867dfcde8845eb17aa8a4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:15 +0000 Subject: KVM: Rename/refactor kvm_is_reserved_pfn() to kvm_pfn_to_refcounted_page() Rename and refactor kvm_is_reserved_pfn() to kvm_pfn_to_refcounted_page() to better reflect what KVM is actually checking, and to eliminate extra pfn_to_page() lookups. The kvm_release_pfn_*() an kvm_try_get_pfn() helpers in particular benefit from "refouncted" nomenclature, as it's not all that obvious why KVM needs to get/put refcounts for some PG_reserved pages (ZERO_PAGE and ZONE_DEVICE). Add a comment to call out that the list of exceptions to PG_reserved is all but guaranteed to be incomplete. The list has mostly been compiled by people throwing noodles at KVM and finding out they stick a little too well, e.g. the ZERO_PAGE's refcount overflowed and ZONE_DEVICE pages didn't get freed. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-10-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 15 ++++++----- arch/x86/kvm/mmu/tdp_mmu.c | 2 +- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 66 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 63 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index b209aaf096df..7ebb97c95da7 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -534,6 +534,7 @@ static int mmu_spte_clear_track_bits(struct kvm *kvm, u64 *sptep) kvm_pfn_t pfn; u64 old_spte = *sptep; int level = sptep_to_sp(sptep)->role.level; + struct page *page; if (!is_shadow_present_pte(old_spte) || !spte_has_volatile_bits(old_spte)) @@ -549,11 +550,13 @@ static int mmu_spte_clear_track_bits(struct kvm *kvm, u64 *sptep) pfn = spte_to_pfn(old_spte); /* - * KVM does not hold the refcount of the page used by - * kvm mmu, before reclaiming the page, we should - * unmap it from mmu first. + * KVM doesn't hold a reference to any pages mapped into the guest, and + * instead uses the mmu_notifier to ensure that KVM unmaps any pages + * before they are reclaimed. Sanity check that, if the pfn is backed + * by a refcounted page, the refcount is elevated. */ - WARN_ON(!kvm_is_reserved_pfn(pfn) && !page_count(pfn_to_page(pfn))); + page = kvm_pfn_to_refcounted_page(pfn); + WARN_ON(page && !page_count(page)); if (is_accessed_spte(old_spte)) kvm_set_pfn_accessed(pfn); @@ -2881,7 +2884,7 @@ void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault if (unlikely(fault->max_level == PG_LEVEL_4K)) return; - if (is_error_noslot_pfn(fault->pfn) || kvm_is_reserved_pfn(fault->pfn)) + if (is_error_noslot_pfn(fault->pfn) || !kvm_pfn_to_refcounted_page(fault->pfn)) return; if (kvm_slot_dirty_track_enabled(slot)) @@ -5993,7 +5996,7 @@ restart: * the guest, and the guest page table is using 4K page size * mapping if the indirect sp has level = 1. */ - if (sp->role.direct && !kvm_is_reserved_pfn(pfn) && + if (sp->role.direct && kvm_pfn_to_refcounted_page(pfn) && sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn, pfn, PG_LEVEL_NUM)) { pte_list_remove(kvm, rmap_head, sptep); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 8e8d412fb65c..1e777b739ac4 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1751,7 +1751,7 @@ static void zap_collapsible_spte_range(struct kvm *kvm, */ pfn = spte_to_pfn(iter.old_spte); - if (kvm_is_reserved_pfn(pfn)) + if (!kvm_pfn_to_refcounted_page(pfn)) continue; max_mapping_level = kvm_mmu_max_mapping_level(kvm, slot, diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 6fb433ac2ba1..a2bbdf3ab086 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1570,7 +1570,7 @@ void kvm_arch_sync_events(struct kvm *kvm); int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); -bool kvm_is_reserved_pfn(kvm_pfn_t pfn); +struct page *kvm_pfn_to_refcounted_page(kvm_pfn_t pfn); bool kvm_is_zone_device_page(struct page *page); struct kvm_irq_ack_notifier { diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index aa1bcd5f140d..04196096f9e4 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -182,19 +182,36 @@ bool kvm_is_zone_device_page(struct page *page) return is_zone_device_page(page); } -bool kvm_is_reserved_pfn(kvm_pfn_t pfn) +/* + * Returns a 'struct page' if the pfn is "valid" and backed by a refcounted + * page, NULL otherwise. Note, the list of refcounted PG_reserved page types + * is likely incomplete, it has been compiled purely through people wanting to + * back guest with a certain type of memory and encountering issues. + */ +struct page *kvm_pfn_to_refcounted_page(kvm_pfn_t pfn) { + struct page *page; + + if (!pfn_valid(pfn)) + return NULL; + + page = pfn_to_page(pfn); + if (!PageReserved(page)) + return page; + + /* The ZERO_PAGE(s) is marked PG_reserved, but is refcounted. */ + if (is_zero_pfn(pfn)) + return page; + /* * ZONE_DEVICE pages currently set PG_reserved, but from a refcounting * perspective they are "normal" pages, albeit with slightly different * usage rules. */ - if (pfn_valid(pfn)) - return PageReserved(pfn_to_page(pfn)) && - !is_zero_pfn(pfn) && - !kvm_is_zone_device_page(pfn_to_page(pfn)); + if (kvm_is_zone_device_page(page)) + return page; - return true; + return NULL; } /* @@ -2501,9 +2518,12 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault) static int kvm_try_get_pfn(kvm_pfn_t pfn) { - if (kvm_is_reserved_pfn(pfn)) + struct page *page = kvm_pfn_to_refcounted_page(pfn); + + if (!page) return 1; - return get_page_unless_zero(pfn_to_page(pfn)); + + return get_page_unless_zero(page); } static int hva_to_pfn_remapped(struct vm_area_struct *vma, @@ -2728,6 +2748,7 @@ EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic); */ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) { + struct page *page; kvm_pfn_t pfn; pfn = gfn_to_pfn(kvm, gfn); @@ -2735,10 +2756,11 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) if (is_error_noslot_pfn(pfn)) return KVM_ERR_PTR_BAD_PAGE; - if (kvm_is_reserved_pfn(pfn)) + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) return KVM_ERR_PTR_BAD_PAGE; - return pfn_to_page(pfn); + return page; } EXPORT_SYMBOL_GPL(gfn_to_page); @@ -2841,8 +2863,16 @@ EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(kvm_pfn_t pfn) { - if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) - kvm_release_page_clean(pfn_to_page(pfn)); + struct page *page; + + if (is_error_noslot_pfn(pfn)) + return; + + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) + return; + + kvm_release_page_clean(page); } EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); @@ -2857,8 +2887,16 @@ EXPORT_SYMBOL_GPL(kvm_release_page_dirty); void kvm_release_pfn_dirty(kvm_pfn_t pfn) { - if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) - kvm_release_page_dirty(pfn_to_page(pfn)); + struct page *page; + + if (is_error_noslot_pfn(pfn)) + return; + + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) + return; + + kvm_release_page_dirty(page); } EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); -- cgit v1.2.3 From 7b0a0e3c3a88260b6fcb017e49f198463aa62ed1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Apr 2022 16:50:57 +0200 Subject: wifi: cfg80211: do some rework towards MLO link APIs In order to support multi-link operation with multiple links, start adding some APIs. The notable addition here is to have the link ID in a new nl80211 attribute, that will be used to differentiate the links in many nl80211 operations. So far, this patch adds the netlink NL80211_ATTR_MLO_LINK_ID attribute (as well as the NL80211_ATTR_MLO_LINKS attribute) and plugs it through the system in some places, checking the validity etc. along with other infrastructure needed for it. For now, I've decided to include only the over-the-air link ID in the API. I know we discussed that we eventually need to have to have other ways of identifying a link, but for local AP mode and auth/assoc commands as well as set_key etc. we'll use the OTA ID. Also included in this patch is some refactoring of the data structures in struct wireless_dev, splitting for the first time the data into type dependent pieces, to make reasoning about these things easier. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 6 +- drivers/net/wireless/ath/wil6210/cfg80211.c | 9 +- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 4 +- drivers/net/wireless/marvell/libertas/mesh.c | 10 +- drivers/net/wireless/marvell/mwifiex/11h.c | 2 +- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 18 +- drivers/net/wireless/microchip/wilc1000/cfg80211.c | 3 +- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 14 +- drivers/net/wireless/quantenna/qtnfmac/commands.c | 2 +- drivers/net/wireless/quantenna/qtnfmac/event.c | 15 +- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 4 +- include/linux/ieee80211.h | 3 + include/net/cfg80211.h | 99 +++- include/uapi/linux/nl80211.h | 28 + net/mac80211/cfg.c | 8 +- net/mac80211/mlme.c | 2 +- net/wireless/ap.c | 46 +- net/wireless/chan.c | 196 +++++-- net/wireless/core.c | 28 +- net/wireless/core.h | 13 +- net/wireless/ibss.c | 57 +- net/wireless/mesh.c | 31 +- net/wireless/mlme.c | 74 +-- net/wireless/nl80211.c | 623 +++++++++++++++------ net/wireless/ocb.c | 5 +- net/wireless/rdev-ops.h | 32 +- net/wireless/reg.c | 139 +++-- net/wireless/scan.c | 8 +- net/wireless/sme.c | 102 ++-- net/wireless/trace.h | 86 ++- net/wireless/util.c | 44 +- net/wireless/wext-compat.c | 48 +- net/wireless/wext-sme.c | 29 +- 33 files changed, 1255 insertions(+), 533 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index bd1183830e91..33ed54738d47 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1119,7 +1119,7 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); mutex_lock(&vif->wdev.mtx); - cfg80211_ch_switch_notify(vif->ndev, &chandef); + cfg80211_ch_switch_notify(vif->ndev, &chandef, 0); mutex_unlock(&vif->wdev.mtx); } @@ -2967,7 +2967,8 @@ static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev, return ath6kl_set_ies(vif, beacon); } -static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); @@ -3368,6 +3369,7 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, const u8 *addr, const struct cfg80211_bitrate_mask *mask) { diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 8f2638f5b87b..f93bdffa4d1d 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -2098,8 +2098,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, bcon->tail_len)) privacy = 1; - memcpy(vif->ssid, wdev->ssid, wdev->ssid_len); - vif->ssid_len = wdev->ssid_len; + memcpy(vif->ssid, wdev->u.ap.ssid, wdev->u.ap.ssid_len); + vif->ssid_len = wdev->u.ap.ssid_len; /* in case privacy has changed, need to restart the AP */ if (vif->privacy != privacy) { @@ -2108,7 +2108,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid, vif->ssid_len, privacy, - wdev->beacon_interval, + wdev->links[0].ap.beacon_interval, vif->channel, vif->wmi_edmg_channel, bcon, vif->hidden_ssid, @@ -2186,7 +2186,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, } static int wil_cfg80211_stop_ap(struct wiphy *wiphy, - struct net_device *ndev) + struct net_device *ndev, + unsigned int link_id) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_vif *vif = ndev_to_vif(ndev); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 605206abe424..11e1f07f83e0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -4965,7 +4965,8 @@ exit: return err; } -static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) +static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev, + unsigned int link_id) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); @@ -5302,6 +5303,7 @@ exit: static int brcmf_cfg80211_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index a58c1e141f2c..90ffe8d1e0e8 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -109,9 +109,9 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action, if (priv->mesh_dev) { mesh_wdev = priv->mesh_dev->ieee80211_ptr; - ie->val.mesh_id_len = mesh_wdev->mesh_id_up_len; - memcpy(ie->val.mesh_id, mesh_wdev->ssid, - mesh_wdev->mesh_id_up_len); + ie->val.mesh_id_len = mesh_wdev->u.mesh.id_up_len; + memcpy(ie->val.mesh_id, mesh_wdev->u.mesh.id, + mesh_wdev->u.mesh.id_up_len); } ie->len = sizeof(struct mrvl_meshie_val) - @@ -986,8 +986,8 @@ static int lbs_add_mesh(struct lbs_private *priv) mesh_wdev->wiphy = priv->wdev->wiphy; if (priv->mesh_tlv) { - sprintf(mesh_wdev->ssid, "mesh"); - mesh_wdev->mesh_id_up_len = 4; + sprintf(mesh_wdev->u.mesh.id, "mesh"); + mesh_wdev->u.mesh.id_up_len = 4; } mesh_wdev->netdev = mesh_dev; diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index 3fa25cd64cda..4ca8d0135708 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -304,6 +304,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) mwifiex_dbg(priv->adapter, MSG, "indicating channel switch completion to kernel\n"); mutex_lock(&priv->wdev.mtx); - cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef); + cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0); mutex_unlock(&priv->wdev.mtx); } diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 6f23ec34e2e2..d68c40e0e122 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1753,10 +1753,12 @@ mwifiex_mgmt_stypes[NUM_NL80211_IFTYPES] = { * Function configures data rates to firmware using bitrate mask * provided by cfg80211. */ -static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, - struct net_device *dev, - const u8 *peer, - const struct cfg80211_bitrate_mask *mask) +static int +mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + unsigned int link_id, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; @@ -1998,7 +2000,8 @@ mwifiex_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) /* cfg80211 operation handler for stop ap. * Function stops BSS running at uAP interface. */ -static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); @@ -2421,7 +2424,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } - if (priv->wdev.current_bss) { + if (priv->wdev.connected) { mwifiex_dbg(adapter, ERROR, "%s: already connected\n", dev->name); return -EALREADY; @@ -2649,7 +2652,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, return -EBUSY; } - if (!priv->wdev.current_bss && priv->scan_block) + if (!priv->wdev.connected && priv->scan_block) priv->scan_block = false; if (!mwifiex_stop_bg_scan(priv)) @@ -4025,6 +4028,7 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index 1ac4684fab25..5c2c7f1dbffd 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1426,7 +1426,8 @@ static int change_beacon(struct wiphy *wiphy, struct net_device *dev, return wilc_add_beacon(vif, 0, 0, beacon); } -static int stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { int ret; struct wilc_vif *vif = netdev_priv(dev); diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 84b15a655eab..1593e810b3ca 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -352,7 +352,8 @@ static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev, return ret; } -static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); int ret; @@ -500,7 +501,7 @@ qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev, switch (vif->wdev.iftype) { case NL80211_IFTYPE_STATION: - if (idx != 0 || !vif->wdev.current_bss) + if (idx != 0 || !vif->wdev.connected) return -ENOENT; ether_addr_copy(mac, vif->bssid); @@ -729,7 +730,7 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, vif->vifid); - if (vif->wdev.current_bss) { + if (vif->wdev.connected) { netif_carrier_off(vif->netdev); cfg80211_disconnected(vif->netdev, reason_code, NULL, 0, true, GFP_KERNEL); @@ -745,10 +746,11 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, struct qtnf_wmac *mac = wiphy_priv(wiphy); struct wireless_dev *wdev = dev->ieee80211_ptr; struct ieee80211_supported_band *sband; - const struct cfg80211_chan_def *chandef = &wdev->chandef; + const struct cfg80211_chan_def *chandef = wdev_chandef(wdev, 0); struct ieee80211_channel *chan; int ret; + sband = wiphy->bands[NL80211_BAND_2GHZ]; if (sband && idx >= sband->n_channels) { idx -= sband->n_channels; @@ -765,7 +767,7 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, survey->channel = chan; survey->filled = 0x0; - if (chan == chandef->chan) + if (chandef && chan == chandef->chan) survey->filled = SURVEY_INFO_IN_USE; ret = qtnf_cmd_get_chan_stats(mac, chan->center_freq, survey); @@ -778,7 +780,7 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, static int qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, - struct cfg80211_chan_def *chandef) + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct net_device *ndev = wdev->netdev; struct qtnf_vif *vif; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index c68563c83098..3d734a7a5ba8 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -2005,7 +2005,7 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac) dwell_active = scan_req->duration; dwell_passive = scan_req->duration; } else if (wdev->iftype == NL80211_IFTYPE_STATION && - wdev->current_bss) { + wdev->connected) { /* let device select dwell based on traffic conditions */ dwell_active = QTNF_SCAN_TIME_AUTO; dwell_passive = QTNF_SCAN_TIME_AUTO; diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 8dc80574d08d..4fafe370101a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -189,7 +189,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, vif->mac->macid, vif->vifid, join_info->bssid, chandef.chan->hw_value); - if (!vif->wdev.ssid_len) { + if (!vif->wdev.u.client.ssid_len) { pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n", vif->mac->macid, vif->vifid, join_info->bssid); @@ -197,7 +197,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, goto done; } - ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL); + ie = kzalloc(2 + vif->wdev.u.client.ssid_len, GFP_KERNEL); if (!ie) { pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n", vif->mac->macid, vif->vifid, @@ -207,14 +207,15 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, } ie[0] = WLAN_EID_SSID; - ie[1] = vif->wdev.ssid_len; - memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len); + ie[1] = vif->wdev.u.client.ssid_len; + memcpy(ie + 2, vif->wdev.u.client.ssid, + vif->wdev.u.client.ssid_len); bss = cfg80211_inform_bss(wiphy, chandef.chan, CFG80211_BSS_FTYPE_UNKNOWN, join_info->bssid, 0, WLAN_CAPABILITY_ESS, 100, - ie, 2 + vif->wdev.ssid_len, + ie, 2 + vif->wdev.u.client.ssid_len, 0, GFP_KERNEL); if (!bss) { pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n", @@ -470,14 +471,14 @@ qtnf_event_handle_freq_change(struct qtnf_wmac *mac, continue; if (vif->wdev.iftype == NL80211_IFTYPE_STATION && - !vif->wdev.current_bss) + !vif->wdev.connected) continue; if (!vif->netdev) continue; mutex_lock(&vif->wdev.mtx); - cfg80211_ch_switch_notify(vif->netdev, &chandef); + cfg80211_ch_switch_notify(vif->netdev, &chandef, 0); mutex_unlock(&vif->wdev.mtx); } diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 43b5604c0bca..349aa3c4b668 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -2086,6 +2086,7 @@ static u8 rtw_get_chan_type(struct adapter *adapter) } static int cfg80211_rtw_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct adapter *adapter = wiphy_to_adapter(wiphy); @@ -2446,7 +2447,8 @@ static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *nd return rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len); } -static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) +static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev, + unsigned int link_id) { return 0; } diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 5c65ae6b8154..e15771965916 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4376,4 +4376,7 @@ enum ieee80211_range_params_max_total_ltf { IEEE80211_RANGE_PARAMS_MAX_TOTAL_LTF_UNSPECIFIED, }; +/* multi-link device */ +#define IEEE80211_MLD_MAX_NUM_LINKS 15 + #endif /* LINUX_IEEE80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6d02e12e4702..772e099fc932 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1158,6 +1158,7 @@ struct cfg80211_mbssid_elems { /** * struct cfg80211_beacon_data - beacon data + * @link_id: the link ID for the AP MLD link sending this beacon * @head: head portion of beacon (before TIM IE) * or %NULL if not changed * @tail: tail portion of beacon (after TIM IE) @@ -1188,6 +1189,8 @@ struct cfg80211_mbssid_elems { * attribute is present in beacon data or not. */ struct cfg80211_beacon_data { + unsigned int link_id; + const u8 *head, *tail; const u8 *beacon_ies; const u8 *proberesp_ies; @@ -4201,7 +4204,8 @@ struct cfg80211_ops { struct cfg80211_ap_settings *settings); int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *info); - int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev); + int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id); int (*add_station)(struct wiphy *wiphy, struct net_device *dev, @@ -4309,6 +4313,7 @@ struct cfg80211_ops { int (*set_bitrate_mask)(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, const u8 *peer, const struct cfg80211_bitrate_mask *mask); @@ -4384,6 +4389,7 @@ struct cfg80211_ops { int (*get_channel)(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef); int (*start_p2p_device)(struct wiphy *wiphy, @@ -4420,6 +4426,7 @@ struct cfg80211_ops { struct cfg80211_qos_map *qos_map); int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, struct cfg80211_chan_def *chandef); int (*add_tx_ts)(struct wiphy *wiphy, struct net_device *dev, @@ -4545,10 +4552,14 @@ struct cfg80211_ops { * @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation * before connection. * @WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK: The device supports bigger kek and kck keys + * @WIPHY_FLAG_SUPPORTS_MLO: This is a temporary flag gating the MLO APIs, + * in order to not have them reachable in normal drivers, until we have + * complete feature/interface combinations/etc. advertisement. No driver + * should set this flag for now. */ enum wiphy_flags { WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0), - /* use hole at 1 */ + WIPHY_FLAG_SUPPORTS_MLO = BIT(1), WIPHY_FLAG_SPLIT_SCAN_6GHZ = BIT(2), WIPHY_FLAG_NETNS_OK = BIT(3), WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), @@ -5505,6 +5516,8 @@ static inline void wiphy_unlock(struct wiphy *wiphy) * @netdev: (private) Used to reference back to the netdev, may be %NULL * @identifier: (private) Identifier used in nl80211 to identify this * wireless device if it has no netdev + * @connected_addr: (private) BSSID or AP MLD address if connected + * @connected: indicates if connected or not (STA mode) * @current_bss: (private) Used by the internal configuration code * @chandef: (private) Used by the internal configuration code to track * the user-set channel definition. @@ -5585,8 +5598,6 @@ struct wireless_dev { u8 address[ETH_ALEN] __aligned(sizeof(u16)); /* currently used for IBSS and SME - might be rearranged later */ - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_len, mesh_id_len, mesh_id_up_len; struct cfg80211_conn *conn; struct cfg80211_cached_keys *connect_keys; enum ieee80211_bss_type conn_bss_type; @@ -5598,20 +5609,17 @@ struct wireless_dev { struct list_head event_list; spinlock_t event_lock; - struct cfg80211_internal_bss *current_bss; /* associated / joined */ - struct cfg80211_chan_def preset_chandef; - struct cfg80211_chan_def chandef; + u8 connected:1; bool ps; int ps_timeout; - int beacon_interval; - u32 ap_unexpected_nlportid; u32 owner_nlportid; bool nl_owner_dead; + /* FIXME: need to rework radar detection for MLO */ bool cac_started; unsigned long cac_start_time; unsigned int cac_time_ms; @@ -5639,6 +5647,50 @@ struct wireless_dev { struct work_struct pmsr_free_wk; unsigned long unprot_beacon_reported; + + union { + struct { + u8 connected_addr[ETH_ALEN] __aligned(2); + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + } client; + struct { + int beacon_interval; + struct cfg80211_chan_def preset_chandef; + struct cfg80211_chan_def chandef; + u8 id[IEEE80211_MAX_SSID_LEN]; + u8 id_len, id_up_len; + } mesh; + struct { + struct cfg80211_chan_def preset_chandef; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + } ap; + struct { + struct cfg80211_internal_bss *current_bss; + struct cfg80211_chan_def chandef; + int beacon_interval; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + } ibss; + struct { + struct cfg80211_chan_def chandef; + } ocb; + } u; + + struct { + u8 addr[ETH_ALEN] __aligned(2); + union { + struct { + unsigned int beacon_interval; + struct cfg80211_chan_def chandef; + } ap; + struct { + struct cfg80211_internal_bss *current_bss; + } client; + }; + } links[IEEE80211_MLD_MAX_NUM_LINKS]; + u16 valid_links; }; static inline const u8 *wdev_address(struct wireless_dev *wdev) @@ -5667,6 +5719,31 @@ static inline void *wdev_priv(struct wireless_dev *wdev) return wiphy_priv(wdev->wiphy); } +/** + * wdev_chandef - return chandef pointer from wireless_dev + * @wdev: the wdev + * @link_id: the link ID for MLO + * + * Return: The chandef depending on the mode, or %NULL. + */ +struct cfg80211_chan_def *wdev_chandef(struct wireless_dev *wdev, + unsigned int link_id); + +static inline void WARN_INVALID_LINK_ID(struct wireless_dev *wdev, + unsigned int link_id) +{ + WARN_ON(link_id && !wdev->valid_links); + WARN_ON(wdev->valid_links && + !(wdev->valid_links & BIT(link_id))); +} + +#define for_each_valid_link(wdev, link_id) \ + for (link_id = 0; \ + link_id < ((wdev)->valid_links ? ARRAY_SIZE((wdev)->links) : 1); \ + link_id++) \ + if (!(wdev)->valid_links || \ + ((wdev)->valid_links & BIT(link_id))) + /** * DOC: Utility functions * @@ -7882,12 +7959,14 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy, * cfg80211_ch_switch_notify - update wdev channel and notify userspace * @dev: the device which switched channels * @chandef: the new channel definition + * @link_id: the link ID for MLO, must be 0 for non-MLO * * Caller must acquire wdev_lock, therefore must only be called from sleepable * driver context! */ void cfg80211_ch_switch_notify(struct net_device *dev, - struct cfg80211_chan_def *chandef); + struct cfg80211_chan_def *chandef, + unsigned int link_id); /* * cfg80211_ch_switch_started_notify - notify channel switch start diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 98f905f16411..a9a2c9fef295 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -323,6 +323,17 @@ * Once the association is done, the driver cleans the FILS AAD data. */ +/** + * DOC: Multi-Link Operation + * + * In Multi-Link Operation, a connection between to MLDs utilizes multiple + * links. To use this in nl80211, various commands and responses now need + * to or will include the new %NL80211_ATTR_MLO_LINKS attribute. + * Additionally, various commands that need to operate on a specific link + * now need to be given the %NL80211_ATTR_MLO_LINK_ID attribute, e.g. to + * use %NL80211_CMD_START_AP or similar functions. + */ + /** * enum nl80211_commands - supported nl80211 commands * @@ -1237,6 +1248,12 @@ * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to * specify the timeout value. * + * @NL80211_CMD_ADD_LINK: Add a new link to an interface. The + * %NL80211_ATTR_MLO_LINK_ID attribute is used for the new link. + * @NL80211_CMD_REMOVE_LINK: Remove a link from an interface. This may come + * without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links + * in preparation for e.g. roaming to a regular (non-MLO) AP. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1481,6 +1498,9 @@ enum nl80211_commands { NL80211_CMD_ASSOC_COMEBACK, + NL80211_CMD_ADD_LINK, + NL80211_CMD_REMOVE_LINK, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2663,6 +2683,11 @@ enum nl80211_commands { * association request when used with NL80211_CMD_NEW_STATION). Can be set * only if %NL80211_STA_FLAG_WME is set. * + * @NL80211_ATTR_MLO_LINK_ID: A (u8) link ID for use with MLO, to be used with + * various commands that need a link ID to operate. + * @NL80211_ATTR_MLO_LINKS: A nested array of links, each containing some + * per-link information and a link ID. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3177,6 +3202,9 @@ enum nl80211_attrs { NL80211_ATTR_DISABLE_EHT, + NL80211_ATTR_MLO_LINKS, + NL80211_ATTR_MLO_LINK_ID, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 881efbfb96f6..362cac9e2135 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1342,7 +1342,8 @@ static void ieee80211_free_next_beacon(struct ieee80211_sub_if_data *sdata) sdata->u.ap.next_beacon = NULL; } -static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *vlan; @@ -3049,6 +3050,7 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy, static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, const u8 *addr, const struct cfg80211_bitrate_mask *mask) { @@ -3390,7 +3392,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (err) return err; - cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); + cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef, 0); return 0; } @@ -3898,6 +3900,7 @@ unlock: static int ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); @@ -3958,6 +3961,7 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy, static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6d5ad71ef02c..e0a9b7d63071 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1314,7 +1314,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) return; } - cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef); + cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef, 0); } void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 550ac9d827fe..e68923200018 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -1,4 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Parts of this file are + * Copyright (C) 2022 Intel Corporation + */ #include #include #include @@ -7,8 +11,9 @@ #include "rdev-ops.h" -int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool notify) +static int ___cfg80211_stop_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev, unsigned int link_id, + bool notify) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; @@ -22,15 +27,16 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - if (!wdev->beacon_interval) + if (!wdev->links[link_id].ap.beacon_interval) return -ENOENT; - err = rdev_stop_ap(rdev, dev); + err = rdev_stop_ap(rdev, dev, link_id); if (!err) { wdev->conn_owner_nlportid = 0; - wdev->beacon_interval = 0; - memset(&wdev->chandef, 0, sizeof(wdev->chandef)); - wdev->ssid_len = 0; + wdev->links[link_id].ap.beacon_interval = 0; + memset(&wdev->links[link_id].ap.chandef, 0, + sizeof(wdev->links[link_id].ap.chandef)); + wdev->u.ap.ssid_len = 0; rdev_set_qos_map(rdev, dev, NULL); if (notify) nl80211_send_ap_stopped(wdev); @@ -46,14 +52,36 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, return err; } +int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev, int link_id, + bool notify) +{ + unsigned int link; + int ret = 0; + + if (link_id >= 0) + return ___cfg80211_stop_ap(rdev, dev, link_id, notify); + + for_each_valid_link(dev->ieee80211_ptr, link) { + int ret1 = ___cfg80211_stop_ap(rdev, dev, link, notify); + + if (ret1) + ret = ret1; + /* try the next one also if one errored */ + } + + return ret; +} + int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool notify) + struct net_device *dev, int link_id, + bool notify) { struct wireless_dev *wdev = dev->ieee80211_ptr; int err; wdev_lock(wdev); - err = __cfg80211_stop_ap(rdev, dev, notify); + err = __cfg80211_stop_ap(rdev, dev, link_id, notify); wdev_unlock(wdev); return err; diff --git a/net/wireless/chan.c b/net/wireless/chan.c index f74f176e0d9d..efc2de4bab57 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -672,14 +672,21 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, * range of chandef. */ bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, - struct ieee80211_channel *chan) + struct ieee80211_channel *chan, + bool primary_only) { int width; u32 freq; + if (!chandef->chan) + return false; + if (chandef->chan->center_freq == chan->center_freq) return true; + if (primary_only) + return false; + width = cfg80211_chandef_get_width(chandef); if (width <= 20) return false; @@ -704,23 +711,25 @@ bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) { - bool active = false; + unsigned int link; ASSERT_WDEV_LOCK(wdev); - if (!wdev->chandef.chan) - return false; - switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - active = wdev->beacon_interval != 0; + for_each_valid_link(wdev, link) { + if (wdev->links[link].ap.beacon_interval) + return true; + } break; case NL80211_IFTYPE_ADHOC: - active = wdev->ssid_len != 0; + if (wdev->u.ibss.ssid_len) + return true; break; case NL80211_IFTYPE_MESH_POINT: - active = wdev->mesh_id_len != 0; + if (wdev->u.mesh.id_len) + return true; break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_OCB: @@ -737,7 +746,35 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) WARN_ON(1); } - return active; + return false; +} + +bool cfg80211_wdev_on_sub_chan(struct wireless_dev *wdev, + struct ieee80211_channel *chan, + bool primary_only) +{ + unsigned int link; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + for_each_valid_link(wdev, link) { + if (cfg80211_is_sub_chan(&wdev->links[link].ap.chandef, + chan, primary_only)) + return true; + } + break; + case NL80211_IFTYPE_ADHOC: + return cfg80211_is_sub_chan(&wdev->u.ibss.chandef, chan, + primary_only); + case NL80211_IFTYPE_MESH_POINT: + return cfg80211_is_sub_chan(&wdev->u.mesh.chandef, chan, + primary_only); + default: + break; + } + + return false; } static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy, @@ -752,7 +789,7 @@ static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy, continue; } - if (cfg80211_is_sub_chan(&wdev->chandef, chan)) { + if (cfg80211_wdev_on_sub_chan(wdev, chan, false)) { wdev_unlock(wdev); return true; } @@ -772,7 +809,8 @@ cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, if (!cfg80211_chandef_valid(&rdev->background_radar_chandef)) return false; - return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel); + return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel, + false); } bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, @@ -1176,6 +1214,68 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_chandef_usable); +static bool cfg80211_ir_permissive_check_wdev(enum nl80211_iftype iftype, + struct wireless_dev *wdev, + struct ieee80211_channel *chan) +{ + struct ieee80211_channel *other_chan = NULL; + unsigned int link_id; + int r1, r2; + + for_each_valid_link(wdev, link_id) { + if (wdev->iftype == NL80211_IFTYPE_STATION && + wdev->links[link_id].client.current_bss) + other_chan = wdev->links[link_id].client.current_bss->pub.channel; + + /* + * If a GO already operates on the same GO_CONCURRENT channel, + * this one (maybe the same one) can beacon as well. We allow + * the operation even if the station we relied on with + * GO_CONCURRENT is disconnected now. But then we must make sure + * we're not outdoor on an indoor-only channel. + */ + if (iftype == NL80211_IFTYPE_P2P_GO && + wdev->iftype == NL80211_IFTYPE_P2P_GO && + wdev->links[link_id].ap.beacon_interval && + !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY)) + other_chan = wdev->links[link_id].ap.chandef.chan; + + if (!other_chan) + continue; + + if (chan == other_chan) + return true; + + if (chan->band != NL80211_BAND_5GHZ && + chan->band != NL80211_BAND_6GHZ) + continue; + + r1 = cfg80211_get_unii(chan->center_freq); + r2 = cfg80211_get_unii(other_chan->center_freq); + + if (r1 != -EINVAL && r1 == r2) { + /* + * At some locations channels 149-165 are considered a + * bundle, but at other locations, e.g., Indonesia, + * channels 149-161 are considered a bundle while + * channel 165 is left out and considered to be in a + * different bundle. Thus, in case that there is a + * station interface connected to an AP on channel 165, + * it is assumed that channels 149-161 are allowed for + * GO operations. However, having a station interface + * connected to an AP on channels 149-161, does not + * allow GO operation on channel 165. + */ + if (chan->center_freq == 5825 && + other_chan->center_freq != 5825) + continue; + return true; + } + } + + return false; +} + /* * Check if the channel can be used under permissive conditions mandated by * some regulatory bodies, i.e., the channel is marked with @@ -1219,59 +1319,14 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy, * the current registered device. */ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { - struct ieee80211_channel *other_chan = NULL; - int r1, r2; + bool ret; wdev_lock(wdev); - if (wdev->iftype == NL80211_IFTYPE_STATION && - wdev->current_bss) - other_chan = wdev->current_bss->pub.channel; - - /* - * If a GO already operates on the same GO_CONCURRENT channel, - * this one (maybe the same one) can beacon as well. We allow - * the operation even if the station we relied on with - * GO_CONCURRENT is disconnected now. But then we must make sure - * we're not outdoor on an indoor-only channel. - */ - if (iftype == NL80211_IFTYPE_P2P_GO && - wdev->iftype == NL80211_IFTYPE_P2P_GO && - wdev->beacon_interval && - !(chan->flags & IEEE80211_CHAN_INDOOR_ONLY)) - other_chan = wdev->chandef.chan; + ret = cfg80211_ir_permissive_check_wdev(iftype, wdev, chan); wdev_unlock(wdev); - if (!other_chan) - continue; - - if (chan == other_chan) - return true; - - if (chan->band != NL80211_BAND_5GHZ && - chan->band != NL80211_BAND_6GHZ) - continue; - - r1 = cfg80211_get_unii(chan->center_freq); - r2 = cfg80211_get_unii(other_chan->center_freq); - - if (r1 != -EINVAL && r1 == r2) { - /* - * At some locations channels 149-165 are considered a - * bundle, but at other locations, e.g., Indonesia, - * channels 149-161 are considered a bundle while - * channel 165 is left out and considered to be in a - * different bundle. Thus, in case that there is a - * station interface connected to an AP on channel 165, - * it is assumed that channels 149-161 are allowed for - * GO operations. However, having a station interface - * connected to an AP on channels 149-161, does not - * allow GO operation on channel 165. - */ - if (chan->center_freq == 5825 && - other_chan->center_freq != 5825) - continue; - return true; - } + if (ret) + return ret; } return false; @@ -1374,3 +1429,24 @@ bool cfg80211_any_usable_channels(struct wiphy *wiphy, return false; } EXPORT_SYMBOL(cfg80211_any_usable_channels); + +struct cfg80211_chan_def *wdev_chandef(struct wireless_dev *wdev, + unsigned int link_id) +{ + ASSERT_WDEV_LOCK(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_MESH_POINT: + return &wdev->u.mesh.chandef; + case NL80211_IFTYPE_ADHOC: + return &wdev->u.ibss.chandef; + case NL80211_IFTYPE_OCB: + return &wdev->u.ocb.chandef; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + return &wdev->links[link_id].ap.chandef; + default: + return NULL; + } +} +EXPORT_SYMBOL(wdev_chandef); diff --git a/net/wireless/core.c b/net/wireless/core.c index f08d4b3bb148..3e5d12040726 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1118,6 +1118,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev, bool unregister_netdev) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + unsigned int link_id; ASSERT_RTNL(); lockdep_assert_held(&rdev->wiphy.mtx); @@ -1167,11 +1168,22 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev, */ cfg80211_process_wdev_events(wdev); - if (WARN_ON(wdev->current_bss)) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - wdev->current_bss = NULL; + if (wdev->iftype == NL80211_IFTYPE_STATION || + wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) { + for (link_id = 0; link_id < ARRAY_SIZE(wdev->links); link_id++) { + struct cfg80211_internal_bss *curbss; + + curbss = wdev->links[link_id].client.current_bss; + + if (WARN_ON(curbss)) { + cfg80211_unhold_bss(curbss); + cfg80211_put_bss(wdev->wiphy, &curbss->pub); + wdev->links[link_id].client.current_bss = NULL; + } + } } + + wdev->connected = false; } void cfg80211_unregister_wdev(struct wireless_dev *wdev) @@ -1233,7 +1245,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - __cfg80211_stop_ap(rdev, dev, true); + __cfg80211_stop_ap(rdev, dev, -1, true); break; case NL80211_IFTYPE_OCB: __cfg80211_leave_ocb(rdev, dev); @@ -1463,9 +1475,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, memcpy(&setup, &default_mesh_setup, sizeof(setup)); /* back compat only needed for mesh_id */ - setup.mesh_id = wdev->ssid; - setup.mesh_id_len = wdev->mesh_id_up_len; - if (wdev->mesh_id_up_len) + setup.mesh_id = wdev->u.mesh.id; + setup.mesh_id_len = wdev->u.mesh.id_up_len; + if (wdev->u.mesh.id_up_len) __cfg80211_join_mesh(rdev, dev, &setup, &default_mesh_config); diff --git a/net/wireless/core.h b/net/wireless/core.h index 5436ada91b1a..2c195067ddff 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -307,6 +307,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *rdev); void cfg80211_bss_age(struct cfg80211_registered_device *rdev, unsigned long age_secs); void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, + unsigned int link, struct ieee80211_channel *channel); /* IBSS */ @@ -353,9 +354,11 @@ int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, /* AP */ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool notify); + struct net_device *dev, int link, + bool notify); int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev, bool notify); + struct net_device *dev, int link, + bool notify); /* MLME */ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, @@ -507,7 +510,11 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev); bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, - struct ieee80211_channel *chan); + struct ieee80211_channel *chan, + bool primary_only); +bool cfg80211_wdev_on_sub_chan(struct wireless_dev *wdev, + struct ieee80211_channel *chan, + bool primary_only); static inline unsigned int elapsed_jiffies_msecs(unsigned long start) { diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 5d89eec2869a..4935f94d1acc 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -28,7 +28,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) return; - if (!wdev->ssid_len) + if (!wdev->u.ibss.ssid_len) return; bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, @@ -37,13 +37,13 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, if (WARN_ON(!bss)) return; - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); + if (wdev->u.ibss.current_bss) { + cfg80211_unhold_bss(wdev->u.ibss.current_bss); + cfg80211_put_bss(wdev->wiphy, &wdev->u.ibss.current_bss->pub); } cfg80211_hold_bss(bss_from_pub(bss)); - wdev->current_bss = bss_from_pub(bss); + wdev->u.ibss.current_bss = bss_from_pub(bss); if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) cfg80211_upload_connect_keys(wdev); @@ -96,7 +96,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, lockdep_assert_held(&rdev->wiphy.mtx); ASSERT_WDEV_LOCK(wdev); - if (wdev->ssid_len) + if (wdev->u.ibss.ssid_len) return -EALREADY; if (!params->basic_rates) { @@ -131,7 +131,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, kfree_sensitive(wdev->connect_keys); wdev->connect_keys = connkeys; - wdev->chandef = params->chandef; + wdev->u.ibss.chandef = params->chandef; if (connkeys) { params->wep_keys = connkeys->params; params->wep_tx_key = connkeys->def; @@ -146,8 +146,8 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, return err; } - memcpy(wdev->ssid, params->ssid, params->ssid_len); - wdev->ssid_len = params->ssid_len; + memcpy(wdev->u.ibss.ssid, params->ssid, params->ssid_len); + wdev->u.ibss.ssid_len = params->ssid_len; return 0; } @@ -173,14 +173,14 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) for (i = 0; i < 6; i++) rdev_del_key(rdev, dev, i, false, NULL); - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); + if (wdev->u.ibss.current_bss) { + cfg80211_unhold_bss(wdev->u.ibss.current_bss); + cfg80211_put_bss(wdev->wiphy, &wdev->u.ibss.current_bss->pub); } - wdev->current_bss = NULL; - wdev->ssid_len = 0; - memset(&wdev->chandef, 0, sizeof(wdev->chandef)); + wdev->u.ibss.current_bss = NULL; + wdev->u.ibss.ssid_len = 0; + memset(&wdev->u.ibss.chandef, 0, sizeof(wdev->u.ibss.chandef)); #ifdef CONFIG_CFG80211_WEXT if (!nowext) wdev->wext.ibss.ssid_len = 0; @@ -205,7 +205,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); - if (!wdev->ssid_len) + if (!wdev->u.ibss.ssid_len) return -ENOLINK; err = rdev_leave_ibss(rdev, dev); @@ -339,7 +339,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, wdev_lock(wdev); err = 0; - if (wdev->ssid_len) + if (wdev->u.ibss.ssid_len) err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); @@ -374,8 +374,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, return -EINVAL; wdev_lock(wdev); - if (wdev->current_bss) - chan = wdev->current_bss->pub.channel; + if (wdev->u.ibss.current_bss) + chan = wdev->u.ibss.current_bss->pub.channel; else if (wdev->wext.ibss.chandef.chan) chan = wdev->wext.ibss.chandef.chan; wdev_unlock(wdev); @@ -408,7 +408,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, wdev_lock(wdev); err = 0; - if (wdev->ssid_len) + if (wdev->u.ibss.ssid_len) err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); @@ -419,8 +419,8 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, if (len > 0 && ssid[len - 1] == '\0') len--; - memcpy(wdev->ssid, ssid, len); - wdev->wext.ibss.ssid = wdev->ssid; + memcpy(wdev->u.ibss.ssid, ssid, len); + wdev->wext.ibss.ssid = wdev->u.ibss.ssid; wdev->wext.ibss.ssid_len = len; wdev_lock(wdev); @@ -443,10 +443,10 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev, data->flags = 0; wdev_lock(wdev); - if (wdev->ssid_len) { + if (wdev->u.ibss.ssid_len) { data->flags = 1; - data->length = wdev->ssid_len; - memcpy(ssid, wdev->ssid, data->length); + data->length = wdev->u.ibss.ssid_len; + memcpy(ssid, wdev->u.ibss.ssid, data->length); } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) { data->flags = 1; data->length = wdev->wext.ibss.ssid_len; @@ -494,7 +494,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, wdev_lock(wdev); err = 0; - if (wdev->ssid_len) + if (wdev->u.ibss.ssid_len) err = __cfg80211_leave_ibss(rdev, dev, true); wdev_unlock(wdev); @@ -527,8 +527,9 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; wdev_lock(wdev); - if (wdev->current_bss) - memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); + if (wdev->u.ibss.current_bss) + memcpy(ap_addr->sa_data, wdev->u.ibss.current_bss->pub.bssid, + ETH_ALEN); else if (wdev->wext.ibss.bssid) memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); else diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index e4e363138279..59a3c5c092b1 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -1,4 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Portions + * Copyright (C) 2022 Intel Corporation + */ #include #include #include @@ -114,7 +118,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, setup->is_secure) return -EOPNOTSUPP; - if (wdev->mesh_id_len) + if (wdev->u.mesh.id_len) return -EALREADY; if (!setup->mesh_id_len) @@ -125,7 +129,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!setup->chandef.chan) { /* if no channel explicitly given, use preset channel */ - setup->chandef = wdev->preset_chandef; + setup->chandef = wdev->u.mesh.preset_chandef; } if (!setup->chandef.chan) { @@ -209,10 +213,10 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, err = rdev_join_mesh(rdev, dev, conf, setup); if (!err) { - memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); - wdev->mesh_id_len = setup->mesh_id_len; - wdev->chandef = setup->chandef; - wdev->beacon_interval = setup->beacon_interval; + memcpy(wdev->u.mesh.id, setup->mesh_id, setup->mesh_id_len); + wdev->u.mesh.id_len = setup->mesh_id_len; + wdev->u.mesh.chandef = setup->chandef; + wdev->u.mesh.beacon_interval = setup->beacon_interval; } return err; @@ -241,15 +245,15 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, chandef->chan); if (!err) - wdev->chandef = *chandef; + wdev->u.mesh.chandef = *chandef; return err; } - if (wdev->mesh_id_len) + if (wdev->u.mesh.id_len) return -EBUSY; - wdev->preset_chandef = *chandef; + wdev->u.mesh.preset_chandef = *chandef; return 0; } @@ -267,15 +271,16 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, if (!rdev->ops->leave_mesh) return -EOPNOTSUPP; - if (!wdev->mesh_id_len) + if (!wdev->u.mesh.id_len) return -ENOTCONN; err = rdev_leave_mesh(rdev, dev); if (!err) { wdev->conn_owner_nlportid = 0; - wdev->mesh_id_len = 0; - wdev->beacon_interval = 0; - memset(&wdev->chandef, 0, sizeof(wdev->chandef)); + wdev->u.mesh.id_len = 0; + wdev->u.mesh.beacon_interval = 0; + memset(&wdev->u.mesh.chandef, 0, + sizeof(wdev->u.mesh.chandef)); rdev_set_qos_map(rdev, dev, NULL); cfg80211_sched_dfs_chan_update(rdev); } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index c8155a483ec2..fab2d6206cdd 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -92,8 +92,7 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev, nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL); - if (!wdev->current_bss || - !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) + if (!wdev->connected || !ether_addr_equal(wdev->u.client.connected_addr, bssid)) return; __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); @@ -113,8 +112,8 @@ static void cfg80211_process_disassoc(struct wireless_dev *wdev, nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL); - if (WARN_ON(!wdev->current_bss || - !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) + if (WARN_ON(!wdev->connected || + !ether_addr_equal(wdev->u.client.connected_addr, bssid))) return; __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); @@ -260,8 +259,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, if (!key || !key_len || key_idx < 0 || key_idx > 3) return -EINVAL; - if (wdev->current_bss && - ether_addr_equal(bssid, wdev->current_bss->pub.bssid)) + if (wdev->connected && + ether_addr_equal(bssid, wdev->u.client.connected_addr)) return -EALREADY; req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, @@ -322,9 +321,9 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); - if (wdev->current_bss && - (!req->prev_bssid || !ether_addr_equal(wdev->current_bss->pub.bssid, - req->prev_bssid))) + if (wdev->connected && + (!req->prev_bssid || + !ether_addr_equal(wdev->u.client.connected_addr, req->prev_bssid))) return -EALREADY; cfg80211_oper_and_ht_capa(&req->ht_capa_mask, @@ -364,13 +363,13 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); if (local_state_change && - (!wdev->current_bss || - !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) + (!wdev->connected || + !ether_addr_equal(wdev->u.client.connected_addr, bssid))) return 0; if (ether_addr_equal(wdev->disconnect_bssid, bssid) || - (wdev->current_bss && - ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) + (wdev->connected && + ether_addr_equal(wdev->u.client.connected_addr, bssid))) wdev->conn_owner_nlportid = 0; return rdev_deauth(rdev, dev, &req); @@ -392,11 +391,12 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, ASSERT_WDEV_LOCK(wdev); - if (!wdev->current_bss) + if (!wdev->connected) return -ENOTCONN; - if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) - req.bss = &wdev->current_bss->pub; + if (ether_addr_equal(wdev->links[0].client.current_bss->pub.bssid, + bssid)) + req.bss = &wdev->links[0].client.current_bss->pub; else return -ENOTCONN; @@ -405,7 +405,7 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, return err; /* driver should have reported the disassoc */ - WARN_ON(wdev->current_bss); + WARN_ON(wdev->connected); return 0; } @@ -420,10 +420,10 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, if (!rdev->ops->deauth) return; - if (!wdev->current_bss) + if (!wdev->connected) return; - memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); + memcpy(bssid, wdev->u.client.connected_addr, ETH_ALEN); cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, WLAN_REASON_DEAUTH_LEAVING, false); } @@ -676,28 +676,34 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: + /* + * check for IBSS DA must be done by driver as + * cfg80211 doesn't track the stations + */ + if (!wdev->u.ibss.current_bss || + !ether_addr_equal(wdev->u.ibss.current_bss->pub.bssid, + mgmt->bssid)) { + err = -ENOTCONN; + break; + } + break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (!wdev->current_bss) { + if (!wdev->connected) { err = -ENOTCONN; break; } - if (!ether_addr_equal(wdev->current_bss->pub.bssid, + /* FIXME: MLD may address this differently */ + + if (!ether_addr_equal(wdev->u.client.connected_addr, mgmt->bssid)) { err = -ENOTCONN; break; } - /* - * check for IBSS DA must be done by driver as - * cfg80211 doesn't track the stations - */ - if (wdev->iftype == NL80211_IFTYPE_ADHOC) - break; - /* for station, check that DA is the AP */ - if (!ether_addr_equal(wdev->current_bss->pub.bssid, + if (!ether_addr_equal(wdev->u.client.connected_addr, mgmt->da)) { err = -ENOTCONN; break; @@ -743,12 +749,12 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, if (!ieee80211_is_action(mgmt->frame_control) || mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) return -EINVAL; - if (!wdev->current_bss && + if (!wdev->connected && !wiphy_ext_feature_isset( &rdev->wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA)) return -EINVAL; - if (wdev->current_bss && + if (wdev->connected && !wiphy_ext_feature_isset( &rdev->wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED)) @@ -940,12 +946,16 @@ void cfg80211_cac_event(struct net_device *netdev, struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); unsigned long timeout; + /* not yet supported */ + if (wdev->valid_links) + return; + trace_cfg80211_cac_event(netdev, event); if (WARN_ON(!wdev->cac_started && event != NL80211_RADAR_CAC_STARTED)) return; - if (WARN_ON(!wdev->chandef.chan)) + if (WARN_ON(!wdev->links[0].ap.chandef.chan)) return; switch (event) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 740b29481bc6..af31978fc9cc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -792,6 +792,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NL80211_EHT_MIN_CAPABILITY_LEN, NL80211_EHT_MAX_CAPABILITY_LEN), [NL80211_ATTR_DISABLE_EHT] = { .type = NLA_FLAG }, + [NL80211_ATTR_MLO_LINKS] = + NLA_POLICY_NESTED_ARRAY(nl80211_policy), + [NL80211_ATTR_MLO_LINK_ID] = + NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS), }; /* policy for the key attributes */ @@ -1225,6 +1229,37 @@ static bool nl80211_put_txq_stats(struct sk_buff *msg, /* netlink command implementations */ +/** + * nl80211_link_id - return link ID + * @attrs: attributes to look at + * + * Returns: the link ID or 0 if not given + * + * Note this function doesn't do any validation of the link + * ID validity wrt. links that were actually added, so it must + * be called only from ops with %NL80211_FLAG_MLO_VALID_LINK_ID + * or if additional validation is done. + */ +static unsigned int nl80211_link_id(struct nlattr **attrs) +{ + struct nlattr *linkid = attrs[NL80211_ATTR_MLO_LINK_ID]; + + if (!linkid) + return 0; + + return nla_get_u8(linkid); +} + +static int nl80211_link_id_or_invalid(struct nlattr **attrs) +{ + struct nlattr *linkid = attrs[NL80211_ATTR_MLO_LINK_ID]; + + if (!linkid) + return -1; + + return nla_get_u8(linkid); +} + struct key_parse { struct key_params p; int idx; @@ -1496,11 +1531,15 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) case NL80211_IFTYPE_MESH_POINT: break; case NL80211_IFTYPE_ADHOC: + if (wdev->u.ibss.current_bss) + return 0; + return -ENOLINK; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (!wdev->current_bss) - return -ENOLINK; - break; + /* for MLO, require driver validation of the link ID */ + if (wdev->connected) + return 0; + return -ENOLINK; case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_OCB: case NL80211_IFTYPE_MONITOR: @@ -3232,12 +3271,14 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, struct net_device *dev, - struct genl_info *info) + struct genl_info *info, + int _link_id) { struct cfg80211_chan_def chandef; int result; enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; struct wireless_dev *wdev = NULL; + int link_id = _link_id; if (dev) wdev = dev->ieee80211_ptr; @@ -3246,6 +3287,12 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, if (wdev) iftype = wdev->iftype; + if (link_id < 0) { + if (wdev && wdev->valid_links) + return -EINVAL; + link_id = 0; + } + result = nl80211_parse_chandef(rdev, info, &chandef); if (result) return result; @@ -3254,49 +3301,48 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef, - iftype)) { - result = -EINVAL; - break; - } - if (wdev->beacon_interval) { + iftype)) + return -EINVAL; + if (wdev->links[link_id].ap.beacon_interval) { + struct ieee80211_channel *cur_chan; + if (!dev || !rdev->ops->set_ap_chanwidth || !(rdev->wiphy.features & - NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) { - result = -EBUSY; - break; - } + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) + return -EBUSY; /* Only allow dynamic channel width changes */ - if (chandef.chan != wdev->preset_chandef.chan) { - result = -EBUSY; - break; - } - result = rdev_set_ap_chanwidth(rdev, dev, &chandef); + cur_chan = wdev->links[link_id].ap.chandef.chan; + if (chandef.chan != cur_chan) + return -EBUSY; + + result = rdev_set_ap_chanwidth(rdev, dev, link_id, + &chandef); if (result) - break; + return result; + wdev->links[link_id].ap.chandef = chandef; + } else { + wdev->u.ap.preset_chandef = chandef; } - wdev->preset_chandef = chandef; - result = 0; - break; + return 0; case NL80211_IFTYPE_MESH_POINT: - result = cfg80211_set_mesh_channel(rdev, wdev, &chandef); - break; + return cfg80211_set_mesh_channel(rdev, wdev, &chandef); case NL80211_IFTYPE_MONITOR: - result = cfg80211_set_monitor_channel(rdev, &chandef); - break; + return cfg80211_set_monitor_channel(rdev, &chandef); default: - result = -EINVAL; + break; } - return result; + return -EINVAL; } static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int link_id = nl80211_link_id_or_invalid(info->attrs); struct net_device *netdev = info->user_ptr[1]; - return __nl80211_set_channel(rdev, netdev, info); + return __nl80211_set_channel(rdev, netdev, info, link_id); } static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) @@ -3411,7 +3457,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) result = __nl80211_set_channel( rdev, nl80211_can_set_dev_channel(wdev) ? netdev : NULL, - info); + info, -1); if (result) goto out; } @@ -3696,15 +3742,13 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr)) goto nla_put_failure; - if (rdev->ops->get_channel) { - int ret; + if (rdev->ops->get_channel && !wdev->valid_links) { struct cfg80211_chan_def chandef = {}; + int ret; - ret = rdev_get_channel(rdev, wdev, &chandef); - if (ret == 0) { - if (nl80211_send_chandef(msg, &chandef)) - goto nla_put_failure; - } + ret = rdev_get_channel(rdev, wdev, 0, &chandef); + if (ret == 0 && nl80211_send_chandef(msg, &chandef)) + goto nla_put_failure; } if (rdev->ops->get_tx_power) { @@ -3721,27 +3765,24 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - if (wdev->ssid_len && - nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid)) + if (wdev->u.ap.ssid_len && + nla_put(msg, NL80211_ATTR_SSID, wdev->u.ap.ssid_len, + wdev->u.ap.ssid)) goto nla_put_failure_locked; break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_ADHOC: { - const struct element *ssid_elem; - - if (!wdev->current_bss) - break; - rcu_read_lock(); - ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub, - WLAN_EID_SSID); - if (ssid_elem && - nla_put(msg, NL80211_ATTR_SSID, ssid_elem->datalen, - ssid_elem->data)) - goto nla_put_failure_rcu_locked; - rcu_read_unlock(); + if (wdev->u.client.ssid_len && + nla_put(msg, NL80211_ATTR_SSID, wdev->u.client.ssid_len, + wdev->u.client.ssid)) + goto nla_put_failure_locked; + break; + case NL80211_IFTYPE_ADHOC: + if (wdev->u.ibss.ssid_len && + nla_put(msg, NL80211_ATTR_SSID, wdev->u.ibss.ssid_len, + wdev->u.ibss.ssid)) + goto nla_put_failure_locked; break; - } default: /* nothing */ break; @@ -3761,8 +3802,6 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag genlmsg_end(msg, hdr); return 0; - nla_put_failure_rcu_locked: - rcu_read_unlock(); nla_put_failure_locked: wdev_unlock(wdev); nla_put_failure: @@ -4014,10 +4053,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) wdev_lock(wdev); BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); - wdev->mesh_id_up_len = + wdev->u.mesh.id_up_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); - memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), - wdev->mesh_id_up_len); + memcpy(wdev->u.mesh.id, + nla_data(info->attrs[NL80211_ATTR_MESH_ID]), + wdev->u.mesh.id_up_len); wdev_unlock(wdev); } @@ -4122,10 +4162,11 @@ static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) wdev_lock(wdev); BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); - wdev->mesh_id_up_len = + wdev->u.mesh.id_up_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); - memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]), - wdev->mesh_id_up_len); + memcpy(wdev->u.mesh.id, + nla_data(info->attrs[NL80211_ATTR_MESH_ID]), + wdev->u.mesh.id_up_len); wdev_unlock(wdev); break; case NL80211_IFTYPE_NAN: @@ -4662,7 +4703,7 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EOPNOTSUPP; - if (!dev->ieee80211_ptr->beacon_interval) + if (!dev->ieee80211_ptr->links[0].ap.beacon_interval) return -EINVAL; acl = parse_acl_data(&rdev->wiphy, info); @@ -4818,14 +4859,24 @@ static void he_build_mcs_mask(u16 he_mcs_map, } } -static u16 he_get_txmcsmap(struct genl_info *info, +static u16 he_get_txmcsmap(struct genl_info *info, unsigned int link_id, const struct ieee80211_sta_he_cap *he_cap) { struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; - __le16 tx_mcs; + struct cfg80211_chan_def *chandef; + __le16 tx_mcs; - switch (wdev->chandef.width) { + chandef = wdev_chandef(wdev, link_id); + if (!chandef) { + /* + * This is probably broken, but we never maintained + * a chandef in these cases, so it always was. + */ + return le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); + } + + switch (chandef->width) { case NL80211_CHAN_WIDTH_80P80: tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80p80; break; @@ -4836,6 +4887,7 @@ static u16 he_get_txmcsmap(struct genl_info *info, tx_mcs = he_cap->he_mcs_nss_supp.tx_mcs_80; break; } + return le16_to_cpu(tx_mcs); } @@ -4843,7 +4895,8 @@ static bool he_set_mcs_mask(struct genl_info *info, struct wireless_dev *wdev, struct ieee80211_supported_band *sband, struct nl80211_txrate_he *txrate, - u16 mcs[NL80211_HE_NSS_MAX]) + u16 mcs[NL80211_HE_NSS_MAX], + unsigned int link_id) { const struct ieee80211_sta_he_cap *he_cap; u16 tx_mcs_mask[NL80211_HE_NSS_MAX] = {}; @@ -4856,7 +4909,7 @@ static bool he_set_mcs_mask(struct genl_info *info, memset(mcs, 0, sizeof(u16) * NL80211_HE_NSS_MAX); - tx_mcs_map = he_get_txmcsmap(info, he_cap); + tx_mcs_map = he_get_txmcsmap(info, link_id, he_cap); /* Build he_mcs_mask from HE capabilities */ he_build_mcs_mask(tx_mcs_map, tx_mcs_mask); @@ -4876,7 +4929,8 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, enum nl80211_attrs attr, struct cfg80211_bitrate_mask *mask, struct net_device *dev, - bool default_all_enabled) + bool default_all_enabled, + unsigned int link_id) { struct nlattr *tb[NL80211_TXRATE_MAX + 1]; struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -4913,7 +4967,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, if (!he_cap) continue; - he_tx_mcs_map = he_get_txmcsmap(info, he_cap); + he_tx_mcs_map = he_get_txmcsmap(info, link_id, he_cap); he_build_mcs_mask(he_tx_mcs_map, mask->control[i].he_mcs); mask->control[i].he_gi = 0xFF; @@ -4978,7 +5032,8 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, if (tb[NL80211_TXRATE_HE] && !he_set_mcs_mask(info, wdev, sband, nla_data(tb[NL80211_TXRATE_HE]), - mask->control[band].he_mcs)) + mask->control[band].he_mcs, + link_id)) return -EINVAL; if (tb[NL80211_TXRATE_HE_GI]) @@ -5215,6 +5270,8 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, memset(bcn, 0, sizeof(*bcn)); + bcn->link_id = nl80211_link_id(attrs); + if (attrs[NL80211_ATTR_BEACON_HEAD]) { bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]); bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]); @@ -5468,22 +5525,20 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, struct cfg80211_ap_settings *params) { struct wireless_dev *wdev; - bool ret = false; list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (wdev->iftype != NL80211_IFTYPE_AP && wdev->iftype != NL80211_IFTYPE_P2P_GO) continue; - if (!wdev->preset_chandef.chan) + if (!wdev->u.ap.preset_chandef.chan) continue; - params->chandef = wdev->preset_chandef; - ret = true; - break; + params->chandef = wdev->u.ap.preset_chandef; + return true; } - return ret; + return false; } static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, @@ -5541,6 +5596,7 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_ap_settings *params; @@ -5553,7 +5609,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->start_ap) return -EOPNOTSUPP; - if (wdev->beacon_interval) + if (wdev->links[link_id].ap.beacon_interval) return -EALREADY; /* these are required for START_AP */ @@ -5595,6 +5651,18 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) err = -EINVAL; goto out; } + + if (wdev->u.ap.ssid_len && + (wdev->u.ap.ssid_len != params->ssid_len || + memcmp(wdev->u.ap.ssid, params->ssid, params->ssid_len))) { + /* require identical SSID for MLO */ + err = -EINVAL; + goto out; + } + } else if (wdev->valid_links) { + /* require SSID for MLO */ + err = -EINVAL; + goto out; } if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) @@ -5662,8 +5730,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) err = nl80211_parse_chandef(rdev, info, ¶ms->chandef); if (err) goto out; - } else if (wdev->preset_chandef.chan) { - params->chandef = wdev->preset_chandef; + } else if (wdev->valid_links) { + /* with MLD need to specify the channel configuration */ + err = -EINVAL; + goto out; + } else if (wdev->u.ap.preset_chandef.chan) { + params->chandef = wdev->u.ap.preset_chandef; } else if (!nl80211_get_ap_channel(rdev, params)) { err = -EINVAL; goto out; @@ -5679,7 +5751,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) err = nl80211_parse_tx_bitrate_mask(info, info->attrs, NL80211_ATTR_TX_RATES, ¶ms->beacon_rate, - dev, false); + dev, false, link_id); if (err) goto out; @@ -5779,19 +5851,28 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) params->flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT; wdev_lock(wdev); + if (wdev->conn_owner_nlportid && + info->attrs[NL80211_ATTR_SOCKET_OWNER] && + wdev->conn_owner_nlportid != info->snd_portid) { + err = -EINVAL; + goto out_unlock; + } + + /* FIXME: validate MLO/link-id against driver capabilities */ + err = rdev_start_ap(rdev, dev, params); if (!err) { - wdev->preset_chandef = params->chandef; - wdev->beacon_interval = params->beacon_interval; - wdev->chandef = params->chandef; - wdev->ssid_len = params->ssid_len; - memcpy(wdev->ssid, params->ssid, wdev->ssid_len); + wdev->links[link_id].ap.beacon_interval = params->beacon_interval; + wdev->links[link_id].ap.chandef = params->chandef; + wdev->u.ap.ssid_len = params->ssid_len; + memcpy(wdev->u.ap.ssid, params->ssid, + params->ssid_len); if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) wdev->conn_owner_nlportid = info->snd_portid; } +out_unlock: wdev_unlock(wdev); - out: kfree(params->acl); kfree(params->beacon.mbssid_ies); @@ -5807,6 +5888,7 @@ out: static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_beacon_data params; @@ -5819,7 +5901,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->change_beacon) return -EOPNOTSUPP; - if (!wdev->beacon_interval) + if (!wdev->links[link_id].ap.beacon_interval) return -EINVAL; err = nl80211_parse_beacon(rdev, info->attrs, ¶ms); @@ -5838,9 +5920,10 @@ out: static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; - return cfg80211_stop_ap(rdev, dev, false); + return cfg80211_stop_ap(rdev, dev, link_id, false); } static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { @@ -7590,7 +7673,7 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, wdev_lock(wdev); /* If not connected, get default parameters */ - if (!wdev->mesh_id_len) + if (!wdev->u.mesh.id_len) memcpy(&cur_params, &default_mesh_config, sizeof(cur_params)); else err = rdev_get_mesh_config(rdev, dev, &cur_params); @@ -7971,7 +8054,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb, return err; wdev_lock(wdev); - if (!wdev->mesh_id_len) + if (!wdev->u.mesh.id_len) err = -ENOLINK; if (!err) @@ -8463,14 +8546,44 @@ int nl80211_parse_random_mac(struct nlattr **attrs, return 0; } -static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev) +static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev, + struct ieee80211_channel *chan) { + unsigned int link_id; + bool all_ok = true; + ASSERT_WDEV_LOCK(wdev); if (!cfg80211_beaconing_iface_active(wdev)) return true; - if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR)) + /* + * FIXME: check if we have a free HW resource/link for chan + * + * This, as well as the FIXME below, requires knowing the link + * capabilities of the hardware. + */ + + /* we cannot leave radar channels */ + for_each_valid_link(wdev, link_id) { + struct cfg80211_chan_def *chandef; + + chandef = wdev_chandef(wdev, link_id); + if (!chandef) + continue; + + /* + * FIXME: don't require all_ok, but rather check only the + * correct HW resource/link onto which 'chan' falls, + * as only that link leaves the channel for doing + * the off-channel operation. + */ + + if (chandef->chan->flags & IEEE80211_CHAN_RADAR) + all_ok = false; + } + + if (all_ok) return true; return regulatory_pre_cac_allowed(wdev->wiphy); @@ -8553,7 +8666,7 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev, int err; if (!(wiphy->features & randomness_flag) || - (wdev && wdev->current_bss)) + (wdev && wdev->connected)) return -EOPNOTSUPP; err = nl80211_parse_random_mac(attrs, mac_addr, mac_addr_mask); @@ -8690,17 +8803,14 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->n_channels = i; wdev_lock(wdev); - if (!cfg80211_off_channel_oper_allowed(wdev)) { - struct ieee80211_channel *chan; + for (i = 0; i < request->n_channels; i++) { + struct ieee80211_channel *chan = request->channels[i]; - if (request->n_channels != 1) { - wdev_unlock(wdev); - err = -EBUSY; - goto out_free; - } + /* if we can go off-channel to the target channel we're good */ + if (cfg80211_off_channel_oper_allowed(wdev, chan)) + continue; - chan = request->channels[0]; - if (chan->center_freq != wdev->chandef.chan->center_freq) { + if (!cfg80211_wdev_on_sub_chan(wdev, chan, true)) { wdev_unlock(wdev); err = -EBUSY; goto out_free; @@ -9445,7 +9555,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms); if (!err) { - wdev->chandef = chandef; + wdev->links[0].ap.chandef = chandef; wdev->cac_started = true; wdev->cac_start_time = jiffies; wdev->cac_time_ms = cac_time_ms; @@ -9513,6 +9623,7 @@ static int nl80211_notify_radar_detection(struct sk_buff *skb, static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_csa_settings params; @@ -9539,15 +9650,15 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) need_handle_dfs_flag = false; /* useless if AP is not running */ - if (!wdev->beacon_interval) + if (!wdev->links[link_id].ap.beacon_interval) return -ENOTCONN; break; case NL80211_IFTYPE_ADHOC: - if (!wdev->ssid_len) + if (!wdev->u.ibss.ssid_len) return -ENOTCONN; break; case NL80211_IFTYPE_MESH_POINT: - if (!wdev->mesh_id_len) + if (!wdev->u.mesh.id_len) return -ENOTCONN; break; default: @@ -9718,6 +9829,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, { struct cfg80211_bss *res = &intbss->pub; const struct cfg80211_bss_ies *ies; + unsigned int link_id; void *hdr; struct nlattr *bss; @@ -9822,13 +9934,15 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, switch (wdev->iftype) { case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - if (intbss == wdev->current_bss && - nla_put_u32(msg, NL80211_BSS_STATUS, - NL80211_BSS_STATUS_ASSOCIATED)) - goto nla_put_failure; + for_each_valid_link(wdev, link_id) { + if (intbss == wdev->links[link_id].client.current_bss && + nla_put_u32(msg, NL80211_BSS_STATUS, + NL80211_BSS_STATUS_ASSOCIATED)) + goto nla_put_failure; + } break; case NL80211_IFTYPE_ADHOC: - if (intbss == wdev->current_bss && + if (intbss == wdev->u.ibss.current_bss && nla_put_u32(msg, NL80211_BSS_STATUS, NL80211_BSS_STATUS_IBSS_JOINED)) goto nla_put_failure; @@ -11362,7 +11476,7 @@ static int nl80211_update_connect_params(struct sk_buff *skb, } wdev_lock(dev->ieee80211_ptr); - if (!wdev->current_bss) + if (!wdev->connected) ret = -ENOLINK; else ret = rdev_update_connect_params(rdev, dev, &connect, changed); @@ -11575,9 +11689,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; + unsigned int link_id = nl80211_link_id(info->attrs); struct wireless_dev *wdev = info->user_ptr[1]; struct cfg80211_chan_def chandef; - const struct cfg80211_chan_def *compat_chandef; struct sk_buff *msg; void *hdr; u64 cookie; @@ -11607,10 +11721,22 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, return err; wdev_lock(wdev); - if (!cfg80211_off_channel_oper_allowed(wdev) && - !cfg80211_chandef_identical(&wdev->chandef, &chandef)) { - compat_chandef = cfg80211_chandef_compatible(&wdev->chandef, - &chandef); + if (!cfg80211_off_channel_oper_allowed(wdev, chandef.chan)) { + const struct cfg80211_chan_def *oper_chandef, *compat_chandef; + + oper_chandef = wdev_chandef(wdev, link_id); + + if (WARN_ON(!oper_chandef)) { + /* cannot happen since we must beacon to get here */ + WARN_ON(1); + wdev_unlock(wdev); + return -EBUSY; + } + + /* note: returns first one if identical chandefs */ + compat_chandef = cfg80211_chandef_compatible(&chandef, + oper_chandef); + if (compat_chandef != &chandef) { wdev_unlock(wdev); return -EBUSY; @@ -11672,6 +11798,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_bitrate_mask mask; + unsigned int link_id = nl80211_link_id(info->attrs); struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -11683,11 +11810,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, wdev_lock(wdev); err = nl80211_parse_tx_bitrate_mask(info, info->attrs, NL80211_ATTR_TX_RATES, &mask, - dev, true); + dev, true, link_id); if (err) goto out; - err = rdev_set_bitrate_mask(rdev, dev, NULL, &mask); + err = rdev_set_bitrate_mask(rdev, dev, link_id, NULL, &mask); out: wdev_unlock(wdev); return err; @@ -11812,7 +11939,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) return -EINVAL; wdev_lock(wdev); - if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) { + if (params.offchan && + !cfg80211_off_channel_oper_allowed(wdev, chandef.chan)) { wdev_unlock(wdev); return -EBUSY; } @@ -12030,12 +12158,13 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev, * connection is established and enough beacons received to calculate * the average. */ - if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss && + if (!wdev->cqm_config->last_rssi_event_value && + wdev->links[0].client.current_bss && rdev->ops->get_station) { struct station_info sinfo = {}; u8 *mac_addr; - mac_addr = wdev->current_bss->pub.bssid; + mac_addr = wdev->links[0].client.current_bss->pub.bssid; err = rdev_get_station(rdev, dev, mac_addr, &sinfo); if (err) @@ -12298,7 +12427,7 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) err = nl80211_parse_tx_bitrate_mask(info, info->attrs, NL80211_ATTR_TX_RATES, &setup.beacon_rate, - dev, false); + dev, false, 0); if (err) return err; @@ -13268,7 +13397,7 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) rekey_data.akm = nla_get_u32(tb[NL80211_REKEY_DATA_AKM]); wdev_lock(wdev); - if (!wdev->current_bss) { + if (!wdev->connected) { err = -ENOTCONN; goto out; } @@ -14537,7 +14666,7 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (wdev->current_bss) + if (wdev->connected) break; err = -ENOTCONN; goto out; @@ -14710,13 +14839,13 @@ static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info) return -EINVAL; wdev_lock(wdev); - if (!wdev->current_bss) { + if (!wdev->connected) { ret = -ENOTCONN; goto out; } pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]); - if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) { + if (memcmp(pmk_conf.aa, wdev->u.client.connected_addr, ETH_ALEN)) { ret = -EINVAL; goto out; } @@ -14844,9 +14973,13 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info) case NL80211_IFTYPE_MESH_POINT: break; case NL80211_IFTYPE_ADHOC: + if (wdev->u.ibss.current_bss) + break; + err = -ENOTCONN; + goto out; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (wdev->current_bss) + if (wdev->connected) break; err = -ENOTCONN; goto out; @@ -14882,12 +15015,14 @@ static int nl80211_get_ftm_responder_stats(struct sk_buff *skb, struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_ftm_responder_stats ftm_stats = {}; + unsigned int link_id = nl80211_link_id(info->attrs); struct sk_buff *msg; void *hdr; struct nlattr *ftm_stats_attr; int err; - if (wdev->iftype != NL80211_IFTYPE_AP || !wdev->beacon_interval) + if (wdev->iftype != NL80211_IFTYPE_AP || + !wdev->links[link_id].ap.beacon_interval) return -EOPNOTSUPP; err = rdev_get_ftm_responder_stats(rdev, dev, &ftm_stats); @@ -15017,7 +15152,8 @@ static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info) static int parse_tid_conf(struct cfg80211_registered_device *rdev, struct nlattr *attrs[], struct net_device *dev, struct cfg80211_tid_cfg *tid_conf, - struct genl_info *info, const u8 *peer) + struct genl_info *info, const u8 *peer, + unsigned int link_id) { struct netlink_ext_ack *extack = info->extack; u64 mask; @@ -15092,7 +15228,7 @@ static int parse_tid_conf(struct cfg80211_registered_device *rdev, attr = NL80211_TID_CONFIG_ATTR_TX_RATE; err = nl80211_parse_tx_bitrate_mask(info, attrs, attr, &tid_conf->txrate_mask, dev, - true); + true, link_id); if (err) return err; @@ -15119,6 +15255,7 @@ static int nl80211_set_tid_config(struct sk_buff *skb, { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct nlattr *attrs[NL80211_TID_CONFIG_ATTR_MAX + 1]; + unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct cfg80211_tid_config *tid_config; struct nlattr *tid; @@ -15156,7 +15293,7 @@ static int nl80211_set_tid_config(struct sk_buff *skb, ret = parse_tid_conf(rdev, attrs, dev, &tid_config->tid_conf[conf_idx], - info, tid_config->peer); + info, tid_config->peer, link_id); if (ret) goto bad_tid_conf; @@ -15295,6 +15432,62 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, return rdev_set_fils_aad(rdev, dev, &fils_aad); } +static int nl80211_add_link(struct sk_buff *skb, struct genl_info *info) +{ + unsigned int link_id = nl80211_link_id(info->attrs); + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (!(wdev->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) + return -EINVAL; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + break; + default: + return -EINVAL; + } + + if (!info->attrs[NL80211_ATTR_MAC] || + !is_valid_ether_addr(nla_data(info->attrs[NL80211_ATTR_MAC]))) + return -EINVAL; + + wdev_lock(wdev); + wdev->valid_links |= BIT(link_id); + ether_addr_copy(wdev->links[link_id].addr, + nla_data(info->attrs[NL80211_ATTR_MAC])); + wdev_unlock(wdev); + + return 0; +} + +static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info) +{ + unsigned int link_id = nl80211_link_id(info->attrs); + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + /* cannot remove if there's no link */ + if (!info->attrs[NL80211_ATTR_MLO_LINK_ID]) + return -EINVAL; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + break; + default: + return -EINVAL; + } + + /* FIXME: stop the link operations first */ + + wdev_lock(wdev); + wdev->valid_links &= ~BIT(link_id); + eth_zero_addr(wdev->links[link_id].addr); + wdev_unlock(wdev); + + return 0; +} + #define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_RTNL 0x04 @@ -15307,6 +15500,8 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, NL80211_FLAG_CHECK_NETDEV_UP) #define NL80211_FLAG_CLEAR_SKB 0x20 #define NL80211_FLAG_NO_WIPHY_MTX 0x40 +#define NL80211_FLAG_MLO_VALID_LINK_ID 0x80 +#define NL80211_FLAG_MLO_UNSUPPORTED 0x100 #define INTERNAL_FLAG_SELECTORS(__sel) \ SELECTOR(__sel, NONE, 0) /* must be first */ \ @@ -15316,6 +15511,12 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, NL80211_FLAG_NEED_WDEV) \ SELECTOR(__sel, NETDEV, \ NL80211_FLAG_NEED_NETDEV) \ + SELECTOR(__sel, NETDEV_LINK, \ + NL80211_FLAG_NEED_NETDEV | \ + NL80211_FLAG_MLO_VALID_LINK_ID) \ + SELECTOR(__sel, NETDEV_NO_MLO, \ + NL80211_FLAG_NEED_NETDEV | \ + NL80211_FLAG_MLO_UNSUPPORTED) \ SELECTOR(__sel, WIPHY_RTNL, \ NL80211_FLAG_NEED_WIPHY | \ NL80211_FLAG_NEED_RTNL) \ @@ -15331,14 +15532,31 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, NL80211_FLAG_NEED_RTNL) \ SELECTOR(__sel, NETDEV_UP, \ NL80211_FLAG_NEED_NETDEV_UP) \ + SELECTOR(__sel, NETDEV_UP_LINK, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_MLO_VALID_LINK_ID) \ + SELECTOR(__sel, NETDEV_UP_NO_MLO, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_MLO_UNSUPPORTED) \ + SELECTOR(__sel, NETDEV_UP_NO_MLO_CLEAR, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_CLEAR_SKB | \ + NL80211_FLAG_MLO_UNSUPPORTED) \ SELECTOR(__sel, NETDEV_UP_NOTMX, \ NL80211_FLAG_NEED_NETDEV_UP | \ NL80211_FLAG_NO_WIPHY_MTX) \ + SELECTOR(__sel, NETDEV_UP_NOTMX_NOMLO, \ + NL80211_FLAG_NEED_NETDEV_UP | \ + NL80211_FLAG_NO_WIPHY_MTX | \ + NL80211_FLAG_MLO_UNSUPPORTED) \ SELECTOR(__sel, NETDEV_UP_CLEAR, \ NL80211_FLAG_NEED_NETDEV_UP | \ NL80211_FLAG_CLEAR_SKB) \ SELECTOR(__sel, WDEV_UP, \ NL80211_FLAG_NEED_WDEV_UP) \ + SELECTOR(__sel, WDEV_UP_LINK, \ + NL80211_FLAG_NEED_WDEV_UP | \ + NL80211_FLAG_MLO_VALID_LINK_ID) \ SELECTOR(__sel, WDEV_UP_RTNL, \ NL80211_FLAG_NEED_WDEV_UP | \ NL80211_FLAG_NEED_RTNL) \ @@ -15362,9 +15580,10 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = NULL; - struct wireless_dev *wdev; - struct net_device *dev; + struct wireless_dev *wdev = NULL; + struct net_device *dev = NULL; u32 internal_flags; + int err; if (WARN_ON(ops->internal_flags >= ARRAY_SIZE(nl80211_internal_flags))) return -EINVAL; @@ -15375,8 +15594,8 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, if (internal_flags & NL80211_FLAG_NEED_WIPHY) { rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); if (IS_ERR(rdev)) { - rtnl_unlock(); - return PTR_ERR(rdev); + err = PTR_ERR(rdev); + goto out_unlock; } info->user_ptr[0] = rdev; } else if (internal_flags & NL80211_FLAG_NEED_NETDEV || @@ -15384,17 +15603,18 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, wdev = __cfg80211_wdev_from_attrs(NULL, genl_info_net(info), info->attrs); if (IS_ERR(wdev)) { - rtnl_unlock(); - return PTR_ERR(wdev); + err = PTR_ERR(wdev); + goto out_unlock; } dev = wdev->netdev; + dev_hold(dev); rdev = wiphy_to_rdev(wdev->wiphy); if (internal_flags & NL80211_FLAG_NEED_NETDEV) { if (!dev) { - rtnl_unlock(); - return -EINVAL; + err = -EINVAL; + goto out_unlock; } info->user_ptr[1] = dev; @@ -15404,14 +15624,44 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, if (internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && !wdev_running(wdev)) { - rtnl_unlock(); - return -ENETDOWN; + err = -ENETDOWN; + goto out_unlock; } - dev_hold(dev); info->user_ptr[0] = rdev; } + if (internal_flags & NL80211_FLAG_MLO_VALID_LINK_ID) { + struct nlattr *link_id = info->attrs[NL80211_ATTR_MLO_LINK_ID]; + + if (!wdev) { + err = -EINVAL; + goto out_unlock; + } + + /* MLO -> require valid link ID */ + if (wdev->valid_links && + (!link_id || + !(wdev->valid_links & BIT(nla_get_u16(link_id))))) { + err = -EINVAL; + goto out_unlock; + } + + /* non-MLO -> no link ID attribute accepted */ + if (!wdev->valid_links && link_id) { + err = -EINVAL; + goto out_unlock; + } + } + + if (internal_flags & NL80211_FLAG_MLO_UNSUPPORTED) { + if (info->attrs[NL80211_ATTR_MLO_LINK_ID] || + (wdev && wdev->valid_links)) { + err = -EINVAL; + goto out_unlock; + } + } + if (rdev && !(internal_flags & NL80211_FLAG_NO_WIPHY_MTX)) { wiphy_lock(&rdev->wiphy); /* we keep the mutex locked until post_doit */ @@ -15421,6 +15671,10 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, rtnl_unlock(); return 0; +out_unlock: + rtnl_unlock(); + dev_put(dev); + return err; } static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, @@ -15636,6 +15890,7 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_set_key, .flags = GENL_UNS_ADMIN_PERM, + /* cannot use NL80211_FLAG_MLO_VALID_LINK_ID, depends on key */ .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_CLEAR_SKB), }, @@ -15659,21 +15914,24 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .flags = GENL_UNS_ADMIN_PERM, .doit = nl80211_set_beacon, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_START_AP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .flags = GENL_UNS_ADMIN_PERM, .doit = nl80211_start_ap, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_STOP_AP, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .flags = GENL_UNS_ADMIN_PERM, .doit = nl80211_stop_ap, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_GET_STATION, @@ -15939,7 +16197,9 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_remain_on_channel, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP), + /* FIXME: requiring a link ID here is probably not good */ + .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, @@ -15953,7 +16213,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_set_tx_bitrate_mask, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_REGISTER_FRAME, @@ -16002,7 +16263,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_set_channel, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_JOIN_MESH, @@ -16163,7 +16425,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_set_mac_acl, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_UNSUPPORTED), }, { .cmd = NL80211_CMD_RADAR_DETECT, @@ -16171,7 +16434,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .doit = nl80211_start_radar_detection, .flags = GENL_UNS_ADMIN_PERM, .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | - NL80211_FLAG_NO_WIPHY_MTX), + NL80211_FLAG_NO_WIPHY_MTX | + NL80211_FLAG_MLO_UNSUPPORTED), }, { .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, @@ -16217,7 +16481,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_channel_switch, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_VENDOR, @@ -16240,7 +16505,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_add_tx_ts, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_UNSUPPORTED), }, { .cmd = NL80211_CMD_DEL_TX_TS, @@ -16301,7 +16567,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_get_ftm_responder_stats, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_PEER_MEASUREMENT_START, @@ -16333,7 +16600,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .cmd = NL80211_CMD_SET_TID_CONFIG, .doit = nl80211_set_tid_config, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_SET_SAR_SPECS, @@ -16357,6 +16625,19 @@ static const struct genl_small_ops nl80211_small_ops[] = { .flags = GENL_UNS_ADMIN_PERM, .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), }, + { + .cmd = NL80211_CMD_ADD_LINK, + .doit = nl80211_add_link, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + }, + { + .cmd = NL80211_CMD_REMOVE_LINK, + .doit = nl80211_remove_link, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), + }, }; static struct genl_family nl80211_fam __ro_after_init = { @@ -17984,23 +18265,37 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, } void cfg80211_ch_switch_notify(struct net_device *dev, - struct cfg80211_chan_def *chandef) + struct cfg80211_chan_def *chandef, + unsigned int link_id) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ASSERT_WDEV_LOCK(wdev); + WARN_INVALID_LINK_ID(wdev, link_id); - trace_cfg80211_ch_switch_notify(dev, chandef); - - wdev->chandef = *chandef; - wdev->preset_chandef = *chandef; + trace_cfg80211_ch_switch_notify(dev, chandef, link_id); - if ((wdev->iftype == NL80211_IFTYPE_STATION || - wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && - !WARN_ON(!wdev->current_bss)) - cfg80211_update_assoc_bss_entry(wdev, chandef->chan); + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (!WARN_ON(!wdev->links[link_id].client.current_bss)) + cfg80211_update_assoc_bss_entry(wdev, link_id, + chandef->chan); + break; + case NL80211_IFTYPE_MESH_POINT: + wdev->u.mesh.chandef = *chandef; + wdev->u.mesh.preset_chandef = *chandef; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + wdev->links[link_id].ap.chandef = *chandef; + break; + default: + WARN_ON(1); + break; + } cfg80211_sched_dfs_chan_update(rdev); diff --git a/net/wireless/ocb.c b/net/wireless/ocb.c index 2d26a6d980bf..27a1732264f9 100644 --- a/net/wireless/ocb.c +++ b/net/wireless/ocb.c @@ -4,6 +4,7 @@ * * Copyright: (c) 2014 Czech Technical University in Prague * (c) 2014 Volkswagen Group Research + * Copyright (C) 2022 Intel Corporation * Author: Rostislav Lisovy * Funded by: Volkswagen Group Research */ @@ -34,7 +35,7 @@ int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev, err = rdev_join_ocb(rdev, dev, setup); if (!err) - wdev->chandef = setup->chandef; + wdev->u.ocb.chandef = setup->chandef; return err; } @@ -69,7 +70,7 @@ int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, err = rdev_leave_ocb(rdev, dev); if (!err) - memset(&wdev->chandef, 0, sizeof(wdev->chandef)); + memset(&wdev->u.ocb.chandef, 0, sizeof(wdev->u.ocb.chandef)); return err; } diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 439bcf52369c..d2300eff03ae 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1,4 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * Portions of this file + * Copyright(c) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2018, 2021-2022 Intel Corporation + */ #ifndef __CFG80211_RDEV_OPS #define __CFG80211_RDEV_OPS @@ -172,11 +177,11 @@ static inline int rdev_change_beacon(struct cfg80211_registered_device *rdev, } static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev, - struct net_device *dev) + struct net_device *dev, unsigned int link_id) { int ret; - trace_rdev_stop_ap(&rdev->wiphy, dev); - ret = rdev->ops->stop_ap(&rdev->wiphy, dev); + trace_rdev_stop_ap(&rdev->wiphy, dev, link_id); + ret = rdev->ops->stop_ap(&rdev->wiphy, dev, link_id); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -651,12 +656,14 @@ static inline int rdev_testmode_dump(struct cfg80211_registered_device *rdev, static inline int rdev_set_bitrate_mask(struct cfg80211_registered_device *rdev, - struct net_device *dev, const u8 *peer, + struct net_device *dev, unsigned int link_id, + const u8 *peer, const struct cfg80211_bitrate_mask *mask) { int ret; - trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, peer, mask); - ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, peer, mask); + trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, link_id, peer, mask); + ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, link_id, + peer, mask); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -944,12 +951,13 @@ static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev, static inline int rdev_get_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, + unsigned int link_id, struct cfg80211_chan_def *chandef) { int ret; - trace_rdev_get_channel(&rdev->wiphy, wdev); - ret = rdev->ops->get_channel(&rdev->wiphy, wdev, chandef); + trace_rdev_get_channel(&rdev->wiphy, wdev, link_id); + ret = rdev->ops->get_channel(&rdev->wiphy, wdev, link_id, chandef); trace_rdev_return_chandef(&rdev->wiphy, ret, chandef); return ret; @@ -1107,12 +1115,14 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev, static inline int rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev, - struct net_device *dev, struct cfg80211_chan_def *chandef) + struct net_device *dev, + unsigned int link_id, + struct cfg80211_chan_def *chandef) { int ret; - trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, chandef); - ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, chandef); + trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, link_id, chandef); + ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, link_id, chandef); trace_rdev_return_int(&rdev->wiphy, ret); return ret; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 58e83ce642ad..c7383ede794f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -5,7 +5,7 @@ * Copyright 2008-2011 Luis R. Rodriguez * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2022 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -2370,6 +2370,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); enum nl80211_iftype iftype; bool ret; + int link; wdev_lock(wdev); iftype = wdev->iftype; @@ -2378,62 +2379,83 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) if (!wdev->netdev || !netif_running(wdev->netdev)) goto wdev_inactive_unlock; - switch (iftype) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_MESH_POINT: - if (!wdev->beacon_interval) - goto wdev_inactive_unlock; - chandef = wdev->chandef; - break; - case NL80211_IFTYPE_ADHOC: - if (!wdev->ssid_len) - goto wdev_inactive_unlock; - chandef = wdev->chandef; - break; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - if (!wdev->current_bss || - !wdev->current_bss->pub.channel) - goto wdev_inactive_unlock; - - if (!rdev->ops->get_channel || - rdev_get_channel(rdev, wdev, &chandef)) - cfg80211_chandef_create(&chandef, - wdev->current_bss->pub.channel, - NL80211_CHAN_NO_HT); - break; - case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_P2P_DEVICE: - /* no enforcement required */ - break; - default: - /* others not implemented for now */ - WARN_ON(1); - break; - } + for (link = 0; link < ARRAY_SIZE(wdev->links); link++) { + struct ieee80211_channel *chan; - wdev_unlock(wdev); + if (!wdev->valid_links && link > 0) + break; + if (!(wdev->valid_links & BIT(link))) + continue; + switch (iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: + if (!wdev->u.mesh.beacon_interval) + continue; + chandef = wdev->u.mesh.chandef; + break; + case NL80211_IFTYPE_ADHOC: + if (!wdev->u.ibss.ssid_len) + continue; + chandef = wdev->u.ibss.chandef; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + /* Maybe we could consider disabling that link only? */ + if (!wdev->links[link].client.current_bss) + continue; - switch (iftype) { - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_P2P_GO: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_MESH_POINT: - wiphy_lock(wiphy); - ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype); - wiphy_unlock(wiphy); + chan = wdev->links[link].client.current_bss->pub.channel; + if (!chan) + continue; - return ret; - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - return cfg80211_chandef_usable(wiphy, &chandef, - IEEE80211_CHAN_DISABLED); - default: - break; + if (!rdev->ops->get_channel || + rdev_get_channel(rdev, wdev, link, &chandef)) + cfg80211_chandef_create(&chandef, chan, + NL80211_CHAN_NO_HT); + break; + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_DEVICE: + /* no enforcement required */ + break; + default: + /* others not implemented for now */ + WARN_ON(1); + break; + } + + wdev_unlock(wdev); + + switch (iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + wiphy_lock(wiphy); + ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef, + iftype); + wiphy_unlock(wiphy); + + if (!ret) + return ret; + break; + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + ret = cfg80211_chandef_usable(wiphy, &chandef, + IEEE80211_CHAN_DISABLED); + if (!ret) + return ret; + break; + default: + break; + } + + wdev_lock(wdev); } + wdev_unlock(wdev); + return true; wdev_inactive_unlock: @@ -4215,8 +4237,17 @@ static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev) * In both cases we should end the CAC on the wdev. */ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { - if (wdev->cac_started && - !cfg80211_chandef_dfs_usable(&rdev->wiphy, &wdev->chandef)) + struct cfg80211_chan_def *chandef; + + if (!wdev->cac_started) + continue; + + /* FIXME: radar detection is tied to link 0 for now */ + chandef = wdev_chandef(wdev, 0); + if (!chandef) + continue; + + if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef)) rdev_end_cac(rdev, wdev->netdev); } } diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 6d82bd9eaf8c..0134e5d5c81a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -5,7 +5,7 @@ * Copyright 2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -2617,7 +2617,8 @@ void cfg80211_bss_iter(struct wiphy *wiphy, spin_lock_bh(&rdev->bss_lock); list_for_each_entry(bss, &rdev->bss_list, list) { - if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel)) + if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel, + false)) iter(wiphy, &bss->pub, iter_data); } @@ -2626,11 +2627,12 @@ void cfg80211_bss_iter(struct wiphy *wiphy, EXPORT_SYMBOL(cfg80211_bss_iter); void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, + unsigned int link_id, struct ieee80211_channel *chan) { struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - struct cfg80211_internal_bss *cbss = wdev->current_bss; + struct cfg80211_internal_bss *cbss = wdev->links[link_id].client.current_bss; struct cfg80211_internal_bss *new = NULL; struct cfg80211_internal_bss *bss; struct cfg80211_bss *nontrans_bss; diff --git a/net/wireless/sme.c b/net/wireless/sme.c index ff4d48fcbfb2..35602201057b 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -5,7 +5,7 @@ * (for nl80211's connect() and wext) * * Copyright 2009 Johannes Berg - * Copyright (C) 2009, 2020 Intel Corporation. All rights reserved. + * Copyright (C) 2009, 2020, 2022 Intel Corporation. All rights reserved. * Copyright 2017 Intel Deutschland GmbH */ @@ -454,6 +454,20 @@ void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev) schedule_work(&rdev->conn_work); } +static void cfg80211_wdev_release_bsses(struct wireless_dev *wdev) +{ + unsigned int link; + + for_each_valid_link(wdev, link) { + if (!wdev->links[link].client.current_bss) + continue; + cfg80211_unhold_bss(wdev->links[link].client.current_bss); + cfg80211_put_bss(wdev->wiphy, + &wdev->links[link].client.current_bss->pub); + wdev->links[link].client.current_bss = NULL; + } +} + static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev, const u8 *ies, size_t ies_len, const u8 **out_ies, size_t *out_ies_len) @@ -521,12 +535,11 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, if (!rdev->ops->auth || !rdev->ops->assoc) return -EOPNOTSUPP; - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - wdev->current_bss = NULL; + cfg80211_wdev_release_bsses(wdev); + if (wdev->connected) { cfg80211_sme_free(wdev); + wdev->connected = false; } if (wdev->conn) @@ -563,8 +576,8 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev, wdev->conn->auto_auth = false; } - wdev->conn->params.ssid = wdev->ssid; - wdev->conn->params.ssid_len = wdev->ssid_len; + wdev->conn->params.ssid = wdev->u.client.ssid; + wdev->conn->params.ssid_len = wdev->u.client.ssid_len; /* see if we have the bss already */ bss = cfg80211_get_conn_bss(wdev); @@ -648,7 +661,7 @@ static bool cfg80211_is_all_idle(void) list_for_each_entry(rdev, &cfg80211_rdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { wdev_lock(wdev); - if (wdev->conn || wdev->current_bss || + if (wdev->conn || wdev->connected || cfg80211_beaconing_iface_active(wdev)) is_all_idle = false; wdev_unlock(wdev); @@ -668,7 +681,6 @@ static void disconnect_work(struct work_struct *work) DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); - /* * API calls for drivers implementing connect/disconnect and * SME event handling @@ -729,23 +741,19 @@ void __cfg80211_connect_result(struct net_device *dev, if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) { WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid, - wdev->ssid, wdev->ssid_len, + wdev->u.client.ssid, wdev->u.client.ssid_len, wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); if (cr->bss) cfg80211_hold_bss(bss_from_pub(cr->bss)); } - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - wdev->current_bss = NULL; - } + cfg80211_wdev_release_bsses(wdev); if (cr->status != WLAN_STATUS_SUCCESS) { kfree_sensitive(wdev->connect_keys); wdev->connect_keys = NULL; - wdev->ssid_len = 0; + wdev->u.client.ssid_len = 0; wdev->conn_owner_nlportid = 0; if (cr->bss) { cfg80211_unhold_bss(bss_from_pub(cr->bss)); @@ -758,7 +766,9 @@ void __cfg80211_connect_result(struct net_device *dev, if (WARN_ON(!cr->bss)) return; - wdev->current_bss = bss_from_pub(cr->bss); + wdev->links[0].client.current_bss = bss_from_pub(cr->bss); + wdev->connected = true; + ether_addr_copy(wdev->u.client.connected_addr, cr->bss->bssid); if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) cfg80211_upload_connect_keys(wdev); @@ -801,7 +811,7 @@ void cfg80211_connect_done(struct net_device *dev, found = cfg80211_get_bss(wdev->wiphy, NULL, params->bss->bssid, - wdev->ssid, wdev->ssid_len, + wdev->u.client.ssid, wdev->u.client.ssid_len, wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); if (found) { @@ -906,18 +916,17 @@ void __cfg80211_roamed(struct wireless_dev *wdev, wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) goto out; - if (WARN_ON(!wdev->current_bss)) + if (WARN_ON(!wdev->connected)) goto out; - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - wdev->current_bss = NULL; + cfg80211_wdev_release_bsses(wdev); if (WARN_ON(!info->bss)) return; cfg80211_hold_bss(bss_from_pub(info->bss)); - wdev->current_bss = bss_from_pub(info->bss); + wdev->links[0].client.current_bss = bss_from_pub(info->bss); + ether_addr_copy(wdev->u.client.connected_addr, info->bss->bssid); wdev->unprot_beacon_reported = 0; nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy), @@ -963,8 +972,8 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, if (!info->bss) { info->bss = cfg80211_get_bss(wdev->wiphy, info->channel, - info->bssid, wdev->ssid, - wdev->ssid_len, + info->bssid, wdev->u.client.ssid, + wdev->u.client.ssid_len, wdev->conn_bss_type, IEEE80211_PRIVACY_ANY); } @@ -1034,8 +1043,8 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return; - if (WARN_ON(!wdev->current_bss) || - WARN_ON(!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) + if (WARN_ON(!wdev->connected) || + WARN_ON(!ether_addr_equal(wdev->u.client.connected_addr, bssid))) return; nl80211_send_port_authorized(wiphy_to_rdev(wdev->wiphy), wdev->netdev, @@ -1087,13 +1096,9 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) return; - if (wdev->current_bss) { - cfg80211_unhold_bss(wdev->current_bss); - cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); - } - - wdev->current_bss = NULL; - wdev->ssid_len = 0; + cfg80211_wdev_release_bsses(wdev); + wdev->connected = false; + wdev->u.client.ssid_len = 0; wdev->conn_owner_nlportid = 0; kfree_sensitive(wdev->connect_keys); wdev->connect_keys = NULL; @@ -1182,19 +1187,20 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, * already connected, so reject a new SSID unless it's the * same (which is the case for re-association.) */ - if (wdev->ssid_len && - (wdev->ssid_len != connect->ssid_len || - memcmp(wdev->ssid, connect->ssid, wdev->ssid_len))) + if (wdev->u.client.ssid_len && + (wdev->u.client.ssid_len != connect->ssid_len || + memcmp(wdev->u.client.ssid, connect->ssid, wdev->u.client.ssid_len))) return -EALREADY; /* * If connected, reject (re-)association unless prev_bssid * matches the current BSSID. */ - if (wdev->current_bss) { + if (wdev->connected) { if (!prev_bssid) return -EALREADY; - if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid)) + if (!ether_addr_equal(prev_bssid, + wdev->u.client.connected_addr)) return -ENOTCONN; } @@ -1245,8 +1251,8 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, } wdev->connect_keys = connkeys; - memcpy(wdev->ssid, connect->ssid, connect->ssid_len); - wdev->ssid_len = connect->ssid_len; + memcpy(wdev->u.client.ssid, connect->ssid, connect->ssid_len); + wdev->u.client.ssid_len = connect->ssid_len; wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS : IEEE80211_BSS_TYPE_ESS; @@ -1262,8 +1268,8 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, * This could be reassoc getting refused, don't clear * ssid_len in that case. */ - if (!wdev->current_bss) - wdev->ssid_len = 0; + if (!wdev->connected) + wdev->u.client.ssid_len = 0; return err; } @@ -1287,7 +1293,7 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, err = cfg80211_sme_disconnect(wdev, reason); else if (!rdev->ops->disconnect) cfg80211_mlme_down(rdev, dev); - else if (wdev->ssid_len) + else if (wdev->u.client.ssid_len) err = rdev_disconnect(rdev, dev, reason); /* @@ -1295,8 +1301,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, * in which case cfg80211_disconnected() will take care of * this later. */ - if (!wdev->current_bss) - wdev->ssid_len = 0; + if (!wdev->connected) + wdev->u.client.ssid_len = 0; return err; } @@ -1320,7 +1326,7 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - __cfg80211_stop_ap(rdev, wdev->netdev, false); + __cfg80211_stop_ap(rdev, wdev->netdev, -1, false); break; case NL80211_IFTYPE_MESH_POINT: __cfg80211_leave_mesh(rdev, wdev->netdev); @@ -1332,7 +1338,7 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) * ops->disconnect not implemented. Otherwise we can * use cfg80211_disconnect. */ - if (rdev->ops->disconnect || wdev->current_bss) + if (rdev->ops->disconnect || wdev->connected) cfg80211_disconnect(rdev, wdev->netdev, WLAN_REASON_DEAUTH_LEAVING, true); diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 228079d7690a..3b2c956b8d78 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -569,6 +569,7 @@ TRACE_EVENT(rdev_start_ap, __field(bool, privacy) __field(enum nl80211_auth_type, auth_type) __field(int, inactivity_timeout) + __field(unsigned int, link_id) ), TP_fast_assign( WIPHY_ASSIGN; @@ -583,16 +584,17 @@ TRACE_EVENT(rdev_start_ap, __entry->inactivity_timeout = settings->inactivity_timeout; memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); memcpy(__entry->ssid, settings->ssid, settings->ssid_len); + __entry->link_id = settings->beacon.link_id; ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", AP settings - ssid: %s, " CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, " "hidden ssid: %d, wpa versions: %u, privacy: %s, " - "auth type: %d, inactivity timeout: %d", + "auth type: %d, inactivity timeout: %d, link_id: %d", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG, __entry->beacon_interval, __entry->dtim_period, __entry->hidden_ssid, __entry->wpa_ver, BOOL_TO_STR(__entry->privacy), __entry->auth_type, - __entry->inactivity_timeout) + __entry->inactivity_timeout, __entry->link_id) ); TRACE_EVENT(rdev_change_beacon, @@ -602,6 +604,7 @@ TRACE_EVENT(rdev_change_beacon, TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY + __field(int, link_id) __dynamic_array(u8, head, info ? info->head_len : 0) __dynamic_array(u8, tail, info ? info->tail_len : 0) __dynamic_array(u8, beacon_ies, info ? info->beacon_ies_len : 0) @@ -615,6 +618,7 @@ TRACE_EVENT(rdev_change_beacon, WIPHY_ASSIGN; NETDEV_ASSIGN; if (info) { + __entry->link_id = info->link_id; if (info->head) memcpy(__get_dynamic_array(head), info->head, info->head_len); @@ -635,9 +639,30 @@ TRACE_EVENT(rdev_change_beacon, if (info->probe_resp) memcpy(__get_dynamic_array(probe_resp), info->probe_resp, info->probe_resp_len); + } else { + __entry->link_id = -1; } ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id:%d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id) +); + +TRACE_EVENT(rdev_stop_ap, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + unsigned int link_id), + TP_ARGS(wiphy, netdev, link_id), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(unsigned int, link_id) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->link_id = link_id; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %d", + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id) ); DECLARE_EVENT_CLASS(wiphy_netdev_evt, @@ -654,11 +679,6 @@ DECLARE_EVENT_CLASS(wiphy_netdev_evt, TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) ); -DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap, - TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), - TP_ARGS(wiphy, netdev) -); - DEFINE_EVENT(wiphy_netdev_evt, rdev_set_rekey_data, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), TP_ARGS(wiphy, netdev) @@ -1619,20 +1639,24 @@ TRACE_EVENT(rdev_testmode_dump, TRACE_EVENT(rdev_set_bitrate_mask, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + unsigned int link_id, const u8 *peer, const struct cfg80211_bitrate_mask *mask), - TP_ARGS(wiphy, netdev, peer, mask), + TP_ARGS(wiphy, netdev, link_id, peer, mask), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY + __field(unsigned int, link_id) MAC_ENTRY(peer) ), TP_fast_assign( WIPHY_ASSIGN; NETDEV_ASSIGN; + __entry->link_id = link_id; MAC_ASSIGN(peer, peer); ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT, - WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %d, peer: " MAC_PR_FMT, + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id, + MAC_PR_ARG(peer)) ); TRACE_EVENT(rdev_update_mgmt_frame_registrations, @@ -2040,9 +2064,22 @@ TRACE_EVENT(rdev_set_noack_map, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) ); -DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, - TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), - TP_ARGS(wiphy, wdev) +TRACE_EVENT(rdev_get_channel, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id), + TP_ARGS(wiphy, wdev, link_id), + TP_STRUCT__entry( + WIPHY_ENTRY + WDEV_ENTRY + __field(unsigned int, link_id) + ), + TP_fast_assign( + WIPHY_ASSIGN; + WDEV_ASSIGN; + __entry->link_id = link_id; + ), + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %u", + WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id) ); TRACE_EVENT(rdev_return_chandef, @@ -2296,20 +2333,24 @@ TRACE_EVENT(rdev_set_qos_map, TRACE_EVENT(rdev_set_ap_chanwidth, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + unsigned int link_id, struct cfg80211_chan_def *chandef), - TP_ARGS(wiphy, netdev, chandef), + TP_ARGS(wiphy, netdev, link_id, chandef), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY CHAN_DEF_ENTRY + __field(unsigned int, link_id) ), TP_fast_assign( WIPHY_ASSIGN; NETDEV_ASSIGN; CHAN_DEF_ASSIGN(chandef); + __entry->link_id = link_id; ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, - WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG) + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d", + WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG, + __entry->link_id) ); TRACE_EVENT(rdev_add_tx_ts, @@ -3022,18 +3063,21 @@ TRACE_EVENT(cfg80211_chandef_dfs_required, TRACE_EVENT(cfg80211_ch_switch_notify, TP_PROTO(struct net_device *netdev, - struct cfg80211_chan_def *chandef), - TP_ARGS(netdev, chandef), + struct cfg80211_chan_def *chandef, + unsigned int link_id), + TP_ARGS(netdev, chandef, link_id), TP_STRUCT__entry( NETDEV_ENTRY CHAN_DEF_ENTRY + __field(unsigned int, link_id) ), TP_fast_assign( NETDEV_ASSIGN; CHAN_DEF_ASSIGN(chandef); + __entry->link_id = link_id; ), - TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, - NETDEV_PR_ARG, CHAN_DEF_PR_ARG) + TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d", + NETDEV_PR_ARG, CHAN_DEF_PR_ARG, __entry->link_id) ); TRACE_EVENT(cfg80211_ch_switch_started_notify, diff --git a/net/wireless/util.c b/net/wireless/util.c index a60d7d638e72..b7257862e0fe 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -5,7 +5,7 @@ * Copyright 2007-2009 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -1041,7 +1041,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return -EBUSY; dev->ieee80211_ptr->use_4addr = false; - dev->ieee80211_ptr->mesh_id_up_len = 0; wdev_lock(dev->ieee80211_ptr); rdev_set_qos_map(rdev, dev, NULL); wdev_unlock(dev->ieee80211_ptr); @@ -1049,7 +1048,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, switch (otype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - cfg80211_stop_ap(rdev, dev, true); + cfg80211_stop_ap(rdev, dev, -1, true); break; case NL80211_IFTYPE_ADHOC: cfg80211_leave_ibss(rdev, dev, false); @@ -1073,6 +1072,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, cfg80211_process_rdev_events(rdev); cfg80211_mlme_purge_registrations(dev->ieee80211_ptr); + + memset(&dev->ieee80211_ptr->u, 0, + sizeof(dev->ieee80211_ptr->u)); + memset(&dev->ieee80211_ptr->links, 0, + sizeof(dev->ieee80211_ptr->links)); } err = rdev_change_virtual_intf(rdev, dev, ntype, params); @@ -1930,6 +1934,24 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef, } EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); +static int cfg80211_wdev_bi(struct wireless_dev *wdev) +{ + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + WARN_ON(wdev->valid_links); + return wdev->links[0].ap.beacon_interval; + case NL80211_IFTYPE_MESH_POINT: + return wdev->u.mesh.beacon_interval; + case NL80211_IFTYPE_ADHOC: + return wdev->u.ibss.beacon_interval; + default: + break; + } + + return 0; +} + static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, u32 *beacon_int_gcd, bool *beacon_int_different) @@ -1940,19 +1962,27 @@ static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, *beacon_int_different = false; list_for_each_entry(wdev, &wiphy->wdev_list, list) { - if (!wdev->beacon_interval) + int wdev_bi; + + /* this feature isn't supported with MLO */ + if (wdev->valid_links) + continue; + + wdev_bi = cfg80211_wdev_bi(wdev); + + if (!wdev_bi) continue; if (!*beacon_int_gcd) { - *beacon_int_gcd = wdev->beacon_interval; + *beacon_int_gcd = wdev_bi; continue; } - if (wdev->beacon_interval == *beacon_int_gcd) + if (wdev_bi == *beacon_int_gcd) continue; *beacon_int_different = true; - *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval); + *beacon_int_gcd = gcd(*beacon_int_gcd, wdev_bi); } if (new_beacon_int && *beacon_int_gcd != new_beacon_int) { diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index a32065d600a1..a9767bfe7330 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -7,7 +7,7 @@ * we directly assign the wireless handlers of wireless interfaces. * * Copyright 2008-2009 Johannes Berg - * Copyright (C) 2019-2021 Intel Corporation + * Copyright (C) 2019-2022 Intel Corporation */ #include @@ -415,6 +415,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, int err, i; bool rejoin = false; + if (wdev->valid_links) + return -EINVAL; + if (pairwise && !addr) return -EINVAL; @@ -437,7 +440,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, return -EOPNOTSUPP; if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { - if (!wdev->current_bss) + if (!wdev->connected) return -ENOLINK; if (!rdev->ops->set_default_mgmt_key) @@ -450,7 +453,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if (remove) { err = 0; - if (wdev->current_bss) { + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) { /* * If removing the current TX key, we will need to * join a new IBSS without the privacy bit clear. @@ -501,7 +506,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, return -EINVAL; err = 0; - if (wdev->current_bss) + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) err = rdev_add_key(rdev, dev, idx, pairwise, addr, params); else if (params->cipher != WLAN_CIPHER_SUITE_WEP40 && params->cipher != WLAN_CIPHER_SUITE_WEP104) @@ -526,7 +533,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || params->cipher == WLAN_CIPHER_SUITE_WEP104) && (tx_key || (!addr && wdev->wext.default_key == -1))) { - if (wdev->current_bss) { + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) { /* * If we are getting a new TX key from not having * had one before we need to join a new IBSS with @@ -549,7 +558,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { - if (wdev->current_bss) + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) err = rdev_set_default_mgmt_key(rdev, dev, idx); if (!err) wdev->wext.default_mgmt_key = idx; @@ -595,6 +606,11 @@ static int cfg80211_wext_siwencode(struct net_device *dev, return -EOPNOTSUPP; wiphy_lock(&rdev->wiphy); + if (wdev->valid_links) { + err = -EOPNOTSUPP; + goto out; + } + idx = erq->flags & IW_ENCODE_INDEX; if (idx == 0) { idx = wdev->wext.default_key; @@ -613,7 +629,9 @@ static int cfg80211_wext_siwencode(struct net_device *dev, /* No key data - just set the default TX key index */ err = 0; wdev_lock(wdev); - if (wdev->current_bss) + if (wdev->connected || + (wdev->iftype == NL80211_IFTYPE_ADHOC && + wdev->u.ibss.current_bss)) err = rdev_set_default_key(rdev, dev, idx, true, true); if (!err) @@ -865,7 +883,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, break; } - ret = rdev_get_channel(rdev, wdev, &chandef); + ret = rdev_get_channel(rdev, wdev, 0, &chandef); if (ret) break; freq->m = chandef.chan->center_freq; @@ -1270,7 +1288,10 @@ static int cfg80211_wext_siwrate(struct net_device *dev, return -EINVAL; wiphy_lock(&rdev->wiphy); - ret = rdev_set_bitrate_mask(rdev, dev, NULL, &mask); + if (dev->ieee80211_ptr->valid_links) + ret = -EOPNOTSUPP; + else + ret = rdev_set_bitrate_mask(rdev, dev, 0, NULL, &mask); wiphy_unlock(&rdev->wiphy); return ret; @@ -1294,8 +1315,9 @@ static int cfg80211_wext_giwrate(struct net_device *dev, err = 0; wdev_lock(wdev); - if (wdev->current_bss) - memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN); + if (!wdev->valid_links && wdev->links[0].client.current_bss) + memcpy(addr, wdev->links[0].client.current_bss->pub.bssid, + ETH_ALEN); else err = -EOPNOTSUPP; wdev_unlock(wdev); @@ -1339,11 +1361,11 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) /* Grab BSSID of current BSS, if any */ wdev_lock(wdev); - if (!wdev->current_bss) { + if (wdev->valid_links || !wdev->links[0].client.current_bss) { wdev_unlock(wdev); return NULL; } - memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); + memcpy(bssid, wdev->links[0].client.current_bss->pub.bssid, ETH_ALEN); wdev_unlock(wdev); memset(&sinfo, 0, sizeof(sinfo)); diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index cd09a9042261..68f45afc352d 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -3,7 +3,7 @@ * cfg80211 wext compat for managed mode. * * Copyright 2009 Johannes Berg - * Copyright (C) 2009, 2020-2021 Intel Corporation. + * Copyright (C) 2009, 2020-2022 Intel Corporation */ #include @@ -124,9 +124,12 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; + if (wdev->valid_links) + return -EOPNOTSUPP; + wdev_lock(wdev); - if (wdev->current_bss) - chan = wdev->current_bss->pub.channel; + if (wdev->links[0].client.current_bss) + chan = wdev->links[0].client.current_bss->pub.channel; else if (wdev->wext.connect.channel) chan = wdev->wext.connect.channel; wdev_unlock(wdev); @@ -208,15 +211,19 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; + if (wdev->valid_links) + return -EINVAL; + data->flags = 0; wdev_lock(wdev); - if (wdev->current_bss) { + if (wdev->links[0].client.current_bss) { const struct element *ssid_elem; rcu_read_lock(); - ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub, - WLAN_EID_SSID); + ssid_elem = ieee80211_bss_get_elem( + &wdev->links[0].client.current_bss->pub, + WLAN_EID_SSID); if (ssid_elem) { data->flags = 1; data->length = ssid_elem->datalen; @@ -300,8 +307,14 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, ap_addr->sa_family = ARPHRD_ETHER; wdev_lock(wdev); - if (wdev->current_bss) - memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); + if (wdev->valid_links) { + wdev_unlock(wdev); + return -EOPNOTSUPP; + } + if (wdev->links[0].client.current_bss) + memcpy(ap_addr->sa_data, + wdev->links[0].client.current_bss->pub.bssid, + ETH_ALEN); else eth_zero_addr(ap_addr->sa_data); wdev_unlock(wdev); -- cgit v1.2.3 From d0a9123ef548def5c8880e83e5df948eb5b55c62 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 May 2022 13:26:44 +0200 Subject: wifi: mac80211: move some future per-link data to bss_conf To add MLD, reuse the bss_conf structure later for per-link information, so move some things into it that are per link. Most transformations were done with the following spatch: @@ expression sdata; identifier var = { chanctx_conf, mu_mimo_owner, csa_active, color_change_active, color_change_color }; @@ -sdata->vif.var +sdata->vif.bss_conf.var @@ struct ieee80211_vif *vif; identifier var = { chanctx_conf, mu_mimo_owner, csa_active, color_change_active, color_change_color }; @@ -vif->var +vif->bss_conf.var Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 8 ++--- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 12 +++---- drivers/net/wireless/ath/ath11k/wmi.c | 4 +-- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 6 ++-- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 4 +-- .../net/wireless/intel/iwlwifi/mvm/ftm-responder.c | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 10 +++--- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +++--- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 4 +-- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 4 +-- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 +- drivers/net/wireless/mac80211_hwsim.c | 22 +++++++----- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 +-- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 10 +++--- drivers/net/wireless/ti/wlcore/main.c | 2 +- include/net/mac80211.h | 40 ++++++++++----------- net/mac80211/airtime.c | 4 +-- net/mac80211/cfg.c | 40 ++++++++++----------- net/mac80211/chan.c | 39 ++++++++++---------- net/mac80211/driver-ops.h | 2 +- net/mac80211/ethtool.c | 4 +-- net/mac80211/ibss.c | 10 +++--- net/mac80211/ieee80211_i.h | 6 ++-- net/mac80211/iface.c | 8 ++--- net/mac80211/main.c | 4 +-- net/mac80211/mesh.c | 14 ++++---- net/mac80211/mlme.c | 42 +++++++++++----------- net/mac80211/ocb.c | 3 +- net/mac80211/offchannel.c | 6 ++-- net/mac80211/rate.c | 5 +-- net/mac80211/rx.c | 2 +- net/mac80211/sta_info.c | 2 +- net/mac80211/tdls.c | 6 ++-- net/mac80211/tx.c | 28 +++++++-------- net/mac80211/util.c | 16 ++++----- net/mac80211/vht.c | 6 ++-- 45 files changed, 209 insertions(+), 202 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index b8461501221a..8a075a711b71 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -3840,7 +3840,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, switch (txrate.flags) { case WMI_RATE_PREAMBLE_OFDM: if (arsta->arvif && arsta->arvif->vif) - conf = rcu_dereference(arsta->arvif->vif->chanctx_conf); + conf = rcu_dereference(arsta->arvif->vif->bss_conf.chanctx_conf); if (conf && conf->def.chan->band == NL80211_BAND_5GHZ) arsta->tx_info.status.rates[0].idx = rate_idx - 4; break; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a04e18250dae..42c657b8b73e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -659,7 +659,7 @@ int ath10k_mac_vif_chan(struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *conf; rcu_read_lock(); - conf = rcu_dereference(vif->chanctx_conf); + conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (!conf) { rcu_read_unlock(); return -ENOENT; @@ -2028,7 +2028,7 @@ static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif) if (arvif->vdev_type != WMI_VDEV_TYPE_AP) return; - if (!vif->csa_active) + if (!vif->bss_conf.csa_active) return; if (!arvif->is_up) @@ -8832,7 +8832,7 @@ ath10k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, { struct ath10k_mac_change_chanctx_arg *arg = data; - if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx) + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != arg->ctx) return; arg->n_vifs++; @@ -8845,7 +8845,7 @@ ath10k_mac_change_chanctx_fill_iter(void *data, u8 *mac, struct ath10k_mac_change_chanctx_arg *arg = data; struct ieee80211_chanctx_conf *ctx; - ctx = rcu_access_pointer(vif->chanctx_conf); + ctx = rcu_access_pointer(vif->bss_conf.chanctx_conf); if (ctx != arg->ctx) return; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 7efbe03fbca8..876410a47d1d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -205,7 +205,7 @@ static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar, } arvif = ath10k_get_arvif(ar, vdev_id); - if (arvif && arvif->is_up && arvif->vif->csa_active) + if (arvif && arvif->is_up && arvif->vif->bss_conf.csa_active) ieee80211_queue_work(ar->hw, &arvif->ap_csa_work); kfree(tb); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index cd438f76f284..af19cab24c76 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3882,7 +3882,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) * Once CSA counter is completed stop sending beacons until * actual channel switch is done */ - if (arvif->vif->csa_active && + if (arvif->vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(arvif->vif)) { ieee80211_csa_finish(arvif->vif); continue; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 42d2e8cf8125..f28e7feca318 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -505,7 +505,7 @@ static int ath11k_mac_vif_chan(struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *conf; rcu_read_lock(); - conf = rcu_dereference(vif->chanctx_conf); + conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (!conf) { rcu_read_unlock(); return -ENOENT; @@ -1398,10 +1398,10 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) { struct ieee80211_vif *vif = arvif->vif; - if (!vif->color_change_active && !arvif->bcca_zero_sent) + if (!vif->bss_conf.color_change_active && !arvif->bcca_zero_sent) return; - if (vif->color_change_active && ieee80211_beacon_cntdwn_is_complete(vif)) { + if (vif->bss_conf.color_change_active && ieee80211_beacon_cntdwn_is_complete(vif)) { arvif->bcca_zero_sent = true; ieee80211_color_change_finish(vif); return; @@ -1409,7 +1409,7 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) arvif->bcca_zero_sent = false; - if (vif->color_change_active) + if (vif->bss_conf.color_change_active) ieee80211_beacon_update_cntdwn(vif); ath11k_mac_setup_bcn_tmpl(arvif); } @@ -6849,7 +6849,7 @@ ath11k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, { struct ath11k_mac_change_chanctx_arg *arg = data; - if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx) + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != arg->ctx) return; arg->n_vifs++; @@ -6862,7 +6862,7 @@ ath11k_mac_change_chanctx_fill_iter(void *data, u8 *mac, struct ath11k_mac_change_chanctx_arg *arg = data; struct ieee80211_chanctx_conf *ctx; - ctx = rcu_access_pointer(vif->chanctx_conf); + ctx = rcu_access_pointer(vif->bss_conf.chanctx_conf); if (ctx != arg->ctx) return; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index f69918b9452a..f2d5e07dc148 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1700,7 +1700,7 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, cmd->vdev_id = vdev_id; cmd->tim_ie_offset = offs->tim_offset; - if (vif->csa_active) { + if (vif->bss_conf.csa_active) { cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0]; cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1]; } @@ -7475,7 +7475,7 @@ ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab, continue; } - if (arvif->is_up && arvif->vif->csa_active) + if (arvif->is_up && arvif->vif->bss_conf.csa_active) ieee80211_csa_finish(arvif->vif); } rcu_read_unlock(); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 72e2e71aac0e..8b1b966bcef1 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -362,7 +362,7 @@ static void ath9k_set_tsfadjust(struct ath_softc *sc, bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) { - if (!vif || !vif->csa_active) + if (!vif || !vif->bss_conf.csa_active) return false; if (!ieee80211_beacon_cntdwn_is_complete(vif)) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index c745897aa3d6..468bc934d848 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -511,7 +511,7 @@ bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv) struct ieee80211_vif *vif; vif = priv->csa_vif; - if (!vif || !vif->csa_active) + if (!vif || !vif->bss_conf.csa_active) return false; if (!ieee80211_beacon_cntdwn_is_complete(vif)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 9b194cb8d65e..8760f2c73369 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2020 Intel Corporation + * Copyright (C) 2013-2014, 2018-2020, 2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH */ #include @@ -106,7 +106,7 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (!chanctx_conf || chanctx_conf->def.chan->band != NL80211_BAND_2GHZ) { @@ -283,7 +283,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, return; } - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); /* If channel context is invalid or not on 2.4GHz .. */ if ((!chanctx_conf || diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 61f9136a333d..8edc8646a23a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -731,7 +731,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EINVAL; rcu_read_lock(); - ctx = rcu_dereference(vif->chanctx_conf); + ctx = rcu_dereference(vif->bss_conf.chanctx_conf); if (WARN_ON(!ctx)) { rcu_read_unlock(); return -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 7d9faeffd154..78d8b37eb71a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -234,7 +234,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, } rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (chanctx_conf) pos += scnprintf(buf+pos, bufsz-pos, "idle rx chains %d, active rx chains: %d\n", @@ -597,7 +597,7 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, mutex_lock(&mvm->mutex); rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); /* make sure the channel context is assigned */ if (!chanctx_conf) { rcu_read_unlock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 9729680476fd..e862d1b43f21 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -398,7 +398,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } rcu_read_lock(); - pctx = rcu_dereference(vif->chanctx_conf); + pctx = rcu_dereference(vif->bss_conf.chanctx_conf); /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care * about changes in the ctx after releasing the lock because the driver * is still protected by the mutex. */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 56fa20596f16..7756ac0faf3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -481,7 +481,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, eth_broadcast_addr(cmd->bssid_addr); rcu_read_lock(); - chanctx = rcu_dereference(vif->chanctx_conf); + chanctx = rcu_dereference(vif->bss_conf.chanctx_conf); iwl_mvm_ack_rates(mvm, vif, chanctx ? chanctx->def.chan->band : NL80211_BAND_2GHZ, &cck_ack_rates, &ofdm_ack_rates); @@ -934,7 +934,7 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, /* Enable FILS on PSC channels only */ rcu_read_lock(); - ctx = rcu_dereference(vif->chanctx_conf); + ctx = rcu_dereference(vif->bss_conf.chanctx_conf); channel = ieee80211_frequency_to_channel(ctx->def.chan->center_freq); WARN_ON(channel == 0); if (cfg80211_channel_is_psc(ctx->def.chan) && @@ -1335,7 +1335,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, csa_vif = rcu_dereference_protected(mvm->csa_vif, lockdep_is_held(&mvm->mutex)); - if (unlikely(csa_vif && csa_vif->csa_active)) + if (unlikely(csa_vif && csa_vif->bss_conf.csa_active)) iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2, (status == TX_STATUS_SUCCESS)); @@ -1558,7 +1558,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, switch (vif->type) { case NL80211_IFTYPE_AP: csa_vif = rcu_dereference(mvm->csa_vif); - if (WARN_ON(!csa_vif || !csa_vif->csa_active || + if (WARN_ON(!csa_vif || !csa_vif->bss_conf.csa_active || csa_vif != vif)) goto out_unlock; @@ -1587,7 +1587,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, */ if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, CHANNEL_SWITCH_ERROR_NOTIF, - 0) && !vif->csa_active) { + 0) && !vif->bss_conf.csa_active) { IWL_DEBUG_INFO(mvm, "Channel Switch was canceled\n"); iwl_mvm_cancel_channel_switch(mvm, vif, mac_id); break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index bb9bd2165355..c5626ff83805 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1768,7 +1768,7 @@ static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm, static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - if (vif->mu_mimo_owner) { + if (vif->bss_conf.mu_mimo_owner) { struct iwl_mu_group_mgmt_notif *notif = _data; /* @@ -1965,7 +1965,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return; @@ -2337,7 +2337,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * However, on HW restart we should restore this data. */ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && - (changes & BSS_CHANGED_MU_GROUPS) && vif->mu_mimo_owner) { + (changes & BSS_CHANGED_MU_GROUPS) && vif->bss_conf.mu_mimo_owner) { ret = iwl_mvm_update_mu_groups(mvm, vif); if (ret) IWL_ERR(mvm, @@ -4004,7 +4004,7 @@ static void iwl_mvm_ftm_responder_chanctx_iter(void *_data, u8 *mac, { struct iwl_mvm_ftm_responder_iter_data *data = _data; - if (rcu_access_pointer(vif->chanctx_conf) == data->ctx && + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) == data->ctx && vif->type == NL80211_IFTYPE_AP && vif->bss_conf.ftmr_params) data->responder = true; } @@ -4631,7 +4631,7 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, csa_vif = rcu_dereference_protected(mvm->csa_vif, lockdep_is_held(&mvm->mutex)); - if (WARN_ONCE(csa_vif && csa_vif->csa_active, + if (WARN_ONCE(csa_vif && csa_vif->bss_conf.csa_active, "Another CSA is already in progress")) { ret = -EBUSY; goto out_unlock; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index b9bd81242b21..afdf3bb523e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -283,7 +283,7 @@ static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) bool radar_detect = false; rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); WARN_ON(!chanctx_conf); if (chanctx_conf) { chan = chanctx_conf->def.chan; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 974eeecc9153..303975f9e2b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1980,7 +1980,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm, #endif rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) band = NUM_NL80211_BANDS; else diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index bf04326e35ff..674dd137fb9f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2020, 2022 Intel Corporation */ #include #include "mvm.h" @@ -380,7 +380,7 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, type == TDLS_MOVE_CH) { /* we need to return to base channel */ struct ieee80211_chanctx_conf *chanctx = - rcu_dereference(vif->chanctx_conf); + rcu_dereference(vif->bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx)) { rcu_read_unlock(); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 6edf2b79db43..4f0794a45bf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -123,7 +123,7 @@ static void iwl_mvm_csa_noa_start(struct iwl_mvm *mvm) rcu_read_lock(); csa_vif = rcu_dereference(mvm->csa_vif); - if (!csa_vif || !csa_vif->csa_active) + if (!csa_vif || !csa_vif->bss_conf.csa_active) goto out_unlock; IWL_DEBUG_TE(mvm, "CSA NOA started\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 8125bb76f59e..f9e08b339e0c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1959,7 +1959,7 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid, if (mvmsta->vif) chanctx_conf = - rcu_dereference(mvmsta->vif->chanctx_conf); + rcu_dereference(mvmsta->vif->bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) goto out; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bd408d260e9c..5905803893b8 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -888,7 +888,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) rcu_read_lock(); mac80211_hwsim_tx_frame(data->hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); rcu_read_unlock(); } @@ -921,7 +921,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, rcu_read_lock(); mac80211_hwsim_tx_frame(data->hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); rcu_read_unlock(); } @@ -1464,11 +1464,11 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, { struct tx_iter_data *data = _data; - if (!vif->chanctx_conf) + if (!vif->bss_conf.chanctx_conf) return; if (!hwsim_chans_compat(data->channel, - rcu_dereference(vif->chanctx_conf)->def.chan)) + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan)) return; data->receive = true; @@ -1686,7 +1686,11 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, } else if (txi->hw_queue == 4) { channel = data->tmp_chan; } else { - chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf); + struct ieee80211_bss_conf *bss_conf; + + bss_conf = &txi->control.vif->bss_conf; + + chanctx_conf = rcu_dereference(bss_conf->chanctx_conf); if (chanctx_conf) { channel = chanctx_conf->def.chan; confbw = chanctx_conf->def.width; @@ -1935,14 +1939,14 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, } mac80211_hwsim_tx_frame(hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); while ((skb = ieee80211_get_buffered_bc(hw, vif)) != NULL) { mac80211_hwsim_tx_frame(hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_dereference(vif->bss_conf.chanctx_conf)->def.chan); } - if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) + if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) ieee80211_csa_finish(vif); } @@ -2204,7 +2208,7 @@ mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *chanctx_conf; rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (!WARN_ON(!chanctx_conf)) confbw = chanctx_conf->def.width; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 18b5de55334c..5f75a8945a6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1459,7 +1459,7 @@ EXPORT_SYMBOL_GPL(mt76_get_sar_power); static void __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) + if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) ieee80211_csa_finish(vif); } @@ -1481,7 +1481,7 @@ __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt76_dev *dev = priv; - if (!vif->csa_active) + if (!vif->bss_conf.csa_active) return; dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 97e2a85cb728..8fb6c9d735dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -363,7 +363,7 @@ out: static void mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->csa_active) + if (vif->bss_conf.csa_active) ieee80211_csa_finish(vif); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b7e2b365356c..1b3d6634a72e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -322,7 +322,7 @@ int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) static void mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->csa_active) + if (vif->bss_conf.csa_active) ieee80211_csa_finish(vif); } @@ -409,7 +409,7 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) static void mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (!vif->color_change_active) + if (!vif->bss_conf.color_change_active) return; ieee80211_color_change_finish(vif); @@ -1818,7 +1818,7 @@ mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, if (!offs->cntdwn_counter_offs[0]) return; - sub_tag = vif->csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC; + sub_tag = vif->bss_conf.csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC; tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info), &bcn->sub_ntlv, &bcn->len); info = (struct bss_info_bcn_cntdwn *)tlv; @@ -1903,9 +1903,9 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (offs->cntdwn_counter_offs[0]) { u16 offset = offs->cntdwn_counter_offs[0]; - if (vif->csa_active) + if (vif->bss_conf.csa_active) cont->csa_ofs = cpu_to_le16(offset - 4); - if (vif->color_change_active) + if (vif->bss_conf.color_change_active) cont->bcc_ofs = cpu_to_le16(offset - 3); } diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 6959efa4bfa9..21a9e3b0cbac 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4675,7 +4675,7 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); rcu_read_lock(); - if (rcu_access_pointer(vif->chanctx_conf) != ctx) { + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != ctx) { rcu_read_unlock(); continue; } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5c9e97eca739..e3ded46f70ac 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -636,6 +636,19 @@ struct ieee80211_fils_discovery { * @tx_pwr_env_num: number of @tx_pwr_env. * @pwr_reduction: power constraint of BSS. * @eht_support: does this BSS support EHT + * @csa_active: marks whether a channel switch is going on. Internally it is + * write-protected by sdata_lock and local->mtx so holding either is fine + * for read access. + * @mu_mimo_owner: indicates interface owns MU-MIMO capability + * @chanctx_conf: The channel context this interface is assigned to, or %NULL + * when it is not assigned. This pointer is RCU-protected due to the TX + * path needing to access it; even though the netdev carrier will always + * be off when it is %NULL there can still be races and packets could be + * processed after it switches back to %NULL. + * @color_change_active: marks whether a color change is ongoing. Internally it is + * write-protected by sdata_lock and local->mtx so holding either is fine + * for read access. + * @color_change_color: the bss color that will be used after the change. */ struct ieee80211_bss_conf { const u8 *bssid; @@ -711,6 +724,13 @@ struct ieee80211_bss_conf { u8 tx_pwr_env_num; u8 pwr_reduction; bool eht_support; + + bool csa_active; + bool mu_mimo_owner; + struct ieee80211_chanctx_conf __rcu *chanctx_conf; + + bool color_change_active; + u8 color_change_color; }; /** @@ -1713,10 +1733,6 @@ enum ieee80211_offload_flags { * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively - * @csa_active: marks whether a channel switch is going on. Internally it is - * write-protected by sdata_lock and local->mtx so holding either is fine - * for read access. - * @mu_mimo_owner: indicates interface owns MU-MIMO capability * @driver_flags: flags/capabilities the driver has for this interface, * these need to be set (or cleared) when the interface is added * or, if supported by the driver, the interface type is changed @@ -1728,11 +1744,6 @@ enum ieee80211_offload_flags { * restrictions. * @hw_queue: hardware queue for each AC * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only - * @chanctx_conf: The channel context this interface is assigned to, or %NULL - * when it is not assigned. This pointer is RCU-protected due to the TX - * path needing to access it; even though the netdev carrier will always - * be off when it is %NULL there can still be races and packets could be - * processed after it switches back to %NULL. * @debugfs_dir: debugfs dentry, can be used by drivers to create own per * interface debug files. Note that it will be NULL for the virtual * monitor interface (if that is requested.) @@ -1747,10 +1758,6 @@ enum ieee80211_offload_flags { * protected by fq->lock. * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see * &enum ieee80211_offload_flags. - * @color_change_active: marks whether a color change is ongoing. Internally it is - * write-protected by sdata_lock and local->mtx so holding either is fine - * for read access. - * @color_change_color: the bss color that will be used after the change. * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled. */ struct ieee80211_vif { @@ -1758,16 +1765,12 @@ struct ieee80211_vif { struct ieee80211_bss_conf bss_conf; u8 addr[ETH_ALEN] __aligned(2); bool p2p; - bool csa_active; - bool mu_mimo_owner; u8 cab_queue; u8 hw_queue[IEEE80211_NUM_ACS]; struct ieee80211_txq *txq; - struct ieee80211_chanctx_conf __rcu *chanctx_conf; - u32 driver_flags; u32 offload_flags; @@ -1780,9 +1783,6 @@ struct ieee80211_vif { bool txqs_stopped[IEEE80211_NUM_ACS]; - bool color_change_active; - u8 color_change_color; - struct ieee80211_vif *mbssid_tx_vif; /* must be last */ diff --git a/net/mac80211/airtime.c b/net/mac80211/airtime.c index 4bab1683652d..2e66598fac79 100644 --- a/net/mac80211/airtime.c +++ b/net/mac80211/airtime.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2019 Felix Fietkau - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation */ #include @@ -637,7 +637,7 @@ u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, len += 38; /* Ethernet header length */ - conf = rcu_dereference(vif->chanctx_conf); + conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (conf) { band = conf->def.chan->band; shift = ieee80211_chandef_get_shift(&conf->def); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 362cac9e2135..8a15c71e7c7d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -53,7 +53,7 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, params->vht_mumimo_follow_addr); } - sdata->vif.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow; + sdata->vif.bss_conf.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow; } static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata, @@ -1310,7 +1310,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, /* don't allow changing the beacon while a countdown is in place - offset * of channel switch counter may change */ - if (sdata->vif.csa_active || sdata->vif.color_change_active) + if (sdata->vif.bss_conf.csa_active || sdata->vif.bss_conf.color_change_active) return -EBUSY; old = sdata_dereference(sdata->u.ap.beacon, sdata); @@ -1368,7 +1368,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, /* abort any running channel switch */ mutex_lock(&local->mtx); - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; if (sdata->csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA); @@ -3067,7 +3067,7 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, * to send something, and if we're an AP we have to be able to do * so at a basic rate so that all clients can receive it. */ - if (rcu_access_pointer(sdata->vif.chanctx_conf) && + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) && sdata->vif.bss_conf.chandef.chan) { u32 basic_rates = sdata->vif.bss_conf.basic_rates; enum nl80211_band band = sdata->vif.bss_conf.chandef.chan->band; @@ -3374,7 +3374,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) &sdata->csa_chandef)) return -EINVAL; - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; err = ieee80211_set_after_csa_beacon(sdata, &changed); if (err) @@ -3418,7 +3418,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work) mutex_lock(&local->chanctx_mtx); /* AP might have been stopped while waiting for the lock. */ - if (!sdata->vif.csa_active) + if (!sdata->vif.bss_conf.csa_active) goto unlock; if (!ieee80211_sdata_running(sdata)) @@ -3570,7 +3570,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, static void ieee80211_color_change_abort(struct ieee80211_sub_if_data *sdata) { - sdata->vif.color_change_active = false; + sdata->vif.bss_conf.color_change_active = false; ieee80211_free_next_beacon(sdata); @@ -3603,11 +3603,11 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; /* don't allow another channel switch if one is already active. */ - if (sdata->vif.csa_active) + if (sdata->vif.bss_conf.csa_active) return -EBUSY; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { err = -EBUSY; @@ -3646,7 +3646,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, } /* if there is a color change in progress, abort it */ - if (sdata->vif.color_change_active) + if (sdata->vif.bss_conf.color_change_active) ieee80211_color_change_abort(sdata); err = ieee80211_set_csa_beacon(sdata, params, &changed); @@ -3657,7 +3657,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, sdata->csa_chandef = params->chandef; sdata->csa_block_tx = params->block_tx; - sdata->vif.csa_active = true; + sdata->vif.bss_conf.csa_active = true; if (sdata->csa_block_tx) ieee80211_stop_vif_queues(local, sdata, @@ -3826,7 +3826,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, mutex_lock(&local->mtx); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { ret = -EINVAL; goto unlock; @@ -3909,7 +3909,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, int ret = -ENODATA; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) { *chandef = sdata->vif.bss_conf.chandef; ret = 0; @@ -4405,7 +4405,7 @@ static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); lockdep_assert_held(&local->mtx); - sdata->vif.color_change_active = false; + sdata->vif.bss_conf.color_change_active = false; err = ieee80211_set_after_color_change_beacon(sdata, &changed); if (err) { @@ -4414,7 +4414,7 @@ static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata) } ieee80211_color_change_bss_config_notify(sdata, - sdata->vif.color_change_color, + sdata->vif.bss_conf.color_change_color, 1, changed); cfg80211_color_change_notify(sdata->dev); @@ -4432,7 +4432,7 @@ void ieee80211_color_change_finalize_work(struct work_struct *work) mutex_lock(&local->mtx); /* AP might have been stopped while waiting for the lock. */ - if (!sdata->vif.color_change_active) + if (!sdata->vif.bss_conf.color_change_active) goto unlock; if (!ieee80211_sdata_running(sdata)) @@ -4460,7 +4460,7 @@ ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - if (sdata->vif.color_change_active || sdata->vif.csa_active) + if (sdata->vif.bss_conf.color_change_active || sdata->vif.bss_conf.csa_active) return; cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap); @@ -4486,7 +4486,7 @@ ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, /* don't allow another color change if one is already active or if csa * is active */ - if (sdata->vif.color_change_active || sdata->vif.csa_active) { + if (sdata->vif.bss_conf.color_change_active || sdata->vif.bss_conf.csa_active) { err = -EBUSY; goto out; } @@ -4495,8 +4495,8 @@ ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, if (err) goto out; - sdata->vif.color_change_active = true; - sdata->vif.color_change_color = params->color; + sdata->vif.bss_conf.color_change_active = true; + sdata->vif.bss_conf.color_change_color = params->color; cfg80211_color_change_started_notify(sdata->dev, params->count); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index d8246e00a10b..eea400902133 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * mac80211 - channel management - * Copyright 2020 - 2021 Intel Corporation + * Copyright 2020 - 2022 Intel Corporation */ #include @@ -72,7 +72,7 @@ ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local __maybe_unused = sdata->local; struct ieee80211_chanctx_conf *conf; - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return NULL; @@ -260,7 +260,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) continue; switch (vif->type) { @@ -298,7 +298,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, /* use the configured bandwidth in case of monitor interface */ sdata = rcu_dereference(local->monitor_sdata); - if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf) + if (sdata && rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf) max_bw = max(max_bw, conf->def.width); rcu_read_unlock(); @@ -368,7 +368,7 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, if (!ieee80211_sdata_running(sta->sdata)) continue; - if (rcu_access_pointer(sta->sdata->vif.chanctx_conf) != + if (rcu_access_pointer(sta->sdata->vif.bss_conf.chanctx_conf) != &ctx->conf) continue; @@ -533,7 +533,7 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local, list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) continue; if (!sdata->radar_required) continue; @@ -689,7 +689,7 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) continue; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; @@ -759,7 +759,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN)) return -ENOTSUPP; - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { @@ -781,7 +781,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, } out: - rcu_assign_pointer(sdata->vif.chanctx_conf, conf); + rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); sdata->vif.bss_conf.idle = !conf; @@ -825,7 +825,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.chanctx_conf) != + if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != &chanctx->conf) continue; @@ -874,7 +874,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, /* Disable SMPS for the monitor interface */ sdata = rcu_dereference(local->monitor_sdata); if (sdata && - rcu_access_pointer(sdata->vif.chanctx_conf) == &chanctx->conf) + rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf) rx_chains_dynamic = rx_chains_static = local->rx_chains; rcu_read_unlock(); @@ -917,7 +917,7 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, * channel context pointer for a while, possibly pointing * to a channel context that has already been freed. */ - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); WARN_ON(!conf); @@ -925,7 +925,7 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, conf = NULL; list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - rcu_assign_pointer(vlan->vif.chanctx_conf, conf); + rcu_assign_pointer(vlan->vif.bss_conf.chanctx_conf, conf); } void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, @@ -1173,7 +1173,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) } list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); - rcu_assign_pointer(sdata->vif.chanctx_conf, &new_ctx->conf); + rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, &new_ctx->conf); if (sdata->vif.type == NL80211_IFTYPE_AP) __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); @@ -1515,7 +1515,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) if (!ieee80211_vif_has_in_place_reservation(sdata)) continue; - rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); + rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, + &ctx->conf); if (sdata->vif.type == NL80211_IFTYPE_AP) __ieee80211_vif_copy_chanctx_to_vlans(sdata, @@ -1634,7 +1635,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return; @@ -1809,7 +1810,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, goto out; } - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { ret = -EINVAL; @@ -1879,9 +1880,9 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(ap->vif.chanctx_conf, + conf = rcu_dereference_protected(ap->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); - rcu_assign_pointer(sdata->vif.chanctx_conf, conf); + rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); mutex_unlock(&local->chanctx_mtx); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4e2fc1a08681..fd2882348211 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -165,7 +165,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || sdata->vif.type == NL80211_IFTYPE_NAN || (sdata->vif.type == NL80211_IFTYPE_MONITOR && - !sdata->vif.mu_mimo_owner && + !sdata->vif.bss_conf.mu_mimo_owner && !(changed & BSS_CHANGED_TXPOWER)))) return; diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c index 31cd3c1ac07f..6e1fc8788101 100644 --- a/net/mac80211/ethtool.c +++ b/net/mac80211/ethtool.c @@ -5,7 +5,7 @@ * Copied from cfg.c - originally * Copyright 2006-2010 Johannes Berg * Copyright 2014 Intel Corporation (Author: Johannes Berg) - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018, 2022 Intel Corporation */ #include #include @@ -150,7 +150,7 @@ do_survey: survey.filled = 0; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) channel = chanctx_conf->def.chan; else diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 14c04fd48b7a..8ff547ff351e 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -9,7 +9,7 @@ * Copyright 2009, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH - * Copyright(c) 2018-2021 Intel Corporation + * Copyright(c) 2018-2022 Intel Corporation */ #include @@ -622,7 +622,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, } rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) return NULL; band = chanctx_conf->def.chan->band; @@ -923,7 +923,7 @@ ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata, if (len < required_len) return; - if (!sdata->vif.csa_active) + if (!sdata->vif.bss_conf.csa_active) ieee80211_ibss_process_chanswitch(sdata, elems, false); } @@ -1143,7 +1143,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, goto put_bss; /* process channel switch */ - if (sdata->vif.csa_active || + if (sdata->vif.bss_conf.csa_active || ieee80211_ibss_process_chanswitch(sdata, elems, true)) goto put_bss; @@ -1220,7 +1220,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, return; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) { rcu_read_unlock(); return; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1cf331572de1..5a1347727b4a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1076,7 +1076,7 @@ ieee80211_vif_get_shift(struct ieee80211_vif *vif) int shift = 0; rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->chanctx_conf); + chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); if (chanctx_conf) shift = ieee80211_chandef_get_shift(&chanctx_conf->def); rcu_read_unlock(); @@ -1527,7 +1527,7 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata) enum nl80211_band band; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); @@ -2224,7 +2224,7 @@ static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, struct ieee80211_chanctx_conf *chanctx_conf; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); kfree_skb(skb); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fb8d102fca48..9e0e71ca8068 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -51,7 +51,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) int power; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); return false; @@ -275,7 +275,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, * will not add another interface while any channel * switch is active. */ - if (nsdata->vif.csa_active) + if (nsdata->vif.bss_conf.csa_active) return -EBUSY; /* @@ -450,7 +450,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do cancel_work_sync(&sdata->recalc_smps); sdata_lock(sdata); mutex_lock(&local->mtx); - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; if (sdata->vif.type == NL80211_IFTYPE_STATION) sdata->u.mgd.csa_waiting_bcn = false; if (sdata->csa_block_tx) { @@ -502,7 +502,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do mutex_lock(&local->mtx); list_del(&sdata->u.vlan.list); mutex_unlock(&local->mtx); - RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL); + RCU_INIT_POINTER(sdata->vif.bss_conf.chanctx_conf, NULL); /* see comment in the default case below */ ieee80211_free_keys(sdata, true); /* no need to tell driver */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 4f3e93c0819b..ebde131efcaa 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -147,7 +147,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (!rcu_access_pointer(sdata->vif.chanctx_conf)) + if (!rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf)) continue; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; @@ -284,7 +284,7 @@ static void ieee80211_restart_work(struct work_struct *work) * Then we can have a race... */ cancel_work_sync(&sdata->u.mgd.csa_connection_drop_work); - if (sdata->vif.csa_active) { + if (sdata->vif.bss_conf.csa_active) { sdata_lock(sdata); ieee80211_sta_connection_lost(sdata, WLAN_REASON_UNSPECIFIED, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 5275f4f32a78..f60e257cba95 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2022 Intel Corporation * Authors: Luis Carlos Cobo * Javier Cardona */ @@ -399,7 +399,7 @@ static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata, return -ENOMEM; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; @@ -455,7 +455,7 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, u8 *pos; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; @@ -527,7 +527,7 @@ int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, u8 *pos; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; @@ -820,7 +820,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); band = chanctx_conf->def.chan->band; rcu_read_unlock(); @@ -1357,7 +1357,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, rx_status); if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && - !sdata->vif.csa_active) + !sdata->vif.bss_conf.csa_active) ieee80211_mesh_process_chnswitch(sdata, elems, true); } @@ -1488,7 +1488,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, ifmsh->pre_value = pre_value; - if (!sdata->vif.csa_active && + if (!sdata->vif.bss_conf.csa_active && !ieee80211_mesh_process_chnswitch(sdata, elems, false)) { mcsa_dbg(sdata, "Failed to process CSA action frame"); goto free; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e0a9b7d63071..c526af66ff8d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -624,7 +624,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *other; list_for_each_entry_rcu(other, &local->interfaces, list) { - if (other->vif.mu_mimo_owner) { + if (other->vif.bss_conf.mu_mimo_owner) { disable_mu_mimo = true; break; } @@ -632,7 +632,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, if (disable_mu_mimo) cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; else - sdata->vif.mu_mimo_owner = true; + sdata->vif.bss_conf.mu_mimo_owner = true; } mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; @@ -664,7 +664,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata, bool reg_cap = false; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!WARN_ON_ONCE(!chanctx_conf)) reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy, &chanctx_conf->def, @@ -705,7 +705,7 @@ static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, bool reg_cap = false; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!WARN_ON_ONCE(!chanctx_conf)) reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy, &chanctx_conf->def, @@ -766,7 +766,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; @@ -1229,7 +1229,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) if (!ifmgd->associated) goto out; - if (!sdata->vif.csa_active) + if (!sdata->vif.bss_conf.csa_active) goto out; /* @@ -1289,7 +1289,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) sdata_assert_lock(sdata); - WARN_ON(!sdata->vif.csa_active); + WARN_ON(!sdata->vif.bss_conf.csa_active); if (sdata->csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, @@ -1297,7 +1297,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) sdata->csa_block_tx = false; } - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; ifmgd->csa_waiting_bcn = false; /* * If the CSA IE is still present on the beacon after the switch, @@ -1361,7 +1361,7 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata) IEEE80211_QUEUE_STOP_REASON_CSA); sdata->csa_block_tx = false; - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; mutex_unlock(&local->mtx); @@ -1412,13 +1412,13 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, if (res < 0) goto lock_and_drop_connection; - if (beacon && sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) { + if (beacon && sdata->vif.bss_conf.csa_active && !ifmgd->csa_waiting_bcn) { if (res) ieee80211_sta_abort_chanswitch(sdata); else drv_channel_switch_rx_beacon(sdata, &ch_switch); return; - } else if (sdata->vif.csa_active || res) { + } else if (sdata->vif.bss_conf.csa_active || res) { /* disregard subsequent announcements if already processing */ return; } @@ -1471,7 +1471,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->mtx); mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { sdata_info(sdata, @@ -1504,7 +1504,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, } mutex_unlock(&local->chanctx_mtx); - sdata->vif.csa_active = true; + sdata->vif.bss_conf.csa_active = true; sdata->csa_chandef = csa_ie.chandef; sdata->csa_block_tx = csa_ie.mode; ifmgd->csa_ignored_same_chan = false; @@ -1543,7 +1543,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, * send a deauthentication frame. Those two fields will be * reset when the disconnection worker runs. */ - sdata->vif.csa_active = true; + sdata->vif.bss_conf.csa_active = true; sdata->csa_block_tx = csa_ie.mode; ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); @@ -2447,7 +2447,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(sdata->vif.bss_conf.mu_group.position, 0, sizeof(sdata->vif.bss_conf.mu_group.position)); changed |= BSS_CHANGED_MU_GROUPS; - sdata->vif.mu_mimo_owner = false; + sdata->vif.bss_conf.mu_mimo_owner = false; sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; @@ -2482,7 +2482,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->mtx); ieee80211_vif_release_channel(sdata); - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; ifmgd->csa_waiting_bcn = false; ifmgd->csa_ignored_same_chan = false; if (sdata->csa_block_tx) { @@ -2808,7 +2808,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, tx, frame_buf); mutex_lock(&local->mtx); - sdata->vif.csa_active = false; + sdata->vif.bss_conf.csa_active = false; ifmgd->csa_waiting_bcn = false; if (sdata->csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, @@ -2948,7 +2948,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, eth_zero_addr(sdata->u.mgd.bssid); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; - sdata->vif.mu_mimo_owner = false; + sdata->vif.bss_conf.mu_mimo_owner = false; mutex_lock(&sdata->local->mtx); ieee80211_vif_release_channel(sdata); @@ -4134,7 +4134,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, return; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); return; @@ -4803,7 +4803,7 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) from_timer(sdata, t, u.mgd.bcn_mon_timer); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) + if (sdata->vif.bss_conf.csa_active && !ifmgd->csa_waiting_bcn) return; if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) @@ -4823,7 +4823,7 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t) struct sta_info *sta; unsigned long timeout; - if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) + if (sdata->vif.bss_conf.csa_active && !ifmgd->csa_waiting_bcn) return; sta = sta_info_get(sdata, ifmgd->bssid); diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index f97cb4c453d3..d0f0d96b0948 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -4,6 +4,7 @@ * * Copyright: (c) 2014 Czech Technical University in Prague * (c) 2014 Volkswagen Group Research + * Copyright (C) 2022 Intel Corporation * Author: Rostislav Lisovy * Funded by: Volkswagen Group Research */ @@ -59,7 +60,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, ocb_dbg(sdata, "Adding new OCB station %pM\n", addr); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON_ONCE(!chanctx_conf)) { rcu_read_unlock(); return; diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index c5d2ab9df1e7..a1fbd562cac1 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -8,7 +8,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007, Michael Wu * Copyright 2009 Johannes Berg - * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2019, 2022 Intel Corporation */ #include #include @@ -845,7 +845,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_chanctx_conf *chanctx_conf; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) { need_offchan = params->chan && @@ -876,7 +876,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, data = skb_put_data(skb, params->buf, params->len); /* Update CSA counters */ - if (sdata->vif.csa_active && + if (sdata->vif.bss_conf.csa_active && (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_MESH_POINT || sdata->vif.type == NL80211_IFTYPE_ADHOC) && diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index ae9700e0a1a5..f22381127948 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -4,6 +4,7 @@ * Copyright 2005-2006, Devicescape Software, Inc. * Copyright (c) 2006 Jiri Benc * Copyright 2017 Intel Deutschland GmbH + * Copyright (C) 2022 Intel Corporation */ #include @@ -43,7 +44,7 @@ void rate_control_rate_init(struct sta_info *sta) rcu_read_lock(); - chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sta->sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return; @@ -100,7 +101,7 @@ void rate_control_rate_update(struct ieee80211_local *local, if (ref && ref->ops->rate_update) { rcu_read_lock(); - chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sta->sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a9f4e90ad893..9a179a18aafc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3167,7 +3167,7 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION)) return; - if (rx->sdata->vif.csa_active) + if (rx->sdata->vif.bss_conf.csa_active) return; baselen = mgmt->u.beacon.variable - rx->skb->data; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e04a0905e941..7eeb6919d2b7 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1467,7 +1467,7 @@ static void ieee80211_send_null_response(struct sta_info *sta, int tid, skb->dev = sdata->dev; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); kfree_skb(skb); diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 4e2d22e47429..fa04021d4c0f 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -6,7 +6,7 @@ * Copyright 2014, Intel Corporation * Copyright 2014 Intel Mobile Communications GmbH * Copyright 2015 - 2016 Intel Deutschland GmbH - * Copyright (C) 2019, 2021 Intel Corporation + * Copyright (C) 2019, 2021-2022 Intel Corporation */ #include @@ -1254,7 +1254,7 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { width = conf->def.width; @@ -1372,7 +1372,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, switch (oper) { case NL80211_TDLS_ENABLE_LINK: - if (sdata->vif.csa_active) { + if (sdata->vif.bss_conf.csa_active) { tdls_dbg(sdata, "TDLS: disallow link during CSA\n"); ret = -EBUSY; break; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 37fe72bb5ab0..e5edc6fd21c0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -57,7 +57,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, return 0; rcu_read_lock(); - chanctx_conf = rcu_dereference(tx->sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(tx->sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) { shift = ieee80211_chandef_get_shift(&chanctx_conf->def); rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); @@ -2345,12 +2345,12 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, } } - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { tmp_sdata = rcu_dereference(local->monitor_sdata); if (tmp_sdata) chanctx_conf = - rcu_dereference(tmp_sdata->vif.chanctx_conf); + rcu_dereference(tmp_sdata->vif.bss_conf.chanctx_conf); } if (chanctx_conf) @@ -2599,7 +2599,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, } ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); - chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2610,7 +2610,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, fallthrough; case NL80211_IFTYPE_AP: if (sdata->vif.type == NL80211_IFTYPE_AP) - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2689,7 +2689,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, skb->data + ETH_ALEN); } - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2732,7 +2732,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, memcpy(hdr.addr3, skb->data, ETH_ALEN); hdrlen = 24; } - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2745,7 +2745,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); eth_broadcast_addr(hdr.addr3); hdrlen = 24; - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2758,7 +2758,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); hdrlen = 24; - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { ret = -ENOTCONN; goto free; @@ -2981,7 +2981,7 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) goto out; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) { rcu_read_unlock(); goto out; @@ -4604,7 +4604,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, sdata = vif_to_sdata(info->control.vif); if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) { - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (unlikely(!chanctx_conf)) { dev_kfree_skb(skb); return true; @@ -4808,7 +4808,7 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, bcn_offsets = beacon->cntdwn_counter_offsets; count = beacon->cntdwn_current_counter; - if (sdata->vif.csa_active) + if (sdata->vif.bss_conf.csa_active) max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM; for (i = 0; i < max_count; ++i) { @@ -5119,7 +5119,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, rcu_read_lock(); sdata = vif_to_sdata(vif); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!ieee80211_sdata_running(sdata) || !chanctx_conf) goto out; @@ -5536,7 +5536,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (!chanctx_conf) goto out; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9e6c4dcef280..48d8f0aad69f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1566,7 +1566,7 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, return; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (chanctx_conf) center_freq = chanctx_conf->def.chan->center_freq; @@ -1613,7 +1613,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, memset(&qparam, 0, sizeof(qparam)); rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); use_11b = (chanctx_conf && chanctx_conf->def.chan->band == NL80211_BAND_2GHZ) && !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); @@ -2264,7 +2264,7 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, return; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { ctx = container_of(conf, struct ieee80211_chanctx, conf); @@ -2523,7 +2523,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) BSS_CHANGED_TXPOWER | BSS_CHANGED_MCAST_RATE; - if (sdata->vif.mu_mimo_owner) + if (sdata->vif.bss_conf.mu_mimo_owner) changed |= BSS_CHANGED_MU_GROUPS; switch (sdata->vif.type) { @@ -2806,8 +2806,8 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); + chanctx_conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); /* * This function can be called from a work, thus it may be possible @@ -2832,8 +2832,8 @@ void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, - lockdep_is_held(&local->chanctx_mtx)); + chanctx_conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); if (WARN_ON_ONCE(!chanctx_conf)) goto unlock; diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index ff26e0c4787b..ac97584b3a0b 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -4,7 +4,7 @@ * * Portions of this file * Copyright(c) 2015 - 2016 Intel Deutschland GmbH - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2022 Intel Corporation */ #include @@ -649,7 +649,7 @@ void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, { struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; - if (!sdata->vif.mu_mimo_owner) + if (!sdata->vif.bss_conf.mu_mimo_owner) return; if (!memcmp(mgmt->u.action.u.vht_group_notif.position, @@ -673,7 +673,7 @@ void ieee80211_update_mu_groups(struct ieee80211_vif *vif, { struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - if (WARN_ON_ONCE(!vif->mu_mimo_owner)) + if (WARN_ON_ONCE(!vif->bss_conf.mu_mimo_owner)) return; memcpy(bss_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN); -- cgit v1.2.3 From f276e20b182dbfc069d192fda259d85feea71143 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 May 2022 17:05:04 +0200 Subject: wifi: mac80211: move interface config to new struct We'll use bss_conf for per-link configuration later, so move out all the non-link-specific data out into a new struct ieee80211_vif_cfg used in the vif. Some adjustments were done with the following spatch: @@ expression sdata; struct ieee80211_vif *vifp; identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator }; @@ ( -sdata->vif.bss_conf.var +sdata->vif.cfg.var | -vifp->bss_conf.var +vifp->cfg.var ) @bss_conf@ struct ieee80211_bss_conf *bss_conf; identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator }; @@ -bss_conf->var +vif_cfg->var (though more manual fixups were needed, e.g. replacing "vif_cfg->" by "vif->cfg." in many files.) Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ar5523/ar5523.c | 10 ++-- drivers/net/wireless/ath/ath10k/mac.c | 29 +++++----- drivers/net/wireless/ath/ath11k/mac.c | 22 ++++---- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 12 ++-- drivers/net/wireless/ath/ath9k/beacon.c | 11 ++-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 16 +++--- drivers/net/wireless/ath/ath9k/main.c | 8 +-- drivers/net/wireless/ath/carl9170/main.c | 2 +- drivers/net/wireless/ath/wcn36xx/main.c | 16 +++--- drivers/net/wireless/ath/wcn36xx/smd.c | 2 +- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 12 ++-- drivers/net/wireless/intel/iwlegacy/3945-mac.c | 6 +- drivers/net/wireless/intel/iwlegacy/4965.c | 6 +- drivers/net/wireless/intel/iwlegacy/common.c | 10 ++-- drivers/net/wireless/intel/iwlwifi/dvm/rxon.c | 22 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 12 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 12 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 28 ++++----- .../net/wireless/intel/iwlwifi/mvm/offloading.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/quota.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/sf.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 8 +-- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 +- drivers/net/wireless/intersil/p54/main.c | 4 +- drivers/net/wireless/mac80211_hwsim.c | 6 +- drivers/net/wireless/marvell/mwl8k.c | 10 ++-- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- .../net/wireless/mediatek/mt76/mt76_connac_mcu.c | 10 ++-- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/mediatek/mt7601u/phy.c | 9 ++- drivers/net/wireless/ralink/rt2x00/rt2x00config.c | 4 +- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 2 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 10 ++-- drivers/net/wireless/realtek/rtlwifi/core.c | 4 +- drivers/net/wireless/realtek/rtw88/bf.c | 2 +- drivers/net/wireless/realtek/rtw88/mac80211.c | 4 +- drivers/net/wireless/realtek/rtw88/main.c | 13 +++-- drivers/net/wireless/realtek/rtw89/cam.c | 2 +- drivers/net/wireless/realtek/rtw89/core.c | 2 +- drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +- drivers/net/wireless/realtek/rtw89/phy.c | 4 +- drivers/net/wireless/rsi/rsi_91x_core.c | 3 +- drivers/net/wireless/rsi/rsi_91x_hal.c | 7 +-- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 31 +++++----- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 3 +- drivers/net/wireless/silabs/wfx/hif_tx.c | 12 ++-- drivers/net/wireless/silabs/wfx/sta.c | 24 ++++---- drivers/net/wireless/st/cw1200/sta.c | 36 ++++++------ drivers/net/wireless/st/cw1200/txrx.c | 4 +- drivers/net/wireless/ti/wl1251/main.c | 8 +-- drivers/net/wireless/ti/wlcore/cmd.c | 4 +- drivers/net/wireless/ti/wlcore/main.c | 37 ++++++------ drivers/staging/vt6655/device_main.c | 6 +- drivers/staging/vt6656/main_usb.c | 4 +- include/net/mac80211.h | 66 +++++++++++++--------- net/mac80211/cfg.c | 10 ++-- net/mac80211/chan.c | 2 +- net/mac80211/debugfs_netdev.c | 6 +- net/mac80211/ibss.c | 26 ++++----- net/mac80211/iface.c | 2 +- net/mac80211/main.c | 10 ++-- net/mac80211/mlme.c | 26 +++++---- net/mac80211/offchannel.c | 2 +- net/mac80211/scan.c | 2 +- net/mac80211/tdls.c | 4 +- net/mac80211/trace.h | 49 +++++++++------- net/mac80211/tx.c | 2 +- net/mac80211/util.c | 2 +- 79 files changed, 402 insertions(+), 368 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 9f84a6fde0c2..4cd06a0942d4 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1256,14 +1256,14 @@ static int ar5523_create_connection(struct ar5523 *ar, sizeof(create), 0); } -static int ar5523_write_associd(struct ar5523 *ar, - struct ieee80211_bss_conf *bss) +static int ar5523_write_associd(struct ar5523 *ar, struct ieee80211_vif *vif) { + struct ieee80211_bss_conf *bss = &vif->bss_conf; struct ar5523_cmd_set_associd associd; memset(&associd, 0, sizeof(associd)); associd.defaultrateix = cpu_to_be32(0); /* XXX */ - associd.associd = cpu_to_be32(bss->aid); + associd.associd = cpu_to_be32(vif->cfg.aid); associd.timoffset = cpu_to_be32(0x3b); /* XXX */ memcpy(associd.bssid, bss->bssid, ETH_ALEN); return ar5523_cmd_write(ar, WDCMSG_WRITE_ASSOCID, &associd, @@ -1284,7 +1284,7 @@ static void ar5523_bss_info_changed(struct ieee80211_hw *hw, if (!(changed & BSS_CHANGED_ASSOC)) goto out_unlock; - if (bss->assoc) { + if (vif->cfg.assoc) { error = ar5523_create_connection(ar, vif, bss); if (error) { ar5523_err(ar, "could not create connection\n"); @@ -1297,7 +1297,7 @@ static void ar5523_bss_info_changed(struct ieee80211_hw *hw, goto out_unlock; } - error = ar5523_write_associd(ar, bss); + error = ar5523_write_associd(ar, vif); if (error) { ar5523_err(ar, "could not set association\n"); goto out_unlock; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 42c657b8b73e..4e7e2da3c859 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1509,8 +1509,8 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, arg.channel.chan_radar = !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { - arg.ssid = arvif->vif->bss_conf.ssid; - arg.ssid_len = arvif->vif->bss_conf.ssid_len; + arg.ssid = arvif->vif->cfg.ssid; + arg.ssid_len = arvif->vif->cfg.ssid_len; } ath10k_dbg(ar, ATH10K_DBG_MAC, @@ -1823,8 +1823,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, } static void ath10k_control_ibss(struct ath10k_vif *arvif, - struct ieee80211_bss_conf *info, - const u8 self_peer[ETH_ALEN]) + struct ieee80211_vif *vif) { struct ath10k *ar = arvif->ar; u32 vdev_param; @@ -1832,7 +1831,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, lockdep_assert_held(&arvif->ar->conf_mutex); - if (!info->ibss_joined) { + if (!vif->cfg.ibss_joined) { if (is_zero_ether_addr(arvif->bssid)) return; @@ -2163,7 +2162,7 @@ static void ath10k_peer_assoc_h_basic(struct ath10k *ar, lockdep_assert_held(&ar->conf_mutex); if (vif->type == NL80211_IFTYPE_STATION) - aid = vif->bss_conf.aid; + aid = vif->cfg.aid; else aid = sta->aid; @@ -2193,7 +2192,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, return; bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, - info->ssid_len ? info->ssid : NULL, info->ssid_len, + vif->cfg.ssid_len ? vif->cfg.ssid : NULL, + vif->cfg.ssid_len, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); if (bss) { const struct cfg80211_bss_ies *ies; @@ -3118,11 +3118,11 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up (associated) bssid %pM aid %d\n", - arvif->vdev_id, bss_conf->bssid, bss_conf->aid); + arvif->vdev_id, bss_conf->bssid, vif->cfg.aid); WARN_ON(arvif->is_up); - arvif->aid = bss_conf->aid; + arvif->aid = vif->cfg.aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); ret = ath10k_wmi_pdev_set_param(ar, @@ -6082,7 +6082,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); if (changed & BSS_CHANGED_IBSS) - ath10k_control_ibss(arvif, info, vif->addr); + ath10k_control_ibss(arvif, vif); if (changed & BSS_CHANGED_BEACON_INT) { arvif->beacon_interval = info->beacon_int; @@ -6147,9 +6147,10 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { - arvif->u.ap.ssid_len = info->ssid_len; - if (info->ssid_len) - memcpy(arvif->u.ap.ssid, info->ssid, info->ssid_len); + arvif->u.ap.ssid_len = vif->cfg.ssid_len; + if (vif->cfg.ssid_len) + memcpy(arvif->u.ap.ssid, vif->cfg.ssid, + vif->cfg.ssid_len); arvif->u.ap.hidden_ssid = info->hidden_ssid; } @@ -6226,7 +6227,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc) { + if (vif->cfg.assoc) { /* Workaround: Make sure monitor vdev is not running * when associating to prevent some firmware revisions * (e.g. 10.1 and 10.2) from crashing. diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f28e7feca318..169161549361 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1539,7 +1539,7 @@ static void ath11k_peer_assoc_h_basic(struct ath11k *ar, lockdep_assert_held(&ar->conf_mutex); if (vif->type == NL80211_IFTYPE_STATION) - aid = vif->bss_conf.aid; + aid = vif->cfg.aid; else aid = sta->aid; @@ -2749,7 +2749,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, WARN_ON(arvif->is_up); - arvif->aid = bss_conf->aid; + arvif->aid = vif->cfg.aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); @@ -2764,7 +2764,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d up (associated) bssid %pM aid %d\n", - arvif->vdev_id, bss_conf->bssid, bss_conf->aid); + arvif->vdev_id, bss_conf->bssid, vif->cfg.aid); spin_lock_bh(&ar->ab->base_lock); @@ -3185,9 +3185,10 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { - arvif->u.ap.ssid_len = info->ssid_len; - if (info->ssid_len) - memcpy(arvif->u.ap.ssid, info->ssid, info->ssid_len); + arvif->u.ap.ssid_len = vif->cfg.ssid_len; + if (vif->cfg.ssid_len) + memcpy(arvif->u.ap.ssid, vif->cfg.ssid, + vif->cfg.ssid_len); arvif->u.ap.hidden_ssid = info->hidden_ssid; } @@ -3275,7 +3276,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc) + if (vif->cfg.assoc) ath11k_bss_assoc(hw, vif, info); else ath11k_bss_disassoc(hw, vif); @@ -3406,14 +3407,15 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ath11k_mac_fils_discovery(arvif, info); if (changed & BSS_CHANGED_ARP_FILTER) { - ipv4_cnt = min(info->arp_addr_cnt, ATH11K_IPV4_MAX_COUNT); - memcpy(arvif->arp_ns_offload.ipv4_addr, info->arp_addr_list, + ipv4_cnt = min(vif->cfg.arp_addr_cnt, ATH11K_IPV4_MAX_COUNT); + memcpy(arvif->arp_ns_offload.ipv4_addr, + vif->cfg.arp_addr_list, ipv4_cnt * sizeof(u32)); memcpy(arvif->arp_ns_offload.mac_addr, vif->addr, ETH_ALEN); arvif->arp_ns_offload.ipv4_count = ipv4_cnt; ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac arp_addr_cnt %d vif->addr %pM, offload_addr %pI4\n", - info->arp_addr_cnt, + vif->cfg.arp_addr_cnt, vif->addr, arvif->arp_ns_offload.ipv4_addr); } diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 532eeac9e83e..0df0fa1da181 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -278,9 +278,9 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changes & BSS_CHANGED_ASSOC) { - avf->assoc = bss_conf->assoc; - if (bss_conf->assoc) - ah->assoc = bss_conf->assoc; + avf->assoc = vif->cfg.assoc; + if (vif->cfg.assoc) + ah->assoc = vif->cfg.assoc; else ah->assoc = ath5k_any_vif_assoc(ah); @@ -288,11 +288,11 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ath5k_set_beacon_filter(hw, ah->assoc); ath5k_hw_set_ledstate(ah, ah->assoc ? AR5K_LED_ASSOC : AR5K_LED_INIT); - if (bss_conf->assoc) { + if (vif->cfg.assoc) { ATH5K_DBG(ah, ATH5K_DEBUG_ANY, "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); - common->curaid = bss_conf->aid; + vif->cfg.aid, common->curbssid); + common->curaid = vif->cfg.aid; ath5k_hw_set_bssid(ah); /* Once ANI is available you would start it here */ } diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 8b1b966bcef1..d41988f8ea3f 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -585,8 +585,9 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, static void ath9k_cache_beacon_config(struct ath_softc *sc, struct ath_chanctx *ctx, - struct ieee80211_bss_conf *bss_conf) + struct ieee80211_vif *vif) { + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_beacon_config *cur_conf = &ctx->beacon; @@ -596,7 +597,7 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, cur_conf->beacon_interval = bss_conf->beacon_int; cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->dtim_count = 1; - cur_conf->ibss_creator = bss_conf->ibss_creator; + cur_conf->ibss_creator = vif->cfg.ibss_creator; /* * It looks like mac80211 may end up using beacon interval of zero in @@ -649,7 +650,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, cur_conf->enable_beacon = beacons; if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { - ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf); + ath9k_cache_beacon_config(sc, ctx, main_vif); ath9k_set_beacon(sc); set_bit(ATH_OP_BEACONS, &common->op_flags); @@ -657,7 +658,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, } /* Update the beacon configuration. */ - ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf); + ath9k_cache_beacon_config(sc, ctx, main_vif); /* * Configure the HW beacon registers only when we have a valid @@ -670,7 +671,7 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, * IBSS interface. */ if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC && - !enabled && beacons && !main_vif->bss_conf.ibss_creator) { + !enabled && beacons && !main_vif->cfg.ibss_creator) { spin_lock_irqsave(&sc->sc_pm_lock, flags); sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index cfee732a89b1..3a5ec4da6a38 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -100,7 +100,7 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) priv->rearm_ani = true; } - if (bss_conf->assoc) { + if (vif->cfg.assoc) { priv->rearm_ani = true; priv->reconfig_beacon = true; } @@ -1488,8 +1488,8 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) { - common->curaid = bss_conf->aid; + if ((vif->type == NL80211_IFTYPE_STATION) && vif->cfg.assoc) { + common->curaid = vif->cfg.aid; common->last_rssi = ATH_RSSI_DUMMY_MARKER; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); @@ -1521,17 +1521,17 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { ath_dbg(common, CONFIG, "BSS Changed ASSOC %d\n", - bss_conf->assoc); + vif->cfg.assoc); - bss_conf->assoc ? + vif->cfg.assoc ? priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; - if (!bss_conf->assoc) + if (!vif->cfg.assoc) clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); if (priv->ah->opmode == NL80211_IFTYPE_STATION) { ath9k_htc_choose_set_bssid(priv); - if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) + if (vif->cfg.assoc && (priv->num_sta_assoc_vif == 1)) ath9k_htc_start_ani(priv); else if (priv->num_sta_assoc_vif == 0) ath9k_htc_stop_ani(priv); @@ -1540,7 +1540,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_IBSS) { if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { - common->curaid = bss_conf->aid; + common->curaid = vif->cfg.aid; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); ath9k_htc_set_bssid(priv); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 77144647f4fc..56c2681e5192 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1881,11 +1881,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", - bss_conf->bssid, bss_conf->assoc); + bss_conf->bssid, vif->cfg.assoc); memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); - avp->aid = bss_conf->aid; - avp->assoc = bss_conf->assoc; + avp->aid = vif->cfg.aid; + avp->assoc = vif->cfg.assoc; ath9k_calculate_summary_state(sc, avp->chanctx); } @@ -1893,7 +1893,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if ((changed & BSS_CHANGED_IBSS) || (changed & BSS_CHANGED_OCB)) { memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = bss_conf->aid; + common->curaid = vif->cfg.aid; ath9k_hw_write_associd(sc->sc_ah); } diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 101295162967..e28a5f3085c0 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1115,7 +1115,7 @@ static void carl9170_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - ar->common.curaid = bss_conf->aid; + ar->common.curaid = vif->cfg.aid; err = carl9170_set_beacon_timers(ar); if (err) goto out; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index e34d3d0b7082..72ba2e2fc93a 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -919,17 +919,17 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ssid\n"); wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ", - bss_conf->ssid, bss_conf->ssid_len); + vif->cfg.ssid, vif->cfg.ssid_len); - vif_priv->ssid.length = bss_conf->ssid_len; + vif_priv->ssid.length = vif->cfg.ssid_len; memcpy(&vif_priv->ssid.ssid, - bss_conf->ssid, - bss_conf->ssid_len); + vif->cfg.ssid, + vif->cfg.ssid_len); } if (changed & BSS_CHANGED_ASSOC) { vif_priv->is_joining = false; - if (bss_conf->assoc) { + if (vif->cfg.assoc) { struct ieee80211_sta *sta; struct wcn36xx_sta *sta_priv; @@ -937,7 +937,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, "mac assoc bss %pM vif %pM AID=%d\n", bss_conf->bssid, vif->addr, - bss_conf->aid); + vif->cfg.aid); vif_priv->sta_assoc = true; @@ -963,7 +963,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_smd_config_bss(wcn, vif, sta, bss_conf->bssid, true); - sta_priv->aid = bss_conf->aid; + sta_priv->aid = vif->cfg.aid; /* * config_sta must be called from because this is the * place where AID is available. @@ -977,7 +977,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, "disassociated bss %pM vif %pM AID=%d\n", bss_conf->bssid, vif->addr, - bss_conf->aid); + vif->cfg.aid); vif_priv->sta_assoc = false; wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 7ac9a1e6f768..46ab21824d63 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -3005,7 +3005,7 @@ int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, msg_body.host_offload_params.enable = WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE; memcpy(&msg_body.host_offload_params.u, - &vif->bss_conf.arp_addr_list[0], sizeof(__be32)); + &vif->cfg.arp_addr_list[0], sizeof(__be32)); } msg_body.ns_offload_params.bss_index = vif_priv->bss_index; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 8c741b98d8e5..e6cd638a85d6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -507,7 +507,7 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) brcms_c_start_station(wl->wlc, vif->addr); else if (vif->type == NL80211_IFTYPE_AP) brcms_c_start_ap(wl->wlc, vif->addr, vif->bss_conf.bssid, - vif->bss_conf.ssid, vif->bss_conf.ssid_len); + vif->cfg.ssid, vif->cfg.ssid_len); else if (vif->type == NL80211_IFTYPE_ADHOC) brcms_c_start_adhoc(wl->wlc, vif->addr); spin_unlock_bh(&wl->lock); @@ -592,9 +592,9 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, * also implies a change in the AID. */ brcms_err(core, "%s: %s: %sassociated\n", KBUILD_MODNAME, - __func__, info->assoc ? "" : "dis"); + __func__, vif->cfg.assoc ? "" : "dis"); spin_lock_bh(&wl->lock); - brcms_c_associate_upd(wl->wlc, info->assoc); + brcms_c_associate_upd(wl->wlc, vif->cfg.assoc); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_ERP_SLOT) { @@ -669,7 +669,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_SSID) { /* BSSID changed, for whatever reason (IBSS and managed mode) */ spin_lock_bh(&wl->lock); - brcms_c_set_ssid(wl->wlc, info->ssid, info->ssid_len); + brcms_c_set_ssid(wl->wlc, vif->cfg.ssid, vif->cfg.ssid_len); spin_unlock_bh(&wl->lock); } if (changed & BSS_CHANGED_BEACON) { @@ -715,13 +715,13 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_IBSS) { /* IBSS join status changed */ brcms_err(core, "%s: IBSS joined: %s (implement)\n", - __func__, info->ibss_joined ? "true" : "false"); + __func__, vif->cfg.ibss_joined ? "true" : "false"); } if (changed & BSS_CHANGED_ARP_FILTER) { /* Hardware ARP filter address list or state changed */ brcms_err(core, "%s: arp filtering: %d addresses" - " (implement)\n", __func__, info->arp_addr_cnt); + " (implement)\n", __func__, vif->cfg.arp_addr_cnt); } if (changed & BSS_CHANGED_QOS) { diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index bd4e7d752958..846138d6e33d 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -2701,7 +2701,7 @@ il3945_post_associate(struct il_priv *il) if (!il->vif || !il->is_open) return; - D_ASSOC("Associated as %d to: %pM\n", il->vif->bss_conf.aid, + D_ASSOC("Associated as %d to: %pM\n", il->vif->cfg.aid, il->active.bssid_addr); if (test_bit(S_EXIT_PENDING, &il->status)) @@ -2718,9 +2718,9 @@ il3945_post_associate(struct il_priv *il) il->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - il->staging.assoc_id = cpu_to_le16(il->vif->bss_conf.aid); + il->staging.assoc_id = cpu_to_le16(il->vif->cfg.aid); - D_ASSOC("assoc id %d beacon interval %d\n", il->vif->bss_conf.aid, + D_ASSOC("assoc id %d beacon interval %d\n", il->vif->cfg.aid, il->vif->bss_conf.beacon_int); if (il->vif->bss_conf.use_short_preamble) diff --git a/drivers/net/wireless/intel/iwlegacy/4965.c b/drivers/net/wireless/intel/iwlegacy/4965.c index 9fa556486511..c34729f576cd 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965.c +++ b/drivers/net/wireless/intel/iwlegacy/4965.c @@ -1756,9 +1756,9 @@ il4965_post_associate(struct il_priv *il) if (il->ops->set_rxon_chain) il->ops->set_rxon_chain(il); - il->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); + il->staging.assoc_id = cpu_to_le16(vif->cfg.aid); - D_ASSOC("assoc id %d beacon interval %d\n", vif->bss_conf.aid, + D_ASSOC("assoc id %d beacon interval %d\n", vif->cfg.aid, vif->bss_conf.beacon_int); if (vif->bss_conf.use_short_preamble) @@ -1775,7 +1775,7 @@ il4965_post_associate(struct il_priv *il) il_commit_rxon(il); - D_ASSOC("Associated as %d to: %pM\n", vif->bss_conf.aid, + D_ASSOC("Associated as %d to: %pM\n", vif->cfg.aid, il->active.bssid_addr); switch (vif->type) { diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 8299d89e7505..b01945415be6 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5427,8 +5427,8 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changes & BSS_CHANGED_ASSOC) { - D_MAC80211("ASSOC %d\n", bss_conf->assoc); - if (bss_conf->assoc) { + D_MAC80211("ASSOC %d\n", vif->cfg.assoc); + if (vif->cfg.assoc) { il->timestamp = bss_conf->sync_tsf; if (!il_is_rfkill(il)) @@ -5437,7 +5437,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, il_set_no_assoc(il, vif); } - if (changes && il_is_associated(il) && bss_conf->aid) { + if (changes && il_is_associated(il) && vif->cfg.aid) { D_MAC80211("Changes (%#x) while associated\n", changes); ret = il_send_rxon_assoc(il); if (!ret) { @@ -5459,10 +5459,10 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changes & BSS_CHANGED_IBSS) { ret = il->ops->manage_ibss_station(il, vif, - bss_conf->ibss_joined); + vif->cfg.ibss_joined); if (ret) IL_ERR("failed to %s IBSS station %pM\n", - bss_conf->ibss_joined ? "add" : "remove", + vif->cfg.ibss_joined ? "add" : "remove", bss_conf->bssid); } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 5dd2d43a01d8..17a14970edec 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -562,12 +562,12 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) slot1 = bcnint - slot0; if (test_bit(STATUS_SCAN_HW, &priv->status) || - (!ctx_bss->vif->bss_conf.idle && - !ctx_bss->vif->bss_conf.assoc)) { + (!ctx_bss->vif->cfg.idle && + !ctx_bss->vif->cfg.assoc)) { slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; slot1 = IWL_MIN_SLOT_TIME; - } else if (!ctx_pan->vif->bss_conf.idle && - !ctx_pan->vif->bss_conf.assoc) { + } else if (!ctx_pan->vif->cfg.idle && + !ctx_pan->vif->cfg.assoc) { slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; slot0 = IWL_MIN_SLOT_TIME; } @@ -1392,7 +1392,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); - if (changes & BSS_CHANGED_IDLE && bss_conf->idle) { + if (changes & BSS_CHANGED_IDLE && vif->cfg.idle) { /* * If we go idle, then clearly no "passive-no-rx" * workaround is needed any more, this is a reset. @@ -1420,14 +1420,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, iwlagn_update_qos(priv, ctx); } - ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); + ctx->staging.assoc_id = cpu_to_le16(vif->cfg.aid); if (vif->bss_conf.use_short_preamble) ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; else ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; if (changes & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { + if (vif->cfg.assoc) { priv->timestamp = bss_conf->sync_tsf; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { @@ -1483,7 +1483,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, */ if (vif->type == NL80211_IFTYPE_STATION) { - if (!bss_conf->assoc) + if (!vif->cfg.assoc) ctx->staging.filter_flags |= RXON_FILTER_BCON_AWARE_MSK; else ctx->staging.filter_flags &= @@ -1493,7 +1493,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) iwlagn_commit_rxon(priv, ctx); - if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) { + if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc) { /* * The chain noise calibration will enable PM upon * completion. If calibration has already been run @@ -1509,10 +1509,10 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_IBSS) { ret = iwlagn_manage_ibss_station(priv, vif, - bss_conf->ibss_joined); + vif->cfg.ibss_joined); if (ret) IWL_ERR(priv, "failed to %s IBSS station %pM\n", - bss_conf->ibss_joined ? "add" : "remove", + vif->cfg.ibss_joined ? "add" : "remove", bss_conf->bssid); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 8760f2c73369..ee3c8a786199 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -311,7 +311,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode = IEEE80211_SMPS_DYNAMIC; /* relax SMPS constraints for next association */ - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) smps_mode = IEEE80211_SMPS_AUTOMATIC; if (mvmvif->phy_ctxt && @@ -382,7 +382,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, * we are not associated */ if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || - mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || + mvm->cfg->bt_shared_single_ant || !vif->cfg.assoc || le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 8edc8646a23a..aeb0015b73d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -749,7 +749,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* add back the MAC */ mvmvif->uploaded = false; - if (WARN_ON(!vif->bss_conf.assoc)) + if (WARN_ON(!vif->cfg.assoc)) return -EINVAL; ret = iwl_mvm_mac_ctxt_add(mvm, vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 430044bc4755..777c568f35a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include #include @@ -67,7 +67,7 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * the TK is already configured for this station, so it * shouldn't be set again here. */ - if (vif->bss_conf.assoc && + if (vif->cfg.assoc && !memcmp(addr, vif->bss_conf.bssid, ETH_ALEN)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; @@ -222,7 +222,7 @@ static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, for (i = 0; i < ETH_ALEN; i++) cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); else eth_broadcast_addr(cmd->range_req_bssid); @@ -254,7 +254,7 @@ static void iwl_mvm_ftm_cmd_common(struct iwl_mvm *mvm, for (i = 0; i < ETH_ALEN; i++) cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; - if (vif->bss_conf.assoc) { + if (vif->cfg.assoc) { memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); /* AP's TSF is only relevant if associated */ @@ -503,7 +503,7 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_ftm_put_target_common(mvm, peer, target); - if (vif->bss_conf.assoc && + if (vif->cfg.assoc && !memcmp(peer->addr, vif->bss_conf.bssid, ETH_ALEN)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; @@ -693,7 +693,7 @@ iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif, target->cipher = entry->cipher; memcpy(target->hltk, entry->hltk, sizeof(target->hltk)); - if (vif->bss_conf.assoc && + if (vif->cfg.assoc && !memcmp(vif->bss_conf.bssid, target->bssid, sizeof(target->bssid))) ieee80211_iter_keys(mvm->hw, vif, iter, target); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 7756ac0faf3f..65df8cbb57d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -570,7 +570,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, } /* We need the dtim_period to set the MAC as associated */ - if (vif->bss_conf.assoc && vif->bss_conf.dtim_period && + if (vif->cfg.assoc && vif->bss_conf.dtim_period && !force_assoc_off) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); u32 dtim_offs; @@ -628,9 +628,9 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, vif->bss_conf.dtim_period); ctxt_sta->listen_interval = cpu_to_le32(mvm->hw->conf.listen_interval); - ctxt_sta->assoc_id = cpu_to_le32(vif->bss_conf.aid); + ctxt_sta->assoc_id = cpu_to_le32(vif->cfg.aid); - if (vif->probe_req_reg && vif->bss_conf.assoc && vif->p2p) + if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p) cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) { @@ -944,8 +944,8 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, IWL_MAC_BEACON_FILS : IWL_MAC_BEACON_FILS_V1; beacon_cmd.short_ssid = - cpu_to_le32(~crc32_le(~0, vif->bss_conf.ssid, - vif->bss_conf.ssid_len)); + cpu_to_le32(~crc32_le(~0, vif->cfg.ssid, + vif->cfg.ssid_len)); } rcu_read_unlock(); @@ -1031,7 +1031,7 @@ static void iwl_mvm_mac_ap_iterator(void *_data, u8 *mac, { struct iwl_mvm_mac_ap_iterator_data *data = _data; - if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) return; /* Station client has higher priority over P2P client*/ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index c5626ff83805..b5257b4fd000 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1614,7 +1614,7 @@ static void iwl_mvm_mc_iface_iterator(void *_data, u8 *mac, return; if (vif->type != NL80211_IFTYPE_STATION || - !vif->bss_conf.assoc) + !vif->cfg.assoc) return; cmd->port_id = data->port_id++; @@ -1740,7 +1740,7 @@ static void iwl_mvm_config_iface_filter(struct ieee80211_hw *hw, return; /* Supported only for p2p client interfaces */ - if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc || + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc || !vif->p2p) return; @@ -2191,7 +2191,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * on the beacon interval, which was not known when the station * interface was added. */ - if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) { + if (changes & BSS_CHANGED_ASSOC && vif->cfg.assoc) { if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id); @@ -2201,7 +2201,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* Update MU EDCA params */ if (changes & BSS_CHANGED_QOS && mvmvif->associated && - bss_conf->assoc && vif->bss_conf.he_support && + vif->cfg.assoc && vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id); @@ -2220,10 +2220,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* after sending it once, adopt mac80211 data */ memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN); - mvmvif->associated = bss_conf->assoc; + mvmvif->associated = vif->cfg.assoc; if (changes & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { + if (vif->cfg.assoc) { /* clear statistics to get clean beacon counter */ iwl_mvm_request_statistics(mvm, true); memset(&mvmvif->beacon_stats, 0, @@ -2627,7 +2627,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) + if (changes & BSS_CHANGED_IDLE && !vif->cfg.idle) iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true); switch (vif->type) { @@ -3020,7 +3020,7 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm, #if IS_ENABLED(CONFIG_IWLMEI) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mei_conn_info conn_info = { - .ssid_len = vif->bss_conf.ssid_len, + .ssid_len = vif->cfg.ssid_len, .channel = vif->bss_conf.chandef.chan->hw_value, }; @@ -3068,7 +3068,7 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm, return; } - memcpy(conn_info.ssid, vif->bss_conf.ssid, vif->bss_conf.ssid_len); + memcpy(conn_info.ssid, vif->cfg.ssid, vif->cfg.ssid_len); memcpy(conn_info.bssid, vif->bss_conf.bssid, ETH_ALEN); /* TODO: add support for collocated AP data */ @@ -3381,7 +3381,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); - if (!vif->bss_conf.idle) { + if (!vif->cfg.idle) { ret = -EBUSY; goto out; } @@ -3747,7 +3747,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, * like the delay to be for 2-3 dtim intervals, in case there are * other time events with higher priority. */ - if (vif->bss_conf.assoc) { + if (vif->cfg.assoc) { delay = min_t(u32, dtim_interval * 3, AUX_ROC_MAX_DELAY); /* We cannot remain off-channel longer than the DTIM interval */ if (dtim_interval <= req_dur) { @@ -4502,7 +4502,7 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, case IWL_MVM_TM_CMD_SET_BEACON_FILTER: /* must be associated client vif - ignore authorized */ if (!vif || vif->type != NL80211_IFTYPE_STATION || - !vif->bss_conf.assoc || !vif->bss_conf.dtim_period || + !vif->cfg.assoc || !vif->bss_conf.dtim_period || !tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]) return -EINVAL; @@ -4670,7 +4670,7 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, * we don't know the dtim period. In this case, the firmware can't * track the beacons. */ - if (!vif->bss_conf.assoc || !vif->bss_conf.dtim_period) { + if (!vif->cfg.assoc || !vif->bss_conf.dtim_period) { ret = -EBUSY; goto out_unlock; } @@ -5069,7 +5069,7 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) return; - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) return; mutex_lock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index c7dabc6b3765..a8bd0f5f795c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2021 Intel Corporation + * Copyright (C) 2012-2014, 2021-2022 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 Intel Deutschland GmbH */ @@ -192,9 +192,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, size = sizeof(cmd.v1); } - if (vif->bss_conf.arp_addr_cnt) { + if (vif->cfg.arp_addr_cnt) { enabled |= IWL_D3_PROTO_OFFLOAD_ARP | IWL_D3_PROTO_IPV4_VALID; - common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0]; + common->host_ipv4_addr = vif->cfg.arp_addr_list[0]; memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index b2f33ebdf485..db43c8a83a31 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -162,7 +162,7 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, vif->bss_conf.chandef.width < NL80211_CHAN_WIDTH_40) return; - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) return; /* this shouldn't happen *again*, ignore it */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index afdf3bb523e9..b49f265a421f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -223,7 +223,7 @@ static void iwl_mvm_p2p_standalone_iterator(void *_data, u8 *mac, *is_p2p_standalone = false; break; case NL80211_IFTYPE_STATION: - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) *is_p2p_standalone = false; break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c index c862bd243b55..cea1a34f9130 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/quota.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018, 2021 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2021-2022 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -47,7 +47,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_STATION: - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) break; return; case NL80211_IFTYPE_AP: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index a4077053e374..582a95ffc7ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1948,14 +1948,14 @@ static void iwl_mvm_scan_6ghz_passive_scan(struct iwl_mvm *mvm, * reset or resume flow, or while not associated and a large interval * has passed since the last 6GHz passive scan. */ - if ((vif->bss_conf.assoc || + if ((vif->cfg.assoc || time_after(mvm->last_6ghz_passive_scan_jiffies + (IWL_MVM_6GHZ_PASSIVE_SCAN_TIMEOUT * HZ), jiffies)) && (time_before(mvm->last_reset_or_resume_time_jiffies + (IWL_MVM_6GHZ_PASSIVE_SCAN_ASSOC_TIMEOUT * HZ), jiffies))) { IWL_DEBUG_SCAN(mvm, "6GHz passive scan: %s\n", - vif->bss_conf.assoc ? "associated" : + vif->cfg.assoc ? "associated" : "timeout did not expire"); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index 693752d8f65b..1f4ac1e93cee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2019 Intel Corporation + * Copyright (C) 2013-2014, 2018-2019, 2022 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH */ #include "mvm.h" @@ -31,7 +31,7 @@ static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION) { data->sta_vif_ap_sta_id = mvmvif->ap_sta_id; - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) data->sta_vif_state = SF_FULL_ON; else data->sta_vif_state = SF_INIT_OFF; @@ -261,7 +261,7 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif, return -EINVAL; if (changed_vif->type != NL80211_IFTYPE_STATION) { new_state = SF_UNINIT; - } else if (changed_vif->bss_conf.assoc && + } else if (changed_vif->cfg.assoc && changed_vif->bss_conf.dtim_period) { mvmvif = iwl_mvm_vif_from_mac80211(changed_vif); sta_id = mvmvif->ap_sta_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index bbb1522e7280..b296f4965895 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1948,7 +1948,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (vif->type == NL80211_IFTYPE_STATION && mvmvif->ap_sta_id == sta_id) { /* if associated - we can't remove the AP STA now */ - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) return ret; /* unassoc - go ahead - remove the AP STA now */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 4f0794a45bf5..ed8ba81a6043 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -160,7 +160,7 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, if (vif->type != NL80211_IFTYPE_STATION) return false; - if (!mvmvif->csa_bcn_pending && vif->bss_conf.assoc && + if (!mvmvif->csa_bcn_pending && vif->cfg.assoc && vif->bss_conf.dtim_period) return false; if (errmsg) @@ -176,7 +176,7 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, rcu_read_unlock(); } - if (vif->bss_conf.assoc) { + if (vif->cfg.assoc) { /* * When not associated, this will be called from * iwl_mvm_event_mlme_callback_ini() @@ -346,7 +346,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, te_data->vif, - !te_data->vif->bss_conf.assoc ? + !te_data->vif->cfg.assoc ? "Not associated and the time event is over already..." : "No beacon heard and the time event is over already..."); break; @@ -859,7 +859,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, vif, - !vif->bss_conf.assoc ? + !vif->cfg.assoc ? "Not associated and the session protection is over already..." : "No beacon heard and the session protection is over already..."); spin_lock_bh(&mvm->time_event_lock); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index bc947733d982..3ee5ea3484be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -604,7 +604,7 @@ static void iwl_mvm_sta_iface_iterator(void *_data, u8 *mac, if (vif->type != NL80211_IFTYPE_STATION) return; - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) data->assoc = true; } @@ -816,7 +816,7 @@ static void iwl_mvm_uapsd_agg_disconnect(struct iwl_mvm *mvm, if (vif->type != NL80211_IFTYPE_STATION) return; - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) return; if (!mvmvif->queue_params[IEEE80211_AC_VO].uapsd && diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index a3ca6620dc0c..a9dfe6a3da0d 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -480,8 +480,8 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev, p54_scan(priv, P54_SCAN_EXIT, 0); } if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc) { - priv->aid = info->aid; + if (vif->cfg.assoc) { + priv->aid = vif->cfg.aid; priv->wakeup_timer = info->beacon_int * info->dtim_period * 5; p54_setup_mac(priv); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5905803893b8..5aaf34f6f43b 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2118,9 +2118,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { wiphy_dbg(hw->wiphy, " ASSOC: assoc=%d aid=%d\n", - info->assoc, info->aid); - vp->assoc = info->assoc; - vp->aid = info->aid; + vif->cfg.assoc, vif->cfg.aid); + vp->assoc = vif->cfg.assoc; + vp->aid = vif->cfg.aid; } if (changed & BSS_CHANGED_BEACON_ENABLED) { diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 36c24d17136c..5f1bcfb5e3f6 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -3250,7 +3250,7 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); cmd->header.length = cpu_to_le16(sizeof(*cmd)); - cmd->aid = cpu_to_le16(vif->bss_conf.aid); + cmd->aid = cpu_to_le16(vif->cfg.aid); memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); if (vif->bss_conf.use_cts_prot) { @@ -5013,13 +5013,13 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* * No need to capture a beacon if we're no longer associated. */ - if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc) + if ((changed & BSS_CHANGED_ASSOC) && !vif->cfg.assoc) priv->capture_beacon = false; /* * Get the AP's legacy and MCS rates. */ - if (vif->bss_conf.assoc) { + if (vif->cfg.assoc) { struct ieee80211_sta *ap; rcu_read_lock(); @@ -5085,7 +5085,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } - if (vif->bss_conf.assoc && !priv->ap_fw && + if (vif->cfg.assoc && !priv->ap_fw && (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT))) { rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); @@ -5093,7 +5093,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } - if (vif->bss_conf.assoc && + if (vif->cfg.assoc && (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) { /* * Finalize the join. Tell rx handler to process diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 91425b454cae..1f14ecda1f55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -305,7 +305,7 @@ mt7603_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BSSID)) { - if (info->assoc || info->ibss_joined) { + if (vif->cfg.assoc || vif->cfg.ibss_joined) { mt76_wr(dev, MT_BSSID0(mvif->idx), get_unaligned_le32(info->bssid)); mt76_wr(dev, MT_BSSID1(mvif->idx), diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index a9c9b97d173e..d992fdea0f32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -616,7 +616,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) - mt7615_mac_set_beacon_filter(phy, vif, info->assoc); + mt7615_mac_set_beacon_filter(phy, vif, vif->cfg.assoc); mt7615_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 8fb6c9d735dc..f58376733c67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2530,7 +2530,7 @@ int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, u8 pad; } req = { .bss_idx = mvif->mt76.idx, - .aid = cpu_to_le16(vif->bss_conf.aid), + .aid = cpu_to_le16(vif->cfg.aid), .dtim_period = vif->bss_conf.dtim_period, .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index faa279bbbcb2..d3da54e6670b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -402,7 +402,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, else conn_type = CONNECTION_INFRA_AP; basic->conn_type = cpu_to_le32(conn_type); - basic->aid = cpu_to_le16(vif->bss_conf.aid); + basic->aid = cpu_to_le16(vif->cfg.aid); break; case NL80211_IFTYPE_ADHOC: basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); @@ -546,7 +546,7 @@ void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, if (sta) { if (vif->type == NL80211_IFTYPE_STATION) - generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); + generic->partial_aid = cpu_to_le16(vif->cfg.aid); else generic->partial_aid = cpu_to_le16(sta->aid); memcpy(generic->peer_addr, sta->addr, ETH_ALEN); @@ -2157,8 +2157,10 @@ int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev, struct mt76_vif *vif, struct ieee80211_bss_conf *info) { + struct ieee80211_vif *mvif = container_of(info, struct ieee80211_vif, + bss_conf); struct sk_buff *skb; - int i, len = min_t(int, info->arp_addr_cnt, + int i, len = min_t(int, mvif->cfg.arp_addr_cnt, IEEE80211_BSS_ARP_ADDR_LIST_LEN); struct { struct { @@ -2186,7 +2188,7 @@ int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev, skb_put_data(skb, &req_hdr, sizeof(req_hdr)); for (i = 0; i < len; i++) - skb_put_data(skb, &info->arp_addr_list[i], sizeof(__be32)); + skb_put_data(skb, &mvif->cfg.arp_addr_list[i], sizeof(__be32)); return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(OFFLOAD), true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 710ca757fb52..05327b0b6fc3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -593,7 +593,7 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - mt7915_mcu_add_bss_info(phy, vif, info->assoc); + mt7915_mcu_add_bss_info(phy, vif, vif->cfg.assoc); mt7915_mcu_add_obss_spr(dev, vif, info->he_obss_pd.enable); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 80279f342109..8532033794bd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -678,7 +678,7 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_ASSOC); if (dev->pm.enable) - mt7921_mcu_set_beacon_filter(dev, vif, info->assoc); + mt7921_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); } if (changed & BSS_CHANGED_ARP_FILTER) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 12bab18c4171..64fc400bd981 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1036,7 +1036,7 @@ mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, u8 pad; } req = { .bss_idx = mvif->mt76.idx, - .aid = cpu_to_le16(vif->bss_conf.aid), + .aid = cpu_to_le16(vif->cfg.aid), .dtim_period = vif->bss_conf.dtim_period, .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), }; diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index 8a00f6a75ca9..d4cd2215aba9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -1097,7 +1097,10 @@ static void mt7601u_phy_freq_cal(struct work_struct *work) void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, struct ieee80211_bss_conf *info) { - if (!info->assoc) + struct ieee80211_vif *vif = container_of(info, struct ieee80211_vif, + bss_conf); + + if (!vif->cfg.assoc) cancel_delayed_work_sync(&dev->freq_cal.work); /* Start/stop collecting beacon data */ @@ -1108,10 +1111,10 @@ void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, spin_unlock_bh(&dev->con_mon_lock); dev->freq_cal.freq = dev->ee->rf_freq_off; - dev->freq_cal.enabled = info->assoc; + dev->freq_cal.enabled = vif->cfg.assoc; dev->freq_cal.adjusting = false; - if (info->assoc) + if (vif->cfg.assoc) ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, MT_FREQ_CAL_INIT_DELAY); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c index 6bafdd991171..f895f560a185 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c @@ -70,6 +70,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, struct ieee80211_bss_conf *bss_conf, u32 changed) { + struct ieee80211_vif *vif = container_of(bss_conf, struct ieee80211_vif, + bss_conf); struct rt2x00lib_erp erp; memset(&erp, 0, sizeof(erp)); @@ -87,7 +89,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.beacon_int = bss_conf->beacon_int; /* Update the AID, this is needed for dynamic PS support */ - rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; + rt2x00dev->aid = vif->cfg.assoc ? vif->cfg.aid : 0; rt2x00dev->last_beacon = bss_conf->sync_tsf; /* Update global beacon interval time, this is needed for PS support */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index dea5babd30fe..660554a01894 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -645,7 +645,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_ASSOC) { rt2x00dev->link.count = 0; - if (bss_conf->assoc) + if (vif->cfg.assoc) rt2x00dev->intf_associated++; else rt2x00dev->intf_associated--; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 8b2ca9e8eac6..0239e12ec8a5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4570,11 +4570,11 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rarpt = &priv->ra_report; if (changed & BSS_CHANGED_ASSOC) { - dev_dbg(dev, "Changed ASSOC: %i!\n", bss_conf->assoc); + dev_dbg(dev, "Changed ASSOC: %i!\n", vif->cfg.assoc); rtl8xxxu_set_linktype(priv, vif->type); - if (bss_conf->assoc) { + if (vif->cfg.assoc) { u32 ramask; int sgi = 0; u8 highest_rate; @@ -4639,7 +4639,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /* joinbss sequence */ rtl8xxxu_write16(priv, REG_BCN_PSR_RPT, - 0xc000 | bss_conf->aid); + 0xc000 | vif->cfg.aid); priv->fops->report_connect(priv, 0, true); } else { @@ -5405,7 +5405,7 @@ void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) vif = priv->vif; btcoex = &priv->bt_coex; - wifi_connected = (vif && vif->bss_conf.assoc); + wifi_connected = (vif && vif->cfg.assoc); if (!wifi_connected) { rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); @@ -5431,7 +5431,7 @@ void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv) vif = priv->vif; btcoex = &priv->bt_coex; - wifi_connected = (vif && vif->bss_conf.assoc); + wifi_connected = (vif && vif->cfg.assoc); if (wifi_connected) { u32 val32 = 0; diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 99a1d91ced5a..5177eb02740e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1094,7 +1094,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { u8 mstatus; - if (bss_conf->assoc) { + if (vif->cfg.assoc) { struct ieee80211_sta *sta = NULL; u8 keep_alive = 10; @@ -1111,7 +1111,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, mac->link_state = MAC80211_LINKED; mac->cnt_after_linked = 0; - mac->assoc_id = bss_conf->aid; + mac->assoc_id = vif->cfg.aid; memcpy(mac->bssid, bss_conf->bssid, ETH_ALEN); if (rtlpriv->cfg->ops->linked_set_reg) diff --git a/drivers/net/wireless/realtek/rtw88/bf.c b/drivers/net/wireless/realtek/rtw88/bf.c index e76841d3417b..76c7f3257dd3 100644 --- a/drivers/net/wireless/realtek/rtw88/bf.c +++ b/drivers/net/wireless/realtek/rtw88/bf.c @@ -67,7 +67,7 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, ether_addr_copy(bfee->mac_addr, bssid); bfee->role = RTW_BFEE_MU; bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); - bfee->aid = bss_conf->aid; + bfee->aid = vif->cfg.aid; bfinfo->bfer_mu_cnt++; rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 4310362dc333..c5954c18862d 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -369,12 +369,12 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { rtw_vif_assoc_changed(rtwvif, conf); - if (conf->assoc) { + if (vif->cfg.assoc) { rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH); rtw_fw_download_rsvd_page(rtwdev); rtw_send_rsvd_page_h2c(rtwdev); - rtw_coex_media_status_notify(rtwdev, conf->assoc); + rtw_coex_media_status_notify(rtwdev, vif->cfg.assoc); if (rtw_bf_support) rtw_bf_assoc(rtwdev, vif, conf); rtw_store_op_chan(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index a44b1810165d..f78b9f28d5f6 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -171,7 +171,7 @@ static void rtw_vif_watch_dog_iter(void *data, u8 *mac, struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; if (vif->type == NL80211_IFTYPE_STATION) - if (vif->bss_conf.assoc) + if (vif->cfg.assoc) iter_data->rtwvif = rtwvif; rtw_dynamic_csi_rate(iter_data->rtwdev, rtwvif); @@ -525,8 +525,13 @@ EXPORT_SYMBOL(rtw_dump_reg); void rtw_vif_assoc_changed(struct rtw_vif *rtwvif, struct ieee80211_bss_conf *conf) { - if (conf && conf->assoc) { - rtwvif->aid = conf->aid; + struct ieee80211_vif *vif = NULL; + + if (conf) + vif = container_of(conf, struct ieee80211_vif, bss_conf); + + if (conf && vif->cfg.assoc) { + rtwvif->aid = vif->cfg.aid; rtwvif->net_type = RTW_NET_MGD_LINKED; } else { rtwvif->aid = 0; @@ -1591,7 +1596,7 @@ static void rtw_vif_smps_iter(void *data, u8 *mac, { struct rtw_dev *rtwdev = (struct rtw_dev *)data; - if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) return; if (rtwdev->hal.txrx_1ss) diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index db3c55f0ccd0..cfa939e26ffd 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -701,7 +701,7 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind); FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id); if (rtwvif->net_type == RTW89_NET_TYPE_INFRA) - FWCMD_SET_ADDR_AID12(cmd, vif->bss_conf.aid & 0xfff); + FWCMD_SET_ADDR_AID12(cmd, vif->cfg.aid & 0xfff); else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0); FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern); diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index d2f2a3d65ef6..bd7b66e98480 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1374,7 +1374,7 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev, if (aid == RTW89_TF_PAD) break; - if (aid == vif->bss_conf.aid) { + if (aid == vif->cfg.aid) { rtwvif->stats.rx_tf_acc++; rtwdev->stats.rx_tf_acc++; break; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 239d47d0ec6d..cf60adaed64a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3715,7 +3715,7 @@ void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; const struct rtw89_chip_info *chip = rtwdev->chip; - if (!vif->bss_conf.he_support || !vif->bss_conf.assoc) + if (!vif->bss_conf.he_support || !vif->cfg.assoc) return; if (chip->ops->set_txpwr_ul_tb_offset) diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 6d0c62c545a7..ac8b9bf2b0bb 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -345,7 +345,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, rtw89_leave_ps_mode(rtwdev); if (changed & BSS_CHANGED_ASSOC) { - if (conf->assoc) { + if (vif->cfg.assoc) { rtw89_station_mode_sta_assoc(rtwdev, vif, conf); rtw89_phy_set_bss_color(rtwdev, vif); rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 217aacb6e8c1..af89c011b0db 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -3630,7 +3630,7 @@ void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif enum rtw89_phy_idx phy_idx = RTW89_PHY_0; u8 bss_color; - if (!vif->bss_conf.he_support || !vif->bss_conf.assoc) + if (!vif->bss_conf.he_support || !vif->cfg.assoc) return; bss_color = vif->bss_conf.he_bss_color.color; @@ -3640,7 +3640,7 @@ void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_TGT, bss_color, phy_idx); rtw89_phy_write32_idx(rtwdev, R_BSS_CLR_MAP, B_BSS_CLR_MAP_STAID, - vif->bss_conf.aid, phy_idx); + vif->cfg.aid, phy_idx); } static void diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 6bfaab48b507..0f3a80f66b61 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -420,7 +420,8 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) rsi_hal_send_sta_notify_frame(common, RSI_IFTYPE_STATION, STA_CONNECTED, bss->bssid, - bss->qos, bss->aid, 0, + bss->qos, vif->cfg.aid, + 0, vif); } diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index dca81a4bbdd7..d3634ad986ac 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -295,7 +295,6 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) struct rsi_hw *adapter = common->priv; struct ieee80211_vif *vif; struct ieee80211_tx_info *info; - struct ieee80211_bss_conf *bss; int status = -EINVAL; if (!skb) @@ -307,11 +306,10 @@ int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) if (!info->control.vif) goto err; vif = info->control.vif; - bss = &vif->bss_conf; if (((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && - (!bss->assoc)) + (!vif->cfg.assoc)) goto err; status = rsi_send_pkt_to_bus(common, skb); @@ -367,7 +365,8 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, xtend_desc = (struct rsi_xtended_desc *)&skb->data[FRAME_DESC_SZ]; /* Indicate to firmware to give cfm for probe */ - if (ieee80211_is_probe_req(wh->frame_control) && !bss->assoc) { + if (ieee80211_is_probe_req(wh->frame_control) && + !info->control.vif->cfg.assoc) { rsi_dbg(INFO_ZONE, "%s: blocking mgmt queue\n", __func__); mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index f01e82b90c07..d4b3834388ab 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -237,7 +237,6 @@ static int rsi_mac80211_hw_scan_start(struct ieee80211_hw *hw, struct cfg80211_scan_request *scan_req = &hw_req->req; struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; - struct ieee80211_bss_conf *bss = &vif->bss_conf; rsi_dbg(INFO_ZONE, "***** Hardware scan start *****\n"); common->mac_ops_resumed = false; @@ -256,7 +255,7 @@ static int rsi_mac80211_hw_scan_start(struct ieee80211_hw *hw, /* If STA is not connected, return with special value 1, in order * to start sw_scan in mac80211 */ - if (!bss->assoc) + if (!vif->cfg.assoc) return 1; mutex_lock(&common->mutex); @@ -579,7 +578,6 @@ static int rsi_channel_change(struct ieee80211_hw *hw) struct ieee80211_channel *curchan = hw->conf.chandef.chan; u16 channel = curchan->hw_value; struct ieee80211_vif *vif; - struct ieee80211_bss_conf *bss; bool assoc = false; int i; @@ -593,8 +591,7 @@ static int rsi_channel_change(struct ieee80211_hw *hw) if (!vif) continue; if (vif->type == NL80211_IFTYPE_STATION) { - bss = &vif->bss_conf; - if (bss->assoc) { + if (vif->cfg.assoc) { assoc = true; break; } @@ -700,7 +697,7 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, } if ((vif->type == NL80211_IFTYPE_STATION || vif->type == NL80211_IFTYPE_P2P_CLIENT) && - (!sta_vif || vif->bss_conf.assoc)) + (!sta_vif || vif->cfg.assoc)) sta_vif = vif; } if (set_ps && sta_vif) { @@ -797,8 +794,8 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&common->mutex); if (changed & BSS_CHANGED_ASSOC) { rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", - __func__, bss_conf->assoc); - if (bss_conf->assoc) { + __func__, vif->cfg.assoc); + if (vif->cfg.assoc) { /* Send the RX filter frame */ rx_filter_word = (ALLOW_DATA_ASSOC_PEER | ALLOW_CTRL_ASSOC_PEER | @@ -807,17 +804,17 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, } rsi_inform_bss_status(common, RSI_OPMODE_STA, - bss_conf->assoc, + vif->cfg.assoc, bss_conf->bssid, bss_conf->qos, - bss_conf->aid, + vif->cfg.aid, NULL, 0, bss_conf->assoc_capability, vif); adapter->ps_info.dtim_interval_duration = bss->dtim_period; adapter->ps_info.listen_interval = conf->listen_interval; /* If U-APSD is updated, send ps parameters to firmware */ - if (bss->assoc) { + if (vif->cfg.assoc) { if (common->uapsd_bitmap) { rsi_dbg(INFO_ZONE, "Configuring UAPSD\n"); rsi_conf_uapsd(adapter, vif); @@ -1359,7 +1356,7 @@ static void rsi_fill_rx_status(struct ieee80211_hw *hw, if (!bss) return; /* CQM only for connected AP beacons, the RSSI is a weighted avg */ - if (bss->assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { + if (vif->cfg.assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { if (ieee80211_is_beacon(hdr->frame_control)) rsi_perform_cqm(common, hdr->addr2, rxs->signal, vif); } @@ -1737,7 +1734,7 @@ static void rsi_resume_conn_channel(struct rsi_common *common) } if (((vif->type == NL80211_IFTYPE_STATION) || (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && - vif->bss_conf.assoc) { + vif->cfg.assoc) { rsi_switch_channel(adapter, vif); break; } @@ -1862,17 +1859,15 @@ static u16 rsi_wow_map_triggers(struct rsi_common *common, int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) { struct rsi_common *common = adapter->priv; + struct ieee80211_vif *vif = adapter->vifs[0]; u16 triggers = 0; u16 rx_filter_word = 0; - struct ieee80211_bss_conf *bss = NULL; rsi_dbg(INFO_ZONE, "Config WoWLAN to device\n"); - if (!adapter->vifs[0]) + if (!vif) return -EINVAL; - bss = &adapter->vifs[0]->bss_conf; - if (WARN_ON(!wowlan)) { rsi_dbg(ERR_ZONE, "WoW triggers not enabled\n"); return -EINVAL; @@ -1884,7 +1879,7 @@ int rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) rsi_dbg(ERR_ZONE, "%s:No valid WoW triggers\n", __func__); return -EINVAL; } - if (!bss->assoc) { + if (!vif->cfg.assoc) { rsi_dbg(ERR_ZONE, "Cannot configure WoWLAN (Station not connected)\n"); common->wow_flags |= RSI_WOW_NO_CONNECTION; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index c14689266fec..1b309e47a1f1 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1635,7 +1635,6 @@ int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, struct ieee80211_vif *vif) { struct rsi_common *common = adapter->priv; - struct ieee80211_bss_conf *bss = &vif->bss_conf; struct rsi_request_ps *ps; struct rsi_ps_info *ps_info; struct sk_buff *skb; @@ -1669,7 +1668,7 @@ int rsi_send_ps_request(struct rsi_hw *adapter, bool enable, ps->ps_sleep.sleep_duration = cpu_to_le32(ps_info->deep_sleep_wakeup_period); - if (bss->assoc) + if (vif->cfg.assoc) ps->ps_sleep.connected_sleep = RSI_CONNECTED_SLEEP; else ps->ps_sleep.connected_sleep = RSI_DEEP_SLEEP; diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.c b/drivers/net/wireless/silabs/wfx/hif_tx.c index d35dd940d968..9402503fbde3 100644 --- a/drivers/net/wireless/silabs/wfx/hif_tx.c +++ b/drivers/net/wireless/silabs/wfx/hif_tx.c @@ -282,6 +282,8 @@ int wfx_hif_stop_scan(struct wfx_vif *wvif) int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, struct ieee80211_channel *channel, const u8 *ssid, int ssid_len) { + struct ieee80211_vif *vif = container_of(conf, struct ieee80211_vif, + bss_conf); int ret; struct wfx_hif_msg *hif; struct wfx_hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif); @@ -289,10 +291,10 @@ int wfx_hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, WARN_ON(!conf->beacon_int); WARN_ON(!conf->basic_rates); WARN_ON(sizeof(body->ssid) < ssid_len); - WARN(!conf->ibss_joined && !ssid_len, "joining an unknown BSS"); + WARN(!vif->cfg.ibss_joined && !ssid_len, "joining an unknown BSS"); if (!hif) return -ENOMEM; - body->infrastructure_bss_mode = !conf->ibss_joined; + body->infrastructure_bss_mode = !vif->cfg.ibss_joined; body->short_preamble = conf->use_short_preamble; body->probe_for_join = !(channel->flags & IEEE80211_CHAN_NO_IR); body->channel_number = channel->hw_value; @@ -417,6 +419,8 @@ int wfx_hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout) int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, const struct ieee80211_channel *channel) { + struct ieee80211_vif *vif = container_of(conf, struct ieee80211_vif, + bss_conf); int ret; struct wfx_hif_msg *hif; struct wfx_hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif); @@ -429,8 +433,8 @@ int wfx_hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, body->channel_number = channel->hw_value; body->beacon_interval = cpu_to_le32(conf->beacon_int); body->basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); - body->ssid_length = conf->ssid_len; - memcpy(body->ssid, conf->ssid, conf->ssid_len); + body->ssid_length = vif->cfg.ssid_len; + memcpy(body->ssid, vif->cfg.ssid, vif->cfg.ssid_len); wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body)); ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); kfree(hif); diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 329d7f4a2b2e..79fafe8143d9 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -156,7 +156,7 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) struct ieee80211_conf *conf = &wvif->wdev->hw->conf; struct ieee80211_vif *vif = wvif_to_vif(wvif); - WARN(!vif->bss_conf.assoc && enable_ps, + WARN(!vif->cfg.assoc && enable_ps, "enable_ps is reliable only if associated"); if (wdev_to_wvif(wvif->wdev, 0)) { struct wfx_vif *wvif_ch0 = wdev_to_wvif(wvif->wdev, 0); @@ -175,7 +175,7 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) /* It is useless to enable PS if channels are the same. */ if (enable_ps) *enable_ps = false; - if (vif->bss_conf.assoc && vif->bss_conf.ps) + if (vif->cfg.assoc && vif->bss_conf.ps) dev_info(wvif->wdev->dev, "ignoring requested PS mode"); return -1; } @@ -189,7 +189,7 @@ static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) } if (enable_ps) *enable_ps = vif->bss_conf.ps; - if (vif->bss_conf.assoc && vif->bss_conf.ps) + if (vif->cfg.assoc && vif->bss_conf.ps) return conf->dynamic_ps_timeout; else return -1; @@ -201,7 +201,7 @@ int wfx_update_pm(struct wfx_vif *wvif) int ps_timeout; bool ps; - if (!vif->bss_conf.assoc) + if (!vif->cfg.assoc) return 0; ps_timeout = wfx_get_ps_timeout(wvif, &ps); if (!ps) @@ -417,7 +417,7 @@ static void wfx_join(struct wfx_vif *wvif) bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, conf->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (!bss && !conf->ibss_joined) { + if (!bss && !vif->cfg.ibss_joined) { wfx_tx_unlock(wvif->wdev); return; } @@ -458,7 +458,7 @@ static void wfx_join_finalize(struct wfx_vif *wvif, struct ieee80211_bss_conf *i bool greenfield = false; rcu_read_lock(); /* protect sta */ - if (info->bssid && !info->ibss_joined) + if (info->bssid && !vif->cfg.ibss_joined) sta = ieee80211_find_sta(vif, info->bssid); if (sta && sta->deflink.ht_cap.ht_supported) ampdu_density = sta->deflink.ht_cap.ampdu_density; @@ -471,7 +471,7 @@ static void wfx_join_finalize(struct wfx_vif *wvif, struct ieee80211_bss_conf *i wfx_hif_set_association_mode(wvif, ampdu_density, greenfield, info->use_short_preamble); wfx_hif_keep_alive_period(wvif, 0); /* beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use the same value. */ - wfx_hif_set_bss_params(wvif, info->aid, 7); + wfx_hif_set_bss_params(wvif, vif->cfg.aid, 7); wfx_hif_set_beacon_wakeup_period(wvif, 1, 1); wfx_update_pm(wvif); } @@ -522,9 +522,9 @@ void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc || info->ibss_joined) + if (vif->cfg.assoc || vif->cfg.ibss_joined) wfx_join_finalize(wvif, info); - else if (!info->assoc && vif->type == NL80211_IFTYPE_STATION) + else if (!vif->cfg.assoc && vif->type == NL80211_IFTYPE_STATION) wfx_reset(wvif); else dev_warn(wdev->dev, "misunderstood change: ASSOC\n"); @@ -540,11 +540,11 @@ void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_ARP_FILTER) { for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) { - __be32 *arp_addr = &info->arp_addr_list[i]; + __be32 *arp_addr = &vif->cfg.arp_addr_list[i]; - if (info->arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) + if (vif->cfg.arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) arp_addr = NULL; - if (i >= info->arp_addr_cnt) + if (i >= vif->cfg.arp_addr_cnt) arp_addr = NULL; wfx_hif_set_arp_ipv4_filter(wvif, i, arp_addr); } diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 321df124d449..3f48def51ebc 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -1208,8 +1208,8 @@ static void cw1200_do_join(struct cw1200_common *priv) struct cfg80211_bss *bss = NULL; struct wsm_protected_mgmt_policy mgmt_policy; struct wsm_join join = { - .mode = conf->ibss_joined ? - WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, + .mode = priv->vif->cfg.ibss_joined ? + WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, .preamble_type = WSM_JOIN_PREAMBLE_LONG, .probe_for_join = 1, .atim_window = 0, @@ -1230,7 +1230,7 @@ static void cw1200_do_join(struct cw1200_common *priv) bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (!bss && !conf->ibss_joined) { + if (!bss && !priv->vif->cfg.ibss_joined) { wsm_unlock_tx(priv); return; } @@ -1284,7 +1284,7 @@ static void cw1200_do_join(struct cw1200_common *priv) join.bssid, join.dtim_period, priv->beacon_int); - if (!conf->ibss_joined) { + if (!priv->vif->cfg.ibss_joined) { const u8 *ssidie; rcu_read_lock(); ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); @@ -1302,7 +1302,7 @@ static void cw1200_do_join(struct cw1200_common *priv) } /* Enable asynchronous join calls */ - if (!conf->ibss_joined) { + if (!priv->vif->cfg.ibss_joined) { join.flags |= WSM_JOIN_FLAGS_FORCE; join.flags |= WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND; } @@ -1813,15 +1813,15 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, int i; pr_debug("[STA] BSS_CHANGED_ARP_FILTER cnt: %d\n", - info->arp_addr_cnt); + vif->cfg.arp_addr_cnt); /* Currently only one IP address is supported by firmware. * In case of more IPs arp filtering will be disabled. */ - if (info->arp_addr_cnt > 0 && - info->arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { - for (i = 0; i < info->arp_addr_cnt; i++) { - filter.ipv4addrs[i] = info->arp_addr_list[i]; + if (vif->cfg.arp_addr_cnt > 0 && + vif->cfg.arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { + for (i = 0; i < vif->cfg.arp_addr_cnt; i++) { + filter.ipv4addrs[i] = vif->cfg.arp_addr_list[i]; pr_debug("[STA] addr[%d]: 0x%X\n", i, filter.ipv4addrs[i]); } @@ -1857,7 +1857,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, if (changed & BSS_CHANGED_BEACON_INT) { pr_debug("CHANGED_BEACON_INT\n"); - if (info->ibss_joined) + if (vif->cfg.ibss_joined) do_join = true; else if (priv->join_status == CW1200_JOIN_STATUS_AP) cw1200_update_beaconing(priv); @@ -1882,7 +1882,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, BSS_CHANGED_BASIC_RATES | BSS_CHANGED_HT)) { pr_debug("BSS_CHANGED_ASSOC\n"); - if (info->assoc) { + if (vif->cfg.assoc) { if (priv->join_status < CW1200_JOIN_STATUS_PRE_STA) { ieee80211_connection_loss(vif); mutex_unlock(&priv->conf_mutex); @@ -1894,7 +1894,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, do_join = true; } - if (info->assoc || info->ibss_joined) { + if (vif->cfg.assoc || vif->cfg.ibss_joined) { struct ieee80211_sta *sta = NULL; __le32 htprot = 0; @@ -1904,7 +1904,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, rcu_read_lock(); - if (info->bssid && !info->ibss_joined) + if (info->bssid && !vif->cfg.ibss_joined) sta = ieee80211_find_sta(vif, info->bssid); if (sta) { priv->ht_info.ht_cap = sta->deflink.ht_cap; @@ -1958,7 +1958,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, cancel_work_sync(&priv->unjoin_work); priv->bss_params.beacon_lost_count = priv->cqm_beacon_loss_count; - priv->bss_params.aid = info->aid; + priv->bss_params.aid = vif->cfg.aid; if (priv->join_dtim_period < 1) priv->join_dtim_period = 1; @@ -1973,7 +1973,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev, priv->association_mode.basic_rate_set); wsm_set_association_mode(priv, &priv->association_mode); - if (!info->ibss_joined) { + if (!vif->cfg.ibss_joined) { wsm_keep_alive_period(priv, 30 /* sec */); wsm_set_bss_params(priv, &priv->bss_params); priv->setbssparams_done = true; @@ -2330,8 +2330,8 @@ static int cw1200_start_ap(struct cw1200_common *priv) memset(start.ssid, 0, sizeof(start.ssid)); if (!conf->hidden_ssid) { - start.ssid_len = conf->ssid_len; - memcpy(start.ssid, conf->ssid, start.ssid_len); + start.ssid_len = priv->vif->cfg.ssid_len; + memcpy(start.ssid, priv->vif->cfg.ssid, start.ssid_len); } priv->beacon_int = conf->beacon_int; diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index 7de666b90ff5..fde21fca6c5e 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -1183,8 +1183,8 @@ void cw1200_rx_cb(struct cw1200_common *priv, /* Disable beacon filter once we're associated... */ if (priv->disable_beacon_filter && - (priv->vif->bss_conf.assoc || - priv->vif->bss_conf.ibss_joined)) { + (priv->vif->cfg.assoc || + priv->vif->cfg.ibss_joined)) { priv->disable_beacon_filter = false; queue_work(priv->workqueue, &priv->update_filtering_work); diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index a25a6143e65f..bdc93c4f54ba 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1123,7 +1123,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { + if (vif->cfg.assoc) { wl->beacon_int = bss_conf->beacon_int; skb = ieee80211_pspoll_get(wl->hw, wl->vif); @@ -1137,7 +1137,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, if (ret < 0) goto out_sleep; - ret = wl1251_acx_aid(wl, bss_conf->aid); + ret = wl1251_acx_aid(wl, vif->cfg.aid); if (ret < 0) goto out_sleep; } else { @@ -1176,10 +1176,10 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ARP_FILTER) { - __be32 addr = bss_conf->arp_addr_list[0]; + __be32 addr = vif->cfg.arp_addr_list[0]; WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); - enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc; + enable = vif->cfg.arp_addr_cnt == 1 && vif->cfg.assoc; ret = wl1251_acx_arp_ip_filter(wl, enable, addr); if (ret < 0) goto out_sleep; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index df6029ef6304..138edd28b0de 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -675,8 +675,8 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif) memcpy(cmd->ap.ssid, wlvif->ssid, wlvif->ssid_len); } else { cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; - cmd->ap.ssid_len = bss_conf->ssid_len; - memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); + cmd->ap.ssid_len = vif->cfg.ssid_len; + memcpy(cmd->ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); } supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES | diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 21a9e3b0cbac..ad9560bd9512 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -2904,10 +2904,12 @@ static int wlcore_set_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct ieee80211_bss_conf *bss_conf, u32 sta_rate_set) { + struct ieee80211_vif *vif = container_of(bss_conf, struct ieee80211_vif, + bss_conf); int ieoffset; int ret; - wlvif->aid = bss_conf->aid; + wlvif->aid = vif->cfg.aid; wlvif->channel_type = cfg80211_get_chandef_type(&bss_conf->chandef); wlvif->beacon_int = bss_conf->beacon_int; wlvif->wmm_enabled = bss_conf->qos; @@ -3935,7 +3937,6 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, u32 rates) { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; int ssid_ie_offset, ie_offset, templ_len; const u8 *ptr; @@ -3948,7 +3949,7 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, probe_rsp_len, 0, rates); - if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { + if (probe_rsp_len + vif->cfg.ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { wl1271_error("probe_rsp template too big"); return -EINVAL; } @@ -3970,12 +3971,12 @@ static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl, /* insert SSID from bss_conf */ probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID; - probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len; + probe_rsp_templ[ssid_ie_offset + 1] = vif->cfg.ssid_len; memcpy(probe_rsp_templ + ssid_ie_offset + 2, - bss_conf->ssid, bss_conf->ssid_len); - templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len; + vif->cfg.ssid, vif->cfg.ssid_len); + templ_len = ssid_ie_offset + 2 + vif->cfg.ssid_len; - memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len, + memcpy(probe_rsp_templ + ssid_ie_offset + 2 + vif->cfg.ssid_len, ptr, probe_rsp_len - (ptr - probe_rsp_data)); templ_len += probe_rsp_len - (ptr - probe_rsp_data); @@ -4255,15 +4256,15 @@ out: } static int wlcore_set_bssid(struct wl1271 *wl, struct wl12xx_vif *wlvif, - struct ieee80211_bss_conf *bss_conf, - u32 sta_rate_set) + struct ieee80211_vif *vif, u32 sta_rate_set) { + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u32 rates; int ret; wl1271_debug(DEBUG_MAC80211, "changed_bssid: %pM, aid: %d, bcn_int: %d, brates: 0x%x sta_rate_set: 0x%x", - bss_conf->bssid, bss_conf->aid, + bss_conf->bssid, vif->cfg.aid, bss_conf->beacon_int, bss_conf->basic_rates, sta_rate_set); @@ -4351,7 +4352,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } if (changed & BSS_CHANGED_IBSS) { - if (bss_conf->ibss_joined) { + if (vif->cfg.ibss_joined) { set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags); ibss_joined = true; } else { @@ -4375,7 +4376,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } if (changed & BSS_CHANGED_IDLE && !is_ibss) - wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle); + wl1271_sta_handle_idle(wl, wlvif, vif->cfg.idle); if (changed & BSS_CHANGED_CQM) { bool enable = false; @@ -4411,7 +4412,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (changed & BSS_CHANGED_BSSID) { if (!is_zero_ether_addr(bss_conf->bssid)) { - ret = wlcore_set_bssid(wl, wlvif, bss_conf, + ret = wlcore_set_bssid(wl, wlvif, vif, sta_rate_set); if (ret < 0) goto out; @@ -4427,9 +4428,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (changed & BSS_CHANGED_IBSS) { wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d", - bss_conf->ibss_joined); + vif->cfg.ibss_joined); - if (bss_conf->ibss_joined) { + if (vif->cfg.ibss_joined) { u32 rates = bss_conf->basic_rates; wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, @@ -4466,7 +4467,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, } if (changed & BSS_CHANGED_ASSOC) { - if (bss_conf->assoc) { + if (vif->cfg.assoc) { ret = wlcore_set_assoc(wl, wlvif, bss_conf, sta_rate_set); if (ret < 0) @@ -4541,11 +4542,11 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, /* Handle arp filtering. Done after join. */ if ((changed & BSS_CHANGED_ARP_FILTER) || (!is_ibss && (changed & BSS_CHANGED_QOS))) { - __be32 addr = bss_conf->arp_addr_list[0]; + __be32 addr = vif->cfg.arp_addr_list[0]; wlvif->sta.qos = bss_conf->qos; WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); - if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) { + if (vif->cfg.arp_addr_cnt == 1 && vif->cfg.assoc) { wlvif->ip_addr = addr; /* * The template should have been configured only upon diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index afaf331fe125..8c5de30478ec 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -979,7 +979,7 @@ static void vnt_check_bb_vga(struct vnt_private *priv) if (priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) return; - if (!(priv->vif->bss_conf.assoc && priv->current_rssi)) + if (!(priv->vif->cfg.assoc && priv->current_rssi)) return; RFvRSSITodBm(priv, (u8)priv->current_rssi, &dbm); @@ -1399,7 +1399,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, { struct vnt_private *priv = hw->priv; - priv->current_aid = conf->aid; + priv->current_aid = vif->cfg.aid; if (changed & BSS_CHANGED_BSSID && conf->bssid) { unsigned long flags; @@ -1468,7 +1468,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) && priv->op_mode != NL80211_IFTYPE_AP) { - if (conf->assoc && conf->beacon_rate) { + if (vif->cfg.assoc && conf->beacon_rate) { CARDbUpdateTSF(priv, conf->beacon_rate->hw_value, conf->sync_tsf); diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index ae7f5916d4d6..3ab8a7bb9715 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -749,7 +749,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, { struct vnt_private *priv = hw->priv; - priv->current_aid = conf->aid; + priv->current_aid = vif->cfg.aid; if (changed & BSS_CHANGED_BSSID && conf->bssid) vnt_mac_set_bssid_addr(priv, (u8 *)conf->bssid); @@ -811,7 +811,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) && priv->op_mode != NL80211_IFTYPE_AP) { - if (conf->assoc && conf->beacon_rate) { + if (vif->cfg.assoc && conf->beacon_rate) { u16 ps_beacon_int = conf->beacon_int; if (conf->dtim_period) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e3ded46f70ac..1520922d21a5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -526,11 +526,6 @@ struct ieee80211_fils_discovery { * mode only, set if the AP advertises TWT responder role) * @twt_protected: does this BSS support protected TWT frames * @twt_broadcast: does this BSS support broadcast TWT - * @assoc: association status - * @ibss_joined: indicates whether this station is part of an IBSS - * or not - * @ibss_creator: indicates if a new IBSS network is being created - * @aid: association ID number, valid only when @assoc is true * @use_cts_prot: use CTS protection * @use_short_preamble: use 802.11b short preamble * @use_short_slot: use short slot time (only relevant for ERP) @@ -551,6 +546,8 @@ struct ieee80211_fils_discovery { * IMPORTANT: These three sync_* parameters would possibly be out of sync * by the time the driver will use them. The synchronized view is currently * guaranteed only in certain callbacks. + * Note also that this is not used with MLD associations, mac80211 doesn't + * know how to track beacons for all of the links for this. * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp * @basic_rates: bitmap of basic rates, each bit stands for an @@ -576,21 +573,9 @@ struct ieee80211_fils_discovery { * threshold event and can't be enabled simultaneously with it. * @cqm_rssi_high: Connection quality monitor RSSI upper threshold. * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis - * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The - * may filter ARP queries targeted for other addresses than listed here. - * The driver must allow ARP queries targeted for all address listed here - * to pass through. An empty list implies no ARP queries need to pass. - * @arp_addr_cnt: Number of addresses currently on the list. Note that this - * may be larger than %IEEE80211_BSS_ARP_ADDR_LIST_LEN (the arp_addr_list - * array size), it's up to the driver what to do in that case. * @qos: This is a QoS-enabled BSS. - * @idle: This interface is idle. There's also a global idle flag in the - * hardware config which may be more appropriate depending on what - * your driver/device needs to do. * @ps: power-save mode (STA only). This flag is NOT affected by * offchannel/dynamic_ps operations. - * @ssid: The SSID of the current vif. Valid in AP and IBSS mode. - * @ssid_len: Length of SSID given in @ssid. * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. * @txpower: TX power in dBm. INT_MIN means not configured. * @txpower_type: TX power adjustment used to control per packet Transmit @@ -628,7 +613,6 @@ struct ieee80211_fils_discovery { * @fils_discovery: FILS discovery configuration * @unsol_bcast_probe_resp_interval: Unsolicited broadcast probe response * interval. - * @s1g: BSS is S1G BSS (affects Association Request format). * @beacon_tx_rate: The configured beacon transmit rate that needs to be passed * to driver when rate control is offloaded to firmware. * @power_type: power type of BSS for 6 GHz @@ -661,10 +645,6 @@ struct ieee80211_bss_conf { bool twt_responder; bool twt_protected; bool twt_broadcast; - /* association related data */ - bool assoc, ibss_joined; - bool ibss_creator; - u16 aid; /* erp related data */ bool use_cts_prot; bool use_short_preamble; @@ -686,13 +666,8 @@ struct ieee80211_bss_conf { s32 cqm_rssi_high; struct cfg80211_chan_def chandef; struct ieee80211_mu_group_data mu_group; - __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; - int arp_addr_cnt; bool qos; - bool idle; bool ps; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; bool hidden_ssid; int txpower; enum nl80211_tx_power_setting txpower_type; @@ -717,7 +692,6 @@ struct ieee80211_bss_conf { struct cfg80211_he_bss_color he_bss_color; struct ieee80211_fils_discovery fils_discovery; u32 unsol_bcast_probe_resp_interval; - bool s1g; struct cfg80211_bitrate_mask beacon_tx_rate; enum ieee80211_ap_reg_power power_type; struct ieee80211_tx_pwr_env tx_pwr_env[IEEE80211_TPE_MAX_IE_COUNT]; @@ -1721,6 +1695,40 @@ enum ieee80211_offload_flags { IEEE80211_OFFLOAD_DECAP_ENABLED = BIT(2), }; +/** + * struct ieee80211_vif_cfg - interface configuration + * @assoc: association status + * @ibss_joined: indicates whether this station is part of an IBSS or not + * @ibss_creator: indicates if a new IBSS network is being created + * @aid: association ID number, valid only when @assoc is true + * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The + * may filter ARP queries targeted for other addresses than listed here. + * The driver must allow ARP queries targeted for all address listed here + * to pass through. An empty list implies no ARP queries need to pass. + * @arp_addr_cnt: Number of addresses currently on the list. Note that this + * may be larger than %IEEE80211_BSS_ARP_ADDR_LIST_LEN (the arp_addr_list + * array size), it's up to the driver what to do in that case. + * @ssid: The SSID of the current vif. Valid in AP and IBSS mode. + * @ssid_len: Length of SSID given in @ssid. + * @s1g: BSS is S1G BSS (affects Association Request format). + * @idle: This interface is idle. There's also a global idle flag in the + * hardware config which may be more appropriate depending on what + * your driver/device needs to do. + */ +struct ieee80211_vif_cfg { + /* association related data */ + bool assoc, ibss_joined; + bool ibss_creator; + u16 aid; + + __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; + int arp_addr_cnt; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + size_t ssid_len; + bool s1g; + bool idle; +}; + /** * struct ieee80211_vif - per-interface data * @@ -1728,6 +1736,7 @@ enum ieee80211_offload_flags { * use during the life of a virtual interface. * * @type: type of this virtual interface + * @cfg: vif configuration, see &struct ieee80211_vif_cfg * @bss_conf: BSS configuration for this interface, either our own * or the BSS we're associated to * @addr: address of this interface @@ -1762,6 +1771,7 @@ enum ieee80211_offload_flags { */ struct ieee80211_vif { enum nl80211_iftype type; + struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; u8 addr[ETH_ALEN] __aligned(2); bool p2p; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8a15c71e7c7d..fd57bad38681 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1216,12 +1216,12 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, sdata->vif.bss_conf.twt_responder = params->twt_responder; sdata->vif.bss_conf.he_obss_pd = params->he_obss_pd; sdata->vif.bss_conf.he_bss_color = params->beacon.he_bss_color; - sdata->vif.bss_conf.s1g = params->chandef.chan->band == + sdata->vif.cfg.s1g = params->chandef.chan->band == NL80211_BAND_S1GHZ; - sdata->vif.bss_conf.ssid_len = params->ssid_len; + sdata->vif.cfg.ssid_len = params->ssid_len; if (params->ssid_len) - memcpy(sdata->vif.bss_conf.ssid, params->ssid, + memcpy(sdata->vif.cfg.ssid, params->ssid, params->ssid_len); sdata->vif.bss_conf.hidden_ssid = (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); @@ -1405,7 +1405,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, sdata->vif.bss_conf.enable_beacon = false; sdata->beacon_rate_set = false; - sdata->vif.bss_conf.ssid_len = 0; + sdata->vif.cfg.ssid_len = 0; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); @@ -3488,7 +3488,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, break; case NL80211_IFTYPE_ADHOC: - if (!sdata->vif.bss_conf.ibss_joined) + if (!sdata->vif.cfg.ibss_joined) return -EINVAL; if (params->chandef.width != sdata->u.ibss.chandef.width) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index eea400902133..deb358eef9d0 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -783,7 +783,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, out: rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); - sdata->vif.bss_conf.idle = !conf; + sdata->vif.cfg.idle = !conf; if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) { ieee80211_recalc_chanctx_chantype(local, curr_ctx); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index cf71484658c6..59b33de0f3b0 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2006 Jiri Benc * Copyright 2007 Johannes Berg - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2022 Intel Corporation */ #include @@ -233,7 +233,7 @@ IEEE80211_IF_FILE_R(hw_queues); /* STA attributes */ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); -IEEE80211_IF_FILE(aid, vif.bss_conf.aid, DEC); +IEEE80211_IF_FILE(aid, vif.cfg.aid, DEC); IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS); static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, @@ -366,7 +366,7 @@ IEEE80211_IF_FILE_W(tkip_mic_test); static ssize_t ieee80211_if_parse_beacon_loss( struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) { - if (!ieee80211_sdata_running(sdata) || !sdata->vif.bss_conf.assoc) + if (!ieee80211_sdata_running(sdata) || !sdata->vif.cfg.assoc) return -ENOTCONN; ieee80211_beacon_loss(&sdata->vif); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8ff547ff351e..afb5982a1d42 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -244,9 +244,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sta_info_flush(sdata); /* if merging, indicate to driver that we leave the old IBSS */ - if (sdata->vif.bss_conf.ibss_joined) { - sdata->vif.bss_conf.ibss_joined = false; - sdata->vif.bss_conf.ibss_creator = false; + if (sdata->vif.cfg.ibss_joined) { + sdata->vif.cfg.ibss_joined = false; + sdata->vif.cfg.ibss_creator = false; sdata->vif.bss_conf.enable_beacon = false; netif_carrier_off(sdata->dev); ieee80211_bss_info_change_notify(sdata, @@ -326,8 +326,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.enable_beacon = true; sdata->vif.bss_conf.beacon_int = beacon_int; sdata->vif.bss_conf.basic_rates = basic_rates; - sdata->vif.bss_conf.ssid_len = ifibss->ssid_len; - memcpy(sdata->vif.bss_conf.ssid, ifibss->ssid, ifibss->ssid_len); + sdata->vif.cfg.ssid_len = ifibss->ssid_len; + memcpy(sdata->vif.cfg.ssid, ifibss->ssid, ifibss->ssid_len); bss_change = BSS_CHANGED_BEACON_INT; bss_change |= ieee80211_reset_erp_info(sdata); bss_change |= BSS_CHANGED_BSSID; @@ -359,15 +359,15 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, ieee80211_set_wmm_default(sdata, true, false); - sdata->vif.bss_conf.ibss_joined = true; - sdata->vif.bss_conf.ibss_creator = creator; + sdata->vif.cfg.ibss_joined = true; + sdata->vif.cfg.ibss_creator = creator; err = drv_join_ibss(local, sdata); if (err) { - sdata->vif.bss_conf.ibss_joined = false; - sdata->vif.bss_conf.ibss_creator = false; + sdata->vif.cfg.ibss_joined = false; + sdata->vif.cfg.ibss_creator = false; sdata->vif.bss_conf.enable_beacon = false; - sdata->vif.bss_conf.ssid_len = 0; + sdata->vif.cfg.ssid_len = 0; RCU_INIT_POINTER(ifibss->presp, NULL); kfree_rcu(presp, rcu_head); mutex_lock(&local->mtx); @@ -708,10 +708,10 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) netif_carrier_off(sdata->dev); - sdata->vif.bss_conf.ibss_joined = false; - sdata->vif.bss_conf.ibss_creator = false; + sdata->vif.cfg.ibss_joined = false; + sdata->vif.cfg.ibss_creator = false; sdata->vif.bss_conf.enable_beacon = false; - sdata->vif.bss_conf.ssid_len = 0; + sdata->vif.cfg.ssid_len = 0; /* remove beacon */ presp = rcu_dereference_protected(ifibss->presp, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 9e0e71ca8068..cce0a9aad2cd 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1642,7 +1642,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, sdata->control_port_no_encrypt = false; sdata->control_port_over_nl80211 = false; sdata->control_port_no_preauth = false; - sdata->vif.bss_conf.idle = true; + sdata->vif.cfg.idle = true; sdata->vif.bss_conf.txpower = INT_MIN; /* unset */ sdata->noack_map = 0; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ebde131efcaa..0c81ae492df4 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -349,7 +349,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, struct wireless_dev *wdev = ndev->ieee80211_ptr; struct in_device *idev; struct ieee80211_sub_if_data *sdata; - struct ieee80211_bss_conf *bss_conf; + struct ieee80211_vif_cfg *vif_cfg; struct ieee80211_if_managed *ifmgd; int c = 0; @@ -361,7 +361,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, return NOTIFY_DONE; sdata = IEEE80211_DEV_TO_SUB_IF(ndev); - bss_conf = &sdata->vif.bss_conf; + vif_cfg = &sdata->vif.cfg; /* ARP filtering is only supported in managed mode */ if (sdata->vif.type != NL80211_IFTYPE_STATION) @@ -374,16 +374,16 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, ifmgd = &sdata->u.mgd; sdata_lock(sdata); - /* Copy the addresses to the bss_conf list */ + /* Copy the addresses to the vif config list */ ifa = rtnl_dereference(idev->ifa_list); while (ifa) { if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN) - bss_conf->arp_addr_list[c] = ifa->ifa_address; + vif_cfg->arp_addr_list[c] = ifa->ifa_address; ifa = rtnl_dereference(ifa->ifa_next); c++; } - bss_conf->arp_addr_cnt = c; + vif_cfg->arp_addr_cnt = c; /* Configure driver only if associated (which also implies it is up) */ if (ifmgd->associated) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c526af66ff8d..4a792e88568d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2258,6 +2258,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss *bss = (void *)cbss->priv; struct ieee80211_local *local = sdata->local; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; bss_info_changed |= BSS_CHANGED_ASSOC; bss_info_changed |= ieee80211_handle_bss_capability(sdata, @@ -2317,7 +2318,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_conf->dtim_period = 0; } - bss_conf->assoc = 1; + vif_cfg->assoc = 1; /* Tell the driver to monitor connection quality (if supported) */ if (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI && @@ -2325,7 +2326,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_info_changed |= BSS_CHANGED_CQM; /* Enable ARP filtering */ - if (bss_conf->arp_addr_cnt) + if (vif_cfg->arp_addr_cnt) bss_info_changed |= BSS_CHANGED_ARP_FILTER; ieee80211_bss_info_change_notify(sdata, bss_info_changed); @@ -2419,7 +2420,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, /* clear bssid only after building the needed mgmt frames */ eth_zero_addr(ifmgd->bssid); - sdata->vif.bss_conf.ssid_len = 0; + sdata->vif.cfg.ssid_len = 0; /* remove AP and TDLS peers */ sta_info_flush(sdata); @@ -2429,7 +2430,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ieee80211_led_assoc(local, 0); changed |= BSS_CHANGED_ASSOC; - sdata->vif.bss_conf.assoc = false; + sdata->vif.cfg.assoc = false; ifmgd->p2p_noa_index = -1; memset(&sdata->vif.bss_conf.p2p_noa_attr, 0, @@ -2455,7 +2456,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, cancel_work_sync(&local->dynamic_ps_enable_work); /* Disable ARP filtering */ - if (sdata->vif.bss_conf.arp_addr_cnt) + if (sdata->vif.cfg.arp_addr_cnt) changed |= BSS_CHANGED_ARP_FILTER; sdata->vif.bss_conf.qos = false; @@ -2642,8 +2643,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) ieee80211_send_nullfunc(sdata->local, sdata, false); } else { ieee80211_mlme_send_probe_req(sdata, sdata->vif.addr, dst, - sdata->vif.bss_conf.ssid, - sdata->vif.bss_conf.ssid_len, + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len, ifmgd->assoc_bss->channel); } @@ -3425,7 +3426,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, goto out; } - sdata->vif.bss_conf.aid = aid; + sdata->vif.cfg.aid = aid; ifmgd->tdls_chan_switch_prohibited = elems->ext_capab && elems->ext_capab_len >= 5 && (elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED); @@ -4102,6 +4103,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; struct ieee80211_mgmt *mgmt = (void *) hdr; size_t baselen; struct ieee802_11_elems *elems; @@ -4226,7 +4228,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ncrc = elems->crc; if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && - ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) { + ieee80211_check_tim(elems->tim, elems->tim_len, vif_cfg->aid)) { if (local->hw.conf.dynamic_ps_timeout > 0) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { local->hw.conf.flags &= ~IEEE80211_CONF_PS; @@ -5877,7 +5879,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_assoc_data *assoc_data; const struct cfg80211_bss_ies *beacon_ies; struct ieee80211_supported_band *sband; - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_vif_cfg *vif_cfg = &sdata->vif.cfg; const struct element *ssid_elem, *ht_elem, *vht_elem; int i, err; bool override = false; @@ -5895,8 +5897,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } memcpy(assoc_data->ssid, ssid_elem->data, ssid_elem->datalen); assoc_data->ssid_len = ssid_elem->datalen; - memcpy(bss_conf->ssid, assoc_data->ssid, assoc_data->ssid_len); - bss_conf->ssid_len = assoc_data->ssid_len; + memcpy(vif_cfg->ssid, assoc_data->ssid, assoc_data->ssid_len); + vif_cfg->ssid_len = assoc_data->ssid_len; rcu_read_unlock(); if (ifmgd->associated) { diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index a1fbd562cac1..7da6b49598ab 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -785,7 +785,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, switch (sdata->vif.type) { case NL80211_IFTYPE_ADHOC: - if (!sdata->vif.bss_conf.ibss_joined) + if (!sdata->vif.cfg.ibss_joined) need_offchan = true; #ifdef CONFIG_MAC80211_MESH fallthrough; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index b698756887eb..f80284eee055 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -177,7 +177,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, rcu_read_lock(); scan_sdata = rcu_dereference(local->scan_sdata); if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION && - scan_sdata->vif.bss_conf.assoc && + scan_sdata->vif.cfg.assoc && ieee80211_have_rx_timestamp(rx_status)) { bss_meta.parent_tsf = ieee80211_calculate_rx_timestamp(local, rx_status, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index fa04021d4c0f..7eb6d8c4f25c 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -230,7 +230,7 @@ ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) *pos++ = WLAN_EID_AID; *pos++ = 2; /* len */ - put_unaligned_le16(sdata->vif.bss_conf.aid, pos); + put_unaligned_le16(sdata->vif.cfg.aid, pos); } /* translate numbering in the WMM parameter IE to the mac80211 notation */ @@ -1444,7 +1444,7 @@ void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) { + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) { sdata_err(sdata, "Discarding TDLS oper %d - not STA or disconnected\n", oper); return; diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 743adfbb9b15..74ef7e71e1ef 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1,9 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* -* Portions of this file -* Copyright(c) 2016-2017 Intel Deutschland GmbH -* Copyright (C) 2018 - 2021 Intel Corporation -*/ + * Portions of this file + * Copyright(c) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2018 - 2022 Intel Corporation + */ #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) #define __MAC80211_DRIVER_TRACE @@ -425,14 +425,14 @@ TRACE_EVENT(drv_bss_info_changed, __field(u32, channel_cfreq1) __field(u32, channel_cfreq1_offset) __dynamic_array(u32, arp_addr_list, - info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? + sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? IEEE80211_BSS_ARP_ADDR_LIST_LEN : - info->arp_addr_cnt) + sdata->vif.cfg.arp_addr_cnt) __field(int, arp_addr_cnt) __field(bool, qos) __field(bool, idle) __field(bool, ps) - __dynamic_array(u8, ssid, info->ssid_len) + __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) __field(bool, hidden_ssid) __field(int, txpower) __field(u8, p2p_oppps_ctwindow) @@ -442,10 +442,10 @@ TRACE_EVENT(drv_bss_info_changed, LOCAL_ASSIGN; VIF_ASSIGN; __entry->changed = changed; - __entry->aid = info->aid; - __entry->assoc = info->assoc; - __entry->ibss_joined = info->ibss_joined; - __entry->ibss_creator = info->ibss_creator; + __entry->aid = sdata->vif.cfg.aid; + __entry->assoc = sdata->vif.cfg.assoc; + __entry->ibss_joined = sdata->vif.cfg.ibss_joined; + __entry->ibss_creator = sdata->vif.cfg.ibss_creator; __entry->shortpre = info->use_short_preamble; __entry->cts = info->use_cts_prot; __entry->shortslot = info->use_short_slot; @@ -465,15 +465,18 @@ TRACE_EVENT(drv_bss_info_changed, __entry->channel_width = info->chandef.width; __entry->channel_cfreq1 = info->chandef.center_freq1; __entry->channel_cfreq1_offset = info->chandef.freq1_offset; - __entry->arp_addr_cnt = info->arp_addr_cnt; - memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, - sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? + __entry->arp_addr_cnt = sdata->vif.cfg.arp_addr_cnt; + memcpy(__get_dynamic_array(arp_addr_list), + sdata->vif.cfg.arp_addr_list, + sizeof(u32) * (sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? IEEE80211_BSS_ARP_ADDR_LIST_LEN : - info->arp_addr_cnt)); + sdata->vif.cfg.arp_addr_cnt)); __entry->qos = info->qos; - __entry->idle = info->idle; + __entry->idle = sdata->vif.cfg.idle; __entry->ps = info->ps; - memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + memcpy(__get_dynamic_array(ssid), + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len); __entry->hidden_ssid = info->hidden_ssid; __entry->txpower = info->txpower; __entry->p2p_oppps_ctwindow = info->p2p_noa_attr.oppps_ctwindow; @@ -1719,7 +1722,7 @@ TRACE_EVENT(drv_start_ap, VIF_ENTRY __field(u8, dtimper) __field(u16, bcnint) - __dynamic_array(u8, ssid, info->ssid_len) + __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) __field(bool, hidden_ssid) ), @@ -1728,7 +1731,9 @@ TRACE_EVENT(drv_start_ap, VIF_ASSIGN; __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; - memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + memcpy(__get_dynamic_array(ssid), + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len); __entry->hidden_ssid = info->hidden_ssid; ), @@ -1786,7 +1791,7 @@ TRACE_EVENT(drv_join_ibss, VIF_ENTRY __field(u8, dtimper) __field(u16, bcnint) - __dynamic_array(u8, ssid, info->ssid_len) + __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) ), TP_fast_assign( @@ -1794,7 +1799,9 @@ TRACE_EVENT(drv_join_ibss, VIF_ASSIGN; __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; - memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); + memcpy(__get_dynamic_array(ssid), + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len); ), TP_printk( diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e5edc6fd21c0..a4270e9ec10e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -5381,7 +5381,7 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, pspoll = skb_put_zero(skb, sizeof(*pspoll)); pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); - pspoll->aid = cpu_to_le16(sdata->vif.bss_conf.aid); + pspoll->aid = cpu_to_le16(sdata->vif.cfg.aid); /* aid in PS-Poll has its two MSBs each set to 1 */ pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 48d8f0aad69f..dccc757baab2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2496,7 +2496,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_MONITOR: break; case NL80211_IFTYPE_ADHOC: - if (sdata->vif.bss_conf.ibss_joined) + if (sdata->vif.cfg.ibss_joined) WARN_ON(drv_join_ibss(local, sdata)); fallthrough; default: -- cgit v1.2.3 From 7b7090b4c6a906cc7c3e2a460335f705b93f4506 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 24 May 2022 10:55:56 +0200 Subject: wifi: mac80211: split bss_info_changed method Split the bss_info_changed method to vif_cfg_changed and link_info_changed, with the latter getting a link ID. Also change the 'changed' parameter to u64 already, we know we need that. Signed-off-by: Johannes Berg --- drivers/net/wireless/admtek/adm8211.c | 2 +- drivers/net/wireless/ath/ar5523/ar5523.c | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 2 +- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/carl9170/main.c | 2 +- drivers/net/wireless/ath/wcn36xx/main.c | 4 +- drivers/net/wireless/atmel/at76c50x-usb.c | 2 +- drivers/net/wireless/broadcom/b43/main.c | 4 +- drivers/net/wireless/broadcom/b43legacy/main.c | 2 +- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 2 +- drivers/net/wireless/intel/iwlegacy/common.c | 6 +- drivers/net/wireless/intel/iwlegacy/common.h | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/agn.h | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/rxon.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +- drivers/net/wireless/intersil/p54/main.c | 2 +- drivers/net/wireless/mac80211_hwsim.c | 4 +- drivers/net/wireless/marvell/libertas_tf/main.c | 2 +- drivers/net/wireless/marvell/mwl8k.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 2 +- drivers/net/wireless/mediatek/mt7601u/main.c | 2 +- drivers/net/wireless/purelifi/plfxlc/mac.c | 4 +- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- drivers/net/wireless/realtek/rtlwifi/core.c | 2 +- drivers/net/wireless/realtek/rtw88/mac80211.c | 2 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 2 +- drivers/net/wireless/silabs/wfx/sta.c | 2 +- drivers/net/wireless/silabs/wfx/sta.h | 2 +- drivers/net/wireless/st/cw1200/sta.c | 4 +- drivers/net/wireless/st/cw1200/sta.h | 2 +- drivers/net/wireless/ti/wl1251/main.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 2 +- drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 4 +- drivers/staging/vt6655/device_main.c | 2 +- drivers/staging/vt6656/main_usb.c | 2 +- include/net/mac80211.h | 28 ++++- net/mac80211/cfg.c | 31 ++--- net/mac80211/chan.c | 9 +- net/mac80211/driver-ops.h | 35 ++++-- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 6 +- net/mac80211/iface.c | 5 +- net/mac80211/main.c | 84 ++++++++++++- net/mac80211/mesh.c | 6 +- net/mac80211/mlme.c | 16 +-- net/mac80211/offchannel.c | 8 +- net/mac80211/sta_info.c | 2 +- net/mac80211/tdls.c | 2 +- net/mac80211/trace.h | 138 +++++++++++++-------- net/mac80211/util.c | 4 +- net/mac80211/vht.c | 2 +- 64 files changed, 324 insertions(+), 170 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index 2db9c948c0fc..6bee16b207d1 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1311,7 +1311,7 @@ static int adm8211_config(struct ieee80211_hw *dev, u32 changed) static void adm8211_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changes) + u64 changes) { struct adm8211_priv *priv = dev->priv; diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 4cd06a0942d4..6f937d2cc126 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1273,7 +1273,7 @@ static int ar5523_write_associd(struct ar5523 *ar, struct ieee80211_vif *vif) static void ar5523_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss, - u32 changed) + u64 changed) { struct ar5523 *ar = hw->priv; int error; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4e7e2da3c859..c1f8123d81fe 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6068,7 +6068,7 @@ static void ath10k_recalculate_mgmt_rate(struct ath10k *ar, static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 169161549361..3e07b1454fe4 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -3091,7 +3091,7 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar, static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 0df0fa1da181..8da232e81518 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -250,7 +250,7 @@ unlock: static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, u32 changes) + struct ieee80211_bss_conf *bss_conf, u64 changes) { struct ath5k_vif *avf = (void *)vif->drv_priv; struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 3a5ec4da6a38..14d713e03872 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1509,7 +1509,7 @@ static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv) static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 56c2681e5192..729f8ee9644d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1863,7 +1863,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { #define CHECK_ANI \ (BSS_CHANGED_ASSOC | \ diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index e28a5f3085c0..3d881028bd00 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1032,7 +1032,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw, static void carl9170_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct ar9170 *ar = hw->priv; struct ath_common *common = &ar->common; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 72ba2e2fc93a..04fb26cb8322 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -872,7 +872,7 @@ void wcn36xx_set_default_rates_v1(struct wcn36xx_hal_supported_rates_v1 *rates) static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct wcn36xx *wcn = hw->priv; struct sk_buff *skb = NULL; @@ -880,7 +880,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, enum wcn36xx_hal_link_state link_state; struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); - wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n", + wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%llx\n", vif, changed); mutex_lock(&wcn->conf_mutex); diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index 7582761c61e2..24e609c1f523 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -2033,7 +2033,7 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed) static void at76_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct at76_priv *priv = hw->priv; diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 17bcec5f3ff7..e3121a9d0579 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -366,7 +366,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev); static void b43_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed); + u64 changed); static int b43_ratelimit(struct b43_wl *wl) { @@ -4097,7 +4097,7 @@ static void b43_update_basic_rates(struct b43_wldev *dev, u32 brates) static void b43_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index eec3af9c3745..96d5a034c09b 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -2806,7 +2806,7 @@ static void b43legacy_update_basic_rates(struct b43legacy_wldev *dev, u32 brates static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index e6cd638a85d6..fd3c131c622c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -582,7 +582,7 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) static void brcms_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { struct brcms_info *wl = hw->priv; struct bcma_device *core = wl->wlc->hw->d11core; diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index b01945415be6..affad34f70f0 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5311,13 +5311,13 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) void il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, u32 changes) + struct ieee80211_bss_conf *bss_conf, u64 changes) { struct il_priv *il = hw->priv; int ret; mutex_lock(&il->mutex); - D_MAC80211("enter: changes 0x%x\n", changes); + D_MAC80211("enter: changes 0x%llx\n", changes); if (!il_is_alive(il)) { D_MAC80211("leave - not alive\n"); @@ -5438,7 +5438,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changes && il_is_associated(il) && vif->cfg.aid) { - D_MAC80211("Changes (%#x) while associated\n", changes); + D_MAC80211("Changes (%#llx) while associated\n", changes); ret = il_send_rxon_assoc(il); if (!ret) { /* Sync active_rxon with latest change. */ diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h index 40877ef1fbf2..d1383b4f0f05 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.h +++ b/drivers/net/wireless/intel/iwlegacy/common.h @@ -1947,7 +1947,7 @@ il_get_hw_mode(struct il_priv *il, enum nl80211_band band) int il_mac_config(struct ieee80211_hw *hw, u32 changed); void il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, u32 changes); + struct ieee80211_bss_conf *bss_conf, u64 changes); void il_tx_cmd_protection(struct il_priv *il, struct ieee80211_tx_info *info, __le16 fc, __le32 *tx_flags); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h index abb8696ba294..411a6f6638b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h @@ -92,7 +92,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed); void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes); + u64 changes); void iwlagn_config_ht40(struct ieee80211_conf *conf, struct iwl_rxon_context *ctx); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 17a14970edec..45e382fe45a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -1383,7 +1383,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv) void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b5257b4fd000..586208506275 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2181,7 +2181,7 @@ static void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; @@ -2590,7 +2590,7 @@ static void iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -2621,7 +2621,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index a9dfe6a3da0d..cc6769a4fec7 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -449,7 +449,7 @@ static int p54_get_stats(struct ieee80211_hw *dev, static void p54_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5aaf34f6f43b..de10a40d5306 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2100,14 +2100,14 @@ static void mac80211_hwsim_bcn_en_iter(void *data, u8 *mac, static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct hwsim_vif_priv *vp = (void *)vif->drv_priv; struct mac80211_hwsim_data *data = hw->priv; hwsim_check_magic(vif); - wiphy_dbg(hw->wiphy, "%s(changed=0x%x vif->addr=%pM)\n", + wiphy_dbg(hw->wiphy, "%s(changed=0x%llx vif->addr=%pM)\n", __func__, changed, vif->addr); if (changed & BSS_CHANGED_BSSID) { diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 02a1e1f547d8..21c3e0bdc444 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -417,7 +417,7 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw, static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct lbtf_private *priv = hw->priv; struct sk_buff *beacon; diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 5f1bcfb5e3f6..7eef3a74d124 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5163,7 +5163,7 @@ out: static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { if (vif->type == NL80211_IFTYPE_STATION) mwl8k_bss_info_changed_sta(hw, vif, info, changed); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 1f14ecda1f55..088c0a4cf774 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -297,7 +297,7 @@ mt7603_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, static void mt7603_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { struct mt7603_dev *dev = hw->priv; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index d992fdea0f32..277c22a4d049 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -576,7 +576,7 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, static void mt7615_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index f76fd22ee035..74ad418f5a70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -187,7 +187,7 @@ void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, void mt76x02_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x02_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed); + struct ieee80211_bss_conf *info, u64 changed); void mt76x02_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 5bd0a0bae688..a0e2d042751b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -636,7 +636,7 @@ EXPORT_SYMBOL_GPL(mt76x02_sta_ps); void mt76x02_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct mt76x02_dev *dev = hw->priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 05327b0b6fc3..fbeac9aa2af6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -573,7 +573,7 @@ mt7915_update_bss_color(struct ieee80211_hw *hw, static void mt7915_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = mt7915_hw_dev(hw); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 8532033794bd..63583605d1cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -637,7 +637,7 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw, static void mt7921_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct mt7921_phy *phy = mt7921_hw_phy(hw); struct mt7921_dev *dev = mt7921_hw_dev(hw); diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index 671d8897ae76..6c9c7a61c5c9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -132,7 +132,7 @@ mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, static void mt7601u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { struct mt7601u_dev *dev = hw->priv; diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c index 90e552532701..1fc1682683e1 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.c +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c @@ -587,12 +587,12 @@ static void plfxlc_op_configure_filter(struct ieee80211_hw *hw, static void plfxlc_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct plfxlc_mac *mac = plfxlc_hw_mac(hw); int associated; - dev_dbg(plfxlc_mac_dev(mac), "changes: %x\n", changes); + dev_dbg(plfxlc_mac_dev(mac), "changes: %llx\n", changes); if (mac->type != NL80211_IFTYPE_ADHOC) { /* for STATION */ associated = is_valid_ether_addr(bss_conf->bssid); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index 9f6fc40649be..918e0477bb7d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1479,7 +1479,7 @@ int rt2x00mac_get_stats(struct ieee80211_hw *hw, void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes); + u64 changes); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 660554a01894..6205d22765c7 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -574,7 +574,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_get_stats); void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_intf *intf = vif_to_intf(vif); diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index 025619cd14e8..10e8fdc31879 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1500,7 +1500,7 @@ static void rtl8180_conf_erp(struct ieee80211_hw *dev, static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct rtl8180_priv *priv = dev->priv; struct rtl8180_vif *vif_priv; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index eb68b2d3caa1..8ab65c888baf 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1251,7 +1251,7 @@ static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct rtl8187_priv *priv = dev->priv; struct rtl8187_vif *vif_priv; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 0239e12ec8a5..65c4cb1e030c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4558,7 +4558,7 @@ rtl8xxxu_wireless_mode(struct ieee80211_hw *hw, struct ieee80211_sta *sta) static void rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, u32 changed) + struct ieee80211_bss_conf *bss_conf, u64 changed) { struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 5177eb02740e..2f7fd8888d3a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1040,7 +1040,7 @@ EXPORT_SYMBOL_GPL(rtl_update_beacon_work_callback); static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtlpriv); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index c5954c18862d..9e0b5692fbab 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -355,7 +355,7 @@ static void rtw_conf_tx(struct rtw_dev *rtwdev, static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct rtw_dev *rtwdev = hw->priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index ac8b9bf2b0bb..5afb8fe5708e 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -336,7 +336,7 @@ static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, - u32 changed) + u64 changed) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index d4b3834388ab..1dff3d263382 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -783,7 +783,7 @@ static void rsi_switch_channel(struct rsi_hw *adapter, static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 79fafe8143d9..f4103a653e3b 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -506,7 +506,7 @@ static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable) } void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) + struct ieee80211_bss_conf *info, u64 changed) { struct wfx_dev *wdev = hw->priv; struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index c69b2227e9ac..d9c6bd632b20 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -36,7 +36,7 @@ void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed); + struct ieee80211_bss_conf *info, u64 changed); int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 3f48def51ebc..5fa6878ee109 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -1796,14 +1796,14 @@ static int cw1200_set_btcoexinfo(struct cw1200_common *priv) void cw1200_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct cw1200_common *priv = dev->priv; bool do_join = false; mutex_lock(&priv->conf_mutex); - pr_debug("BSS CHANGED: %08x\n", changed); + pr_debug("BSS CHANGED: %llx\n", changed); /* TODO: BSS_CHANGED_QOS */ /* TODO: BSS_CHANGED_TXPOWER */ diff --git a/drivers/net/wireless/st/cw1200/sta.h b/drivers/net/wireless/st/cw1200/sta.h index 706dab8e73bf..05e3ab7ccef1 100644 --- a/drivers/net/wireless/st/cw1200/sta.h +++ b/drivers/net/wireless/st/cw1200/sta.h @@ -103,7 +103,7 @@ void cw1200_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, void cw1200_bss_info_changed(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed); + u64 changed); int cw1200_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params); diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index bdc93c4f54ba..340ab4985fe2 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1077,7 +1077,7 @@ out: static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct wl1251 *wl = hw->priv; struct sk_buff *beacon, *skb; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index ad9560bd9512..d365bdce2a10 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4580,7 +4580,7 @@ out: static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index 3ef8533205f9..b42fedba519d 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -1278,12 +1278,12 @@ static void set_rts_cts(struct zd_mac *mac, unsigned int short_preamble) static void zd_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changes) + u64 changes) { struct zd_mac *mac = zd_hw_mac(hw); int associated; - dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); + dev_dbg_f(zd_mac_dev(mac), "changes: %llx\n", changes); if (mac->type == NL80211_IFTYPE_MESH_POINT || mac->type == NL80211_IFTYPE_ADHOC || diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 8c5de30478ec..e8ac7b93b58c 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1395,7 +1395,7 @@ static int vnt_config(struct ieee80211_hw *hw, u32 changed) static void vnt_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf, u32 changed) + struct ieee80211_bss_conf *conf, u64 changed) { struct vnt_private *priv = hw->priv; diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 3ab8a7bb9715..897ee0f7fc6b 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -745,7 +745,7 @@ static int vnt_config(struct ieee80211_hw *hw, u32 changed) static void vnt_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf, u32 changed) + struct ieee80211_bss_conf *conf, u64 changed) { struct vnt_private *priv = hw->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1520922d21a5..17b6eb426356 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -273,8 +273,8 @@ struct ieee80211_vif_chanctx_switch { /** * enum ieee80211_bss_change - BSS change notification flags * - * These flags are used with the bss_info_changed() callback - * to indicate which BSS parameter changed. + * These flags are used with the bss_info_changed(), link_info_changed() + * and vif_cfg_changed() callbacks to indicate which parameter(s) changed. * * @BSS_CHANGED_ASSOC: association status changed (associated/disassociated), * also implies a change in the AID. @@ -3524,6 +3524,22 @@ struct ieee80211_prep_tx_info { * for association indication. The @changed parameter indicates which * of the bss parameters has changed when a call is made. The callback * can sleep. + * Note: this callback is called if @vif_cfg_changed or @link_info_changed + * are not implemented. + * + * @vif_cfg_changed: Handler for configuration requests related to interface + * (MLD) parameters from &struct ieee80211_vif_cfg that vary during the + * lifetime of the interface (e.g. assoc status, IP addresses, etc.) + * The @changed parameter indicates which value changed. + * The callback can sleep. + * + * @link_info_changed: Handler for configuration requests related to link + * parameters from &struct ieee80211_bss_conf that are related to an + * individual link. e.g. legacy/HT/VHT/... rate information. + * The @changed parameter indicates which value changed, and the @link_id + * parameter indicates the link ID. Note that the @link_id will be 0 for + * non-MLO connections. + * The callback can sleep. * * @prepare_multicast: Prepare for multicast filter configuration. * This callback is optional, and its return value is passed @@ -4032,7 +4048,13 @@ struct ieee80211_ops { void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed); + u64 changed); + void (*vif_cfg_changed)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 changed); + void (*link_info_changed)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id, u64 changed); int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0a717cb95400..a1404fe5cfe4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -39,7 +39,8 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, memcpy(sdata->vif.bss_conf.mu_group.position, params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, WLAN_USER_POSITION_LEN); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS); + ieee80211_link_info_change_notify(sdata, 0, + BSS_CHANGED_MU_GROUPS); /* don't care about endianness - just check for 0 */ memcpy(&membership, params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); @@ -1333,7 +1334,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, err |= BSS_CHANGED_HE_BSS_COLOR; } - ieee80211_bss_info_change_notify(sdata, err); + ieee80211_link_info_change_notify(sdata, 0, err); return 0; } @@ -1414,7 +1415,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, sdata->beacon_rate_set = false; sdata->vif.cfg.ssid_len = 0; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BEACON_ENABLED); if (sdata->wdev.cac_started) { chandef = sdata->vif.bss_conf.chandef; @@ -2347,7 +2348,7 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, if (_chg_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)) { conf->ht_opmode = nconf->ht_opmode; sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT); } if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask)) conf->dot11MeshHWMPactivePathToRootTimeout = @@ -2502,7 +2503,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, changed |= BSS_CHANGED_P2P_PS; } - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); return 0; } @@ -2543,7 +2544,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, return -EINVAL; } - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS); return 0; } @@ -2692,7 +2693,7 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(int) * NUM_NL80211_BANDS); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MCAST_RATE); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MCAST_RATE); return 0; } @@ -3026,7 +3027,7 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, /* tell the driver upon association, unless already associated */ if (sdata->u.mgd.associated && sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM); return 0; } @@ -3051,7 +3052,7 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy, /* tell the driver upon association, unless already associated */ if (sdata->u.mgd.associated && sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_CQM); return 0; } @@ -3389,7 +3390,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (err) return err; - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); if (sdata->deflink.csa_block_tx) { ieee80211_wake_vif_queues(local, sdata, @@ -3677,7 +3678,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, params->count, params->block_tx); if (changed) { - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); drv_channel_switch_beacon(sdata, ¶ms->chandef); } else { /* if the beacon didn't change, we can finalize immediately */ @@ -3980,7 +3981,7 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed); if (ret == 0) - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); return ret; } @@ -4389,7 +4390,7 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.he_bss_color.enabled = enable; changed |= BSS_CHANGED_HE_BSS_COLOR; - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); if (!sdata->vif.bss_conf.nontransmitted && sdata->vif.mbssid_tx_vif) { struct ieee80211_sub_if_data *child; @@ -4399,8 +4400,8 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, if (child != sdata && child->vif.mbssid_tx_vif == &sdata->vif) { child->vif.bss_conf.he_bss_color.color = color; child->vif.bss_conf.he_bss_color.enabled = enable; - ieee80211_bss_info_change_notify(child, - BSS_CHANGED_HE_BSS_COLOR); + ieee80211_link_info_change_notify(child, 0, + BSS_CHANGED_HE_BSS_COLOR); } } mutex_unlock(&sdata->local->iflist_mtx); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 67131ca3f649..5d8b49f20198 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -799,8 +799,7 @@ out: if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && sdata->vif.type != NL80211_IFTYPE_MONITOR) - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_IDLE); + ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_IDLE); ieee80211_check_fast_xmit_iface(sdata); @@ -1188,7 +1187,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) ieee80211_recalc_radar_chanctx(local, new_ctx); if (changed) - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); out: ieee80211_vif_chanctx_reservation_complete(sdata); @@ -1533,8 +1532,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ieee80211_vif_update_chandef(sdata, &sdata->deflink.reserved_chandef); if (changed) - ieee80211_bss_info_change_notify(sdata, - changed); + ieee80211_link_info_change_notify(sdata, 0, + changed); ieee80211_recalc_txpower(sdata, false); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index fd2882348211..15ab8d00815b 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -147,10 +147,27 @@ static inline int drv_config(struct ieee80211_local *local, u32 changed) return ret; } -static inline void drv_bss_info_changed(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss_conf *info, - u32 changed) +static inline void drv_vif_cfg_changed(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u64 changed) +{ + might_sleep(); + + if (!check_sdata_in_driver(sdata)) + return; + + trace_drv_vif_cfg_changed(local, sdata, changed); + if (local->ops->vif_cfg_changed) + local->ops->vif_cfg_changed(&local->hw, &sdata->vif, changed); + else if (local->ops->bss_info_changed) + local->ops->bss_info_changed(&local->hw, &sdata->vif, + &sdata->vif.bss_conf, changed); + trace_drv_return_void(local); +} + +static inline void drv_link_info_changed(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + int link_id, u64 changed) { might_sleep(); @@ -172,9 +189,13 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return; - trace_drv_bss_info_changed(local, sdata, info, changed); - if (local->ops->bss_info_changed) - local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); + trace_drv_link_info_changed(local, sdata, link_id, changed); + if (local->ops->link_info_changed) + local->ops->link_info_changed(&local->hw, &sdata->vif, + link_id, changed); + else if (local->ops->bss_info_changed) + local->ops->bss_info_changed(&local->hw, &sdata->vif, + &sdata->vif.bss_conf, changed); trace_drv_return_void(local); } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 066f7c5adeec..3b68e9f4345b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1851,7 +1851,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | IEEE80211_HT_PARAM_RIFS_MODE; changed |= BSS_CHANGED_HT | BSS_CHANGED_MCAST_RATE; - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = local->rx_chains; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f0a8bb444033..20153957cdee 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1836,7 +1836,11 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed); + u64 changed); +void ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata, + u64 changed); +void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, + int link_id, u64 changed); void ieee80211_configure_filter(struct ieee80211_local *local); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2ee34d898821..978dfa48e098 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -80,7 +80,8 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, { if (__ieee80211_recalc_txpower(sdata) || (update_bss && ieee80211_sdata_running(sdata))) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); + ieee80211_link_info_change_notify(sdata, 0, + BSS_CHANGED_TXPOWER); } static u32 __ieee80211_idle_off(struct ieee80211_local *local) @@ -1281,7 +1282,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && sdata->vif.type != NL80211_IFTYPE_NAN) changed |= ieee80211_reset_erp_info(sdata); - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0c81ae492df4..5c71b522013f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -199,15 +199,88 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) return ret; } +#define BSS_CHANGED_VIF_CFG_FLAGS (BSS_CHANGED_ASSOC |\ + BSS_CHANGED_IDLE |\ + BSS_CHANGED_IBSS |\ + BSS_CHANGED_ARP_FILTER |\ + BSS_CHANGED_SSID) + void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed) + u64 changed) { struct ieee80211_local *local = sdata->local; + might_sleep(); + if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) return; - drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); + if (WARN_ON_ONCE(changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED) && + sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_ADHOC && + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && + sdata->vif.type != NL80211_IFTYPE_OCB)) + return; + + if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || + sdata->vif.type == NL80211_IFTYPE_NAN || + (sdata->vif.type == NL80211_IFTYPE_MONITOR && + !sdata->vif.bss_conf.mu_mimo_owner && + !(changed & BSS_CHANGED_TXPOWER)))) + return; + + if (!check_sdata_in_driver(sdata)) + return; + + if (changed & BSS_CHANGED_VIF_CFG_FLAGS) { + u64 ch = changed & BSS_CHANGED_VIF_CFG_FLAGS; + + trace_drv_vif_cfg_changed(local, sdata, changed); + if (local->ops->vif_cfg_changed) + local->ops->vif_cfg_changed(&local->hw, &sdata->vif, ch); + } + + if (changed & ~BSS_CHANGED_VIF_CFG_FLAGS) { + u64 ch = changed & ~BSS_CHANGED_VIF_CFG_FLAGS; + + /* FIXME: should be for each link */ + trace_drv_link_info_changed(local, sdata, 0, changed); + if (local->ops->link_info_changed) + local->ops->link_info_changed(&local->hw, &sdata->vif, + 0, ch); + } + + if (local->ops->bss_info_changed) + local->ops->bss_info_changed(&local->hw, &sdata->vif, + &sdata->vif.bss_conf, changed); + trace_drv_return_void(local); +} + +void ieee80211_vif_cfg_change_notify(struct ieee80211_sub_if_data *sdata, + u64 changed) +{ + struct ieee80211_local *local = sdata->local; + + WARN_ON_ONCE(changed & ~BSS_CHANGED_VIF_CFG_FLAGS); + + if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + return; + + drv_vif_cfg_changed(local, sdata, changed); +} + +void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, + int link_id, u64 changed) +{ + struct ieee80211_local *local = sdata->local; + + WARN_ON_ONCE(changed & BSS_CHANGED_VIF_CFG_FLAGS); + + if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + return; + + drv_link_info_changed(local, sdata, link_id, changed); } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -387,8 +460,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, /* Configure driver only if associated (which also implies it is up) */ if (ifmgd->associated) - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_ARP_FILTER); + ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_ARP_FILTER); sdata_unlock(sdata); @@ -557,6 +629,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) return NULL; + if (WARN_ON(!!ops->link_info_changed != !!ops->vif_cfg_changed || + (ops->link_info_changed && ops->bss_info_changed))) + return NULL; + /* check all or no channel context operations exist */ i = !!ops->add_chanctx + !!ops->remove_chanctx + !!ops->change_chanctx + !!ops->assign_vif_chanctx + diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f60e257cba95..13722a7f2254 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1057,7 +1057,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) } ieee80211_recalc_dtim(local, sdata); - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); netif_carrier_on(sdata->dev); return 0; @@ -1081,7 +1081,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) sdata->vif.bss_conf.enable_beacon = false; sdata->beacon_rate_set = false; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BEACON_ENABLED); /* remove beacon */ bcn = rcu_dereference_protected(ifmsh->beacon, @@ -1581,7 +1581,7 @@ static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata) if (ieee80211_mesh_rebuild_beacon(sdata)) return; - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); } void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fd1b97e1e990..e172bdfe9b0a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1835,7 +1835,7 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata) if (sdata->vif.bss_conf.ps != ps_allowed) { sdata->vif.bss_conf.ps = ps_allowed; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_PS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_PS); } } @@ -2031,7 +2031,7 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) { if (__ieee80211_sta_handle_tspec_ac_params(sdata)) - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_QOS); } static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work) @@ -2920,7 +2920,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, sta_info_destroy_addr(sdata, auth_data->bss->bssid); eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; mutex_lock(&sdata->local->mtx); ieee80211_vif_release_channel(sdata); @@ -2949,7 +2949,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, sta_info_destroy_addr(sdata, assoc_data->bss->bssid); eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; sdata->vif.bss_conf.mu_mimo_owner = false; @@ -4387,7 +4387,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, elems->pwr_constr_elem, elems->cisco_dtpc_elem); - ieee80211_bss_info_change_notify(sdata, changed); + ieee80211_link_info_change_notify(sdata, 0, changed); free: kfree(elems); } @@ -5697,7 +5697,7 @@ skip_rates: * tell driver about BSSID, basic rates and timing * this was set up above, before setting the channel */ - ieee80211_bss_info_change_notify(sdata, + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES | BSS_CHANGED_BEACON_INT); @@ -5865,7 +5865,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, err_clear: eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); ifmgd->auth_data = NULL; mutex_lock(&sdata->local->mtx); ieee80211_vif_release_channel(sdata); @@ -6212,7 +6212,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, return 0; err_clear: eth_zero_addr(sdata->deflink.u.mgd.bssid); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); ifmgd->assoc_data = NULL; err_free: kfree(assoc_data); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 6cd3df1eb687..2ed4e2325914 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -118,8 +118,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) set_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); sdata->vif.bss_conf.enable_beacon = false; - ieee80211_bss_info_change_notify( - sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify( + sdata, 0, BSS_CHANGED_BEACON_ENABLED); } if (sdata->vif.type == NL80211_IFTYPE_STATION && @@ -155,8 +155,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local) if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state)) { sdata->vif.bss_conf.enable_beacon = true; - ieee80211_bss_info_change_notify( - sdata, BSS_CHANGED_BEACON_ENABLED); + ieee80211_link_info_change_notify( + sdata, 0, BSS_CHANGED_BEACON_ENABLED); } } mutex_unlock(&local->iflist_mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 115efa830673..9a70d846d0dd 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -630,7 +630,7 @@ ieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata) if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) { sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_P2P_PS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_P2P_PS); } } diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 8a2ec9c31240..11a3b950b490 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1335,7 +1335,7 @@ iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata, return; sdata->vif.bss_conf.ht_operation_mode = opmode; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_HT); } int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 74ef7e71e1ef..9417378b4fc0 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -390,22 +390,71 @@ TRACE_EVENT(drv_config, ) ); -TRACE_EVENT(drv_bss_info_changed, +TRACE_EVENT(drv_vif_cfg_changed, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss_conf *info, - u32 changed), + u64 changed), - TP_ARGS(local, sdata, info, changed), + TP_ARGS(local, sdata, changed), TP_STRUCT__entry( LOCAL_ENTRY VIF_ENTRY - __field(u32, changed) + __field(u64, changed) __field(bool, assoc) __field(bool, ibss_joined) __field(bool, ibss_creator) __field(u16, aid) + __dynamic_array(u32, arp_addr_list, + sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? + IEEE80211_BSS_ARP_ADDR_LIST_LEN : + sdata->vif.cfg.arp_addr_cnt) + __field(int, arp_addr_cnt) + __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) + __field(int, s1g) + __field(bool, idle) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->changed = changed; + __entry->aid = sdata->vif.cfg.aid; + __entry->assoc = sdata->vif.cfg.assoc; + __entry->ibss_joined = sdata->vif.cfg.ibss_joined; + __entry->ibss_creator = sdata->vif.cfg.ibss_creator; + + __entry->arp_addr_cnt = sdata->vif.cfg.arp_addr_cnt; + memcpy(__get_dynamic_array(arp_addr_list), + sdata->vif.cfg.arp_addr_list, + sizeof(u32) * (sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? + IEEE80211_BSS_ARP_ADDR_LIST_LEN : + sdata->vif.cfg.arp_addr_cnt)); + memcpy(__get_dynamic_array(ssid), + sdata->vif.cfg.ssid, + sdata->vif.cfg.ssid_len); + __entry->s1g = sdata->vif.cfg.s1g; + __entry->idle = sdata->vif.cfg.idle; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " changed:%#llx", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed + ) +); + +TRACE_EVENT(drv_link_info_changed, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + int link_id, u64 changed), + + TP_ARGS(local, sdata, link_id, changed), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u64, changed) + __field(int, link_id) __field(bool, cts) __field(bool, shortpre) __field(bool, shortslot) @@ -424,15 +473,8 @@ TRACE_EVENT(drv_bss_info_changed, __field(u32, channel_width) __field(u32, channel_cfreq1) __field(u32, channel_cfreq1_offset) - __dynamic_array(u32, arp_addr_list, - sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? - IEEE80211_BSS_ARP_ADDR_LIST_LEN : - sdata->vif.cfg.arp_addr_cnt) - __field(int, arp_addr_cnt) __field(bool, qos) - __field(bool, idle) __field(bool, ps) - __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) __field(bool, hidden_ssid) __field(int, txpower) __field(u8, p2p_oppps_ctwindow) @@ -442,49 +484,37 @@ TRACE_EVENT(drv_bss_info_changed, LOCAL_ASSIGN; VIF_ASSIGN; __entry->changed = changed; - __entry->aid = sdata->vif.cfg.aid; - __entry->assoc = sdata->vif.cfg.assoc; - __entry->ibss_joined = sdata->vif.cfg.ibss_joined; - __entry->ibss_creator = sdata->vif.cfg.ibss_creator; - __entry->shortpre = info->use_short_preamble; - __entry->cts = info->use_cts_prot; - __entry->shortslot = info->use_short_slot; - __entry->enable_beacon = info->enable_beacon; - __entry->dtimper = info->dtim_period; - __entry->bcnint = info->beacon_int; - __entry->assoc_cap = info->assoc_capability; - __entry->sync_tsf = info->sync_tsf; - __entry->sync_device_ts = info->sync_device_ts; - __entry->sync_dtim_count = info->sync_dtim_count; - __entry->basic_rates = info->basic_rates; - memcpy(__entry->mcast_rate, info->mcast_rate, + __entry->link_id = link_id; + __entry->shortpre = sdata->vif.bss_conf.use_short_preamble; + __entry->cts = sdata->vif.bss_conf.use_cts_prot; + __entry->shortslot = sdata->vif.bss_conf.use_short_slot; + __entry->enable_beacon = sdata->vif.bss_conf.enable_beacon; + __entry->dtimper = sdata->vif.bss_conf.dtim_period; + __entry->bcnint = sdata->vif.bss_conf.beacon_int; + __entry->assoc_cap = sdata->vif.bss_conf.assoc_capability; + __entry->sync_tsf = sdata->vif.bss_conf.sync_tsf; + __entry->sync_device_ts = sdata->vif.bss_conf.sync_device_ts; + __entry->sync_dtim_count = sdata->vif.bss_conf.sync_dtim_count; + __entry->basic_rates = sdata->vif.bss_conf.basic_rates; + memcpy(__entry->mcast_rate, sdata->vif.bss_conf.mcast_rate, sizeof(__entry->mcast_rate)); - __entry->ht_operation_mode = info->ht_operation_mode; - __entry->cqm_rssi_thold = info->cqm_rssi_thold; - __entry->cqm_rssi_hyst = info->cqm_rssi_hyst; - __entry->channel_width = info->chandef.width; - __entry->channel_cfreq1 = info->chandef.center_freq1; - __entry->channel_cfreq1_offset = info->chandef.freq1_offset; - __entry->arp_addr_cnt = sdata->vif.cfg.arp_addr_cnt; - memcpy(__get_dynamic_array(arp_addr_list), - sdata->vif.cfg.arp_addr_list, - sizeof(u32) * (sdata->vif.cfg.arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? - IEEE80211_BSS_ARP_ADDR_LIST_LEN : - sdata->vif.cfg.arp_addr_cnt)); - __entry->qos = info->qos; - __entry->idle = sdata->vif.cfg.idle; - __entry->ps = info->ps; - memcpy(__get_dynamic_array(ssid), - sdata->vif.cfg.ssid, - sdata->vif.cfg.ssid_len); - __entry->hidden_ssid = info->hidden_ssid; - __entry->txpower = info->txpower; - __entry->p2p_oppps_ctwindow = info->p2p_noa_attr.oppps_ctwindow; - ), - - TP_printk( - LOCAL_PR_FMT VIF_PR_FMT " changed:%#x", - LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed + __entry->ht_operation_mode = sdata->vif.bss_conf.ht_operation_mode; + __entry->cqm_rssi_thold = sdata->vif.bss_conf.cqm_rssi_thold; + __entry->cqm_rssi_hyst = sdata->vif.bss_conf.cqm_rssi_hyst; + __entry->channel_width = sdata->vif.bss_conf.chandef.width; + __entry->channel_cfreq1 = sdata->vif.bss_conf.chandef.center_freq1; + __entry->channel_cfreq1_offset = sdata->vif.bss_conf.chandef.freq1_offset; + __entry->qos = sdata->vif.bss_conf.qos; + __entry->ps = sdata->vif.bss_conf.ps; + __entry->hidden_ssid = sdata->vif.bss_conf.hidden_ssid; + __entry->txpower = sdata->vif.bss_conf.txpower; + __entry->p2p_oppps_ctwindow = sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " link_id:%d, changed:%#llx", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id, + __entry->changed ) ); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9cbc09e6d84e..2a279dc3e457 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1699,8 +1699,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, sdata->vif.type != NL80211_IFTYPE_NAN) { sdata->vif.bss_conf.qos = enable_qos; if (bss_notify) - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_QOS); + ieee80211_link_info_change_notify(sdata, 0, + BSS_CHANGED_QOS); } } diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index ac97584b3a0b..7daca8352deb 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -665,7 +665,7 @@ void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.vht_group_notif.position, WLAN_USER_POSITION_LEN); - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS); + ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MU_GROUPS); } void ieee80211_update_mu_groups(struct ieee80211_vif *vif, -- cgit v1.2.3 From 8e14130d3faf7b6b0fc57b530bb601cd9d6a1dab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 13:09:28 +0200 Subject: wifi: mac80211: add per-link configuration pointer Add pointers so we can start using link_id throughout the code, even if for now only link ID 0 is valid, pointing to the "built-in" bss_conf, which is used by drivers that are not aware of MLD. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 3 +++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 23 +++++++++++++++++++++-- 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 17b6eb426356..9af283b1c3b5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1739,6 +1739,8 @@ struct ieee80211_vif_cfg { * @cfg: vif configuration, see &struct ieee80211_vif_cfg * @bss_conf: BSS configuration for this interface, either our own * or the BSS we're associated to + * @link_conf: in case of MLD, the per-link BSS configuration, + * indexed by link ID * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively @@ -1773,6 +1775,7 @@ struct ieee80211_vif { enum nl80211_iftype type; struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; + struct ieee80211_bss_conf *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; u8 addr[ETH_ALEN] __aligned(2); bool p2p; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 20153957cdee..397b111f006d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1031,6 +1031,7 @@ struct ieee80211_sub_if_data { } u; struct ieee80211_link_data deflink; + struct ieee80211_link_data *link[IEEE80211_MLD_MAX_NUM_LINKS]; #ifdef CONFIG_MAC80211_DEBUGFS struct { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 978dfa48e098..04ee525394e9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1012,6 +1012,23 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; } +static void ieee80211_sdata_init(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + sdata->local = local; + + /* + * Initialize the default link, so we can use link_id 0 for non-MLD, + * and that continues to work for non-MLD-aware drivers that use just + * vif.bss_conf instead of vif.link_conf. + * + * Note that we never change this, so if link ID 0 isn't used in an + * MLD connection, we get a separate allocation for it. + */ + sdata->vif.link_conf[0] = &sdata->vif.bss_conf; + sdata->link[0] = &sdata->deflink; +} + int ieee80211_add_virtual_monitor(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; @@ -1031,12 +1048,13 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) return -ENOMEM; /* set up data */ - sdata->local = local; sdata->vif.type = NL80211_IFTYPE_MONITOR; snprintf(sdata->name, IFNAMSIZ, "%s-monitor", wiphy_name(local->hw.wiphy)); sdata->wdev.iftype = NL80211_IFTYPE_MONITOR; + ieee80211_sdata_init(local, sdata); + ieee80211_set_default_queues(sdata); ret = drv_add_interface(local, sdata); @@ -2074,7 +2092,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, /* initialise type-independent data */ sdata->wdev.wiphy = local->hw.wiphy; - sdata->local = local; + + ieee80211_sdata_init(local, sdata); ieee80211_init_frag_cache(&sdata->frags); -- cgit v1.2.3 From b4f85443c17c7edb49c82fc1d28d26860c8c850d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 18:35:23 +0200 Subject: wifi: mac80211: make channel context code MLO-aware Make the channel context code MLO aware, along with some functions that it uses, so that the chan.c file is now MLD-clean and no longer uses deflink/bss_conf/etc. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 2 + drivers/net/wireless/ath/ath11k/mac.c | 2 + drivers/net/wireless/ath/ath9k/main.c | 2 + drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 + drivers/net/wireless/mac80211_hwsim.c | 2 + drivers/net/wireless/silabs/wfx/sta.c | 2 + drivers/net/wireless/silabs/wfx/sta.h | 2 + drivers/net/wireless/ti/wlcore/main.c | 2 + include/net/mac80211.h | 4 + net/mac80211/cfg.c | 52 +- net/mac80211/chan.c | 642 +++++++++++++--------- net/mac80211/debug.h | 14 + net/mac80211/driver-ops.h | 8 +- net/mac80211/eht.c | 4 +- net/mac80211/he.c | 6 +- net/mac80211/ibss.c | 8 +- net/mac80211/ieee80211_i.h | 51 +- net/mac80211/iface.c | 15 +- net/mac80211/mesh_plink.c | 4 +- net/mac80211/mlme.c | 28 +- net/mac80211/ocb.c | 6 +- net/mac80211/rate.c | 8 +- net/mac80211/rate.h | 7 +- net/mac80211/rx.c | 8 +- net/mac80211/tdls.c | 4 +- net/mac80211/trace.h | 17 +- net/mac80211/util.c | 39 +- net/mac80211/vht.c | 36 +- 28 files changed, 586 insertions(+), 391 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c1f8123d81fe..4808ed6a6e20 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8919,6 +8919,7 @@ unlock: static int ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; @@ -8998,6 +8999,7 @@ err: static void ath10k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct ath10k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 3e07b1454fe4..96a33b49a52f 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7072,6 +7072,7 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, static int ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct ath11k *ar = hw->priv; @@ -7161,6 +7162,7 @@ out: static void ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct ath11k *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 729f8ee9644d..c3d5d9795424 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2596,6 +2596,7 @@ static void ath9k_change_chanctx(struct ieee80211_hw *hw, static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; @@ -2627,6 +2628,7 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 586208506275..5d3cedc146be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4235,6 +4235,7 @@ out: } static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -4308,6 +4309,7 @@ out: static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index de10a40d5306..f9392bec85d9 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2722,6 +2722,7 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { hwsim_check_magic(vif); @@ -2732,6 +2733,7 @@ static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { hwsim_check_magic(vif); diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index f4103a653e3b..97a631ff1bfa 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -680,6 +680,7 @@ void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf * } int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; @@ -692,6 +693,7 @@ int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index d9c6bd632b20..3109d257fe94 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -48,8 +48,10 @@ int wfx_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf void wfx_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf); void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf, u32 changed); int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf); void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *conf); /* Hardware API Callbacks */ diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index d365bdce2a10..b476f244a20e 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4701,6 +4701,7 @@ out: static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct wl1271 *wl = hw->priv; @@ -4751,6 +4752,7 @@ out: static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx) { struct wl1271 *wl = hw->priv; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9af283b1c3b5..4dc51c52dd28 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -261,11 +261,13 @@ enum ieee80211_chanctx_switch_mode { * done. * * @vif: the vif that should be switched from old_ctx to new_ctx + * @link_id: the link ID that's switching * @old_ctx: the old context to which the vif was assigned * @new_ctx: the new context to which the vif must be assigned */ struct ieee80211_vif_chanctx_switch { struct ieee80211_vif *vif; + unsigned int link_id; struct ieee80211_chanctx_conf *old_ctx; struct ieee80211_chanctx_conf *new_ctx; }; @@ -4262,9 +4264,11 @@ struct ieee80211_ops { u32 changed); int (*assign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx); void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, struct ieee80211_chanctx_conf *ctx); int (*switch_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif_chanctx_switch *vifs, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 69f540b0cbc6..884d2cfcec1e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -840,9 +840,10 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata) { - ieee80211_vif_release_channel(sdata); - ret = ieee80211_vif_use_channel(sdata, chandef, - IEEE80211_CHANCTX_EXCLUSIVE); + ieee80211_link_release_channel(sdata->link[0]); + ret = ieee80211_link_use_channel(sdata->link[0], + chandef, + IEEE80211_CHANCTX_EXCLUSIVE); } } else if (local->open_count == local->monitors) { local->_oper_chandef = *chandef; @@ -1183,10 +1184,12 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, } mutex_lock(&local->mtx); - err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, - IEEE80211_CHANCTX_SHARED); + err = ieee80211_link_use_channel(sdata->link[params->beacon.link_id], + ¶ms->chandef, + IEEE80211_CHANCTX_SHARED); if (!err) - ieee80211_vif_copy_chanctx_to_vlans(sdata, false); + ieee80211_link_copy_chanctx_to_vlans(sdata->link[params->beacon.link_id], + false); mutex_unlock(&local->mtx); if (err) { sdata->vif.bss_conf.beacon_int = prev_beacon_int; @@ -1296,7 +1299,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, error: mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[params->beacon.link_id]); mutex_unlock(&local->mtx); return err; @@ -1433,8 +1436,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, ieee80211_purge_tx_queue(&local->hw, &sdata->u.ap.ps.bc_buf); mutex_lock(&local->mtx); - ieee80211_vif_copy_chanctx_to_vlans(sdata, true); - ieee80211_vif_release_channel(sdata); + ieee80211_link_copy_chanctx_to_vlans(sdata->link[link_id], true); + ieee80211_link_release_channel(sdata->link[link_id]); mutex_unlock(&local->mtx); return 0; @@ -2401,8 +2404,8 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, sdata->deflink.needed_rx_chains = sdata->local->rx_chains; mutex_lock(&sdata->local->mtx); - err = ieee80211_vif_use_channel(sdata, &setup->chandef, - IEEE80211_CHANCTX_SHARED); + err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef, + IEEE80211_CHANCTX_SHARED); mutex_unlock(&sdata->local->mtx); if (err) return err; @@ -2416,7 +2419,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) ieee80211_stop_mesh(sdata); mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); kfree(sdata->u.mesh.ie); mutex_unlock(&sdata->local->mtx); @@ -3145,8 +3148,8 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, sdata->deflink.smps_mode = IEEE80211_SMPS_OFF; sdata->deflink.needed_rx_chains = local->rx_chains; - err = ieee80211_vif_use_channel(sdata, chandef, - IEEE80211_CHANCTX_SHARED); + err = ieee80211_link_use_channel(sdata->link[0], chandef, + IEEE80211_CHANCTX_SHARED); if (err) goto out_unlock; @@ -3174,7 +3177,7 @@ static void ieee80211_end_cac(struct wiphy *wiphy, cancel_delayed_work(&sdata->deflink.dfs_cac_timer_work); if (sdata->wdev.cac_started) { - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); sdata->wdev.cac_started = false; } } @@ -3378,7 +3381,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) if (sdata->deflink.reserved_ready) return 0; - return ieee80211_vif_use_reserved_context(sdata); + return ieee80211_link_use_reserved_context(sdata->link[0]); } if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, @@ -3643,16 +3646,16 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (err) goto out; - err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, - chanctx->mode, - params->radar_required); + err = ieee80211_link_reserve_chanctx(sdata->link[0], ¶ms->chandef, + chanctx->mode, + params->radar_required); if (err) goto out; /* if reservation is invalid then this will fail */ err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0); if (err) { - ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_link_unreserve_chanctx(sdata->link[0]); goto out; } @@ -3662,7 +3665,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, err = ieee80211_set_csa_beacon(sdata, params, &changed); if (err) { - ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_link_unreserve_chanctx(sdata->link[0]); goto out; } @@ -3921,9 +3924,9 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, int ret = -ENODATA; rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + chanctx_conf = rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf); if (chanctx_conf) { - *chandef = sdata->vif.bss_conf.chandef; + *chandef = sdata->vif.link_conf[link_id]->chandef; ret = 0; } else if (local->open_count > 0 && local->open_count == local->monitors && @@ -3980,7 +3983,8 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, int ret; u32 changed = 0; - ret = ieee80211_vif_change_bandwidth(sdata, chandef, &changed); + ret = ieee80211_link_change_bandwidth(sdata->link[link_id], chandef, + &changed); if (ret == 0) ieee80211_link_info_change_notify(sdata, link_id, changed); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 5d8b49f20198..4f25660d0eeb 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -15,12 +15,12 @@ static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; int num = 0; lockdep_assert_held(&local->chanctx_mtx); - list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) + list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) num++; return num; @@ -29,12 +29,12 @@ static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local, static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; int num = 0; lockdep_assert_held(&local->chanctx_mtx); - list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) num++; return num; @@ -67,12 +67,14 @@ static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local) } static struct ieee80211_chanctx * -ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) +ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local __maybe_unused = sdata->local; struct ieee80211_chanctx_conf *conf; - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(link_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return NULL; @@ -80,21 +82,27 @@ ieee80211_vif_get_chanctx(struct ieee80211_sub_if_data *sdata) return container_of(conf, struct ieee80211_chanctx, conf); } +static struct ieee80211_chanctx * +ieee80211_link_get_chanctx(struct ieee80211_link_data *link) +{ + return ieee80211_vif_get_chanctx(link->sdata, link->link_id); +} + static const struct cfg80211_chan_def * ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, const struct cfg80211_chan_def *compat) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; lockdep_assert_held(&local->chanctx_mtx); - list_for_each_entry(sdata, &ctx->reserved_vifs, + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { if (!compat) - compat = &sdata->deflink.reserved_chandef; + compat = &link->reserved_chandef; - compat = cfg80211_chandef_compatible(&sdata->deflink.reserved_chandef, + compat = cfg80211_chandef_compatible(&link->reserved_chandef, compat); if (!compat) break; @@ -108,20 +116,23 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, const struct cfg80211_chan_def *compat) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; lockdep_assert_held(&local->chanctx_mtx); - list_for_each_entry(sdata, &ctx->assigned_vifs, + list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) { - if (sdata->deflink.reserved_chanctx != NULL) + struct ieee80211_bss_conf *link_conf = + link->sdata->vif.link_conf[link->link_id]; + + if (link->reserved_chanctx) continue; if (!compat) - compat = &sdata->vif.bss_conf.chandef; + compat = &link_conf->chandef; compat = cfg80211_chandef_compatible( - &sdata->vif.bss_conf.chandef, compat); + &link_conf->chandef, compat); if (!compat) break; } @@ -157,7 +168,7 @@ ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local, if (ieee80211_chanctx_combined_chandef(local, ctx, def)) return true; - if (!list_empty(&ctx->reserved_vifs) && + if (!list_empty(&ctx->reserved_links) && ieee80211_chanctx_reserved_chandef(local, ctx, def)) return true; @@ -193,13 +204,19 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, return NULL; } -static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta) +static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta, + unsigned int link_id) { - enum ieee80211_sta_rx_bandwidth width = ieee80211_sta_cap_rx_bw(sta); + enum ieee80211_sta_rx_bandwidth width = + ieee80211_sta_cap_rx_bw(sta, link_id); + + /* no effect if this STA has no presence on this link */ + if (!sta->sta.link[link_id]) + return NL80211_CHAN_WIDTH_20_NOHT; switch (width) { case IEEE80211_STA_RX_BW_20: - if (sta->sta.deflink.ht_cap.ht_supported) + if (sta->sta.link[link_id]->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20; else return NL80211_CHAN_WIDTH_20_NOHT; @@ -227,7 +244,8 @@ static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta) } static enum nl80211_chan_width -ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) +ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; struct sta_info *sta; @@ -238,7 +256,7 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) !(sta->sdata->bss && sta->sdata->bss == sdata->bss)) continue; - max_bw = max(max_bw, ieee80211_get_sta_bw(sta)); + max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id)); } rcu_read_unlock(); @@ -246,27 +264,28 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) } static enum nl80211_chan_width -ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, - struct ieee80211_chanctx_conf *conf) +ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata, + struct ieee80211_chanctx_conf *conf) { - struct ieee80211_sub_if_data *sdata; enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; + struct ieee80211_vif *vif = &sdata->vif; + int link_id; - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - struct ieee80211_vif *vif = &sdata->vif; + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; - if (!ieee80211_sdata_running(sdata)) + if (!link_conf) continue; - if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) + if (rcu_access_pointer(link_conf->chanctx_conf) != conf) continue; switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: - width = ieee80211_get_max_required_bw(sdata); + width = ieee80211_get_max_required_bw(sdata, link_id); break; case NL80211_IFTYPE_STATION: /* @@ -274,8 +293,8 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, * point, so take the width from the chandef, but * account also for TDLS peers */ - width = max(vif->bss_conf.chandef.width, - ieee80211_get_max_required_bw(sdata)); + width = max(link_conf->chandef.width, + ieee80211_get_max_required_bw(sdata, link_id)); break; case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_NAN: @@ -283,7 +302,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_OCB: - width = vif->bss_conf.chandef.width; + width = link_conf->chandef.width; break; case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_UNSPECIFIED: @@ -293,12 +312,36 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, case NL80211_IFTYPE_P2P_GO: WARN_ON_ONCE(1); } + + max_bw = max(max_bw, width); + } + + return max_bw; +} + +static enum nl80211_chan_width +ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, + struct ieee80211_chanctx_conf *conf) +{ + struct ieee80211_sub_if_data *sdata; + enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + enum nl80211_chan_width width; + + if (!ieee80211_sdata_running(sdata)) + continue; + + width = ieee80211_get_chanctx_vif_max_required_bw(sdata, conf); + max_bw = max(max_bw, width); } /* use the configured bandwidth in case of monitor interface */ sdata = rcu_dereference(local->monitor_sdata); - if (sdata && rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf) + if (sdata && + rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == conf) max_bw = max(max_bw, conf->def.width); rcu_read_unlock(); @@ -350,7 +393,7 @@ static u32 _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, } /* calling this function is assuming that station vif is updated to - * lates changes by calling ieee80211_vif_update_chandef + * lates changes by calling ieee80211_link_update_chandef */ static void ieee80211_chan_bw_change(struct ieee80211_local *local, struct ieee80211_chanctx *ctx, @@ -363,29 +406,38 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { + struct ieee80211_sub_if_data *sdata = sta->sdata; enum ieee80211_sta_rx_bandwidth new_sta_bw; + unsigned int link_id; if (!ieee80211_sdata_running(sta->sdata)) continue; - if (rcu_access_pointer(sta->sdata->vif.bss_conf.chanctx_conf) != - &ctx->conf) - continue; + for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) { + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; + + if (!link_conf) + continue; - new_sta_bw = ieee80211_sta_cur_vht_bw(sta); + if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf) + continue; - /* nothing change */ - if (new_sta_bw == sta->sta.deflink.bandwidth) - continue; + new_sta_bw = ieee80211_sta_cur_vht_bw(sta, link_id); - /* vif changed to narrow BW and narrow BW for station wasn't - * requested or vise versa */ - if ((new_sta_bw < sta->sta.deflink.bandwidth) == !narrowed) - continue; + /* nothing change */ + if (new_sta_bw == sta->sta.link[link_id]->bandwidth) + continue; + + /* vif changed to narrow BW and narrow BW for station wasn't + * requested or vise versa */ + if ((new_sta_bw < sta->sta.link[link_id]->bandwidth) == !narrowed) + continue; - sta->sta.deflink.bandwidth = new_sta_bw; - rate_control_rate_update(local, sband, sta, - IEEE80211_RC_BW_CHANGED); + sta->sta.link[link_id]->bandwidth = new_sta_bw; + rate_control_rate_update(local, sband, sta, link_id, + IEEE80211_RC_BW_CHANGED); + } } rcu_read_unlock(); } @@ -508,9 +560,14 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (sdata->deflink.radar_required) { - rcu_read_unlock(); - return true; + unsigned int link_id; + + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + if (sdata->link[link_id] && + sdata->link[link_id]->radar_required) { + rcu_read_unlock(); + return true; + } } } rcu_read_unlock(); @@ -531,15 +588,27 @@ ieee80211_chanctx_radar_required(struct ieee80211_local *local, rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { + unsigned int link_id; + if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) - continue; - if (!sdata->deflink.radar_required) - continue; + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; - required = true; - break; + if (!link_conf) + continue; + + if (rcu_access_pointer(link_conf->chanctx_conf) != conf) + continue; + if (!sdata->link[link_id]->radar_required) + continue; + required = true; + break; + } + + if (required) + break; } rcu_read_unlock(); @@ -559,8 +628,8 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local, if (!ctx) return NULL; - INIT_LIST_HEAD(&ctx->assigned_vifs); - INIT_LIST_HEAD(&ctx->reserved_vifs); + INIT_LIST_HEAD(&ctx->assigned_links); + INIT_LIST_HEAD(&ctx->reserved_links); ctx->conf.def = *chandef; ctx->conf.rx_chains_static = 1; ctx->conf.rx_chains_dynamic = 1; @@ -686,21 +755,32 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { + int link_id; if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != conf) - continue; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; - if (!compat) - compat = &sdata->vif.bss_conf.chandef; + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; - compat = cfg80211_chandef_compatible( - &sdata->vif.bss_conf.chandef, compat); - if (WARN_ON_ONCE(!compat)) - break; + if (!link_conf) + continue; + + if (rcu_access_pointer(link_conf->chanctx_conf) != conf) + continue; + + if (!compat) + compat = &link_conf->chandef; + + compat = cfg80211_chandef_compatible(&link_conf->chandef, + compat); + if (WARN_ON_ONCE(!compat)) + break; + } } /* TDLS peers can sometimes affect the chandef width */ @@ -748,9 +828,11 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR); } -static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, - struct ieee80211_chanctx *new_ctx) +static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link, + struct ieee80211_chanctx *new_ctx) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *curr_ctx = NULL; @@ -759,29 +841,29 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN)) return -ENOTSUPP; - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { curr_ctx = container_of(conf, struct ieee80211_chanctx, conf); - drv_unassign_vif_chanctx(local, sdata, curr_ctx); + drv_unassign_vif_chanctx(local, sdata, link_id, curr_ctx); conf = NULL; - list_del(&sdata->assigned_chanctx_list); + list_del(&link->assigned_chanctx_list); } if (new_ctx) { - ret = drv_assign_vif_chanctx(local, sdata, new_ctx); + ret = drv_assign_vif_chanctx(local, sdata, link_id, new_ctx); if (ret) goto out; conf = &new_ctx->conf; - list_add(&sdata->assigned_chanctx_list, - &new_ctx->assigned_vifs); + list_add(&link->assigned_chanctx_list, + &new_ctx->assigned_links); } out: - rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); + rcu_assign_pointer(sdata->vif.link_conf[link_id]->chanctx_conf, conf); sdata->vif.cfg.idle = !conf; @@ -820,60 +902,64 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { u8 needed_static, needed_dynamic; + unsigned int link_id; if (!ieee80211_sdata_running(sdata)) continue; - if (rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) != - &chanctx->conf) - continue; - switch (sdata->vif.type) { - case NL80211_IFTYPE_P2P_DEVICE: - case NL80211_IFTYPE_NAN: - continue; case NL80211_IFTYPE_STATION: if (!sdata->u.mgd.associated) continue; break; - case NL80211_IFTYPE_AP_VLAN: - continue; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_OCB: break; default: - WARN_ON_ONCE(1); + continue; } - switch (sdata->deflink.smps_mode) { - default: - WARN_ONCE(1, "Invalid SMPS mode %d\n", - sdata->deflink.smps_mode); - fallthrough; - case IEEE80211_SMPS_OFF: - needed_static = sdata->deflink.needed_rx_chains; - needed_dynamic = sdata->deflink.needed_rx_chains; - break; - case IEEE80211_SMPS_DYNAMIC: - needed_static = 1; - needed_dynamic = sdata->deflink.needed_rx_chains; - break; - case IEEE80211_SMPS_STATIC: - needed_static = 1; - needed_dynamic = 1; - break; - } + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + struct ieee80211_link_data *link = sdata->link[link_id]; + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link_id]; + + if (!link_conf) + continue; + + if (rcu_access_pointer(link_conf->chanctx_conf) != &chanctx->conf) + continue; + + switch (link->smps_mode) { + default: + WARN_ONCE(1, "Invalid SMPS mode %d\n", + link->smps_mode); + fallthrough; + case IEEE80211_SMPS_OFF: + needed_static = link->needed_rx_chains; + needed_dynamic = link->needed_rx_chains; + break; + case IEEE80211_SMPS_DYNAMIC: + needed_static = 1; + needed_dynamic = link->needed_rx_chains; + break; + case IEEE80211_SMPS_STATIC: + needed_static = 1; + needed_dynamic = 1; + break; + } - rx_chains_static = max(rx_chains_static, needed_static); - rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); + rx_chains_static = max(rx_chains_static, needed_static); + rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); + } } /* Disable SMPS for the monitor interface */ sdata = rcu_dereference(local->monitor_sdata); if (sdata && - rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf) + rcu_access_pointer(sdata->vif.link_conf[0]->chanctx_conf) == &chanctx->conf) rx_chains_dynamic = rx_chains_static = local->rx_chains; rcu_read_unlock(); @@ -898,9 +984,12 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, } static void -__ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, - bool clear) +__ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, + bool clear) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local __maybe_unused = sdata->local; struct ieee80211_sub_if_data *vlan; struct ieee80211_chanctx_conf *conf; @@ -916,7 +1005,7 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, * channel context pointer for a while, possibly pointing * to a channel context that has already been freed. */ - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(link_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); WARN_ON(!conf); @@ -924,32 +1013,34 @@ __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, conf = NULL; list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - rcu_assign_pointer(vlan->vif.bss_conf.chanctx_conf, conf); + rcu_assign_pointer(vlan->vif.link_conf[link_id]->chanctx_conf, + conf); } -void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, - bool clear) +void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, + bool clear) { - struct ieee80211_local *local = sdata->local; + struct ieee80211_local *local = link->sdata->local; mutex_lock(&local->chanctx_mtx); - __ieee80211_vif_copy_chanctx_to_vlans(sdata, clear); + __ieee80211_link_copy_chanctx_to_vlans(link, clear); mutex_unlock(&local->chanctx_mtx); } -int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) +int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link) { - struct ieee80211_chanctx *ctx = sdata->deflink.reserved_chanctx; + struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_chanctx *ctx = link->reserved_chanctx; lockdep_assert_held(&sdata->local->chanctx_mtx); if (WARN_ON(!ctx)) return -EINVAL; - list_del(&sdata->reserved_chanctx_list); - sdata->deflink.reserved_chanctx = NULL; + list_del(&link->reserved_chanctx_list); + link->reserved_chanctx = NULL; if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) { if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) { @@ -974,17 +1065,18 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata) return 0; } -int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode, - bool radar_required) +int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode, + bool radar_required) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx; lockdep_assert_held(&local->chanctx_mtx); - curr_ctx = ieee80211_vif_get_chanctx(sdata); + curr_ctx = ieee80211_link_get_chanctx(link); if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx) return -ENOTSUPP; @@ -998,11 +1090,11 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, if (!curr_ctx || (curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) || - !list_empty(&curr_ctx->reserved_vifs)) { + !list_empty(&curr_ctx->reserved_links)) { /* - * Another vif already requested this context + * Another link already requested this context * for a reservation. Find another one hoping - * all vifs assigned to it will also switch + * all links assigned to it will also switch * soon enough. * * TODO: This needs a little more work as some @@ -1011,13 +1103,13 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, * provided some channel context juggling was * performed. * - * Consider ctx1..3, vif1..6, each ctx has 2 - * vifs. vif1 and vif2 from ctx1 request new + * Consider ctx1..3, link1..6, each ctx has 2 + * links. link1 and link2 from ctx1 request new * different chandefs starting 2 in-place * reserations with ctx4 and ctx5 replacing - * ctx1 and ctx2 respectively. Next vif5 and - * vif6 from ctx3 reserve ctx4. If vif3 and - * vif4 remain on ctx2 as they are then this + * ctx1 and ctx2 respectively. Next link5 and + * link6 from ctx3 reserve ctx4. If link3 and + * link4 remain on ctx2 as they are then this * fails unless `replace_ctx` from ctx5 is * replaced with ctx3. */ @@ -1027,7 +1119,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, IEEE80211_CHANCTX_REPLACE_NONE) continue; - if (!list_empty(&ctx->reserved_vifs)) + if (!list_empty(&ctx->reserved_links)) continue; curr_ctx = ctx; @@ -1042,7 +1134,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, if (!curr_ctx || (curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) || - !list_empty(&curr_ctx->reserved_vifs)) + !list_empty(&curr_ctx->reserved_links)) return -EBUSY; new_ctx = ieee80211_alloc_chanctx(local, chandef, mode); @@ -1061,25 +1153,27 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, } } - list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs); - sdata->deflink.reserved_chanctx = new_ctx; - sdata->deflink.reserved_chandef = *chandef; - sdata->deflink.reserved_radar_required = radar_required; - sdata->deflink.reserved_ready = false; + list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links); + link->reserved_chanctx = new_ctx; + link->reserved_chandef = *chandef; + link->reserved_radar_required = radar_required; + link->reserved_ready = false; return 0; } static void -ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) +ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + switch (sdata->vif.type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_OCB: ieee80211_queue_work(&sdata->local->hw, - &sdata->deflink.csa_finalize_work); + &link->csa_finalize_work); break; case NL80211_IFTYPE_STATION: ieee80211_queue_work(&sdata->local->hw, @@ -1100,23 +1194,28 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) } static void -ieee80211_vif_update_chandef(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef) +ieee80211_link_update_chandef(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; struct ieee80211_sub_if_data *vlan; - sdata->vif.bss_conf.chandef = *chandef; + sdata->vif.link_conf[link_id]->chandef = *chandef; if (sdata->vif.type != NL80211_IFTYPE_AP) return; list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) - vlan->vif.bss_conf.chandef = *chandef; + vlan->vif.link_conf[link_id]->chandef = *chandef; } static int -ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) +ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local = sdata->local; struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; struct ieee80211_chanctx *old_ctx, *new_ctx; @@ -1127,10 +1226,10 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->mtx); lockdep_assert_held(&local->chanctx_mtx); - new_ctx = sdata->deflink.reserved_chanctx; - old_ctx = ieee80211_vif_get_chanctx(sdata); + new_ctx = link->reserved_chanctx; + old_ctx = ieee80211_link_get_chanctx(link); - if (WARN_ON(!sdata->deflink.reserved_ready)) + if (WARN_ON(!link->reserved_ready)) return -EBUSY; if (WARN_ON(!new_ctx)) @@ -1144,23 +1243,24 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) return -EINVAL; chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, - &sdata->deflink.reserved_chandef); + &link->reserved_chandef); if (WARN_ON(!chandef)) return -EINVAL; - if (sdata->vif.bss_conf.chandef.width != sdata->deflink.reserved_chandef.width) + if (link_conf->chandef.width != link->reserved_chandef.width) changed = BSS_CHANGED_BANDWIDTH; - ieee80211_vif_update_chandef(sdata, &sdata->deflink.reserved_chandef); + ieee80211_link_update_chandef(link, &link->reserved_chandef); ieee80211_change_chanctx(local, new_ctx, old_ctx, chandef); vif_chsw[0].vif = &sdata->vif; vif_chsw[0].old_ctx = &old_ctx->conf; vif_chsw[0].new_ctx = &new_ctx->conf; + vif_chsw[0].link_id = link->link_id; - list_del(&sdata->reserved_chanctx_list); - sdata->deflink.reserved_chanctx = NULL; + list_del(&link->reserved_chanctx_list); + link->reserved_chanctx = NULL; err = drv_switch_vif_chanctx(local, vif_chsw, 1, CHANCTX_SWMODE_REASSIGN_VIF); @@ -1171,11 +1271,11 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) goto out; } - list_move(&sdata->assigned_chanctx_list, &new_ctx->assigned_vifs); - rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, &new_ctx->conf); + list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links); + rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf); if (sdata->vif.type == NL80211_IFTYPE_AP) - __ieee80211_vif_copy_chanctx_to_vlans(sdata, false); + __ieee80211_link_copy_chanctx_to_vlans(link, false); ieee80211_check_fast_xmit_iface(sdata); @@ -1187,25 +1287,27 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) ieee80211_recalc_radar_chanctx(local, new_ctx); if (changed) - ieee80211_link_info_change_notify(sdata, 0, changed); + ieee80211_link_info_change_notify(sdata, link_id, changed); out: - ieee80211_vif_chanctx_reservation_complete(sdata); + ieee80211_link_chanctx_reservation_complete(link); return err; } static int -ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) +ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *old_ctx, *new_ctx; const struct cfg80211_chan_def *chandef; int err; - old_ctx = ieee80211_vif_get_chanctx(sdata); - new_ctx = sdata->deflink.reserved_chanctx; + old_ctx = ieee80211_vif_get_chanctx(sdata, link_id); + new_ctx = link->reserved_chanctx; - if (WARN_ON(!sdata->deflink.reserved_ready)) + if (WARN_ON(!link->reserved_ready)) return -EINVAL; if (WARN_ON(old_ctx)) @@ -1219,16 +1321,16 @@ ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) return -EINVAL; chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx, - &sdata->deflink.reserved_chandef); + &link->reserved_chandef); if (WARN_ON(!chandef)) return -EINVAL; ieee80211_change_chanctx(local, new_ctx, new_ctx, chandef); - list_del(&sdata->reserved_chanctx_list); - sdata->deflink.reserved_chanctx = NULL; + list_del(&link->reserved_chanctx_list); + link->reserved_chanctx = NULL; - err = ieee80211_assign_vif_chanctx(sdata, new_ctx); + err = ieee80211_assign_link_chanctx(link, new_ctx); if (err) { if (ieee80211_chanctx_refcount(local, new_ctx) == 0) ieee80211_free_chanctx(local, new_ctx); @@ -1237,19 +1339,20 @@ ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata) } out: - ieee80211_vif_chanctx_reservation_complete(sdata); + ieee80211_link_chanctx_reservation_complete(link); return err; } static bool -ieee80211_vif_has_in_place_reservation(struct ieee80211_sub_if_data *sdata) +ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_chanctx *old_ctx, *new_ctx; lockdep_assert_held(&sdata->local->chanctx_mtx); - new_ctx = sdata->deflink.reserved_chanctx; - old_ctx = ieee80211_vif_get_chanctx(sdata); + new_ctx = link->reserved_chanctx; + old_ctx = ieee80211_link_get_chanctx(link); if (!old_ctx) return false; @@ -1289,7 +1392,7 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, int n_vifs) { struct ieee80211_vif_chanctx_switch *vif_chsw; - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; struct ieee80211_chanctx *ctx, *old_ctx; int i, err; @@ -1310,16 +1413,16 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, goto out; } - list_for_each_entry(sdata, &ctx->reserved_vifs, + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - if (!ieee80211_vif_has_in_place_reservation( - sdata)) + if (!ieee80211_link_has_in_place_reservation(link)) continue; - old_ctx = ieee80211_vif_get_chanctx(sdata); - vif_chsw[i].vif = &sdata->vif; + old_ctx = ieee80211_link_get_chanctx(link); + vif_chsw[i].vif = &link->sdata->vif; vif_chsw[i].old_ctx = &old_ctx->conf; vif_chsw[i].new_ctx = &ctx->conf; + vif_chsw[i].link_id = link->link_id; i++; } @@ -1345,7 +1448,7 @@ static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local) if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; - if (!list_empty(&ctx->replace_ctx->assigned_vifs)) + if (!list_empty(&ctx->replace_ctx->assigned_links)) continue; ieee80211_del_chanctx(local, ctx->replace_ctx); @@ -1362,7 +1465,7 @@ err: if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; - if (!list_empty(&ctx->replace_ctx->assigned_vifs)) + if (!list_empty(&ctx->replace_ctx->assigned_links)) continue; ieee80211_del_chanctx(local, ctx); @@ -1374,7 +1477,6 @@ err: static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata, *sdata_tmp; struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx; struct ieee80211_chanctx *new_ctx = NULL; int err, n_assigned, n_reserved, n_ready; @@ -1400,6 +1502,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) */ list_for_each_entry(ctx, &local->chanctx_list, list) { + struct ieee80211_link_data *link; + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; @@ -1417,12 +1521,12 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) n_reserved = 0; n_ready = 0; - list_for_each_entry(sdata, &ctx->replace_ctx->assigned_vifs, + list_for_each_entry(link, &ctx->replace_ctx->assigned_links, assigned_chanctx_list) { n_assigned++; - if (sdata->deflink.reserved_chanctx) { + if (link->reserved_chanctx) { n_reserved++; - if (sdata->deflink.reserved_ready) + if (link->reserved_ready) n_ready++; } } @@ -1439,13 +1543,13 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) } ctx->conf.radar_enabled = false; - list_for_each_entry(sdata, &ctx->reserved_vifs, + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - if (ieee80211_vif_has_in_place_reservation(sdata) && - !sdata->deflink.reserved_ready) + if (ieee80211_link_has_in_place_reservation(link) && + !link->reserved_ready) return -EAGAIN; - old_ctx = ieee80211_vif_get_chanctx(sdata); + old_ctx = ieee80211_link_get_chanctx(link); if (old_ctx) { if (old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) @@ -1456,7 +1560,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) n_vifs_ctxless++; } - if (sdata->deflink.reserved_radar_required) + if (link->reserved_radar_required) ctx->conf.radar_enabled = true; } } @@ -1499,6 +1603,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) * context(s). */ list_for_each_entry(ctx, &local->chanctx_list, list) { + struct ieee80211_link_data *link, *link_tmp; + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; @@ -1507,32 +1613,34 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) goto err; } - list_for_each_entry(sdata, &ctx->reserved_vifs, + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { + struct ieee80211_sub_if_data *sdata = link->sdata; + struct ieee80211_bss_conf *link_conf = + sdata->vif.link_conf[link->link_id]; u32 changed = 0; - if (!ieee80211_vif_has_in_place_reservation(sdata)) + if (!ieee80211_link_has_in_place_reservation(link)) continue; - rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, + rcu_assign_pointer(link_conf->chanctx_conf, &ctx->conf); if (sdata->vif.type == NL80211_IFTYPE_AP) - __ieee80211_vif_copy_chanctx_to_vlans(sdata, - false); + __ieee80211_link_copy_chanctx_to_vlans(link, + false); ieee80211_check_fast_xmit_iface(sdata); - sdata->deflink.radar_required = sdata->deflink.reserved_radar_required; + link->radar_required = link->reserved_radar_required; - if (sdata->vif.bss_conf.chandef.width != - sdata->deflink.reserved_chandef.width) + if (link_conf->chandef.width != link->reserved_chandef.width) changed = BSS_CHANGED_BANDWIDTH; - ieee80211_vif_update_chandef(sdata, - &sdata->deflink.reserved_chandef); + ieee80211_link_update_chandef(link, &link->reserved_chandef); if (changed) - ieee80211_link_info_change_notify(sdata, 0, + ieee80211_link_info_change_notify(sdata, + link->link_id, changed); ieee80211_recalc_txpower(sdata, false); @@ -1543,17 +1651,17 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ieee80211_recalc_radar_chanctx(local, ctx); ieee80211_recalc_chanctx_min_def(local, ctx); - list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links, reserved_chanctx_list) { - if (ieee80211_vif_get_chanctx(sdata) != ctx) + if (ieee80211_link_get_chanctx(link) != ctx) continue; - list_del(&sdata->reserved_chanctx_list); - list_move(&sdata->assigned_chanctx_list, - &ctx->assigned_vifs); - sdata->deflink.reserved_chanctx = NULL; + list_del(&link->reserved_chanctx_list); + list_move(&link->assigned_chanctx_list, + &ctx->assigned_links); + link->reserved_chanctx = NULL; - ieee80211_vif_chanctx_reservation_complete(sdata); + ieee80211_link_chanctx_reservation_complete(link); } /* @@ -1563,31 +1671,29 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) * reservation for originally requested interface has already * succeeded at this point. */ - list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links, reserved_chanctx_list) { - if (WARN_ON(ieee80211_vif_has_in_place_reservation( - sdata))) + if (WARN_ON(ieee80211_link_has_in_place_reservation(link))) continue; - if (WARN_ON(sdata->deflink.reserved_chanctx != ctx)) + if (WARN_ON(link->reserved_chanctx != ctx)) continue; - if (!sdata->deflink.reserved_ready) + if (!link->reserved_ready) continue; - if (ieee80211_vif_get_chanctx(sdata)) - err = ieee80211_vif_use_reserved_reassign( - sdata); + if (ieee80211_link_get_chanctx(link)) + err = ieee80211_link_use_reserved_reassign(link); else - err = ieee80211_vif_use_reserved_assign(sdata); + err = ieee80211_link_use_reserved_assign(link); if (err) { - sdata_info(sdata, - "failed to finalize (re-)assign reservation (err=%d)\n", - err); - ieee80211_vif_unreserve_chanctx(sdata); + link_info(link, + "failed to finalize (re-)assign reservation (err=%d)\n", + err); + ieee80211_link_unreserve_chanctx(link); cfg80211_stop_iface(local->hw.wiphy, - &sdata->wdev, + &link->sdata->wdev, GFP_KERNEL); } } @@ -1613,21 +1719,26 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) err: list_for_each_entry(ctx, &local->chanctx_list, list) { + struct ieee80211_link_data *link, *link_tmp; + if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) continue; - list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, + list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links, reserved_chanctx_list) { - ieee80211_vif_unreserve_chanctx(sdata); - ieee80211_vif_chanctx_reservation_complete(sdata); + ieee80211_link_unreserve_chanctx(link); + ieee80211_link_chanctx_reservation_complete(link); } } return err; } -static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) +static void __ieee80211_link_release_channel(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -1635,38 +1746,38 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(link_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) return; ctx = container_of(conf, struct ieee80211_chanctx, conf); - if (sdata->deflink.reserved_chanctx) { - if (sdata->deflink.reserved_chanctx->replace_state == - IEEE80211_CHANCTX_REPLACES_OTHER && - ieee80211_chanctx_num_reserved(local, - sdata->deflink.reserved_chanctx) > 1) + if (link->reserved_chanctx) { + if (link->reserved_chanctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER && + ieee80211_chanctx_num_reserved(local, link->reserved_chanctx) > 1) use_reserved_switch = true; - ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_link_unreserve_chanctx(link); } - ieee80211_assign_vif_chanctx(sdata, NULL); + ieee80211_assign_link_chanctx(link, NULL); if (ieee80211_chanctx_refcount(local, ctx) == 0) ieee80211_free_chanctx(local, ctx); - sdata->deflink.radar_required = false; + link->radar_required = false; /* Unreserving may ready an in-place reservation. */ if (use_reserved_switch) ieee80211_vif_use_reserved_switch(local); } -int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode) +int ieee80211_link_use_channel(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *ctx; u8 radar_detect_width = 0; @@ -1686,14 +1797,14 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, if (ret > 0) radar_detect_width = BIT(chandef->width); - sdata->deflink.radar_required = ret; + sdata->link[link_id]->radar_required = ret; ret = ieee80211_check_combinations(sdata, chandef, mode, radar_detect_width); if (ret < 0) goto out; - __ieee80211_vif_release_channel(sdata); + __ieee80211_link_release_channel(link); ctx = ieee80211_find_chanctx(local, chandef, mode); if (!ctx) @@ -1703,9 +1814,9 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, goto out; } - ieee80211_vif_update_chandef(sdata, chandef); + ieee80211_link_update_chandef(link, chandef); - ret = ieee80211_assign_vif_chanctx(sdata, ctx); + ret = ieee80211_assign_link_chanctx(link, ctx); if (ret) { /* if assign fails refcount stays the same */ if (ieee80211_chanctx_refcount(local, ctx) == 0) @@ -1717,14 +1828,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_radar_chanctx(local, ctx); out: if (ret) - sdata->deflink.radar_required = false; + link->radar_required = false; mutex_unlock(&local->chanctx_mtx); return ret; } -int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) +int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx *new_ctx; struct ieee80211_chanctx *old_ctx; @@ -1733,8 +1845,8 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&local->mtx); lockdep_assert_held(&local->chanctx_mtx); - new_ctx = sdata->deflink.reserved_chanctx; - old_ctx = ieee80211_vif_get_chanctx(sdata); + new_ctx = link->reserved_chanctx; + old_ctx = ieee80211_link_get_chanctx(link); if (WARN_ON(!new_ctx)) return -EINVAL; @@ -1743,16 +1855,16 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) IEEE80211_CHANCTX_WILL_BE_REPLACED)) return -EINVAL; - if (WARN_ON(sdata->deflink.reserved_ready)) + if (WARN_ON(link->reserved_ready)) return -EINVAL; - sdata->deflink.reserved_ready = true; + link->reserved_ready = true; if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) { if (old_ctx) - return ieee80211_vif_use_reserved_reassign(sdata); + return ieee80211_link_use_reserved_reassign(link); - return ieee80211_vif_use_reserved_assign(sdata); + return ieee80211_link_use_reserved_assign(link); } /* @@ -1784,10 +1896,13 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata) return 0; } -int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - u32 *changed) +int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + u32 *changed) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -1799,18 +1914,18 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, return -EINVAL; mutex_lock(&local->chanctx_mtx); - if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) { + if (cfg80211_chandef_identical(chandef, &link_conf->chandef)) { ret = 0; goto out; } if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) { + link_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) { ret = -EINVAL; goto out; } - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(link_conf->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (!conf) { ret = -EINVAL; @@ -1845,7 +1960,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, break; } - ieee80211_vif_update_chandef(sdata, chandef); + ieee80211_link_update_chandef(link, chandef); ieee80211_recalc_chanctx_chantype(local, ctx); @@ -1856,19 +1971,24 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, return ret; } -void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) +void ieee80211_link_release_channel(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); lockdep_assert_held(&sdata->local->mtx); mutex_lock(&sdata->local->chanctx_mtx); - __ieee80211_vif_release_channel(sdata); + __ieee80211_link_release_channel(link); mutex_unlock(&sdata->local->chanctx_mtx); } -void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) +void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link) { + struct ieee80211_sub_if_data *sdata = link->sdata; + unsigned int link_id = link->link_id; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; struct ieee80211_local *local = sdata->local; struct ieee80211_sub_if_data *ap; struct ieee80211_chanctx_conf *conf; @@ -1880,9 +2000,9 @@ void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(ap->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(ap->vif.link_conf[link_id]->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); - rcu_assign_pointer(sdata->vif.bss_conf.chanctx_conf, conf); + rcu_assign_pointer(link_conf->chanctx_conf, conf); mutex_unlock(&local->chanctx_mtx); } diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h index d90a8f9cc3fd..3302e8da0314 100644 --- a/net/mac80211/debug.h +++ b/net/mac80211/debug.h @@ -1,4 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * Portions + * Copyright (C) 2022 Intel Corporation + */ #ifndef __MAC80211_DEBUG_H #define __MAC80211_DEBUG_H #include @@ -130,6 +134,16 @@ do { \ #define sdata_dbg(sdata, fmt, ...) \ _sdata_dbg(1, sdata, fmt, ##__VA_ARGS__) +#define link_info(link, fmt, ...) \ + _sdata_info((link)->sdata, "[link %d] " fmt, (link)->link_id, \ + ##__VA_ARGS__) +#define link_err(link, fmt, ...) \ + _sdata_err((link)->sdata, "[link %d] " fmt, (link)->link_id, \ + ##__VA_ARGS__) +#define link_dbg(link, fmt, ...) \ + _sdata_dbg(1, (link)->sdata, "[link %d] " fmt, (link)->link_id, \ + ##__VA_ARGS__) + #define ht_dbg(sdata, fmt, ...) \ _sdata_dbg(MAC80211_HT_DEBUG, \ sdata, fmt, ##__VA_ARGS__) diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 15ab8d00815b..9238283a8237 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -938,6 +938,7 @@ static inline void drv_change_chanctx(struct ieee80211_local *local, static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx) { int ret = 0; @@ -945,11 +946,12 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return -EIO; - trace_drv_assign_vif_chanctx(local, sdata, ctx); + trace_drv_assign_vif_chanctx(local, sdata, link_id, ctx); if (local->ops->assign_vif_chanctx) { WARN_ON_ONCE(!ctx->driver_present); ret = local->ops->assign_vif_chanctx(&local->hw, &sdata->vif, + link_id, &ctx->conf); } trace_drv_return_int(local, ret); @@ -959,6 +961,7 @@ static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx) { might_sleep(); @@ -966,11 +969,12 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return; - trace_drv_unassign_vif_chanctx(local, sdata, ctx); + trace_drv_unassign_vif_chanctx(local, sdata, link_id, ctx); if (local->ops->unassign_vif_chanctx) { WARN_ON_ONCE(!ctx->driver_present); local->ops->unassign_vif_chanctx(&local->hw, &sdata->vif, + link_id, &ctx->conf); } trace_drv_return_void(local); diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c index 96c9486bf2fe..2d9c6e845ce4 100644 --- a/net/mac80211/eht.c +++ b/net/mac80211/eht.c @@ -71,6 +71,6 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, eht_cap->has_eht = true; - sta->deflink.cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta); - sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta); + sta->deflink.cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta, 0); + sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta, 0); } diff --git a/net/mac80211/he.c b/net/mac80211/he.c index 1a61f7552edd..20448dda8c4d 100644 --- a/net/mac80211/he.c +++ b/net/mac80211/he.c @@ -3,7 +3,7 @@ * HE handling * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2019 - 2020 Intel Corporation + * Copyright(c) 2019 - 2022 Intel Corporation */ #include "ieee80211_i.h" @@ -153,8 +153,8 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, he_cap->has_he = true; - sta->deflink.cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta); - sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta); + sta->deflink.cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta, 0); + sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta, 0); if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa) ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, sta); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3b68e9f4345b..2ca75f2d3023 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -301,8 +301,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, radar_required = err; mutex_lock(&local->mtx); - if (ieee80211_vif_use_channel(sdata, &chandef, - ifibss->fixed_channel ? + if (ieee80211_link_use_channel(sdata->link[0], &chandef, + ifibss->fixed_channel ? IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE)) { sdata_info(sdata, "Failed to join IBSS, no channel context\n"); @@ -371,7 +371,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, RCU_INIT_POINTER(ifibss->presp, NULL); kfree_rcu(presp, rcu_head); mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&local->mtx); sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n", err); @@ -725,7 +725,7 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) BSS_CHANGED_IBSS); drv_leave_ibss(local, sdata); mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&local->mtx); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 397b111f006d..92ed1e3c2980 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -787,8 +787,8 @@ struct ieee80211_chanctx { struct list_head list; struct rcu_head rcu_head; - struct list_head assigned_vifs; - struct list_head reserved_vifs; + struct list_head assigned_links; + struct list_head reserved_links; enum ieee80211_chanctx_replace_state replace_state; struct ieee80211_chanctx *replace_ctx; @@ -909,6 +909,12 @@ struct ieee80211_link_data_ap { }; struct ieee80211_link_data { + struct ieee80211_sub_if_data *sdata; + unsigned int link_id; + + struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ + struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ + /* multicast keys only */ struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS + @@ -989,9 +995,6 @@ struct ieee80211_sub_if_data { struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; struct mac80211_qos_map __rcu *qos_map; - struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ - struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ - /* used to reconfigure hardware SM PS */ struct work_struct recalc_smps; @@ -2119,8 +2122,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, struct sta_info *sta); -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta); -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); +enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, + unsigned int link_id); +enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, + unsigned int link_id); void ieee80211_sta_set_rx_nss(struct sta_info *sta); enum ieee80211_sta_rx_bandwidth ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width); @@ -2470,26 +2475,26 @@ bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper, u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c); int __must_check -ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode); +ieee80211_link_use_channel(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode); int __must_check -ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - enum ieee80211_chanctx_mode mode, - bool radar_required); +ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + enum ieee80211_chanctx_mode mode, + bool radar_required); int __must_check -ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata); -int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata); +ieee80211_link_use_reserved_context(struct ieee80211_link_data *link); +int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link); int __must_check -ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, - const struct cfg80211_chan_def *chandef, - u32 *changed); -void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); -void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); -void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, - bool clear); +ieee80211_link_change_bandwidth(struct ieee80211_link_data *link, + const struct cfg80211_chan_def *chandef, + u32 *changed); +void ieee80211_link_release_channel(struct ieee80211_link_data *link); +void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link); +void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link, + bool clear); int ieee80211_chanctx_refcount(struct ieee80211_local *local, struct ieee80211_chanctx *ctx); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 04ee525394e9..1764068a18d1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -471,7 +471,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do chandef = sdata->vif.bss_conf.chandef; WARN_ON(local->suspended); mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&local->mtx); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_ABORTED, @@ -1027,6 +1027,7 @@ static void ieee80211_sdata_init(struct ieee80211_local *local, */ sdata->vif.link_conf[0] = &sdata->vif.bss_conf; sdata->link[0] = &sdata->deflink; + sdata->deflink.sdata = sdata; } int ieee80211_add_virtual_monitor(struct ieee80211_local *local) @@ -1077,8 +1078,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) mutex_unlock(&local->iflist_mtx); mutex_lock(&local->mtx); - ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, - IEEE80211_CHANCTX_EXCLUSIVE); + ret = ieee80211_link_use_channel(sdata->link[0], &local->monitor_chandef, + IEEE80211_CHANCTX_EXCLUSIVE); mutex_unlock(&local->mtx); if (ret) { mutex_lock(&local->iflist_mtx); @@ -1122,7 +1123,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) synchronize_net(); mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&local->mtx); drv_remove_interface(local, sdata); @@ -1228,7 +1229,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) case NL80211_IFTYPE_AP_VLAN: /* no need to tell driver, but set carrier and chanctx */ if (sdata->bss->active) { - ieee80211_vif_vlan_copy_chanctx(sdata); + ieee80211_link_vlan_copy_chanctx(sdata->link[0]); netif_carrier_on(dev); ieee80211_set_vif_encap_ops(sdata); } else { @@ -1681,8 +1682,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, ieee80211_csa_finalize_work); INIT_WORK(&sdata->deflink.color_change_finalize_work, ieee80211_color_change_finalize_work); - INIT_LIST_HEAD(&sdata->assigned_chanctx_list); - INIT_LIST_HEAD(&sdata->reserved_chanctx_list); + INIT_LIST_HEAD(&sdata->deflink.assigned_chanctx_list); + INIT_LIST_HEAD(&sdata->deflink.reserved_chanctx_list); switch (type) { case NL80211_IFTYPE_P2P_GO: diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 42ba7424589e..a6cb1db50f1d 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2019, 2021 Intel Corporation + * Copyright (C) 2019, 2021-2022 Intel Corporation * Author: Luis Carlos Cobo */ #include @@ -464,7 +464,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) rate_control_rate_init(sta); else - rate_control_rate_update(local, sband, sta, changed); + rate_control_rate_update(local, sband, sta, 0, changed); out: spin_unlock_bh(&sta->mesh->plink_lock); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e172bdfe9b0a..ca9e0d83e2a4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -479,7 +479,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, return -EINVAL; } - ret = ieee80211_vif_change_bandwidth(sdata, &chandef, changed); + ret = ieee80211_link_change_bandwidth(&sdata->deflink, &chandef, changed); if (ret) { sdata_info(sdata, @@ -1248,7 +1248,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) if (sdata->deflink.reserved_ready) goto out; - ret = ieee80211_vif_use_reserved_context(sdata); + ret = ieee80211_link_use_reserved_context(&sdata->deflink); if (ret) { sdata_info(sdata, "failed to use reserved channel context, disconnecting (err=%d)\n", @@ -1354,7 +1354,7 @@ ieee80211_sta_abort_chanswitch(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->mtx); mutex_lock(&local->chanctx_mtx); - ieee80211_vif_unreserve_chanctx(sdata); + ieee80211_link_unreserve_chanctx(&sdata->deflink); mutex_unlock(&local->chanctx_mtx); if (sdata->deflink.csa_block_tx) @@ -1496,8 +1496,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, goto drop_connection; } - res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, - chanctx->mode, false); + res = ieee80211_link_reserve_chanctx(&sdata->deflink, &csa_ie.chandef, + chanctx->mode, false); if (res) { sdata_info(sdata, "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", @@ -1942,7 +1942,7 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) mutex_lock(&sdata->local->mtx); if (sdata->wdev.cac_started) { - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); @@ -2483,7 +2483,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags = 0; mutex_lock(&local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); sdata->vif.bss_conf.csa_active = false; sdata->deflink.u.mgd.csa_waiting_bcn = false; @@ -2923,7 +2923,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); } @@ -2954,7 +2954,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.mu_mimo_owner = false; mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); if (abandon) @@ -5497,8 +5497,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, * on incompatible channels, e.g. 80+80 and 160 sharing the * same control channel) try to use a smaller bandwidth. */ - ret = ieee80211_vif_use_channel(sdata, &chandef, - IEEE80211_CHANCTX_SHARED); + ret = ieee80211_link_use_channel(&sdata->deflink, &chandef, + IEEE80211_CHANCTX_SHARED); /* don't downgrade for 5 and 10 MHz channels, though. */ if (chandef.width == NL80211_CHAN_WIDTH_5 || @@ -5507,8 +5507,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); - ret = ieee80211_vif_use_channel(sdata, &chandef, - IEEE80211_CHANCTX_SHARED); + ret = ieee80211_link_use_channel(&sdata->deflink, &chandef, + IEEE80211_CHANCTX_SHARED); } out: mutex_unlock(&local->mtx); @@ -5868,7 +5868,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_BSSID); ifmgd->auth_data = NULL; mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&sdata->local->mtx); kfree(auth_data); return err; diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index ab2658ad73ce..468c741a9aeb 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -186,8 +186,8 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, sdata->deflink.needed_rx_chains = sdata->local->rx_chains; mutex_lock(&sdata->local->mtx); - err = ieee80211_vif_use_channel(sdata, &setup->chandef, - IEEE80211_CHANCTX_SHARED); + err = ieee80211_link_use_channel(sdata->link[0], &setup->chandef, + IEEE80211_CHANCTX_SHARED); mutex_unlock(&sdata->local->mtx); if (err) return err; @@ -229,7 +229,7 @@ int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB); mutex_lock(&sdata->local->mtx); - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); mutex_unlock(&sdata->local->mtx); skb_queue_purge(&sdata->skb_queue); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index f22381127948..b268088585eb 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -90,14 +90,17 @@ void rate_control_tx_status(struct ieee80211_local *local, } void rate_control_rate_update(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta, u32 changed) + struct ieee80211_supported_band *sband, + struct sta_info *sta, unsigned int link_id, + u32 changed) { struct rate_control_ref *ref = local->rate_ctrl; struct ieee80211_sta *ista = &sta->sta; void *priv_sta = sta->rate_ctrl_priv; struct ieee80211_chanctx_conf *chanctx_conf; + WARN_ON(link_id != 0); + if (ref && ref->ops->rate_update) { rcu_read_lock(); @@ -113,6 +116,7 @@ void rate_control_rate_update(struct ieee80211_local *local, spin_unlock_bh(&sta->rate_ctrl_lock); rcu_read_unlock(); } + drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); } diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 79b44d3db171..fbc8bdb54c43 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -3,6 +3,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright (c) 2006 Jiri Benc + * Copyright (C) 2022 Intel Corporation */ #ifndef IEEE80211_RATE_H @@ -31,8 +32,10 @@ void rate_control_tx_status(struct ieee80211_local *local, void rate_control_rate_init(struct sta_info *sta); void rate_control_rate_update(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta, u32 changed); + struct ieee80211_supported_band *sband, + struct sta_info *sta, + unsigned int link_id, + u32 changed); static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, struct sta_info *sta, gfp_t gfp) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 21e7424f261a..1774d0f9feaa 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3369,7 +3369,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sband = rx->local->hw.wiphy->bands[status->band]; - rate_control_rate_update(local, sband, rx->sta, + rate_control_rate_update(local, sband, rx->sta, 0, IEEE80211_RC_SMPS_CHANGED); cfg80211_sta_opmode_change_notify(sdata->dev, rx->sta->addr, @@ -3391,11 +3391,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) max_bw = IEEE80211_STA_RX_BW_20; else - max_bw = ieee80211_sta_cap_rx_bw(rx->sta); + max_bw = ieee80211_sta_cap_rx_bw(rx->sta, 0); /* set cur_max_bandwidth and recalc sta bw */ rx->sta->deflink.cur_max_bandwidth = max_bw; - new_bw = ieee80211_sta_cur_vht_bw(rx->sta); + new_bw = ieee80211_sta_cur_vht_bw(rx->sta, 0); if (rx->sta->sta.deflink.bandwidth == new_bw) goto handled; @@ -3406,7 +3406,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) ieee80211_sta_rx_bw_to_chan_width(rx->sta); sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; - rate_control_rate_update(local, sband, rx->sta, + rate_control_rate_update(local, sband, rx->sta, 0, IEEE80211_RC_BW_CHANGED); cfg80211_sta_opmode_change_notify(sdata->dev, rx->sta->addr, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 11a3b950b490..86a13ef31ef1 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1268,10 +1268,10 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata, enum ieee80211_sta_rx_bandwidth bw; bw = ieee80211_chan_width_to_rx_bw(conf->def.width); - bw = min(bw, ieee80211_sta_cap_rx_bw(sta)); + bw = min(bw, ieee80211_sta_cap_rx_bw(sta, 0)); if (bw != sta->sta.deflink.bandwidth) { sta->sta.deflink.bandwidth = bw; - rate_control_rate_update(local, sband, sta, + rate_control_rate_update(local, sband, sta, 0, IEEE80211_RC_BW_CHANGED); /* * if a TDLS peer BW was updated, we need to diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 9417378b4fc0..2f325eaf4576 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1625,6 +1625,7 @@ struct trace_chandef_entry { struct trace_switch_entry { struct trace_vif_entry vif; + unsigned int link_id; struct trace_chandef_entry old_chandef; struct trace_chandef_entry new_chandef; } __packed; @@ -1664,6 +1665,7 @@ TRACE_EVENT(drv_switch_vif_chanctx, SWITCH_ENTRY_ASSIGN(vif.vif_type, vif->type); SWITCH_ENTRY_ASSIGN(vif.p2p, vif->p2p); + SWITCH_ENTRY_ASSIGN(link_id, link_id); strncpy(local_vifs[i].vif.vif_name, sdata->name, sizeof(local_vifs[i].vif.vif_name)); @@ -1704,40 +1706,45 @@ TRACE_EVENT(drv_switch_vif_chanctx, DECLARE_EVENT_CLASS(local_sdata_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, ctx), + TP_ARGS(local, sdata, link_id, ctx), TP_STRUCT__entry( LOCAL_ENTRY VIF_ENTRY CHANCTX_ENTRY + __field(unsigned int, link_id) ), TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; CHANCTX_ASSIGN; + __entry->link_id = link_id; ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT CHANCTX_PR_FMT, - LOCAL_PR_ARG, VIF_PR_ARG, CHANCTX_PR_ARG + LOCAL_PR_FMT VIF_PR_FMT " link_id:%d" CHANCTX_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id, CHANCTX_PR_ARG ) ); DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, ctx) + TP_ARGS(local, sdata, link_id, ctx) ); DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_chanctx *ctx), - TP_ARGS(local, sdata, ctx) + TP_ARGS(local, sdata, link_id, ctx) ); TRACE_EVENT(drv_start_ap, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 2a279dc3e457..4ec96170a679 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2255,7 +2255,8 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) } static void ieee80211_assign_chanctx(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *ctx; @@ -2264,11 +2265,11 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local, return; mutex_lock(&local->chanctx_mtx); - conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); if (conf) { ctx = container_of(conf, struct ieee80211_chanctx, conf); - drv_assign_vif_chanctx(local, sdata, ctx); + drv_assign_vif_chanctx(local, sdata, link_id, ctx); } mutex_unlock(&local->chanctx_mtx); } @@ -2474,7 +2475,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata && ieee80211_sdata_running(sdata)) - ieee80211_assign_chanctx(local, sdata); + ieee80211_assign_chanctx(local, sdata, 0); } /* reconfigure hardware */ @@ -2484,12 +2485,16 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { + unsigned int link; u32 changed; if (!ieee80211_sdata_running(sdata)) continue; - ieee80211_assign_chanctx(local, sdata); + for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) { + if (sdata->vif.link_conf[link]) + ieee80211_assign_chanctx(local, sdata, link); + } switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: @@ -3975,7 +3980,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) if (sdata->wdev.cac_started) { chandef = sdata->vif.bss_conf.chandef; - ieee80211_vif_release_channel(sdata); + ieee80211_link_release_channel(sdata->link[0]); cfg80211_cac_event(sdata->dev, &chandef, NL80211_RADAR_CAC_ABORTED, @@ -4401,7 +4406,7 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_link_data *link; u8 radar_detect = 0; lockdep_assert_held(&local->chanctx_mtx); @@ -4409,20 +4414,26 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)) return 0; - list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list) - if (sdata->deflink.reserved_radar_required) - radar_detect |= BIT(sdata->deflink.reserved_chandef.width); + list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) + if (link->reserved_radar_required) + radar_detect |= BIT(link->reserved_chandef.width); /* * An in-place reservation context should not have any assigned vifs * until it replaces the other context. */ WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER && - !list_empty(&ctx->assigned_vifs)); + !list_empty(&ctx->assigned_links)); + + list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) { + struct ieee80211_sub_if_data *sdata = link->sdata; - list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list) - if (sdata->deflink.radar_required) - radar_detect |= BIT(sdata->vif.bss_conf.chandef.width); + if (!link->radar_required) + continue; + + radar_detect |= + BIT(sdata->vif.link_conf[link->link_id]->chandef.width); + } return radar_detect; } diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 7daca8352deb..27d260be9123 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -313,7 +313,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; } - sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta); + sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta, 0); switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: @@ -330,19 +330,21 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, } /* FIXME: move this to some better location - parses HE/EHT now */ -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) +enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, + unsigned int link_id) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.deflink.vht_cap; - struct ieee80211_sta_he_cap *he_cap = &sta->sta.deflink.he_cap; - struct ieee80211_sta_eht_cap *eht_cap = &sta->sta.deflink.eht_cap; + struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id]; + struct ieee80211_link_sta *link_sta = sta->sta.link[link_id]; + struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; + struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; u32 cap_width; if (he_cap->has_he) { u8 info; if (eht_cap->has_eht && - sta->sdata->vif.bss_conf.chandef.chan->band == - NL80211_BAND_6GHZ) { + link_conf->chandef.chan->band == NL80211_BAND_6GHZ) { info = eht_cap->eht_cap_elem.phy_cap_info[0]; if (info & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) @@ -351,8 +353,7 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) info = he_cap->he_cap_elem.phy_cap_info[0]; - if (sta->sdata->vif.bss_conf.chandef.chan->band == - NL80211_BAND_2GHZ) { + if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ) { if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) return IEEE80211_STA_RX_BW_40; else @@ -369,7 +370,7 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) } if (!vht_cap->vht_supported) - return sta->sta.deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + return link_sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; @@ -466,14 +467,15 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width) } /* FIXME: rename/move - this deals with everything not just VHT */ -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) +enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, + unsigned int link_id) { - struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id]; + enum nl80211_chan_width bss_width = link_conf->chandef.width; enum ieee80211_sta_rx_bandwidth bw; - enum nl80211_chan_width bss_width = sdata->vif.bss_conf.chandef.width; - bw = ieee80211_sta_cap_rx_bw(sta); - bw = min(bw, sta->deflink.cur_max_bandwidth); + bw = ieee80211_sta_cap_rx_bw(sta, link_id); + bw = min(bw, sta->link[link_id]->cur_max_bandwidth); /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of * IEEE80211-2016 specification makes higher bandwidth operation @@ -629,7 +631,7 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, break; } - new_bw = ieee80211_sta_cur_vht_bw(sta); + new_bw = ieee80211_sta_cur_vht_bw(sta, 0); if (new_bw != sta->sta.deflink.bandwidth) { sta->sta.deflink.bandwidth = new_bw; sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta); @@ -692,7 +694,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, if (changed > 0) { ieee80211_recalc_min_chandef(sdata); - rate_control_rate_update(local, sband, sta, changed); + rate_control_rate_update(local, sband, sta, 0, changed); } } -- cgit v1.2.3 From ec7a04073d3b31c03a9ad00e0709ffd78b5cfd1b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 22:36:30 +0200 Subject: wifi: mac80211: use IEEE80211_MLD_MAX_NUM_LINKS Remove MAX_STA_LINKS and use IEEE80211_MLD_MAX_NUM_LINKS instead to unify between the station and other data structures. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 +--- net/mac80211/sta_info.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4dc51c52dd28..902a10ee50f2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2061,8 +2061,6 @@ struct ieee80211_sta_txpwr { enum nl80211_tx_power_setting type; }; -#define MAX_STA_LINKS 15 - /** * struct ieee80211_link_sta - station Link specific info * All link specific info for a STA link for a non MLD STA(single) @@ -2190,7 +2188,7 @@ struct ieee80211_sta { bool multi_link_sta; struct ieee80211_link_sta deflink; - struct ieee80211_link_sta *link[MAX_STA_LINKS]; + struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 134a7dad0ac4..2ff3d5fd0cbf 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -710,7 +710,7 @@ struct sta_info { bool multi_link_sta; struct link_sta_info deflink; - struct link_sta_info *link[MAX_STA_LINKS]; + struct link_sta_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* keep last! */ struct ieee80211_sta sta; -- cgit v1.2.3 From afe0d181905ed03c2379fcb81d423704f59f8788 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 23:22:19 +0200 Subject: wifi: mac80211: add link_id to vht.c code for MLO Update the code in vht.c and add the link_id parameter where necessary. Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- include/net/mac80211.h | 3 +- net/mac80211/cfg.c | 5 +- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 18 ++-- net/mac80211/iface.c | 6 +- net/mac80211/mesh_plink.c | 2 +- net/mac80211/mlme.c | 6 +- net/mac80211/rate.c | 2 +- net/mac80211/rx.c | 2 +- net/mac80211/tdls.c | 2 +- net/mac80211/vht.c | 122 ++++++++++++---------- 12 files changed, 92 insertions(+), 80 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5d3cedc146be..2539dc5aaa3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1776,7 +1776,7 @@ static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac, * the data received from firmware as if it came from the * action frame, so no conversion is needed. */ - ieee80211_update_mu_groups(vif, + ieee80211_update_mu_groups(vif, 0, (u8 *)¬if->membership_status, (u8 *)¬if->user_position); } diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 902a10ee50f2..0a26cb2871d6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6548,6 +6548,7 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif) * ieee80211_update_mu_groups - set the VHT MU-MIMO groud data * * @vif: the specified virtual interface + * @link_id: the link ID for MLO, otherwise 0 * @membership: 64 bits array - a bit is set if station is member of the group * @position: 2 bits per group id indicating the position in the group * @@ -6556,7 +6557,7 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif) * matching GroupId management frame. * Calls to this function need to be serialized with RX path. */ -void ieee80211_update_mu_groups(struct ieee80211_vif *vif, +void ieee80211_update_mu_groups(struct ieee80211_vif *vif, unsigned int link_id, const u8 *membership, const u8 *position); void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 884d2cfcec1e..53aac8f277e1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1763,7 +1763,7 @@ static int sta_apply_parameters(struct ieee80211_local *local, /* VHT can override some HT caps such as the A-MSDU max length */ if (params->vht_capa) ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - params->vht_capa, sta); + params->vht_capa, sta, 0); if (params->he_capa) ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, @@ -1784,7 +1784,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, /* returned value is only needed for rc update, but the * rc isn't initialized here yet, so ignore it */ - __ieee80211_vht_handle_opmode(sdata, sta, params->opmode_notif, + __ieee80211_vht_handle_opmode(sdata, sta, 0, + params->opmode_notif, sband->band); } diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 2ca75f2d3023..87815a3624f3 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1068,7 +1068,7 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, &chandef); memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - &cap_ie, sta); + &cap_ie, sta, 0); if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap))) rates_updated |= true; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 92ed1e3c2980..5be96b0bbd96 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2121,29 +2121,31 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, - struct sta_info *sta); + struct sta_info *sta, unsigned int link_id); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, unsigned int link_id); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, unsigned int link_id); -void ieee80211_sta_set_rx_nss(struct sta_info *sta); +void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id); enum ieee80211_sta_rx_bandwidth ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width); -enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta); +enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, + unsigned int link_id); void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_mgmt *mgmt); u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum nl80211_band band); + struct sta_info *sta, unsigned int link_id, + u8 opmode, enum nl80211_band band); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum nl80211_band band); + struct sta_info *sta, unsigned int link_id, + u8 opmode, enum nl80211_band band); void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta_vht_cap *vht_cap); void ieee80211_get_vht_mask_from_cap(__le16 vht_cap, u16 vht_mask[NL80211_VHT_NSS_MAX]); enum nl80211_chan_width -ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta); +ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id); /* HE */ void diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fa684d76a169..c5be60ee12d8 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1496,14 +1496,14 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local, sta = sta_info_get_bss(sdata, mgmt->sa); if (sta) - ieee80211_vht_handle_opmode(sdata, sta, opmode, - band); + ieee80211_vht_handle_opmode(sdata, sta, 0, + opmode, band); mutex_unlock(&local->sta_mtx); break; } case WLAN_VHT_ACTION_GROUPID_MGMT: - ieee80211_process_mu_groups(sdata, mgmt); + ieee80211_process_mu_groups(sdata, 0, mgmt); break; default: WARN_ON(1); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a6cb1db50f1d..fb7e8a9600ca 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -442,7 +442,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, changed |= IEEE80211_RC_BW_CHANGED; ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - elems->vht_cap_elem, sta); + elems->vht_cap_elem, sta, 0); ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, elems->he_cap_len, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ca9e0d83e2a4..643ef0ae786e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3570,7 +3570,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, if (elems->vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - elems->vht_cap_elem, sta); + elems->vht_cap_elem, + sta, 0); if (elems->he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && elems->he_cap) { @@ -4377,7 +4378,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (sta && elems->opmode_notif) - ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif, + ieee80211_vht_handle_opmode(sdata, sta, 0, + *elems->opmode_notif, rx_status->band); mutex_unlock(&local->sta_mtx); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index b268088585eb..402e898b75c3 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -37,7 +37,7 @@ void rate_control_rate_init(struct sta_info *sta) struct ieee80211_supported_band *sband; struct ieee80211_chanctx_conf *chanctx_conf; - ieee80211_sta_set_rx_nss(sta); + ieee80211_sta_set_rx_nss(sta, 0); if (!ref) return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1774d0f9feaa..e6b16ebbdb48 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3403,7 +3403,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) rx->sta->sta.deflink.bandwidth = new_bw; sband = rx->local->hw.wiphy->bands[status->band]; sta_opmode.bw = - ieee80211_sta_rx_bw_to_chan_width(rx->sta); + ieee80211_sta_rx_bw_to_chan_width(rx->sta, 0); sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; rate_control_rate_update(local, sband, rx->sta, 0, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 86a13ef31ef1..4fc120c64022 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -308,7 +308,7 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, /* IEEE802.11ac-2013 Table E-4 */ u16 centers_80mhz[] = { 5210, 5290, 5530, 5610, 5690, 5775 }; struct cfg80211_chan_def uc = sta->tdls_chandef; - enum nl80211_chan_width max_width = ieee80211_sta_cap_chan_bw(sta); + enum nl80211_chan_width max_width = ieee80211_sta_cap_chan_bw(sta, 0); int i; /* only support upgrading non-narrow channels up to 80Mhz */ diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 27d260be9123..acfe1459535f 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -116,16 +116,16 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, - struct sta_info *sta) + struct sta_info *sta, unsigned int link_id) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.deflink.vht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap; struct ieee80211_sta_vht_cap own_cap; u32 cap_info, i; bool have_80mhz; memset(vht_cap, 0, sizeof(*vht_cap)); - if (!sta->sta.deflink.ht_cap.ht_supported) + if (!sta->sta.link[link_id]->ht_cap.ht_supported) return; if (!vht_cap_ie || !sband->vht_cap.vht_supported) @@ -295,10 +295,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; break; default: - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; if (!(vht_cap->vht_mcs.tx_highest & cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) @@ -310,10 +310,11 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, * above) between 160 and 80+80 yet. */ if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + sta->link[link_id]->cur_max_bandwidth = + IEEE80211_STA_RX_BW_160; } - sta->sta.deflink.bandwidth = ieee80211_sta_cur_vht_bw(sta, 0); + sta->sta.link[link_id]->bandwidth = ieee80211_sta_cur_vht_bw(sta, link_id); switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: @@ -391,16 +392,17 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, return IEEE80211_STA_RX_BW_80; } -enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta) +enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, + unsigned int link_id) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.deflink.vht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap; u32 cap_width; if (!vht_cap->vht_supported) { - if (!sta->sta.deflink.ht_cap.ht_supported) + if (!sta->sta.link[link_id]->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20_NOHT; - return sta->sta.deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + return sta->sta.link[link_id]->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? NL80211_CHAN_WIDTH_40 : NL80211_CHAN_WIDTH_20; } @@ -415,15 +417,17 @@ enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta) } enum nl80211_chan_width -ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta) +ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id) { - enum ieee80211_sta_rx_bandwidth cur_bw = sta->sta.deflink.bandwidth; - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.deflink.vht_cap; + enum ieee80211_sta_rx_bandwidth cur_bw = + sta->sta.link[link_id]->bandwidth; + struct ieee80211_sta_vht_cap *vht_cap = + &sta->sta.link[link_id]->vht_cap; u32 cap_width; switch (cur_bw) { case IEEE80211_STA_RX_BW_20: - if (!sta->sta.deflink.ht_cap.ht_supported) + if (!sta->sta.link[link_id]->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20_NOHT; else return NL80211_CHAN_WIDTH_20; @@ -497,18 +501,18 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, return bw; } -void ieee80211_sta_set_rx_nss(struct sta_info *sta) +void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) { u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss; bool support_160; /* if we received a notification already don't overwrite it */ - if (sta->sta.deflink.rx_nss) + if (sta->sta.link[link_id]->rx_nss) return; - if (sta->sta.deflink.eht_cap.has_eht) { + if (sta->sta.link[link_id]->eht_cap.has_eht) { int i; - const u8 *rx_nss_mcs = (void *)&sta->sta.deflink.eht_cap.eht_mcs_nss_supp; + const u8 *rx_nss_mcs = (void *)&sta->sta.link[link_id]->eht_cap.eht_mcs_nss_supp; /* get the max nss for EHT over all possible bandwidths and mcs */ for (i = 0; i < sizeof(struct ieee80211_eht_mcs_nss_supp); i++) @@ -517,10 +521,10 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta) IEEE80211_EHT_MCS_NSS_RX)); } - if (sta->sta.deflink.he_cap.has_he) { + if (sta->sta.link[link_id]->he_cap.has_he) { int i; u8 rx_mcs_80 = 0, rx_mcs_160 = 0; - const struct ieee80211_sta_he_cap *he_cap = &sta->sta.deflink.he_cap; + const struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap; u16 mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); u16 mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); @@ -551,23 +555,23 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta) he_rx_nss = rx_mcs_80; } - if (sta->sta.deflink.ht_cap.ht_supported) { - if (sta->sta.deflink.ht_cap.mcs.rx_mask[0]) + if (sta->sta.link[link_id]->ht_cap.ht_supported) { + if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[0]) ht_rx_nss++; - if (sta->sta.deflink.ht_cap.mcs.rx_mask[1]) + if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[1]) ht_rx_nss++; - if (sta->sta.deflink.ht_cap.mcs.rx_mask[2]) + if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[2]) ht_rx_nss++; - if (sta->sta.deflink.ht_cap.mcs.rx_mask[3]) + if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[3]) ht_rx_nss++; /* FIXME: consider rx_highest? */ } - if (sta->sta.deflink.vht_cap.vht_supported) { + if (sta->sta.link[link_id]->vht_cap.vht_supported) { int i; u16 rx_mcs_map; - rx_mcs_map = le16_to_cpu(sta->sta.deflink.vht_cap.vht_mcs.rx_mcs_map); + rx_mcs_map = le16_to_cpu(sta->sta.link[link_id]->vht_cap.vht_mcs.rx_mcs_map); for (i = 7; i >= 0; i--) { u8 mcs = (rx_mcs_map >> (2 * i)) & 3; @@ -583,12 +587,12 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta) rx_nss = max(vht_rx_nss, ht_rx_nss); rx_nss = max(he_rx_nss, rx_nss); rx_nss = max(eht_rx_nss, rx_nss); - sta->sta.deflink.rx_nss = max_t(u8, 1, rx_nss); + sta->sta.link[link_id]->rx_nss = max_t(u8, 1, rx_nss); } u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum nl80211_band band) + struct sta_info *sta, unsigned int link_id, + u8 opmode, enum nl80211_band band) { enum ieee80211_sta_rx_bandwidth new_bw; struct sta_opmode_info sta_opmode = {}; @@ -603,8 +607,8 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; nss += 1; - if (sta->sta.deflink.rx_nss != nss) { - sta->sta.deflink.rx_nss = nss; + if (sta->sta.link[link_id]->rx_nss != nss) { + sta->sta.link[link_id]->rx_nss = nss; sta_opmode.rx_nss = nss; changed |= IEEE80211_RC_NSS_CHANGED; sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED; @@ -613,28 +617,28 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_20; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_40; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80) - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; else - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: /* legacy only, no longer used by newer spec */ - sta->deflink.cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; break; } - new_bw = ieee80211_sta_cur_vht_bw(sta, 0); - if (new_bw != sta->sta.deflink.bandwidth) { - sta->sta.deflink.bandwidth = new_bw; - sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta); + new_bw = ieee80211_sta_cur_vht_bw(sta, link_id); + if (new_bw != sta->sta.link[link_id]->bandwidth) { + sta->sta.link[link_id]->bandwidth = new_bw; + sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta, link_id); changed |= IEEE80211_RC_BW_CHANGED; sta_opmode.changed |= STA_OPMODE_MAX_BW_CHANGED; } @@ -647,54 +651,56 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, } void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, + unsigned int link_id, struct ieee80211_mgmt *mgmt) { - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; - if (!sdata->vif.bss_conf.mu_mimo_owner) + if (!link_conf->mu_mimo_owner) return; if (!memcmp(mgmt->u.action.u.vht_group_notif.position, - bss_conf->mu_group.position, WLAN_USER_POSITION_LEN) && + link_conf->mu_group.position, WLAN_USER_POSITION_LEN) && !memcmp(mgmt->u.action.u.vht_group_notif.membership, - bss_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN)) + link_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN)) return; - memcpy(bss_conf->mu_group.membership, + memcpy(link_conf->mu_group.membership, mgmt->u.action.u.vht_group_notif.membership, WLAN_MEMBERSHIP_LEN); - memcpy(bss_conf->mu_group.position, + memcpy(link_conf->mu_group.position, mgmt->u.action.u.vht_group_notif.position, WLAN_USER_POSITION_LEN); - ieee80211_link_info_change_notify(sdata, 0, BSS_CHANGED_MU_GROUPS); + ieee80211_link_info_change_notify(sdata, link_id, BSS_CHANGED_MU_GROUPS); } -void ieee80211_update_mu_groups(struct ieee80211_vif *vif, +void ieee80211_update_mu_groups(struct ieee80211_vif *vif, unsigned int link_id, const u8 *membership, const u8 *position) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ieee80211_bss_conf *link_conf = vif->link_conf[link_id]; - if (WARN_ON_ONCE(!vif->bss_conf.mu_mimo_owner)) + if (WARN_ON_ONCE(!link_conf->mu_mimo_owner)) return; - memcpy(bss_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN); - memcpy(bss_conf->mu_group.position, position, WLAN_USER_POSITION_LEN); + memcpy(link_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN); + memcpy(link_conf->mu_group.position, position, WLAN_USER_POSITION_LEN); } EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, u8 opmode, - enum nl80211_band band) + struct sta_info *sta, unsigned int link_id, + u8 opmode, enum nl80211_band band) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; - u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band); + u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, link_id, + opmode, band); if (changed > 0) { ieee80211_recalc_min_chandef(sdata); - rate_control_rate_update(local, sband, sta, 0, changed); + rate_control_rate_update(local, sband, sta, link_id, changed); } } -- cgit v1.2.3 From e9aac179ad4526afa3190856b71aa41decb6dc6a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 May 2022 23:45:04 +0200 Subject: wifi: mac80211: make some SMPS code MLD-aware Start making some SMPS related code MLD-aware. This isn't really done yet, but again cuts down our 'deflink' reliance. Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/dvm/lib.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 +- drivers/net/wireless/realtek/rtw88/main.c | 4 ++-- include/net/mac80211.h | 3 ++- net/mac80211/cfg.c | 19 +++++++++++------ net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/ht.c | 29 ++++++++++++++------------ net/mac80211/ieee80211_i.h | 4 +++- net/mac80211/iface.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/util.c | 5 +++-- 11 files changed, 45 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 40d790b36d85..1dc974e2c511 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014, 2022 Intel Corporation. All rights reserved. *****************************************************************************/ #include #include @@ -441,7 +441,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) priv->current_ht_config.smps = smps_request; for_each_context(priv, ctx) { if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) - ieee80211_request_smps(ctx->vif, smps_request); + ieee80211_request_smps(ctx->vif, 0, smps_request); } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 3ee5ea3484be..14b2de65bd84 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -304,7 +304,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, smps_mode = IEEE80211_SMPS_DYNAMIC; } - ieee80211_request_smps(vif, smps_mode); + ieee80211_request_smps(vif, 0, smps_mode); } static bool iwl_wait_stats_complete(struct iwl_notif_wait_data *notif_wait, diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f78b9f28d5f6..985ee36efc0f 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1600,9 +1600,9 @@ static void rtw_vif_smps_iter(void *data, u8 *mac, return; if (rtwdev->hal.txrx_1ss) - ieee80211_request_smps(vif, IEEE80211_SMPS_STATIC); + ieee80211_request_smps(vif, 0, IEEE80211_SMPS_STATIC); else - ieee80211_request_smps(vif, IEEE80211_SMPS_OFF); + ieee80211_request_smps(vif, 0, IEEE80211_SMPS_OFF); } void rtw_set_txrx_1ss(struct rtw_dev *rtwdev, bool txrx_1ss) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0a26cb2871d6..302340f6fa08 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6210,13 +6210,14 @@ void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, /** * ieee80211_request_smps - request SM PS transition * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_id: link ID for MLO, or 0 * @smps_mode: new SM PS mode * * This allows the driver to request an SM PS transition in managed * mode. This is useful when the driver has more information than * the stack about possible interference, for example by bluetooth. */ -void ieee80211_request_smps(struct ieee80211_vif *vif, +void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id, enum ieee80211_smps_mode smps_mode); /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d7f2eb7421c3..2c9554174bcf 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2913,6 +2913,7 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy, #endif int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, + unsigned int link_id, enum ieee80211_smps_mode smps_mode) { const u8 *ap; @@ -2926,8 +2927,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) return -EINVAL; - old_req = sdata->deflink.u.mgd.req_smps; - sdata->deflink.u.mgd.req_smps = smps_mode; + old_req = sdata->link[link_id]->u.mgd.req_smps; + sdata->link[link_id]->u.mgd.req_smps = smps_mode; if (old_req == smps_mode && smps_mode != IEEE80211_SMPS_AUTOMATIC) @@ -2939,10 +2940,10 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, * the new value until we associate. */ if (!sdata->u.mgd.associated || - sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) + sdata->vif.link_conf[link_id]->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) return 0; - ap = sdata->deflink.u.mgd.bssid; + ap = sdata->link[link_id]->u.mgd.bssid; rcu_read_lock(); list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { @@ -2966,7 +2967,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, err = ieee80211_send_smps_action(sdata, smps_mode, ap, ap); if (err) - sdata->deflink.u.mgd.req_smps = old_req; + sdata->link[link_id]->u.mgd.req_smps = old_req; else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found) ieee80211_teardown_tdls_peers(sdata); @@ -2978,6 +2979,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + unsigned int link_id; if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; @@ -2994,7 +2996,12 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, /* no change, but if automatic follow powersave */ sdata_lock(sdata); - __ieee80211_request_smps_mgd(sdata, sdata->deflink.u.mgd.req_smps); + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + if (!sdata->link[link_id]) + continue; + __ieee80211_request_smps_mgd(sdata, link_id, + sdata->link[link_id]->u.mgd.req_smps); + } sdata_unlock(sdata); if (ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS)) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index bd398b631763..dfb194e15018 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -256,7 +256,7 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, return -EOPNOTSUPP; sdata_lock(sdata); - err = __ieee80211_request_smps_mgd(sdata, smps_mode); + err = __ieee80211_request_smps_mgd(sdata, 0, smps_mode); sdata_unlock(sdata); return err; diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 22677df83ed8..111828b559a0 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -542,30 +542,33 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, void ieee80211_request_smps_mgd_work(struct work_struct *work) { - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, - deflink.u.mgd.request_smps_work); - - sdata_lock(sdata); - __ieee80211_request_smps_mgd(sdata, - sdata->deflink.u.mgd.driver_smps_mode); - sdata_unlock(sdata); + struct ieee80211_link_data *link = + container_of(work, struct ieee80211_link_data, + u.mgd.request_smps_work); + + sdata_lock(link->sdata); + __ieee80211_request_smps_mgd(link->sdata, link->link_id, + link->u.mgd.driver_smps_mode); + sdata_unlock(link->sdata); } -void ieee80211_request_smps(struct ieee80211_vif *vif, +void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id, enum ieee80211_smps_mode smps_mode) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_link_data *link = sdata->link[link_id]; if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION)) return; - if (sdata->deflink.u.mgd.driver_smps_mode == smps_mode) + if (WARN_ON(!link)) return; - sdata->deflink.u.mgd.driver_smps_mode = smps_mode; - ieee80211_queue_work(&sdata->local->hw, - &sdata->deflink.u.mgd.request_smps_work); + if (link->u.mgd.driver_smps_mode == smps_mode) + return; + + link->u.mgd.driver_smps_mode = smps_mode; + ieee80211_queue_work(&sdata->local->hw, &link->u.mgd.request_smps_work); } /* this might change ... don't want non-open drivers using it */ EXPORT_SYMBOL_GPL(ieee80211_request_smps); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e75496a99299..0948d074c4b9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2422,8 +2422,10 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, enum nl80211_band band, u32 *basic_rates); int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, + unsigned int link_id, enum ieee80211_smps_mode smps_mode); -void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata, + unsigned int link_id); void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index c5be60ee12d8..ea75d5d5cb6a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1657,7 +1657,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, recalc_smps); - ieee80211_recalc_smps(sdata); + ieee80211_recalc_smps(sdata, 0); } /* diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 30423b2d4eee..cdbf7a5dc2ba 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2337,7 +2337,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_ps(local); mutex_unlock(&local->iflist_mtx); - ieee80211_recalc_smps(sdata); + ieee80211_recalc_smps(sdata, 0); ieee80211_recalc_ps_vif(sdata); netif_carrier_on(sdata->dev); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4ec96170a679..ecda655e7481 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2803,7 +2803,8 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif) } EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); -void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) +void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *chanctx_conf; @@ -2811,7 +2812,7 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) mutex_lock(&local->chanctx_mtx); - chanctx_conf = rcu_dereference_protected(sdata->vif.bss_conf.chanctx_conf, + chanctx_conf = rcu_dereference_protected(sdata->vif.link_conf[link_id]->chanctx_conf, lockdep_is_held(&local->chanctx_mtx)); /* -- cgit v1.2.3 From 0f48b8b88aa9ed7b65d7cb55dbc57ec914ddada1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 May 2022 14:03:38 +0200 Subject: wifi: ieee80211: add definitions for multi-link element Add the definitions necessary to build and parse some of the multi-link element, the per-STA profile isn't fully included. Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 222 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) (limited to 'include') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e15771965916..870f659087d6 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4379,4 +4379,226 @@ enum ieee80211_range_params_max_total_ltf { /* multi-link device */ #define IEEE80211_MLD_MAX_NUM_LINKS 15 +#define IEEE80211_ML_CONTROL_TYPE 0x0007 +#define IEEE80211_ML_CONTROL_TYPE_BASIC 0 +#define IEEE80211_ML_CONTROL_TYPE_PREQ 1 +#define IEEE80211_ML_CONTROL_TYPE_RECONF 2 +#define IEEE80211_ML_CONTROL_TYPE_TDLS 3 +#define IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS 4 +#define IEEE80211_ML_CONTROL_PRESENCE_MASK 0xfff0 + +struct ieee80211_multi_link_elem { + __le16 control; + u8 variable[]; +} __packed; + +#define IEEE80211_MLC_BASIC_PRES_LINK_ID 0x0010 +#define IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT 0x0020 +#define IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY 0x0040 +#define IEEE80211_MLC_BASIC_PRES_EML_CAPA 0x0080 +#define IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP 0x0100 +#define IEEE80211_MLC_BASIC_PRES_MLD_ID 0x0200 + +#define IEEE80211_MED_SYNC_DELAY_DURATION 0x00ff +#define IEEE80211_MED_SYNC_DELAY_SYNC_OFDM_ED_THRESH 0x0f00 +#define IEEE80211_MED_SYNC_DELAY_SYNC_MAX_NUM_TXOPS 0xf000 + +#define IEEE80211_EML_CAP_EMLSR_SUPP 0x0001 +#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY 0x000e +#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_0US 0 +#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US 1 +#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_64US 2 +#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_128US 3 +#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US 4 +#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY 0x0070 +#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_0US 0 +#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_16US 1 +#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_32US 2 +#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US 3 +#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_128US 4 +#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US 5 +#define IEEE80211_EML_CAP_EMLMR_SUPPORT 0x0080 +#define IEEE80211_EML_CAP_EMLMR_DELAY 0x0700 +#define IEEE80211_EML_CAP_EMLMR_DELAY_0US 0 +#define IEEE80211_EML_CAP_EMLMR_DELAY_32US 1 +#define IEEE80211_EML_CAP_EMLMR_DELAY_64US 2 +#define IEEE80211_EML_CAP_EMLMR_DELAY_128US 3 +#define IEEE80211_EML_CAP_EMLMR_DELAY_256US 4 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT 0x7800 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_0 0 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128US 1 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_256US 2 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_512US 3 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_1TU 4 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_2TU 5 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_4TU 6 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_8TU 7 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_16TU 8 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_32TU 9 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_64TU 10 +#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU 11 + +#define IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS 0x000f +#define IEEE80211_MLD_CAP_OP_SRS_SUPPORT 0x0010 +#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP 0x0060 +#define IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND 0x0f80 +#define IEEE80211_MLD_CAP_OP_AAR_SUPPORT 0x1000 + +struct ieee80211_mle_basic_common_info { + u8 len; + u8 mld_mac_addr[ETH_ALEN]; + u8 variable[]; +} __packed; + +#define IEEE80211_MLC_PREQ_PRES_MLD_ID 0x0010 + +struct ieee80211_mle_preq_common_info { + u8 len; + u8 variable[]; +} __packed; + +#define IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR 0x0010 + +/* no fixed fields in RECONF */ + +struct ieee80211_mle_tdls_common_info { + u8 len; + u8 ap_mld_mac_addr[ETH_ALEN]; +} __packed; + +#define IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR 0x0010 + +/* no fixed fields in PRIO_ACCESS */ + +/** + * ieee80211_mle_common_size - check multi-link element common size + * @data: multi-link element, must already be checked for size using + * ieee80211_mle_size_ok() + */ +static inline u8 ieee80211_mle_common_size(const u8 *data) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u16 control = le16_to_cpu(mle->control); + u8 common = 0; + + switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) { + case IEEE80211_ML_CONTROL_TYPE_BASIC: + common += sizeof(struct ieee80211_mle_basic_common_info); + break; + case IEEE80211_ML_CONTROL_TYPE_PREQ: + common += sizeof(struct ieee80211_mle_preq_common_info); + break; + case IEEE80211_ML_CONTROL_TYPE_RECONF: + if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR) + common += ETH_ALEN; + return common; + case IEEE80211_ML_CONTROL_TYPE_TDLS: + common += sizeof(struct ieee80211_mle_tdls_common_info); + break; + case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS: + if (control & IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR) + common += ETH_ALEN; + return common; + default: + WARN_ON(1); + return 0; + } + + return common + mle->variable[0]; +} + +/** + * ieee80211_mle_size_ok - validate multi-link element size + * @data: pointer to the element data + * @len: length of the containing element + */ +static inline bool ieee80211_mle_size_ok(const u8 *data, u8 len) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u8 fixed = sizeof(*mle); + u8 common = 0; + bool check_common_len = false; + u16 control; + + if (len < fixed) + return false; + + control = le16_to_cpu(mle->control); + + switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) { + case IEEE80211_ML_CONTROL_TYPE_BASIC: + common += sizeof(struct ieee80211_mle_basic_common_info); + check_common_len = true; + if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) + common += 2; + if (control & IEEE80211_MLC_BASIC_PRES_EML_CAPA) + common += 2; + if (control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP) + common += 2; + if (control & IEEE80211_MLC_BASIC_PRES_MLD_ID) + common += 1; + break; + case IEEE80211_ML_CONTROL_TYPE_PREQ: + common += sizeof(struct ieee80211_mle_preq_common_info); + if (control & IEEE80211_MLC_PREQ_PRES_MLD_ID) + common += 1; + check_common_len = true; + break; + case IEEE80211_ML_CONTROL_TYPE_RECONF: + if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR) + common += ETH_ALEN; + break; + case IEEE80211_ML_CONTROL_TYPE_TDLS: + common += sizeof(struct ieee80211_mle_tdls_common_info); + check_common_len = true; + break; + case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS: + if (control & IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR) + common += ETH_ALEN; + break; + default: + /* we don't know this type */ + return true; + } + + if (len < fixed + common) + return false; + + if (!check_common_len) + return true; + + /* if present, common length is the first octet there */ + return mle->variable[0] >= common; +} + +enum ieee80211_mle_subelems { + IEEE80211_MLE_SUBELEM_PER_STA_PROFILE = 0, +}; + +#define IEEE80211_MLE_STA_CONTROL_LINK_ID 0x000f +#define IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE 0x0010 +#define IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT 0x0020 +#define IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT 0x0040 +#define IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT 0x0080 +#define IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT 0x0100 +#define IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT 0x0200 +#define IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE 0x0400 +#define IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT 0x0800 + +struct ieee80211_mle_per_sta_profile { + __le16 control; + u8 sta_info_len; + u8 variable[]; +} __packed; + +#define for_each_mle_subelement(_elem, _data, _len) \ + if (ieee80211_mle_size_ok(_data, _len)) \ + for_each_element(_elem, \ + _data + ieee80211_mle_common_size(_data),\ + _len - ieee80211_mle_common_size(_data)) + #endif /* LINUX_IEEE80211_H */ -- cgit v1.2.3 From d648c23024bd01333acd2fd5e34bcde0ffb66b16 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 May 2022 19:48:33 +0200 Subject: wifi: nl80211: support MLO in auth/assoc For authentication, we need the BSS, the link_id and the AP MLD address to create the link and station, (for now) the driver assigns a link address and sends the frame, the MLD address needs to be the address of the interface. For association, pass the list of BSSes that were selected for the MLO connection, along with extra per-STA profile elements, the AP MLD address and the link ID on which the association request should be sent. Note that for now we don't have a proper way to pass the link address(es) and so the driver/mac80211 will select one, but depending on how that selection works it means that assoc w/o auth data still being around (mac80211 implementation detail) the association won't necessarily work - so this will need to be extended in the future to sort out the link addressing. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 31 +++++++++++++++ include/uapi/linux/nl80211.h | 3 ++ net/wireless/mlme.c | 30 +++++++++++++-- net/wireless/nl80211.c | 91 ++++++++++++++++++++++++++++++++++++++++++-- net/wireless/sme.c | 2 + 5 files changed, 151 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 772e099fc932..a4f9e6094118 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2718,6 +2718,12 @@ static inline const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 id) * Authentication algorithm number, i.e., starting at the Authentication * transaction sequence number field. * @auth_data_len: Length of auth_data buffer in octets + * @link_id: if >= 0, indicates authentication should be done as an MLD, + * the interface address is included as the MLD address and the + * necessary link (with the given link_id) will be created (and + * given an MLD address) by the driver + * @ap_mld_addr: AP MLD address in case of authentication request with + * an AP MLD, valid iff @link_id >= 0 */ struct cfg80211_auth_request { struct cfg80211_bss *bss; @@ -2728,6 +2734,21 @@ struct cfg80211_auth_request { u8 key_len, key_idx; const u8 *auth_data; size_t auth_data_len; + s8 link_id; + const u8 *ap_mld_addr; +}; + +/** + * struct cfg80211_assoc_link - per-link information for MLO association + * @bss: the BSS pointer, see also &struct cfg80211_assoc_request::bss; + * if this is %NULL for a link, that link is not requested + * @elems: extra elements for the per-STA profile for this link + * @elems_len: length of the elements + */ +struct cfg80211_assoc_link { + struct cfg80211_bss *bss; + const u8 *elems; + size_t elems_len; }; /** @@ -2761,6 +2782,8 @@ enum cfg80211_assoc_req_flags { * given a reference that it must give back to cfg80211_send_rx_assoc() * or to cfg80211_assoc_timeout(). To ensure proper refcounting, new * association requests while already associating must be rejected. + * This also applies to the @links.bss parameter, which is used instead + * of this one (it is %NULL) for MLO associations. * @ie: Extra IEs to add to (Re)Association Request frame or %NULL * @ie_len: Length of ie buffer in octets * @use_mfp: Use management frame protection (IEEE 802.11w) in this association @@ -2785,6 +2808,11 @@ enum cfg80211_assoc_req_flags { * with 16 octets of STA Nonce followed by 16 octets of AP Nonce. * @s1g_capa: S1G capability override * @s1g_capa_mask: S1G capability override mask + * @links: per-link information for MLO connections + * @link_id: >= 0 for MLO connections, where links are given, and indicates + * the link on which the association request should be sent + * @ap_mld_addr: AP MLD address in case of MLO association request, + * valid iff @link_id >= 0 */ struct cfg80211_assoc_request { struct cfg80211_bss *bss; @@ -2800,6 +2828,9 @@ struct cfg80211_assoc_request { size_t fils_kek_len; const u8 *fils_nonces; struct ieee80211_s1g_cap s1g_capa, s1g_capa_mask; + struct cfg80211_assoc_link links[IEEE80211_MLD_MAX_NUM_LINKS]; + const u8 *ap_mld_addr; + s8 link_id; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index a9a2c9fef295..60ad9a9f153d 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2687,6 +2687,8 @@ enum nl80211_commands { * various commands that need a link ID to operate. * @NL80211_ATTR_MLO_LINKS: A nested array of links, each containing some * per-link information and a link ID. + * @NL80211_ATTR_MLD_ADDR: An MLD address, used with various commands such as + * authenticate/associate. * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined @@ -3204,6 +3206,7 @@ enum nl80211_attrs { NL80211_ATTR_MLO_LINKS, NL80211_ATTR_MLO_LINK_ID, + NL80211_ATTR_MLD_ADDR, /* add attributes here, update the policy in nl80211.c */ diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 532113937469..d92eed0e52cd 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -241,6 +241,10 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, if (!req->bss) return -ENOENT; + if (req->link_id >= 0 && + !(wdev->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) + return -EINVAL; + if (req->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { if (!req->key || !req->key_len || req->key_idx < 0 || req->key_idx > 3) @@ -294,10 +298,19 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct cfg80211_assoc_request *req) { struct wireless_dev *wdev = dev->ieee80211_ptr; - int err; + int err, i, j; ASSERT_WDEV_LOCK(wdev); + for (i = 1; i < ARRAY_SIZE(req->links); i++) { + if (!req->links[i].bss) + continue; + for (j = 0; j < i; j++) { + if (req->links[i].bss == req->links[j].bss) + return -EINVAL; + } + } + if (wdev->connected && (!req->prev_bssid || !ether_addr_equal(wdev->u.client.connected_addr, req->prev_bssid))) @@ -310,8 +323,19 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, err = rdev_assoc(rdev, dev, req); if (!err) { - cfg80211_ref_bss(&rdev->wiphy, req->bss); - cfg80211_hold_bss(bss_from_pub(req->bss)); + int link_id; + + if (req->bss) { + cfg80211_ref_bss(&rdev->wiphy, req->bss); + cfg80211_hold_bss(bss_from_pub(req->bss)); + } + + for (link_id = 0; link_id < ARRAY_SIZE(req->links); link_id++) { + if (!req->links[link_id].bss) + continue; + cfg80211_ref_bss(&rdev->wiphy, req->links[link_id].bss); + cfg80211_hold_bss(bss_from_pub(req->links[link_id].bss)); + } } return err; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5a4d3ddcdf80..9bc66a21ac3a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -796,6 +796,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NLA_POLICY_NESTED_ARRAY(nl80211_policy), [NL80211_ATTR_MLO_LINK_ID] = NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS), + [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), }; /* policy for the key attributes */ @@ -10282,6 +10283,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) req.key = key.p.key; req.key_len = key.p.key_len; req.key_idx = key.idx; + req.link_id = nl80211_link_id_or_invalid(info->attrs); + if (req.link_id >= 0) { + if (!info->attrs[NL80211_ATTR_MLD_ADDR]) + return -EINVAL; + req.ap_mld_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]); + } req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, IEEE80211_BSS_TYPE_ESS, @@ -10475,7 +10482,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct cfg80211_assoc_request req = {}; + struct nlattr **attrs = NULL; const u8 *bssid, *ssid; + unsigned int link_id; int err, ssid_len; if (dev->ieee80211_ptr->conn_owner_nlportid && @@ -10585,9 +10594,81 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) sizeof(req.s1g_capa)); } - req.bss = nl80211_assoc_bss(rdev, ssid, ssid_len, info->attrs, &bssid); - if (IS_ERR(req.bss)) - return PTR_ERR(req.bss); + req.link_id = nl80211_link_id_or_invalid(info->attrs); + + if (info->attrs[NL80211_ATTR_MLO_LINKS]) { + unsigned int attrsize = NUM_NL80211_ATTR * sizeof(*attrs); + struct nlattr *link; + int rem = 0; + + if (req.link_id < 0) + return -EINVAL; + + if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_MLO)) + return -EINVAL; + + if (info->attrs[NL80211_ATTR_MAC] || + info->attrs[NL80211_ATTR_WIPHY_FREQ] || + !info->attrs[NL80211_ATTR_MLD_ADDR]) + return -EINVAL; + + req.ap_mld_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]); + + attrs = kzalloc(attrsize, GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + nla_for_each_nested(link, + info->attrs[NL80211_ATTR_MLO_LINKS], + rem) { + memset(attrs, 0, attrsize); + + nla_parse_nested(attrs, NL80211_ATTR_MAX, + link, NULL, NULL); + + if (!attrs[NL80211_ATTR_MLO_LINK_ID]) { + err = -EINVAL; + goto free; + } + + link_id = nla_get_u8(attrs[NL80211_ATTR_MLO_LINK_ID]); + /* cannot use the same link ID again */ + if (req.links[link_id].bss) { + err = -EINVAL; + goto free; + } + req.links[link_id].bss = + nl80211_assoc_bss(rdev, ssid, ssid_len, attrs, + &bssid); + if (IS_ERR(req.links[link_id].bss)) { + err = PTR_ERR(req.links[link_id].bss); + goto free; + } + + if (attrs[NL80211_ATTR_IE]) { + req.links[link_id].elems = + nla_data(attrs[NL80211_ATTR_IE]); + req.links[link_id].elems_len = + nla_len(attrs[NL80211_ATTR_IE]); + } + } + + if (!req.links[req.link_id].bss) { + err = -EINVAL; + goto free; + } + + kfree(attrs); + attrs = NULL; + } else { + if (req.link_id >= 0) + return -EINVAL; + + req.bss = nl80211_assoc_bss(rdev, ssid, ssid_len, info->attrs, + &bssid); + if (IS_ERR(req.bss)) + return PTR_ERR(req.bss); + } err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); if (!err) { @@ -10605,7 +10686,11 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) wdev_unlock(dev->ieee80211_ptr); } +free: + for (link_id = 0; link_id < ARRAY_SIZE(req.links); link_id++) + cfg80211_put_bss(&rdev->wiphy, req.links[link_id].bss); cfg80211_put_bss(&rdev->wiphy, req.bss); + kfree(attrs); return err; } diff --git a/net/wireless/sme.c b/net/wireless/sme.c index c8a99b90723b..b3c6ce4f85ee 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -177,6 +177,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev, params->ssid, params->ssid_len, IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); + auth_req.link_id = -1; err = cfg80211_mlme_auth(rdev, wdev->netdev, &auth_req); cfg80211_put_bss(&rdev->wiphy, auth_req.bss); return err; @@ -198,6 +199,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev, req.ht_capa_mask = params->ht_capa_mask; req.vht_capa = params->vht_capa; req.vht_capa_mask = params->vht_capa_mask; + req.link_id = -1; req.bss = cfg80211_get_bss(&rdev->wiphy, params->channel, params->bssid, -- cgit v1.2.3 From d8787ec6b4ef1857b827699eca6f5978d0aecd74 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 May 2022 23:20:08 +0200 Subject: wifi: mac80211: add vif link addition/removal Add the necessary infrastructure, including a new driver method, to add/remove links to/from an interface. Also add the missing link address to bss_conf (which we use as link_conf too), and fill it, in station mode for now just randomly, in AP mode we get the address from cfg80211 since the link must be created with an address first. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 15 +++++ net/mac80211/driver-ops.h | 21 +++++++ net/mac80211/ieee80211_i.h | 3 + net/mac80211/iface.c | 134 ++++++++++++++++++++++++++++++++++++++++++++- net/mac80211/trace.h | 27 +++++++++ 5 files changed, 197 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 302340f6fa08..f221afdfa475 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -515,6 +515,7 @@ struct ieee80211_fils_discovery { * This structure keeps information about a BSS (and an association * to that BSS) that can change during the lifetime of the BSS. * + * @addr: (link) address used locally * @htc_trig_based_pkt_ext: default PE in 4us units, if BSS supports HE * @uora_exists: is the UORA element advertised by AP * @ack_enabled: indicates support to receive a multi-TID that solicits either @@ -638,6 +639,7 @@ struct ieee80211_fils_discovery { */ struct ieee80211_bss_conf { const u8 *bssid; + u8 addr[ETH_ALEN] __aligned(2); u8 htc_trig_based_pkt_ext; bool uora_exists; u8 uora_ocw_range; @@ -1743,6 +1745,7 @@ struct ieee80211_vif_cfg { * or the BSS we're associated to * @link_conf: in case of MLD, the per-link BSS configuration, * indexed by link ID + * @valid_links: bitmap of valid links, or 0 for non-MLO. * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively @@ -1778,6 +1781,7 @@ struct ieee80211_vif { struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; struct ieee80211_bss_conf *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; + u16 valid_links; u8 addr[ETH_ALEN] __aligned(2); bool p2p; @@ -4028,6 +4032,13 @@ struct ieee80211_prep_tx_info { * disable background CAC/radar detection. * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to * resolve a path for hardware flow offloading + * @change_vif_links: Change the valid links on an interface, note that while + * removing the old link information is still valid (link_conf pointer), + * but may immediately disappear after the function returns. The old or + * new links bitmaps may be 0 if going from/to a non-MLO situation. + * The @old[] array contains pointers to the old bss_conf structures + * that were already removed, in case they're needed. + * This callback can sleep. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -4371,6 +4382,10 @@ struct ieee80211_ops { struct ieee80211_sta *sta, struct net_device_path_ctx *ctx, struct net_device_path *path); + int (*change_vif_links)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 old_links, u16 new_links, + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 9238283a8237..c8133c84d7d5 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1533,4 +1533,25 @@ static inline int drv_net_fill_forward_path(struct ieee80211_local *local, return ret; } +static inline int drv_change_vif_links(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u16 old_links, u16 new_links, + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) +{ + int ret = -EOPNOTSUPP; + + might_sleep(); + + if (!check_sdata_in_driver(sdata)) + return -EIO; + + trace_drv_change_vif_links(local, sdata, old_links, new_links); + if (local->ops->change_vif_links) + ret = local->ops->change_vif_links(&local->hw, &sdata->vif, + old_links, new_links, old); + trace_drv_return_int(local, ret); + + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8286e607152c..22f17231dede 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2006,6 +2006,9 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); int ieee80211_add_virtual_monitor(struct ieee80211_local *local); void ieee80211_del_virtual_monitor(struct ieee80211_local *local); +int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, + u16 new_links); + bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, bool update_bss); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ea75d5d5cb6a..f118e7710fb1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -220,8 +220,10 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) ret = eth_mac_addr(dev, sa); - if (ret == 0) + if (ret == 0) { memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); + ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); + } return ret; } @@ -449,7 +451,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do cancel_work_sync(&local->dynamic_ps_enable_work); cancel_work_sync(&sdata->recalc_smps); + sdata_lock(sdata); + WARN(sdata->vif.valid_links, + "destroying interface with valid links 0x%04x\n", + sdata->vif.valid_links); + mutex_lock(&local->mtx); sdata->vif.bss_conf.csa_active = false; if (sdata->vif.type == NL80211_IFTYPE_STATION) @@ -1013,10 +1020,15 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) } static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata, - unsigned int link_id, + int link_id, struct ieee80211_link_data *link, struct ieee80211_bss_conf *link_conf) { + bool deflink = link_id < 0; + + if (link_id < 0) + link_id = 0; + sdata->vif.link_conf[link_id] = link_conf; sdata->link[link_id] = link; @@ -1031,6 +1043,23 @@ static void ieee80211_link_init(struct ieee80211_sub_if_data *sdata, INIT_LIST_HEAD(&link->reserved_chanctx_list); INIT_DELAYED_WORK(&link->dfs_cac_timer_work, ieee80211_dfs_cac_timer_work); + + if (!deflink) { + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + ether_addr_copy(link_conf->addr, + sdata->wdev.links[link_id].addr); + WARN_ON(!(sdata->wdev.valid_links & BIT(link_id))); + break; + case NL80211_IFTYPE_STATION: + eth_random_addr(link_conf->addr); + ether_addr_copy(sdata->wdev.links[link_id].addr, + link_conf->addr); + break; + default: + WARN_ON(1); + } + } } static void ieee80211_sdata_init(struct ieee80211_local *local, @@ -1046,7 +1075,7 @@ static void ieee80211_sdata_init(struct ieee80211_local *local, * Note that we never change this, so if link ID 0 isn't used in an * MLD connection, we get a separate allocation for it. */ - ieee80211_link_init(sdata, 0, &sdata->deflink, &sdata->vif.bss_conf); + ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf); } int ieee80211_add_virtual_monitor(struct ieee80211_local *local) @@ -1768,6 +1797,10 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, if (!local->ops->change_interface) return -EBUSY; + /* for now, don't support changing while links exist */ + if (sdata->vif.valid_links) + return -EBUSY; + switch (sdata->vif.type) { case NL80211_IFTYPE_AP: if (!list_empty(&sdata->u.ap.vlans)) @@ -2030,6 +2063,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, strlcpy(sdata->name, name, IFNAMSIZ); ieee80211_assign_perm_addr(local, wdev->address, type); memcpy(sdata->vif.addr, wdev->address, ETH_ALEN); + ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); } else { int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size, sizeof(void *)); @@ -2094,6 +2128,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, sdata = netdev_priv(ndev); ndev->ieee80211_ptr = &sdata->wdev; memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); + ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr); memcpy(sdata->name, ndev->name, IFNAMSIZ); if (txq_size) { @@ -2318,3 +2353,96 @@ void ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata) else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) atomic_dec(&sdata->u.vlan.num_mcast_sta); } + +int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, + u16 new_links) +{ + u16 old_links = sdata->vif.valid_links; + unsigned long add = new_links & ~old_links; + unsigned long rem = old_links & ~new_links; + unsigned int link_id; + int ret; + struct { + struct ieee80211_link_data data; + struct ieee80211_bss_conf conf; + } *links[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *link; + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]; + struct ieee80211_link_data *old_data[IEEE80211_MLD_MAX_NUM_LINKS]; + bool use_deflink = old_links == 0; /* set for error case */ + + sdata_assert_lock(sdata); + + if (old_links == new_links) + return 0; + + /* allocate new link structures first */ + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) { + ret = -ENOMEM; + goto free; + } + links[link_id] = link; + } + + /* keep track of the old pointers for the driver */ + BUILD_BUG_ON(sizeof(old) != sizeof(sdata->vif.link_conf)); + memcpy(old, sdata->vif.link_conf, sizeof(old)); + /* and for us in error cases */ + BUILD_BUG_ON(sizeof(old_data) != sizeof(sdata->link)); + memcpy(old_data, sdata->link, sizeof(old_data)); + + /* link them into data structures */ + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + WARN_ON(!use_deflink && + sdata->link[link_id] == &sdata->deflink); + + link = links[link_id]; + ieee80211_link_init(sdata, link_id, &link->data, &link->conf); + } + + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { + sdata->link[link_id] = NULL; + sdata->vif.link_conf[link_id] = NULL; + } + + sdata->vif.valid_links = new_links; + + /* tell the driver */ + ret = drv_change_vif_links(sdata->local, sdata, + old_links, new_links, + old); + if (ret) { + /* restore config */ + memcpy(sdata->link, old_data, sizeof(old_data)); + memcpy(sdata->vif.link_conf, old, sizeof(old)); + sdata->vif.valid_links = old_links; + /* and free the newly allocated links */ + goto free; + } + + /* use deflink/bss_conf again if and only if there are no more links */ + use_deflink = new_links == 0; + + /* now use this to free the old links */ + memset(links, 0, sizeof(links)); + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { + if (sdata->link[link_id] == &sdata->deflink) + continue; + /* + * we must have allocated the data through this path so + * we know we can free both at the same time + */ + links[link_id] = container_of(sdata->link[link_id], + typeof(*links[link_id]), + data); + } + +free: + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) + kfree(links[link_id]); + if (use_deflink) + ieee80211_link_init(sdata, -1, &sdata->deflink, + &sdata->vif.bss_conf); + return ret; +} diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 295db57a76a2..256ebab13cda 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2455,6 +2455,33 @@ DEFINE_EVENT(sta_event, drv_net_fill_forward_path, TP_ARGS(local, sdata, sta) ); +TRACE_EVENT(drv_change_vif_links, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u16 old_links, u16 new_links), + + TP_ARGS(local, sdata, old_links, new_links), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u16, old_links) + __field(u16, new_links) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->old_links = old_links; + __entry->new_links = new_links; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " old_links:0x%04x, new_links:0x%04x\n", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->old_links, __entry->new_links + ) +); + /* * Tracing for API calls that drivers call. */ -- cgit v1.2.3 From eef25a6679adb3cc73b611cf6c78386f54df0e0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jun 2022 15:59:31 +0200 Subject: wifi: mac80211: remove band from TX info in MLO If the interface is an MLD, then we don't know which band the frame will be transmitted on, and we don't know how to look up the band. Set the band information to zero in that case, the driver cannot rely on it anyway. No longer inline ieee80211_tx_skb_tid() since it's even bigger now. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ++- net/mac80211/ieee80211_i.h | 19 ++-------- net/mac80211/tx.c | 89 +++++++++++++++++++++++++++++++++++----------- 3 files changed, 73 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f221afdfa475..8222419c9ead 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1029,7 +1029,9 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate) * (3) TX status information - driver tells mac80211 what happened * * @flags: transmit info flags, defined above - * @band: the band to transmit on (use for checking for races) + * @band: the band to transmit on (use e.g. for checking for races), + * not valid if the interface is an MLD since we won't know which + * link the frame will be transmitted on * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC * @ack_frame_id: internal frame ID for TX status, used internally * @tx_time_est: TX time estimate in units of 4us, used internally diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 22f17231dede..0f69859e4e39 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2251,23 +2251,8 @@ ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); } -static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, int tid) -{ - struct ieee80211_chanctx_conf *chanctx_conf; - - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); - if (WARN_ON(!chanctx_conf)) { - rcu_read_unlock(); - kfree_skb(skb); - return; - } - - __ieee80211_tx_skb_tid_band(sdata, skb, tid, - chanctx_conf->def.chan->band); - rcu_read_unlock(); -} +void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid); static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0589d2d66fe6..e8a5e27a3dd1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2566,8 +2566,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, bool tdls_peer; bool multicast; u16 info_id = 0; - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_sub_if_data *ap_sdata; + struct ieee80211_chanctx_conf *chanctx_conf = NULL; enum nl80211_band band; int ret; @@ -2584,7 +2583,9 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, ethertype = (skb->data[12] << 8) | skb->data[13]; fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (!sdata->vif.valid_links) + chanctx_conf = + rcu_dereference(sdata->vif.bss_conf.chanctx_conf); switch (sdata->vif.type) { case NL80211_IFTYPE_AP_VLAN: @@ -2599,10 +2600,16 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); wme_sta = sta->sta.wme; } - /* override chanctx_conf from AP (we don't have one) */ - ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, - u.ap); - chanctx_conf = rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf); + if (!sdata->vif.valid_links) { + struct ieee80211_sub_if_data *ap_sdata; + + /* override chanctx_conf from AP (we don't have one) */ + ap_sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); + chanctx_conf = + rcu_dereference(ap_sdata->vif.bss_conf.chanctx_conf); + } if (sdata->wdev.use_4addr) break; fallthrough; @@ -2738,10 +2745,15 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, } if (!chanctx_conf) { - ret = -ENOTCONN; - goto free; + if (!sdata->vif.valid_links) { + ret = -ENOTCONN; + goto free; + } + /* MLD transmissions must not rely on the band */ + band = 0; + } else { + band = chanctx_conf->def.chan->band; } - band = chanctx_conf->def.chan->band; multicast = is_multicast_ether_addr(hdr.addr1); @@ -2953,14 +2965,20 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) !ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG)) goto out; - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); - if (!chanctx_conf) { + if (!sdata->vif.valid_links) { + rcu_read_lock(); + chanctx_conf = + rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (!chanctx_conf) { + rcu_read_unlock(); + goto out; + } + build.band = chanctx_conf->def.chan->band; rcu_read_unlock(); - goto out; + } else { + /* MLD transmissions must not rely on the band */ + build.band = 0; } - build.band = chanctx_conf->def.chan->band; - rcu_read_unlock(); fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); @@ -4577,12 +4595,16 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, sdata = vif_to_sdata(info->control.vif); if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) { - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); - if (unlikely(!chanctx_conf)) { - dev_kfree_skb(skb); - return true; + /* update band only for non-MLD */ + if (!sdata->vif.valid_links) { + chanctx_conf = + rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (unlikely(!chanctx_conf)) { + dev_kfree_skb(skb); + return true; + } + info->band = chanctx_conf->def.chan->band; } - info->band = chanctx_conf->def.chan->band; result = ieee80211_tx(sdata, NULL, skb, true); } else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { @@ -5665,6 +5687,31 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, local_bh_enable(); } +void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, int tid) +{ + struct ieee80211_chanctx_conf *chanctx_conf; + enum nl80211_band band; + + rcu_read_lock(); + if (!sdata->vif.valid_links) { + chanctx_conf = + rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + kfree_skb(skb); + return; + } + band = chanctx_conf->def.chan->band; + } else { + /* MLD transmissions must not rely on the band */ + band = 0; + } + + __ieee80211_tx_skb_tid_band(sdata, skb, tid, band); + rcu_read_unlock(); +} + int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, const u8 *buf, size_t len, const u8 *dest, __be16 proto, bool unencrypted, -- cgit v1.2.3 From 69d41b5a9c9d8d24c0faeb376fc2f52fc810d855 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 9 Jun 2022 22:05:07 +0200 Subject: wifi: mac80211: add MLO link ID to TX frame metadata Take a few bits out of the control.flags to add the link ID to TX frame metadata, so drivers don't need to look it up by the address themselves. Implement that lookup where it's needed, for internal frame TX, and set it to "unspecified" for data transmissions. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 7 +++++++ net/mac80211/tx.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8222419c9ead..1bea225c0d4d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -867,6 +867,10 @@ enum mac80211_tx_info_flags { * @IEEE80211_TX_CTRL_DONT_REORDER: This frame should not be reordered * relative to other frames that have this flag set, independent * of their QoS TID or other priority field values. + * @IEEE80211_TX_CTRL_MLO_LINK: If not @IEEE80211_LINK_UNSPECIFIED, this + * frame should be transmitted on the specific link. This really is + * only relevant for frames that do not have data present, and is + * also not used for 802.3 format frames. * * These flags are used in tx_info->control.flags. */ @@ -880,8 +884,11 @@ enum mac80211_tx_control_flags { IEEE80211_TX_INTCFL_NEED_TXPROCESSING = BIT(6), IEEE80211_TX_CTRL_NO_SEQNO = BIT(7), IEEE80211_TX_CTRL_DONT_REORDER = BIT(8), + IEEE80211_TX_CTRL_MLO_LINK = 0xf0000000, }; +#define IEEE80211_LINK_UNSPECIFIED 0xf + /** * enum mac80211_tx_status_flags - flags to describe transmit status * diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e8a5e27a3dd1..17313954c628 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2889,7 +2889,9 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, info->flags = info_flags; info->ack_frame_id = info_id; info->band = band; - info->control.flags = ctrl_flags; + info->control.flags = ctrl_flags | + u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, + IEEE80211_TX_CTRL_MLO_LINK); return skb; free: @@ -3558,7 +3560,9 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT | IEEE80211_TX_CTL_DONTFRAG | (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); - info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT; + info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT | + u32_encode_bits(IEEE80211_LINK_UNSPECIFIED, + IEEE80211_TX_CTRL_MLO_LINK); #ifdef CONFIG_MAC80211_DEBUGFS if (local->force_tx_status) @@ -5668,7 +5672,9 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int tid, enum nl80211_band band) { + const struct ieee80211_hdr *hdr = (void *)skb->data; int ac = ieee80211_ac_from_tid(tid); + unsigned int link; skb_reset_mac_header(skb); skb_set_queue_mapping(skb, ac); @@ -5676,6 +5682,30 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, skb->dev = sdata->dev; + BUILD_BUG_ON(IEEE80211_LINK_UNSPECIFIED < IEEE80211_MLD_MAX_NUM_LINKS); + BUILD_BUG_ON(!FIELD_FIT(IEEE80211_TX_CTRL_MLO_LINK, + IEEE80211_LINK_UNSPECIFIED)); + + if (!sdata->vif.valid_links) { + link = 0; + } else if (memcmp(sdata->vif.addr, hdr->addr2, ETH_ALEN) == 0) { + /* address from the MLD */ + link = IEEE80211_LINK_UNSPECIFIED; + } else { + /* otherwise must be addressed from a link */ + for (link = 0; link < ARRAY_SIZE(sdata->vif.link_conf); link++) { + if (memcmp(sdata->vif.link_conf[link]->addr, + hdr->addr2, ETH_ALEN) == 0) + break; + } + + if (WARN_ON_ONCE(link == ARRAY_SIZE(sdata->vif.link_conf))) + link = ffs(sdata->vif.valid_links) - 1; + } + + IEEE80211_SKB_CB(skb)->control.flags |= + u32_encode_bits(link, IEEE80211_TX_CTRL_MLO_LINK); + /* * The other path calling ieee80211_xmit is from the tasklet, * and while we can handle concurrent transmissions locking -- cgit v1.2.3 From cb71f1d136a635decf43c3b502ee34fb05640fcd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 31 May 2022 23:20:08 +0200 Subject: wifi: mac80211: add sta link addition/removal Add the necessary infrastructure, including a new driver method, to add/remove links to/from a station. To do this, refactor the link alloc/free a bit, splitting that so we can do it without linking them, to handle failures better. Note that a station entry must be created representing an MLD or a non-MLD STA, it cannot change between the two. When representing an MLD, the 'deflink' is used for the first link, which might be removed later, in which case the memory isn't reused. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 13 +++- net/mac80211/cfg.c | 2 +- net/mac80211/driver-ops.h | 21 +++++++ net/mac80211/ibss.c | 4 +- net/mac80211/mesh_plink.c | 2 +- net/mac80211/mlme.c | 2 +- net/mac80211/ocb.c | 2 +- net/mac80211/sta_info.c | 156 +++++++++++++++++++++++++++++++++++++++------- net/mac80211/sta_info.h | 8 ++- net/mac80211/trace.h | 31 +++++++++ 10 files changed, 206 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1bea225c0d4d..1bc9d1d9769a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2150,7 +2150,6 @@ struct ieee80211_link_sta { * @max_tid_amsdu_len: Maximum A-MSDU size in bytes for this TID * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that * the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames - * @multi_link_sta: Identifies if this sta is a MLD STA * @deflink: This holds the default link STA information, for non MLO STA all link * specific STA information is accessed through @deflink or through * link[0] which points to address of @deflink. For MLO Link STA @@ -2162,6 +2161,7 @@ struct ieee80211_link_sta { * @deflink address and remaining would be allocated and the address * would be assigned to link[link_id] where link_id is the id assigned * by the AP. + * @valid_links: bitmap of valid links, or 0 for non-MLO */ struct ieee80211_sta { u8 addr[ETH_ALEN]; @@ -2199,7 +2199,7 @@ struct ieee80211_sta { struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1]; - bool multi_link_sta; + u16 valid_links; struct ieee80211_link_sta deflink; struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -4048,6 +4048,11 @@ struct ieee80211_prep_tx_info { * The @old[] array contains pointers to the old bss_conf structures * that were already removed, in case they're needed. * This callback can sleep. + * @change_sta_links: Change the valid links of a station, similar to + * @change_vif_links. This callback can sleep. + * Note that a sta can also be inserted or removed with valid links, + * i.e. passed to @sta_add/@sta_state with sta->valid_links not zero. + * In fact, cannot change from having valid_links and not having them. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -4395,6 +4400,10 @@ struct ieee80211_ops { struct ieee80211_vif *vif, u16 old_links, u16 new_links, struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]); + int (*change_sta_links)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u16 old_links, u16 new_links); }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e30659b1242b..abc3fa5a8d7e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1839,7 +1839,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, !sdata->u.mgd.associated) return -EINVAL; - sta = sta_info_alloc(sdata, mac, GFP_KERNEL); + sta = sta_info_alloc(sdata, mac, -1, GFP_KERNEL); if (!sta) return -ENOMEM; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index c8133c84d7d5..52be89f8f0bc 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1554,4 +1554,25 @@ static inline int drv_change_vif_links(struct ieee80211_local *local, return ret; } +static inline int drv_change_sta_links(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + u16 old_links, u16 new_links) +{ + int ret = -EOPNOTSUPP; + + might_sleep(); + + if (!check_sdata_in_driver(sdata)) + return -EIO; + + trace_drv_change_sta_links(local, sdata, sta, old_links, new_links); + if (local->ops->change_sta_links) + ret = local->ops->change_sta_links(&local->hw, &sdata->vif, sta, + old_links, new_links); + trace_drv_return_int(local, ret); + + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 09c11c067cbf..65a3808dc92a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -629,7 +629,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, GFP_KERNEL); + sta = sta_info_alloc(sdata, addr, -1, GFP_KERNEL); if (!sta) { rcu_read_lock(); return NULL; @@ -1229,7 +1229,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); + sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC); if (!sta) return; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index e24bd48bc915..fe54ac431202 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -510,7 +510,7 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) if (aid < 0) return NULL; - sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); + sta = sta_info_alloc(sdata, hw_addr, -1, GFP_KERNEL); if (!sta) return NULL; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b6ee8da07663..c2c997086553 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5579,7 +5579,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, } if (!have_sta) { - new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); + new_sta = sta_info_alloc(sdata, cbss->bssid, -1, GFP_KERNEL); if (!new_sta) return -ENOMEM; } diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index 468c741a9aeb..0fd29d9c496c 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -69,7 +69,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); rcu_read_unlock(); - sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); + sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC); if (!sta) return; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f20ce7bbcb39..b1426a2459e8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -64,6 +64,11 @@ * freed before they are done using it. */ +struct sta_link_alloc { + struct link_sta_info info; + struct ieee80211_link_sta sta; +}; + static const struct rhashtable_params sta_rht_params = { .nelem_hint = 3, /* start small */ .automatic_shrinking = true, @@ -245,17 +250,27 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, return NULL; } -static void sta_info_free_links(struct sta_info *sta) +static void sta_info_free_link(struct link_sta_info *link_sta) { - unsigned int link_id; + free_percpu(link_sta->pcpu_rx_stats); +} - for (link_id = 0; link_id < ARRAY_SIZE(sta->link); link_id++) { - if (!sta->link[link_id]) - continue; - free_percpu(sta->link[link_id]->pcpu_rx_stats); +static void sta_remove_link(struct sta_info *sta, unsigned int link_id) +{ + struct sta_link_alloc *alloc = NULL; - if (sta->link[link_id] != &sta->deflink) - kfree(sta->link[link_id]); + if (WARN_ON(!sta->link[link_id])) + return; + + if (sta->link[link_id] != &sta->deflink) + alloc = container_of(sta->link[link_id], typeof(*alloc), info); + + sta->sta.valid_links &= ~BIT(link_id); + sta->link[link_id] = NULL; + sta->sta.link[link_id] = NULL; + if (alloc) { + sta_info_free_link(&alloc->info); + kfree(alloc); } } @@ -272,6 +287,15 @@ static void sta_info_free_links(struct sta_info *sta) */ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { + int i; + + for (i = 0; i < ARRAY_SIZE(sta->link); i++) { + if (!(sta->sta.valid_links & BIT(i))) + continue; + + sta_remove_link(sta, i); + } + /* * If we had used sta_info_pre_move_state() then we might not * have gone through the state transitions down again, so do @@ -302,7 +326,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) kfree(sta->mesh); #endif - sta_info_free_links(sta); + sta_info_free_link(&sta->deflink); kfree(sta); } @@ -348,19 +372,13 @@ static int sta_prepare_rate_control(struct ieee80211_local *local, return 0; } -static int sta_info_init_link(struct sta_info *sta, - unsigned int link_id, - struct link_sta_info *link_info, - struct ieee80211_link_sta *link_sta, - gfp_t gfp) +static int sta_info_alloc_link(struct ieee80211_local *local, + struct link_sta_info *link_info, + gfp_t gfp) { - struct ieee80211_local *local = sta->local; struct ieee80211_hw *hw = &local->hw; int i; - link_info->sta = sta; - link_info->link_id = link_id; - if (ieee80211_hw_check(hw, USES_RSS)) { link_info->pcpu_rx_stats = alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp); @@ -368,9 +386,6 @@ static int sta_info_init_link(struct sta_info *sta, return -ENOMEM; } - sta->link[link_id] = link_info; - sta->sta.link[link_id] = link_sta; - link_info->rx_stats.last_rx = jiffies; u64_stats_init(&link_info->rx_stats.syncp); @@ -382,8 +397,19 @@ static int sta_info_init_link(struct sta_info *sta, return 0; } +static void sta_info_add_link(struct sta_info *sta, + unsigned int link_id, + struct link_sta_info *link_info, + struct ieee80211_link_sta *link_sta) +{ + link_info->sta = sta; + link_info->link_id = link_id; + sta->link[link_id] = link_info; + sta->sta.link[link_id] = link_sta; +} + struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, - const u8 *addr, gfp_t gfp) + const u8 *addr, int link_id, gfp_t gfp) { struct ieee80211_local *local = sdata->local; struct ieee80211_hw *hw = &local->hw; @@ -397,9 +423,17 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->local = local; sta->sdata = sdata; - if (sta_info_init_link(sta, 0, &sta->deflink, &sta->sta.deflink, gfp)) + if (sta_info_alloc_link(local, &sta->deflink, gfp)) return NULL; + if (link_id >= 0) { + sta_info_add_link(sta, link_id, &sta->deflink, + &sta->sta.deflink); + sta->sta.valid_links = BIT(link_id); + } else { + sta_info_add_link(sta, 0, &sta->deflink, &sta->sta.deflink); + } + spin_lock_init(&sta->lock); spin_lock_init(&sta->ps_lock); INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); @@ -565,7 +599,7 @@ free_txq: if (sta->sta.txq[0]) kfree(to_txq_info(sta->sta.txq[0])); free: - sta_info_free_links(sta); + sta_info_free_link(&sta->deflink); #ifdef CONFIG_MAC80211_MESH kfree(sta->mesh); #endif @@ -2613,3 +2647,77 @@ void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, sta_update_codel_params(sta, thr); } + +int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + struct sta_link_alloc *alloc; + int ret; + + lockdep_assert_held(&sdata->local->sta_mtx); + + /* must represent an MLD from the start */ + if (WARN_ON(!sta->sta.valid_links)) + return -EINVAL; + + if (WARN_ON(sta->sta.valid_links & BIT(link_id) || + sta->link[link_id])) + return -EBUSY; + + alloc = kzalloc(sizeof(*alloc), GFP_KERNEL); + if (!alloc) + return -ENOMEM; + + ret = sta_info_alloc_link(sdata->local, &alloc->info, GFP_KERNEL); + if (ret) { + kfree(alloc); + return ret; + } + + sta_info_add_link(sta, link_id, &alloc->info, &alloc->sta); + + return 0; +} + +int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + u16 old_links = sta->sta.valid_links; + u16 new_links = old_links | BIT(link_id); + int ret; + + lockdep_assert_held(&sdata->local->sta_mtx); + + if (WARN_ON(old_links == new_links || !sta->link[link_id])) + return -EINVAL; + + sta->sta.valid_links = new_links; + + if (!test_sta_flag(sta, WLAN_STA_INSERTED)) + return 0; + + ret = drv_change_sta_links(sdata->local, sdata, &sta->sta, + old_links, new_links); + if (ret) { + sta->sta.valid_links = old_links; + sta_remove_link(sta, link_id); + } + + return ret; +} + +void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + + lockdep_assert_held(&sdata->local->sta_mtx); + + sta->sta.valid_links &= ~BIT(link_id); + + if (test_sta_flag(sta, WLAN_STA_INSERTED)) + drv_change_sta_links(sdata->local, sdata, &sta->sta, + sta->sta.valid_links, + sta->sta.valid_links & ~BIT(link_id)); + + sta_remove_link(sta, link_id); +} diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 2ff3d5fd0cbf..8ec65bb7d13e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -623,7 +623,6 @@ struct link_sta_info { * @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to * the BSS one. * @frags: fragment cache - * @multi_link_sta: Identifies if this sta is a MLD STA or regular STA * @deflink: This is the default link STA information, for non MLO STA all link * specific STA information is accessed through @deflink or through * link[0] which points to address of @deflink. For MLO Link STA @@ -708,7 +707,6 @@ struct sta_info { struct ieee80211_fragment_cache frags; - bool multi_link_sta; struct link_sta_info deflink; struct link_sta_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -833,7 +831,7 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, * until sta_info_insert(). */ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, - const u8 *addr, gfp_t gfp); + const u8 *addr, int link_id, gfp_t gfp); void sta_info_free(struct ieee80211_local *local, struct sta_info *sta); @@ -892,6 +890,10 @@ u32 sta_get_expected_throughput(struct sta_info *sta); void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, unsigned long exp_time); +int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id); +int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id); +void ieee80211_sta_remove_link(struct sta_info *sta, unsigned int link_id); + void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta); void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta); void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 256ebab13cda..9804634e7d99 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2482,6 +2482,37 @@ TRACE_EVENT(drv_change_vif_links, ) ); +TRACE_EVENT(drv_change_sta_links, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + u16 old_links, u16 new_links), + + TP_ARGS(local, sdata, sta, old_links, new_links), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + __field(u16, old_links) + __field(u16, new_links) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + __entry->old_links = old_links; + __entry->new_links = new_links; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " old_links:0x%04x, new_links:0x%04x\n", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, + __entry->old_links, __entry->new_links + ) +); + /* * Tracing for API calls that drivers call. */ -- cgit v1.2.3 From f2a0290b2df2b0e65ab78b71c4a15e732afd4458 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jun 2022 11:07:55 +0200 Subject: wifi: cfg80211: add optional link add/remove callbacks Add some optional callbacks for link add/remove so that drivers can react here. Initially, I thought it would be sufficient to just create the link in start_ap etc., but it turns out that's not so simple, since there are quite a few callbacks that can be called: if they're erroneously without start_ap, things might crash. Thus it might be easier for drivers to allocate all the necessary data structures immediately, to not have to worry about it in each callback, since cfg80211 checks that the link ID is valid (has been added.) Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 12 ++++++++++++ net/wireless/nl80211.c | 14 +++++++++++++- net/wireless/rdev-ops.h | 26 ++++++++++++++++++++++++++ net/wireless/trace.h | 20 +++++++++++++++++++- 4 files changed, 70 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a4f9e6094118..5706f96b819a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3858,6 +3858,11 @@ struct mgmt_frame_regs { * keep the struct wireless_dev's iftype updated. * This additionally holds the RTNL to be able to do netdev changes. * + * @add_intf_link: Add a new MLO link to the given interface. Note that + * the wdev->link[] data structure has been updated, so the new link + * address is available. + * @del_intf_link: Remove an MLO link from the given interface. + * * @add_key: add a key with the given parameters. @mac_addr will be %NULL * when adding a group key. * @@ -4212,6 +4217,13 @@ struct cfg80211_ops { enum nl80211_iftype type, struct vif_params *params); + int (*add_intf_link)(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id); + void (*del_intf_link)(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id); + int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9bc66a21ac3a..0a69a5a6b74d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -15556,9 +15556,11 @@ static int nl80211_set_fils_aad(struct sk_buff *skb, static int nl80211_add_link(struct sk_buff *skb, struct genl_info *info) { + struct cfg80211_registered_device *rdev = info->user_ptr[0]; unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; + int ret; if (!(wdev->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)) return -EINVAL; @@ -15578,13 +15580,20 @@ static int nl80211_add_link(struct sk_buff *skb, struct genl_info *info) wdev->valid_links |= BIT(link_id); ether_addr_copy(wdev->links[link_id].addr, nla_data(info->attrs[NL80211_ATTR_MAC])); + + ret = rdev_add_intf_link(rdev, wdev, link_id); + if (ret) { + wdev->valid_links &= ~BIT(link_id); + eth_zero_addr(wdev->links[link_id].addr); + } wdev_unlock(wdev); - return 0; + return ret; } static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info) { + struct cfg80211_registered_device *rdev = info->user_ptr[0]; unsigned int link_id = nl80211_link_id(info->attrs); struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; @@ -15604,6 +15613,9 @@ static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info) wdev_lock(wdev); wdev->valid_links &= ~BIT(link_id); + + rdev_del_intf_link(rdev, wdev, link_id); + eth_zero_addr(wdev->links[link_id].addr); wdev_unlock(wdev); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index d2300eff03ae..a329ba036989 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1422,4 +1422,30 @@ rdev_set_radar_background(struct cfg80211_registered_device *rdev, return ret; } +static inline int +rdev_add_intf_link(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + unsigned int link_id) +{ + int ret = 0; + + trace_rdev_add_intf_link(&rdev->wiphy, wdev, link_id); + if (rdev->ops->add_intf_link) + ret = rdev->ops->add_intf_link(&rdev->wiphy, wdev, link_id); + trace_rdev_return_int(&rdev->wiphy, ret); + + return ret; +} + +static inline void +rdev_del_intf_link(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + unsigned int link_id) +{ + trace_rdev_del_intf_link(&rdev->wiphy, wdev, link_id); + if (rdev->ops->add_intf_link) + rdev->ops->add_intf_link(&rdev->wiphy, wdev, link_id); + trace_rdev_return_void(&rdev->wiphy); +} + #endif /* __CFG80211_RDEV_OPS */ diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 92742430958e..65f8b814ecd0 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2064,7 +2064,7 @@ TRACE_EVENT(rdev_set_noack_map, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) ); -TRACE_EVENT(rdev_get_channel, +DECLARE_EVENT_CLASS(wiphy_wdev_link_evt, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, unsigned int link_id), TP_ARGS(wiphy, wdev, link_id), @@ -2082,6 +2082,12 @@ TRACE_EVENT(rdev_get_channel, WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id) ); +DEFINE_EVENT(wiphy_wdev_link_evt, rdev_get_channel, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id), + TP_ARGS(wiphy, wdev, link_id) +); + TRACE_EVENT(rdev_return_chandef, TP_PROTO(struct wiphy *wiphy, int ret, struct cfg80211_chan_def *chandef), @@ -2823,6 +2829,18 @@ TRACE_EVENT(rdev_set_radar_background, WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ); +DEFINE_EVENT(wiphy_wdev_link_evt, rdev_add_intf_link, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id), + TP_ARGS(wiphy, wdev, link_id) +); + +DEFINE_EVENT(wiphy_wdev_link_evt, rdev_del_intf_link, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id), + TP_ARGS(wiphy, wdev, link_id) +); + /************************************************************* * cfg80211 exported functions traces * *************************************************************/ -- cgit v1.2.3 From ae7ba17b49b6707e62f31643dda25592c29482f8 Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Thu, 2 Jun 2022 15:08:16 +0300 Subject: wifi: mac80211: pass the link id in start/stop ap In start_ap and stop_ap mac80211 callbacks pass the link_id to the drivers. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 40 +++++++++++++++++++---- drivers/net/wireless/realtek/rtw88/mac80211.c | 3 +- drivers/net/wireless/realtek/rtw89/mac80211.c | 6 ++-- drivers/net/wireless/silabs/wfx/sta.c | 6 ++-- drivers/net/wireless/silabs/wfx/sta.h | 6 ++-- include/net/mac80211.h | 6 ++-- net/mac80211/cfg.c | 4 +-- net/mac80211/driver-ops.h | 15 +++++---- net/mac80211/trace.h | 36 ++++++++++++++++---- net/mac80211/util.c | 2 +- 10 files changed, 93 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 2539dc5aaa3f..eaffc3163bd1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2396,7 +2396,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, } static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + unsigned int link_id) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -2522,8 +2523,22 @@ out_unlock: return ret; } +static int iwl_mvm_start_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id) +{ + return iwl_mvm_start_ap_ibss(hw, vif, link_id); +} + +static int iwl_mvm_start_ibss(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + return iwl_mvm_start_ap_ibss(hw, vif, 0); +} + static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + unsigned int link_id) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -2586,6 +2601,19 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id) +{ + iwl_mvm_stop_ap_ibss(hw, vif, link_id); +} + +static void iwl_mvm_stop_ibss(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + iwl_mvm_stop_ap_ibss(hw, vif, 0); +} + static void iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -5408,10 +5436,10 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx, .switch_vif_chanctx = iwl_mvm_switch_vif_chanctx, - .start_ap = iwl_mvm_start_ap_ibss, - .stop_ap = iwl_mvm_stop_ap_ibss, - .join_ibss = iwl_mvm_start_ap_ibss, - .leave_ibss = iwl_mvm_stop_ap_ibss, + .start_ap = iwl_mvm_start_ap, + .stop_ap = iwl_mvm_stop_ap, + .join_ibss = iwl_mvm_start_ibss, + .leave_ibss = iwl_mvm_stop_ibss, .tx_last_beacon = iwl_mvm_tx_last_beacon, diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 9e0b5692fbab..ba60ca7ecdbf 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -429,7 +429,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } -static int rtw_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +static int rtw_ops_start_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, unsigned int link_id) { struct rtw_dev *rtwdev = hw->priv; struct rtw_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 5afb8fe5708e..0e3c95cf4c99 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -381,7 +381,8 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } -static int rtw89_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +static int rtw89_ops_start_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, unsigned int link_id) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; @@ -401,7 +402,8 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif } static -void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 97a631ff1bfa..3ae93573f787 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -378,7 +378,8 @@ static void wfx_set_mfp_ap(struct wfx_vif *wvif) } } -int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; struct wfx_dev *wdev = wvif->wdev; @@ -396,7 +397,8 @@ int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) return ret; } -void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id) { struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index 3109d257fe94..93ea992de1d7 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -29,8 +29,10 @@ void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id); +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id); int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1bc9d1d9769a..48c688fdf23d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4084,8 +4084,10 @@ struct ieee80211_ops { struct ieee80211_vif *vif, unsigned int link_id, u64 changed); - int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); - void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); + int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id); + void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id); u64 (*prepare_multicast)(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f1ee73d96dfb..009f1723c990 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1287,7 +1287,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP; } - err = drv_start_ap(sdata->local, sdata); + err = drv_start_ap(sdata->local, sdata, link_id); if (err) { old = sdata_dereference(link->u.ap.beacon, sdata); @@ -1442,7 +1442,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, GFP_KERNEL); } - drv_stop_ap(sdata->local, sdata); + drv_stop_ap(sdata->local, sdata, link_id); /* free all potentially still buffered bcast frames */ local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 52be89f8f0bc..db38c8cc9d8f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -985,7 +985,8 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local, int n_vifs, enum ieee80211_chanctx_switch_mode mode); static inline int drv_start_ap(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { int ret = 0; @@ -994,22 +995,24 @@ static inline int drv_start_ap(struct ieee80211_local *local, if (!check_sdata_in_driver(sdata)) return -EIO; - trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); + trace_drv_start_ap(local, sdata, sdata->vif.link_conf[link_id], + link_id); if (local->ops->start_ap) - ret = local->ops->start_ap(&local->hw, &sdata->vif); + ret = local->ops->start_ap(&local->hw, &sdata->vif, link_id); trace_drv_return_int(local, ret); return ret; } static inline void drv_stop_ap(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { if (!check_sdata_in_driver(sdata)) return; - trace_drv_stop_ap(local, sdata); + trace_drv_stop_ap(local, sdata, link_id); if (local->ops->stop_ap) - local->ops->stop_ap(&local->hw, &sdata->vif); + local->ops->stop_ap(&local->hw, &sdata->vif, link_id); trace_drv_return_void(local); } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 9804634e7d99..f96e7cdca4c2 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1752,13 +1752,15 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, TRACE_EVENT(drv_start_ap, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss_conf *info), + struct ieee80211_bss_conf *info, + unsigned int link_id), - TP_ARGS(local, sdata, info), + TP_ARGS(local, sdata, info, link_id), TP_STRUCT__entry( LOCAL_ENTRY VIF_ENTRY + __field(u32, link_id) __field(u8, dtimper) __field(u16, bcnint) __dynamic_array(u8, ssid, sdata->vif.cfg.ssid_len) @@ -1768,6 +1770,7 @@ TRACE_EVENT(drv_start_ap, TP_fast_assign( LOCAL_ASSIGN; VIF_ASSIGN; + __entry->link_id = link_id; __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; memcpy(__get_dynamic_array(ssid), @@ -1777,15 +1780,34 @@ TRACE_EVENT(drv_start_ap, ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT, - LOCAL_PR_ARG, VIF_PR_ARG + LOCAL_PR_FMT VIF_PR_FMT " link id %u", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id ) ); -DEFINE_EVENT(local_sdata_evt, drv_stop_ap, +TRACE_EVENT(drv_stop_ap, TP_PROTO(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata), - TP_ARGS(local, sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id), + + TP_ARGS(local, sdata, link_id), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u32, link_id) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->link_id = link_id; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " link id %u", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->link_id + ) ); TRACE_EVENT(drv_reconfig_complete, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ecda655e7481..bccc3a309ed0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2568,7 +2568,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) changed |= BSS_CHANGED_AP_PROBE_RESP; if (rcu_access_pointer(sdata->deflink.u.ap.beacon)) - drv_start_ap(local, sdata); + drv_start_ap(local, sdata, 0); } fallthrough; case NL80211_IFTYPE_MESH_POINT: -- cgit v1.2.3 From 6e8912a503759bb8f1f01c5b761d0d45815fa6de Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Mon, 6 Jun 2022 14:25:54 +0300 Subject: wifi: mac80211: return a beacon for a specific link Pass the link id through to the get_beacon and return the beacon for a specific link id. Signed-off-by: Shaul Triebitz Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/ath11k/mac.c | 2 +- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 2 +- drivers/net/wireless/ath/carl9170/tx.c | 2 +- drivers/net/wireless/ath/wcn36xx/main.c | 2 +- drivers/net/wireless/broadcom/b43/main.c | 2 +- drivers/net/wireless/broadcom/b43legacy/main.c | 2 +- .../broadcom/brcm80211/brcmsmac/mac80211_if.c | 4 +- drivers/net/wireless/intel/iwlegacy/common.c | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 4 +- drivers/net/wireless/intel/iwlwifi/dvm/rxon.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/intersil/p54/main.c | 2 +- drivers/net/wireless/mac80211_hwsim.c | 2 +- drivers/net/wireless/marvell/libertas_tf/main.c | 4 +- drivers/net/wireless/marvell/mwl8k.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7603/beacon.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 +- .../net/wireless/mediatek/mt76/mt76x02_beacon.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/purelifi/plfxlc/mac.c | 4 +- drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- drivers/net/wireless/realtek/rtlwifi/core.c | 2 +- drivers/net/wireless/realtek/rtlwifi/pci.c | 2 +- drivers/net/wireless/realtek/rtw88/fw.c | 2 +- drivers/net/wireless/realtek/rtw89/fw.c | 3 +- drivers/net/wireless/rsi/rsi_91x_hal.c | 2 +- drivers/net/wireless/silabs/wfx/sta.c | 6 +- drivers/net/wireless/st/cw1200/sta.c | 4 +- drivers/net/wireless/ti/wl1251/main.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 4 +- drivers/net/wireless/zydas/zd1211rw/zd_mac.c | 9 +-- drivers/staging/vt6655/rxtx.c | 2 +- drivers/staging/vt6656/rxtx.c | 2 +- include/net/mac80211.h | 14 ++-- net/mac80211/tx.c | 75 +++++++++++++--------- 43 files changed, 109 insertions(+), 88 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4808ed6a6e20..3d111d6447f0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1630,7 +1630,7 @@ static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif) arvif->vdev_type != WMI_VDEV_TYPE_IBSS) return 0; - bcn = ieee80211_beacon_get_template(hw, vif, &offs); + bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!bcn) { ath10k_warn(ar, "failed to get beacon template from mac80211\n"); return -EPERM; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index af19cab24c76..074d8ba5072a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3888,7 +3888,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) continue; } - bcn = ieee80211_beacon_get(ar->hw, arvif->vif); + bcn = ieee80211_beacon_get(ar->hw, arvif->vif, 0); if (!bcn) { ath10k_warn(ar, "could not get mac80211 beacon\n"); continue; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 96a33b49a52f..17dbc7d9cf29 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1362,7 +1362,7 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) if (arvif->vdev_type != WMI_VDEV_TYPE_AP) return 0; - bcn = ieee80211_beacon_get_template(hw, vif, &offs); + bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!bcn) { ath11k_warn(ab, "failed to get beacon template from mac80211\n"); return -EPERM; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 66d123f48085..85c982e0a1cd 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1946,7 +1946,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; } - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (!skb) { ret = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index d41988f8ea3f..ee72faac2f1d 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -135,7 +135,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, bf->bf_mpdu = NULL; } - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (skb == NULL) return NULL; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 468bc934d848..533471e69400 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -215,7 +215,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, } /* Get a new beacon */ - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) { spin_unlock_bh(&priv->beacon_lock); return; diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 514f568d9d07..6bb9aa2bfe65 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -1628,7 +1628,7 @@ int carl9170_update_beacon(struct ar9170 *ar, const bool submit) goto out_unlock; skb = ieee80211_beacon_get_tim(ar->hw, carl9170_get_vif(cvif), - NULL, NULL); + NULL, NULL, 0); if (!skb) { err = -ENOMEM; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 04fb26cb8322..ace8641909bd 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1010,7 +1010,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_smd_config_bss(wcn, vif, NULL, vif->addr, false); skb = ieee80211_beacon_get_tim(hw, vif, &tim_off, - &tim_len); + &tim_len, 0); if (!skb) { wcn36xx_err("failed to alloc beacon skb\n"); goto out; diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index e3121a9d0579..6b4188066f0b 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -1832,7 +1832,7 @@ static void b43_update_templates(struct b43_wl *wl) * the TIM field, but that would probably require resizing and * moving of data within the beacon template. * Simply request a new beacon and let mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(wl->hw, wl->vif); + beacon = ieee80211_beacon_get(wl->hw, wl->vif, 0); if (unlikely(!beacon)) return; diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index 96d5a034c09b..532013184389 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -1241,7 +1241,7 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) * field, but that would probably require resizing and moving of data * within the beacon template. Simply request a new beacon and let * mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(wl->hw, wl->vif); + beacon = ieee80211_beacon_get(wl->hw, wl->vif, 0); if (unlikely(!beacon)) return; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index fd3c131c622c..61d7404aded4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -678,7 +678,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, u16 tim_offset = 0; spin_lock_bh(&wl->lock); - beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL); + beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL, 0); brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset, info->dtim_period); spin_unlock_bh(&wl->lock); @@ -950,7 +950,7 @@ static int brcms_ops_beacon_set_tim(struct ieee80211_hw *hw, spin_lock_bh(&wl->lock); if (wl->wlc->vif) beacon = ieee80211_beacon_get_tim(hw, wl->wlc->vif, - &tim_offset, NULL); + &tim_offset, NULL, 0); if (beacon) brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset, wl->wlc->vif->bss_conf.dtim_period); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index affad34f70f0..6f007e63f0c2 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5276,7 +5276,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) struct il_priv *il = hw->priv; unsigned long flags; __le64 timestamp; - struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct sk_buff *skb = ieee80211_beacon_get(hw, vif, 0); if (!skb) return; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index caf452922dbd..a873be109f43 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2003 - 2014, 2018 - 2021 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014, 2018 - 2022 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well @@ -284,7 +284,7 @@ static void iwl_bg_beacon_update(struct work_struct *work) } /* Pull updated AP beacon from mac80211. will fail if not in AP mode */ - beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif); + beacon = ieee80211_beacon_get(priv->hw, priv->beacon_ctx->vif, 0); if (!beacon) { IWL_ERR(priv, "update beacon failed -- keeping old\n"); goto out; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 45e382fe45a2..f80cce37e2c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -183,7 +183,7 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, lockdep_assert_held(&priv->mutex); dev_kfree_skb(priv->beacon_skb); - priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif); + priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif, 0); if (!priv->beacon_skb) return -ENOMEM; return iwlagn_send_beacon_cmd(priv); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 49898fd99594..c0bd697b080a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1233,7 +1233,7 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len) mvm->hw->extra_beacon_tailroom = len; - beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL); + beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL, 0); if (!beacon) goto out_err; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 65df8cbb57d9..ed586e6d7d64 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1002,7 +1002,7 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, WARN_ON(vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_ADHOC); - beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL); + beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL, 0); if (!beacon) return -ENOMEM; diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index cc6769a4fec7..115be1f3f33d 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -139,7 +139,7 @@ static int p54_beacon_update(struct p54_common *priv, struct sk_buff *beacon; int ret; - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) return -ENOMEM; ret = p54_beacon_format_ie_tim(beacon); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index be83904c642b..44174a4c2117 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1908,7 +1908,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, vif->type != NL80211_IFTYPE_OCB) return; - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (skb == NULL) return; info = IEEE80211_SKB_CB(skb); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 21c3e0bdc444..74c4942b9a5a 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -427,7 +427,7 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, switch (priv->vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - beacon = ieee80211_beacon_get(hw, vif); + beacon = ieee80211_beacon_get(hw, vif, 0); if (beacon) { lbtf_beacon_set(priv, beacon); kfree_skb(beacon); @@ -691,7 +691,7 @@ void lbtf_bcn_sent(struct lbtf_private *priv) } } - skb = ieee80211_beacon_get(priv->hw, priv->vif); + skb = ieee80211_beacon_get(priv->hw, priv->vif, 0); if (skb) { lbtf_beacon_set(priv, skb); diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 7eef3a74d124..293bec9bb8dd 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5147,7 +5147,7 @@ mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) { struct sk_buff *skb; - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (skb != NULL) { mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len); kfree_skb(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c index b5e8308e0cc7..c67fc29bb7c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c @@ -20,7 +20,7 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!(mdev->beacon_mask & BIT(mvif->idx))) return; - skb = ieee80211_beacon_get(mt76_hw(dev), vif); + skb = ieee80211_beacon_get(mt76_hw(dev), vif, 0); if (!skb) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index f58376733c67..3f8f06d9628c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -706,7 +706,7 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev, if (!enable) goto out; - skb = ieee80211_beacon_get_template(hw, vif, &offs); + skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!skb) return -EINVAL; @@ -1076,7 +1076,7 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev, if (!enable) goto out; - skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs); + skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); if (!skb) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c index 5d034cec191b..b72510949877 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c @@ -139,7 +139,7 @@ mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (!(dev->mt76.beacon_mask & BIT(mvif->idx))) return; - skb = ieee80211_beacon_get(mt76_hw(dev), vif); + skb = ieee80211_beacon_get(mt76_hw(dev), vif, 0); if (!skb) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 1b3d6634a72e..8c91257ba1c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2086,7 +2086,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!en) goto out; - skb = ieee80211_beacon_get_template(hw, vif, &offs); + skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!skb) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 64fc400bd981..3b5b475b0875 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1258,7 +1258,7 @@ mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev, if (!enable) goto out; - skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs); + skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); if (!skb) return -EINVAL; diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c index 1fc1682683e1..d3cdffbded69 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.c +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c @@ -133,7 +133,7 @@ int plfxlc_restore_settings(struct plfxlc_mac *mac) return 0; if (mac->vif) { - beacon = ieee80211_beacon_get(mac->hw, mac->vif); + beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0); if (beacon) { /*beacon is hardcoded in firmware */ kfree_skb(beacon); @@ -601,7 +601,7 @@ static void plfxlc_op_bss_info_changed(struct ieee80211_hw *hw, /* for ADHOC */ associated = true; if (changes & BSS_CHANGED_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif, 0); if (beacon) { /*beacon is hardcoded in firmware */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index aa6b2f3d2eff..4d06038afd83 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -758,7 +758,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, */ rt2x00queue_free_skb(intf->beacon); - intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); + intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif, 0); if (!intf->beacon->skb) return -ENOMEM; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index 10e8fdc31879..f66cc9083972 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1300,7 +1300,7 @@ static void rtl8180_beacon_work(struct work_struct *work) goto resched; /* grab a fresh beacon */ - skb = ieee80211_beacon_get(dev, vif); + skb = ieee80211_beacon_get(dev, vif, 0); if (!skb) goto resched; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 8ab65c888baf..edc84f9dc984 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1075,7 +1075,7 @@ static void rtl8187_beacon_work(struct work_struct *work) goto resched; /* grab a fresh beacon */ - skb = ieee80211_beacon_get(dev, vif); + skb = ieee80211_beacon_get(dev, vif, 0); if (!skb) goto resched; diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 2f7fd8888d3a..8537cc6d7a89 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1009,7 +1009,7 @@ static void send_beacon_frame(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + struct sk_buff *skb = ieee80211_beacon_get(hw, vif, 0); struct rtl_tcb_desc tcb_desc; if (skb) { diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 8e4c15654746..ca79f652fef3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -1100,7 +1100,7 @@ static void _rtl_pci_prepare_bcn_tasklet(struct tasklet_struct *t) } /*NB: the beacon data buffer must be 32-bit aligned. */ - pskb = ieee80211_beacon_get(hw, mac->vif); + pskb = ieee80211_beacon_get(hw, mac->vif, 0); if (!pskb) return; hdr = rtl_get_hdr(pskb); diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index c3ae631c2264..4fdab0329695 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -1070,7 +1070,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, switch (rsvd_pkt->type) { case RSVD_BEACON: - skb_new = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL); + skb_new = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL, 0); rsvd_pkt->tim_offset = tim_offset; break; case RSVD_PS_POLL: diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 2d9c3157d878..179ec9276e32 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -1043,7 +1043,8 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, u16 tim_offset; int bcn_total_len; - skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset, NULL); + skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset, + NULL, 0); if (!skb_beacon) { rtw89_err(rtwdev, "failed to get beacon skb\n"); return -ENOMEM; diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index d3634ad986ac..40f9a31f9ca7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -443,7 +443,7 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) return -EINVAL; mac_bcn = ieee80211_beacon_get_tim(adapter->hw, vif, - &tim_offset, NULL); + &tim_offset, NULL, 0); if (!mac_bcn) { rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n"); return -EINVAL; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 3ae93573f787..0378144795ca 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -339,7 +339,7 @@ static int wfx_upload_ap_templates(struct wfx_vif *wvif) struct ieee80211_vif *vif = wvif_to_vif(wvif); struct sk_buff *skb; - skb = ieee80211_beacon_get(wvif->wdev->hw, vif); + skb = ieee80211_beacon_get(wvif->wdev->hw, vif, 0); if (!skb) return -ENOMEM; wfx_hif_set_template_frame(wvif, skb, HIF_TMPLT_BCN, API_RATE_INDEX_B_1MBPS); @@ -356,7 +356,7 @@ static int wfx_upload_ap_templates(struct wfx_vif *wvif) static void wfx_set_mfp_ap(struct wfx_vif *wvif) { struct ieee80211_vif *vif = wvif_to_vif(wvif); - struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, vif); + struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, vif, 0); const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset, skb->len - ieoffset); @@ -588,7 +588,7 @@ static int wfx_update_tim(struct wfx_vif *wvif) u8 *tim_ptr; skb = ieee80211_beacon_get_tim(wvif->wdev->hw, vif, &tim_offset, - &tim_length); + &tim_length, 0); if (!skb) return -ENOENT; tim_ptr = skb->data + tim_offset; diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 5fa6878ee109..a3f6942df0c1 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -1671,7 +1671,7 @@ static int cw1200_set_tim_impl(struct cw1200_common *priv, bool aid0_bit_set) pr_debug("[AP] mcast: %s.\n", aid0_bit_set ? "ena" : "dis"); skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, - &tim_offset, &tim_length); + &tim_offset, &tim_length, 0); if (!skb) { if (!__cw1200_flush(priv, true)) wsm_unlock_tx(priv); @@ -2203,7 +2203,7 @@ static int cw1200_upload_beacon(struct cw1200_common *priv) frame.rate = WSM_TRANSMIT_RATE_6; frame.skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, - &tim_offset, &tim_len); + &tim_offset, &tim_len, 0); if (!frame.skb) return -ENOMEM; diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 340ab4985fe2..d76558964420 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1186,7 +1186,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON) { - beacon = ieee80211_beacon_get(hw, vif); + beacon = ieee80211_beacon_get(hw, vif, 0); if (!beacon) goto out_sleep; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index b476f244a20e..a1923ef52d55 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -4039,7 +4039,7 @@ static int wlcore_set_beacon_template(struct wl1271 *wl, u32 min_rate; int ret; int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); - struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); + struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif, 0); u16 tmpl_id; if (!beacon) { @@ -5493,7 +5493,7 @@ static const void *wlcore_get_beacon_ie(struct wl1271 *wl, { int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); struct sk_buff *beacon = - ieee80211_beacon_get(wl->hw, wl12xx_wlvif_to_vif(wlvif)); + ieee80211_beacon_get(wl->hw, wl12xx_wlvif_to_vif(wlvif), 0); if (!beacon) return NULL; diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index b42fedba519d..80b905d49954 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -398,7 +398,7 @@ int zd_restore_settings(struct zd_mac *mac) mac->type == NL80211_IFTYPE_ADHOC || mac->type == NL80211_IFTYPE_AP) { if (mac->vif != NULL) { - beacon = ieee80211_beacon_get(mac->hw, mac->vif); + beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0); if (beacon) zd_mac_config_beacon(mac->hw, beacon, false); } @@ -1167,7 +1167,7 @@ static void zd_beacon_done(struct zd_mac *mac) /* * Fetch next beacon so that tim_count is updated. */ - beacon = ieee80211_beacon_get(mac->hw, mac->vif); + beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0); if (beacon) zd_mac_config_beacon(mac->hw, beacon, true); @@ -1290,7 +1290,8 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, mac->type == NL80211_IFTYPE_AP) { associated = true; if (changes & BSS_CHANGED_BEACON) { - struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif, + 0); if (beacon) { zd_chip_disable_hwint(&mac->chip); @@ -1447,7 +1448,7 @@ static void beacon_watchdog_handler(struct work_struct *work) zd_chip_disable_hwint(&mac->chip); - beacon = ieee80211_beacon_get(mac->hw, mac->vif); + beacon = ieee80211_beacon_get(mac->hw, mac->vif, 0); if (beacon) { zd_mac_free_cur_beacon(mac); diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 71cbfa607d96..85cd01c463e8 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1435,7 +1435,7 @@ int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif) { struct sk_buff *beacon; - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) return -ENOMEM; diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 4d29f8ebb393..cd99091c6c28 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -699,7 +699,7 @@ int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif) { struct sk_buff *beacon; - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) return -ENOMEM; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 48c688fdf23d..06545ef1d41c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5069,6 +5069,7 @@ struct ieee80211_mutable_offsets { * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @offs: &struct ieee80211_mutable_offsets pointer to struct that will * receive the offsets that may be updated by the driver. + * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) * * If the driver implements beaconing modes, it must use this function to * obtain the beacon template. @@ -5085,7 +5086,8 @@ struct ieee80211_mutable_offsets { struct sk_buff * ieee80211_beacon_get_template(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_mutable_offsets *offs); + struct ieee80211_mutable_offsets *offs, + unsigned int link_id); /** * ieee80211_beacon_get_tim - beacon generation function @@ -5096,6 +5098,7 @@ ieee80211_beacon_get_template(struct ieee80211_hw *hw, * @tim_length: pointer to variable that will receive the TIM IE length, * (including the ID and length bytes!). * Set to 0 if invalid (in non-AP modes). + * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) * * If the driver implements beaconing modes, it must use this function to * obtain the beacon frame. @@ -5111,21 +5114,24 @@ ieee80211_beacon_get_template(struct ieee80211_hw *hw, */ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 *tim_offset, u16 *tim_length); + u16 *tim_offset, u16 *tim_length, + unsigned int link_id); /** * ieee80211_beacon_get - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) * * See ieee80211_beacon_get_tim(). * * Return: See ieee80211_beacon_get_tim(). */ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + unsigned int link_id) { - return ieee80211_beacon_get_tim(hw, vif, NULL, NULL); + return ieee80211_beacon_get_tim(hw, vif, NULL, NULL, link_id); } /** diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 17313954c628..c3e14ef20c05 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4689,11 +4689,12 @@ void ieee80211_tx_pending(struct tasklet_struct *t) static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, struct ps_data *ps, struct sk_buff *skb, - bool is_template) + bool is_template, unsigned int link_id) { u8 *pos, *tim; int aid0 = 0; int i, have_bits = 0, n1, n2; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; /* Generate bitmap for TIM only if there are any STAs in power save * mode. */ @@ -4704,7 +4705,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, IEEE80211_MAX_AID+1); if (!is_template) { if (ps->dtim_count == 0) - ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1; + ps->dtim_count = link_conf->dtim_period - 1; else ps->dtim_count--; } @@ -4713,7 +4714,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, *pos++ = WLAN_EID_TIM; *pos++ = 4; *pos++ = ps->dtim_count; - *pos++ = sdata->vif.bss_conf.dtim_period; + *pos++ = link_conf->dtim_period; if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf)) aid0 = 1; @@ -4754,7 +4755,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, struct ps_data *ps, struct sk_buff *skb, - bool is_template) + bool is_template, unsigned int link_id) { struct ieee80211_local *local = sdata->local; @@ -4766,10 +4767,12 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, * of the tim bitmap in mac80211 and the driver. */ if (local->tim_in_locked_section) { - __ieee80211_beacon_add_tim(sdata, ps, skb, is_template); + __ieee80211_beacon_add_tim(sdata, ps, skb, is_template, + link_id); } else { spin_lock_bh(&local->tim_lock); - __ieee80211_beacon_add_tim(sdata, ps, skb, is_template); + __ieee80211_beacon_add_tim(sdata, ps, skb, is_template, + link_id); spin_unlock_bh(&local->tim_lock); } @@ -4777,7 +4780,8 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, - struct beacon_data *beacon) + struct beacon_data *beacon, + unsigned int link_id) { u8 *beacon_data, count, max_count = 1; struct probe_resp *resp; @@ -4803,11 +4807,11 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, } rcu_read_lock(); - resp = rcu_dereference(sdata->deflink.u.ap.probe_resp); + resp = rcu_dereference(sdata->link[link_id]->u.ap.probe_resp); bcn_offsets = beacon->cntdwn_counter_offsets; count = beacon->cntdwn_current_counter; - if (sdata->vif.bss_conf.csa_active) + if (sdata->vif.link_conf[link_id]->csa_active) max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM; for (i = 0; i < max_count; ++i) { @@ -4948,14 +4952,15 @@ EXPORT_SYMBOL(ieee80211_beacon_cntdwn_is_complete); static int ieee80211_beacon_protect(struct sk_buff *skb, struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, + unsigned int link_id) { ieee80211_tx_result res; struct ieee80211_tx_data tx; struct sk_buff *check_skb; memset(&tx, 0, sizeof(tx)); - tx.key = rcu_dereference(sdata->deflink.default_beacon_key); + tx.key = rcu_dereference(sdata->link[link_id]->default_beacon_key); if (!tx.key) return 0; tx.local = local; @@ -4979,7 +4984,8 @@ ieee80211_beacon_get_finish(struct ieee80211_hw *hw, struct beacon_data *beacon, struct sk_buff *skb, struct ieee80211_chanctx_conf *chanctx_conf, - u16 csa_off_base) + u16 csa_off_base, + unsigned int link_id) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -5010,7 +5016,7 @@ ieee80211_beacon_get_finish(struct ieee80211_hw *hw, memset(&txrc, 0, sizeof(txrc)); txrc.hw = hw; txrc.sband = local->hw.wiphy->bands[band]; - txrc.bss_conf = &sdata->vif.bss_conf; + txrc.bss_conf = sdata->vif.link_conf[link_id]; txrc.skb = skb; txrc.reported_rate.idx = -1; if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) @@ -5045,7 +5051,8 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, struct ieee80211_mutable_offsets *offs, bool is_template, struct beacon_data *beacon, - struct ieee80211_chanctx_conf *chanctx_conf) + struct ieee80211_chanctx_conf *chanctx_conf, + unsigned int link_id) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -5058,7 +5065,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, if (!is_template) ieee80211_beacon_update_cntdwn(vif); - ieee80211_set_beacon_cntdwn(sdata, beacon); + ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); } /* headroom, head length, @@ -5074,7 +5081,7 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, skb_reserve(skb, local->tx_headroom); skb_put_data(skb, beacon->head, beacon->head_len); - ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template); + ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template, link_id); if (offs) { offs->tim_offset = beacon->head_len; @@ -5093,11 +5100,11 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw, if (beacon->tail) skb_put_data(skb, beacon->tail, beacon->tail_len); - if (ieee80211_beacon_protect(skb, local, sdata) < 0) + if (ieee80211_beacon_protect(skb, local, sdata, link_id) < 0) return NULL; ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf, - csa_off_base); + csa_off_base, link_id); return skb; } @@ -5105,7 +5112,8 @@ static struct sk_buff * __ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_mutable_offsets *offs, - bool is_template) + bool is_template, + unsigned int link_id) { struct ieee80211_local *local = hw_to_local(hw); struct beacon_data *beacon = NULL; @@ -5116,7 +5124,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, rcu_read_lock(); sdata = vif_to_sdata(vif); - chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + chanctx_conf = + rcu_dereference(sdata->vif.link_conf[link_id]->chanctx_conf); if (!ieee80211_sdata_running(sdata) || !chanctx_conf) goto out; @@ -5125,12 +5134,12 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, memset(offs, 0, sizeof(*offs)); if (sdata->vif.type == NL80211_IFTYPE_AP) { - beacon = rcu_dereference(sdata->deflink.u.ap.beacon); + beacon = rcu_dereference(sdata->link[link_id]->u.ap.beacon); if (!beacon) goto out; skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template, - beacon, chanctx_conf); + beacon, chanctx_conf, link_id); } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_hdr *hdr; @@ -5143,7 +5152,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (!is_template) __ieee80211_beacon_update_cntdwn(beacon); - ieee80211_set_beacon_cntdwn(sdata, beacon); + ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); } skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + @@ -5158,7 +5167,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, IEEE80211_STYPE_BEACON); ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, - chanctx_conf, 0); + chanctx_conf, 0, link_id); } else if (ieee80211_vif_is_mesh(&sdata->vif)) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; @@ -5175,7 +5184,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, */ __ieee80211_beacon_update_cntdwn(beacon); - ieee80211_set_beacon_cntdwn(sdata, beacon); + ieee80211_set_beacon_cntdwn(sdata, beacon, link_id); } if (ifmsh->sync_ops) @@ -5190,7 +5199,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, goto out; skb_reserve(skb, local->tx_headroom); skb_put_data(skb, beacon->head, beacon->head_len); - ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template); + ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template, + link_id); if (offs) { offs->tim_offset = beacon->head_len; @@ -5199,7 +5209,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, skb_put_data(skb, beacon->tail, beacon->tail_len); ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, - chanctx_conf, 0); + chanctx_conf, 0, link_id); } else { WARN_ON(1); goto out; @@ -5214,18 +5224,21 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, struct sk_buff * ieee80211_beacon_get_template(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_mutable_offsets *offs) + struct ieee80211_mutable_offsets *offs, + unsigned int link_id) { - return __ieee80211_beacon_get(hw, vif, offs, true); + return __ieee80211_beacon_get(hw, vif, offs, true, link_id); } EXPORT_SYMBOL(ieee80211_beacon_get_template); struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 *tim_offset, u16 *tim_length) + u16 *tim_offset, u16 *tim_length, + unsigned int link_id) { struct ieee80211_mutable_offsets offs = {}; - struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false); + struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false, + link_id); struct sk_buff *copy; int shift; -- cgit v1.2.3 From c71420db653aba30a234d1e4cf86dde376e604fa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 15 Jun 2022 09:20:45 +0200 Subject: wifi: mac80211: RCU-ify link STA pointers We need to be able to access these in a race-free way under traffic while adding/removing them, so RCU-ify the pointers. This requires passing a link_sta to a lot of functions so we don't have to do the RCU handling everywhere. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 +- net/mac80211/cfg.c | 12 ++-- net/mac80211/chan.c | 25 +++++--- net/mac80211/eht.c | 13 ++--- net/mac80211/he.c | 17 +++--- net/mac80211/ht.c | 14 ++--- net/mac80211/ibss.c | 5 +- net/mac80211/ieee80211_i.h | 30 +++++----- net/mac80211/iface.c | 3 +- net/mac80211/mesh_plink.c | 8 ++- net/mac80211/mlme.c | 12 ++-- net/mac80211/rate.c | 2 +- net/mac80211/rx.c | 6 +- net/mac80211/sta_info.c | 28 +++++---- net/mac80211/sta_info.h | 5 +- net/mac80211/tdls.c | 5 +- net/mac80211/vht.c | 139 ++++++++++++++++++++++++--------------------- 17 files changed, 180 insertions(+), 146 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 06545ef1d41c..27f24ac0426d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2201,7 +2201,7 @@ struct ieee80211_sta { u16 valid_links; struct ieee80211_link_sta deflink; - struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS]; + struct ieee80211_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 009f1723c990..b387f5f4fef0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1771,19 +1771,21 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (params->ht_capa) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, - params->ht_capa, sta, 0); + params->ht_capa, + &sta->deflink); /* VHT can override some HT caps such as the A-MSDU max length */ if (params->vht_capa) ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - params->vht_capa, sta, 0); + params->vht_capa, + &sta->deflink); if (params->he_capa) ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, (void *)params->he_capa, params->he_capa_len, (void *)params->he_6ghz_capa, - sta, 0); + &sta->deflink); if (params->eht_capa) ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband, @@ -1791,13 +1793,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, params->he_capa_len, params->eht_capa, params->eht_capa_len, - sta, 0); + &sta->deflink); if (params->opmode_notif_used) { /* returned value is only needed for rc update, but the * rc isn't initialized here yet, so ignore it */ - __ieee80211_vht_handle_opmode(sdata, sta, 0, + __ieee80211_vht_handle_opmode(sdata, &sta->deflink, params->opmode_notif, sband->band); } diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 4f25660d0eeb..6853b563fb6c 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -207,16 +207,20 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta, unsigned int link_id) { - enum ieee80211_sta_rx_bandwidth width = - ieee80211_sta_cap_rx_bw(sta, link_id); + enum ieee80211_sta_rx_bandwidth width; + struct link_sta_info *link_sta; + + link_sta = rcu_dereference(sta->link[link_id]); /* no effect if this STA has no presence on this link */ - if (!sta->sta.link[link_id]) + if (!link_sta) return NL80211_CHAN_WIDTH_20_NOHT; + width = ieee80211_sta_cap_rx_bw(link_sta); + switch (width) { case IEEE80211_STA_RX_BW_20: - if (sta->sta.link[link_id]->ht_cap.ht_supported) + if (link_sta->pub->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20; else return NL80211_CHAN_WIDTH_20_NOHT; @@ -416,6 +420,7 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) { struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct link_sta_info *link_sta; if (!link_conf) continue; @@ -423,18 +428,22 @@ static void ieee80211_chan_bw_change(struct ieee80211_local *local, if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf) continue; - new_sta_bw = ieee80211_sta_cur_vht_bw(sta, link_id); + link_sta = rcu_dereference(sta->link[link_id]); + if (!link_sta) + continue; + + new_sta_bw = ieee80211_sta_cur_vht_bw(link_sta); /* nothing change */ - if (new_sta_bw == sta->sta.link[link_id]->bandwidth) + if (new_sta_bw == link_sta->pub->bandwidth) continue; /* vif changed to narrow BW and narrow BW for station wasn't * requested or vise versa */ - if ((new_sta_bw < sta->sta.link[link_id]->bandwidth) == !narrowed) + if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed) continue; - sta->sta.link[link_id]->bandwidth = new_sta_bw; + link_sta->pub->bandwidth = new_sta_bw; rate_control_rate_update(local, sband, sta, link_id, IEEE80211_RC_BW_CHANGED); } diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c index de762a803c38..31e20a342f21 100644 --- a/net/mac80211/eht.c +++ b/net/mac80211/eht.c @@ -12,11 +12,10 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const u8 *he_cap_ie, u8 he_cap_len, const struct ieee80211_eht_cap_elem *eht_cap_ie_elem, - u8 eht_cap_len, struct sta_info *sta, - unsigned int link_id) + u8 eht_cap_len, + struct link_sta_info *link_sta) { - struct ieee80211_sta_eht_cap *eht_cap = - &sta->sta.link[link_id]->eht_cap; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap; struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie; u8 eht_ppe_size = 0; u8 mcs_nss_size; @@ -73,8 +72,6 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, eht_cap->has_eht = true; - sta->link[link_id]->cur_max_bandwidth = - ieee80211_sta_cap_rx_bw(sta, link_id); - sta->sta.link[link_id]->bandwidth = - ieee80211_sta_cur_vht_bw(sta, link_id); + link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta); + link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); } diff --git a/net/mac80211/he.c b/net/mac80211/he.c index e48e9a021622..d9228fd3f77a 100644 --- a/net/mac80211/he.c +++ b/net/mac80211/he.c @@ -10,8 +10,9 @@ static void ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_capa, - struct sta_info *sta, unsigned int link_id) + struct link_sta_info *link_sta) { + struct sta_info *sta = link_sta->sta; enum ieee80211_smps_mode smps_mode; if (sta->sdata->vif.type == NL80211_IFTYPE_AP || @@ -49,7 +50,7 @@ ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_ break; } - sta->sta.link[link_id]->he_6ghz_capa = *he_6ghz_capa; + link_sta->pub->he_6ghz_capa = *he_6ghz_capa; } static void ieee80211_he_mcs_disable(__le16 *he_mcs) @@ -108,9 +109,9 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const u8 *he_cap_ie, u8 he_cap_len, const struct ieee80211_he_6ghz_capa *he_6ghz_capa, - struct sta_info *sta, unsigned int link_id) + struct link_sta_info *link_sta) { - struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap; + struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; struct ieee80211_sta_he_cap own_he_cap; struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie; u8 he_ppe_size; @@ -153,13 +154,11 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, he_cap->has_he = true; - sta->link[link_id]->cur_max_bandwidth = - ieee80211_sta_cap_rx_bw(sta, link_id); - sta->sta.link[link_id]->bandwidth = - ieee80211_sta_cur_vht_bw(sta, link_id); + link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta); + link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa) - ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, sta, link_id); + ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta); ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80, &he_cap->he_mcs_nss_supp.rx_mcs_80, diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 111828b559a0..2eb3a409b70f 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -138,8 +138,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_ht_cap *ht_cap_ie, - struct sta_info *sta, unsigned int link_id) + struct link_sta_info *link_sta) { + struct sta_info *sta = link_sta->sta; struct ieee80211_sta_ht_cap ht_cap, own_cap; u8 ampdu_info, tx_mcs_set_cap; int i, max_tx_streams; @@ -243,12 +244,11 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839; apply: - changed = memcmp(&sta->sta.link[link_id]->ht_cap, - &ht_cap, sizeof(ht_cap)); + changed = memcmp(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap)); - memcpy(&sta->sta.link[link_id]->ht_cap, &ht_cap, sizeof(ht_cap)); + memcpy(&link_sta->pub->ht_cap, &ht_cap, sizeof(ht_cap)); - switch (sdata->vif.link_conf[link_id]->chandef.width) { + switch (sdata->vif.link_conf[link_sta->link_id]->chandef.width) { default: WARN_ON_ONCE(1); fallthrough; @@ -265,9 +265,9 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, break; } - sta->sta.link[link_id]->bandwidth = bw; + link_sta->pub->bandwidth = bw; - sta->link[link_id]->cur_max_bandwidth = + link_sta->cur_max_bandwidth = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 65a3808dc92a..65b6255c6747 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1051,7 +1051,7 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, &htcap_ie, - sta, 0); + &sta->deflink); if (elems->vht_operation && elems->vht_cap_elem && sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20 && @@ -1068,7 +1068,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, &chandef); memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - &cap_ie, sta, 0); + &cap_ie, + &sta->deflink); if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap))) rates_updated |= true; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index aa5e4c2734b7..46f4e89825a0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2061,7 +2061,7 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_ht_cap *ht_cap_ie, - struct sta_info *sta, unsigned int link_id); + struct link_sta_info *link_sta); void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid, u16 initiator, u16 reason_code); @@ -2117,31 +2117,31 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, - struct sta_info *sta, unsigned int link_id); -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, - unsigned int link_id); -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, - unsigned int link_id); -void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id); + struct link_sta_info *link_sta); +enum ieee80211_sta_rx_bandwidth +ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta); +enum ieee80211_sta_rx_bandwidth +ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta); +void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta); enum ieee80211_sta_rx_bandwidth ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width); -enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, - unsigned int link_id); +enum nl80211_chan_width +ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta); void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata, unsigned int link_id, struct ieee80211_mgmt *mgmt); u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, unsigned int link_id, + struct link_sta_info *sta, u8 opmode, enum nl80211_band band); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, unsigned int link_id, + struct link_sta_info *sta, u8 opmode, enum nl80211_band band); void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta_vht_cap *vht_cap); void ieee80211_get_vht_mask_from_cap(__le16 vht_cap, u16 vht_mask[NL80211_VHT_NSS_MAX]); enum nl80211_chan_width -ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id); +ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info *sta); /* HE */ void @@ -2149,7 +2149,7 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const u8 *he_cap_ie, u8 he_cap_len, const struct ieee80211_he_6ghz_capa *he_6ghz_capa, - struct sta_info *sta, unsigned int link_id); + struct link_sta_info *link_sta); void ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif *vif, const struct ieee80211_he_spr *he_spr_ie_elem); @@ -2560,6 +2560,6 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const u8 *he_cap_ie, u8 he_cap_len, const struct ieee80211_eht_cap_elem *eht_cap_ie_elem, - u8 eht_cap_len, struct sta_info *sta, - unsigned int link_id); + u8 eht_cap_len, + struct link_sta_info *link_sta); #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f118e7710fb1..0cf5a395d925 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1525,7 +1525,8 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local, sta = sta_info_get_bss(sdata, mgmt->sa); if (sta) - ieee80211_vht_handle_opmode(sdata, sta, 0, + ieee80211_vht_handle_opmode(sdata, + &sta->deflink, opmode, band); mutex_unlock(&local->sta_mtx); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index fe54ac431202..55bed9ce98fe 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -438,16 +438,18 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, sta->sta.deflink.supp_rates[sband->band] = rates; if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, - elems->ht_cap_elem, sta, 0)) + elems->ht_cap_elem, + &sta->deflink)) changed |= IEEE80211_RC_BW_CHANGED; ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, - elems->vht_cap_elem, sta, 0); + elems->vht_cap_elem, + &sta->deflink); ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, elems->he_cap_len, elems->he_6ghz_capa, - sta, 0); + &sta->deflink); if (bw != sta->sta.deflink.bandwidth) changed |= IEEE80211_RC_BW_CHANGED; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c2c997086553..01a72d1fcfcc 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3566,12 +3566,13 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, /* Set up internal HT/VHT capabilities */ if (elems->ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, - elems->ht_cap_elem, sta, 0); + elems->ht_cap_elem, + &sta->deflink); if (elems->vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, elems->vht_cap_elem, - sta, 0); + &sta->deflink); if (elems->he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && elems->he_cap) { @@ -3579,7 +3580,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, elems->he_cap, elems->he_cap_len, elems->he_6ghz_capa, - sta, 0); + &sta->deflink); bss_conf->he_support = sta->sta.deflink.he_cap.has_he; if (elems->rsnx && elems->rsnx_len && @@ -3599,7 +3600,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, elems->he_cap_len, elems->eht_cap, elems->eht_cap_len, - sta, 0); + &sta->deflink); bss_conf->eht_support = sta->sta.deflink.eht_cap.has_eht; } else { @@ -4378,7 +4379,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (sta && elems->opmode_notif) - ieee80211_vht_handle_opmode(sdata, sta, 0, + ieee80211_vht_handle_opmode(sdata, + &sta->deflink, *elems->opmode_notif, rx_status->band); mutex_unlock(&local->sta_mtx); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index c58d9689f51f..7947e9a162a9 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -37,7 +37,7 @@ void rate_control_rate_init(struct sta_info *sta) struct ieee80211_supported_band *sband; struct ieee80211_chanctx_conf *chanctx_conf; - ieee80211_sta_set_rx_nss(sta, 0); + ieee80211_sta_set_rx_nss(&sta->deflink); if (!ref) return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0b5c34d00c14..d017ad14d7db 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3391,11 +3391,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) max_bw = IEEE80211_STA_RX_BW_20; else - max_bw = ieee80211_sta_cap_rx_bw(rx->sta, 0); + max_bw = ieee80211_sta_cap_rx_bw(&rx->sta->deflink); /* set cur_max_bandwidth and recalc sta bw */ rx->sta->deflink.cur_max_bandwidth = max_bw; - new_bw = ieee80211_sta_cur_vht_bw(rx->sta, 0); + new_bw = ieee80211_sta_cur_vht_bw(&rx->sta->deflink); if (rx->sta->sta.deflink.bandwidth == new_bw) goto handled; @@ -3403,7 +3403,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) rx->sta->sta.deflink.bandwidth = new_bw; sband = rx->local->hw.wiphy->bands[status->band]; sta_opmode.bw = - ieee80211_sta_rx_bw_to_chan_width(rx->sta, 0); + ieee80211_sta_rx_bw_to_chan_width(&rx->sta->deflink); sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; rate_control_rate_update(local, sband, rx->sta, 0, diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index b1426a2459e8..1f4189e08675 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -67,6 +67,7 @@ struct sta_link_alloc { struct link_sta_info info; struct ieee80211_link_sta sta; + struct rcu_head rcu_head; }; static const struct rhashtable_params sta_rht_params = { @@ -258,19 +259,23 @@ static void sta_info_free_link(struct link_sta_info *link_sta) static void sta_remove_link(struct sta_info *sta, unsigned int link_id) { struct sta_link_alloc *alloc = NULL; + struct link_sta_info *link_sta; - if (WARN_ON(!sta->link[link_id])) + link_sta = rcu_dereference_protected(sta->link[link_id], + lockdep_is_held(&sta->local->sta_mtx)); + + if (WARN_ON(!link_sta)) return; - if (sta->link[link_id] != &sta->deflink) - alloc = container_of(sta->link[link_id], typeof(*alloc), info); + if (link_sta != &sta->deflink) + alloc = container_of(link_sta, typeof(*alloc), info); sta->sta.valid_links &= ~BIT(link_id); - sta->link[link_id] = NULL; - sta->sta.link[link_id] = NULL; + RCU_INIT_POINTER(sta->link[link_id], NULL); + RCU_INIT_POINTER(sta->sta.link[link_id], NULL); if (alloc) { sta_info_free_link(&alloc->info); - kfree(alloc); + kfree_rcu(alloc, rcu_head); } } @@ -404,8 +409,9 @@ static void sta_info_add_link(struct sta_info *sta, { link_info->sta = sta; link_info->link_id = link_id; - sta->link[link_id] = link_info; - sta->sta.link[link_id] = link_sta; + link_info->pub = link_sta; + rcu_assign_pointer(sta->link[link_id], link_info); + rcu_assign_pointer(sta->sta.link[link_id], link_sta); } struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, @@ -2682,13 +2688,15 @@ int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id) int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) { struct ieee80211_sub_if_data *sdata = sta->sdata; + struct link_sta_info *link_sta; u16 old_links = sta->sta.valid_links; u16 new_links = old_links | BIT(link_id); int ret; - lockdep_assert_held(&sdata->local->sta_mtx); + link_sta = rcu_dereference_protected(sta->link[link_id], + lockdep_is_held(&sdata->local->sta_mtx)); - if (WARN_ON(old_links == new_links || !sta->link[link_id])) + if (WARN_ON(old_links == new_links || !link_sta)) return -EINVAL; sta->sta.valid_links = new_links; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 8ec65bb7d13e..27c96c04b13f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -516,6 +516,7 @@ struct ieee80211_fragment_cache { * @status_stats.last_ack_signal: last ACK signal * @status_stats.ack_signal_filled: last ACK signal validity * @status_stats.avg_ack_signal: average ACK signal + * @pub: public (driver visible) link STA data * TODO Move other link params from sta_info as required for MLD operation */ struct link_sta_info { @@ -561,6 +562,8 @@ struct link_sta_info { } tx_stats; enum ieee80211_sta_rx_bandwidth cur_max_bandwidth; + + struct ieee80211_link_sta *pub; }; /** @@ -708,7 +711,7 @@ struct sta_info { struct ieee80211_fragment_cache frags; struct link_sta_info deflink; - struct link_sta_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; + struct link_sta_info __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* keep last! */ struct ieee80211_sta sta; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 4fc120c64022..c531fa17f426 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -308,7 +308,8 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, /* IEEE802.11ac-2013 Table E-4 */ u16 centers_80mhz[] = { 5210, 5290, 5530, 5610, 5690, 5775 }; struct cfg80211_chan_def uc = sta->tdls_chandef; - enum nl80211_chan_width max_width = ieee80211_sta_cap_chan_bw(sta, 0); + enum nl80211_chan_width max_width = + ieee80211_sta_cap_chan_bw(&sta->deflink); int i; /* only support upgrading non-narrow channels up to 80Mhz */ @@ -1268,7 +1269,7 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata, enum ieee80211_sta_rx_bandwidth bw; bw = ieee80211_chan_width_to_rx_bw(conf->def.width); - bw = min(bw, ieee80211_sta_cap_rx_bw(sta, 0)); + bw = min(bw, ieee80211_sta_cap_rx_bw(&sta->deflink)); if (bw != sta->sta.deflink.bandwidth) { sta->sta.deflink.bandwidth = bw; rate_control_rate_update(local, sband, sta, 0, diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index acfe1459535f..fa14627b499a 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -116,16 +116,16 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, const struct ieee80211_vht_cap *vht_cap_ie, - struct sta_info *sta, unsigned int link_id) + struct link_sta_info *link_sta) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; struct ieee80211_sta_vht_cap own_cap; u32 cap_info, i; bool have_80mhz; memset(vht_cap, 0, sizeof(*vht_cap)); - if (!sta->sta.link[link_id]->ht_cap.ht_supported) + if (!link_sta->pub->ht_cap.ht_supported) return; if (!vht_cap_ie || !sband->vht_cap.vht_supported) @@ -162,7 +162,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, * our own capabilities and then use those below. */ if (sdata->vif.type == NL80211_IFTYPE_STATION && - !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) + !test_sta_flag(link_sta->sta, WLAN_STA_TDLS_PEER)) ieee80211_apply_vhtcap_overrides(sdata, &own_cap); /* take some capabilities as-is */ @@ -286,8 +286,9 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, */ if (vht_cap->vht_mcs.rx_mcs_map == cpu_to_le16(0xFFFF)) { vht_cap->vht_supported = false; - sdata_info(sdata, "Ignoring VHT IE from %pM due to invalid rx_mcs_map\n", - sta->addr); + sdata_info(sdata, + "Ignoring VHT IE from %pM (link:%pM) due to invalid rx_mcs_map\n", + link_sta->sta->addr, link_sta->addr); return; } @@ -295,10 +296,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; break; default: - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; if (!(vht_cap->vht_mcs.tx_highest & cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) @@ -310,35 +311,40 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, * above) between 160 and 80+80 yet. */ if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) - sta->link[link_id]->cur_max_bandwidth = + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; } - sta->sta.link[link_id]->bandwidth = ieee80211_sta_cur_vht_bw(sta, link_id); + link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); + /* + * FIXME - should the amsdu len be per link? store per link + * and maintain a minimum? + */ switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: - sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454; + link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454; break; case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991: - sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991; + link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991; break; case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895: default: - sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895; + link_sta->sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895; break; } } /* FIXME: move this to some better location - parses HE/EHT now */ -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, - unsigned int link_id) +enum ieee80211_sta_rx_bandwidth +ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta) { - struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id]; - struct ieee80211_link_sta *link_sta = sta->sta.link[link_id]; - struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; - struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; - struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; + unsigned int link_id = link_sta->link_id; + struct ieee80211_sub_if_data *sdata = link_sta->sta->sdata; + struct ieee80211_bss_conf *link_conf = sdata->vif.link_conf[link_id]; + struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; + struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->pub->eht_cap; u32 cap_width; if (he_cap->has_he) { @@ -371,7 +377,7 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, } if (!vht_cap->vht_supported) - return link_sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + return link_sta->pub->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; @@ -392,17 +398,17 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta, return IEEE80211_STA_RX_BW_80; } -enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, - unsigned int link_id) +enum nl80211_chan_width +ieee80211_sta_cap_chan_bw(struct link_sta_info *link_sta) { - struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.link[link_id]->vht_cap; + struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; u32 cap_width; if (!vht_cap->vht_supported) { - if (!sta->sta.link[link_id]->ht_cap.ht_supported) + if (!link_sta->pub->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20_NOHT; - return sta->sta.link[link_id]->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? + return link_sta->pub->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? NL80211_CHAN_WIDTH_40 : NL80211_CHAN_WIDTH_20; } @@ -417,17 +423,17 @@ enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta, } enum nl80211_chan_width -ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta, unsigned int link_id) +ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info *link_sta) { enum ieee80211_sta_rx_bandwidth cur_bw = - sta->sta.link[link_id]->bandwidth; + link_sta->pub->bandwidth; struct ieee80211_sta_vht_cap *vht_cap = - &sta->sta.link[link_id]->vht_cap; + &link_sta->pub->vht_cap; u32 cap_width; switch (cur_bw) { case IEEE80211_STA_RX_BW_20: - if (!sta->sta.link[link_id]->ht_cap.ht_supported) + if (!link_sta->pub->ht_cap.ht_supported) return NL80211_CHAN_WIDTH_20_NOHT; else return NL80211_CHAN_WIDTH_20; @@ -471,15 +477,17 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width) } /* FIXME: rename/move - this deals with everything not just VHT */ -enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, - unsigned int link_id) +enum ieee80211_sta_rx_bandwidth +ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta) { - struct ieee80211_bss_conf *link_conf = sta->sdata->vif.link_conf[link_id]; + struct sta_info *sta = link_sta->sta; + struct ieee80211_bss_conf *link_conf = + sta->sdata->vif.link_conf[link_sta->link_id]; enum nl80211_chan_width bss_width = link_conf->chandef.width; enum ieee80211_sta_rx_bandwidth bw; - bw = ieee80211_sta_cap_rx_bw(sta, link_id); - bw = min(bw, sta->link[link_id]->cur_max_bandwidth); + bw = ieee80211_sta_cap_rx_bw(link_sta); + bw = min(bw, link_sta->cur_max_bandwidth); /* Don't consider AP's bandwidth for TDLS peers, section 11.23.1 of * IEEE80211-2016 specification makes higher bandwidth operation @@ -501,18 +509,18 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta, return bw; } -void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) +void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta) { u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss; bool support_160; /* if we received a notification already don't overwrite it */ - if (sta->sta.link[link_id]->rx_nss) + if (link_sta->pub->rx_nss) return; - if (sta->sta.link[link_id]->eht_cap.has_eht) { + if (link_sta->pub->eht_cap.has_eht) { int i; - const u8 *rx_nss_mcs = (void *)&sta->sta.link[link_id]->eht_cap.eht_mcs_nss_supp; + const u8 *rx_nss_mcs = (void *)&link_sta->pub->eht_cap.eht_mcs_nss_supp; /* get the max nss for EHT over all possible bandwidths and mcs */ for (i = 0; i < sizeof(struct ieee80211_eht_mcs_nss_supp); i++) @@ -521,10 +529,10 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) IEEE80211_EHT_MCS_NSS_RX)); } - if (sta->sta.link[link_id]->he_cap.has_he) { + if (link_sta->pub->he_cap.has_he) { int i; u8 rx_mcs_80 = 0, rx_mcs_160 = 0; - const struct ieee80211_sta_he_cap *he_cap = &sta->sta.link[link_id]->he_cap; + const struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; u16 mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); u16 mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); @@ -555,23 +563,23 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) he_rx_nss = rx_mcs_80; } - if (sta->sta.link[link_id]->ht_cap.ht_supported) { - if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[0]) + if (link_sta->pub->ht_cap.ht_supported) { + if (link_sta->pub->ht_cap.mcs.rx_mask[0]) ht_rx_nss++; - if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[1]) + if (link_sta->pub->ht_cap.mcs.rx_mask[1]) ht_rx_nss++; - if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[2]) + if (link_sta->pub->ht_cap.mcs.rx_mask[2]) ht_rx_nss++; - if (sta->sta.link[link_id]->ht_cap.mcs.rx_mask[3]) + if (link_sta->pub->ht_cap.mcs.rx_mask[3]) ht_rx_nss++; /* FIXME: consider rx_highest? */ } - if (sta->sta.link[link_id]->vht_cap.vht_supported) { + if (link_sta->pub->vht_cap.vht_supported) { int i; u16 rx_mcs_map; - rx_mcs_map = le16_to_cpu(sta->sta.link[link_id]->vht_cap.vht_mcs.rx_mcs_map); + rx_mcs_map = le16_to_cpu(link_sta->pub->vht_cap.vht_mcs.rx_mcs_map); for (i = 7; i >= 0; i--) { u8 mcs = (rx_mcs_map >> (2 * i)) & 3; @@ -587,11 +595,11 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta, unsigned int link_id) rx_nss = max(vht_rx_nss, ht_rx_nss); rx_nss = max(he_rx_nss, rx_nss); rx_nss = max(eht_rx_nss, rx_nss); - sta->sta.link[link_id]->rx_nss = max_t(u8, 1, rx_nss); + link_sta->pub->rx_nss = max_t(u8, 1, rx_nss); } u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, unsigned int link_id, + struct link_sta_info *link_sta, u8 opmode, enum nl80211_band band) { enum ieee80211_sta_rx_bandwidth new_bw; @@ -607,8 +615,8 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; nss += 1; - if (sta->sta.link[link_id]->rx_nss != nss) { - sta->sta.link[link_id]->rx_nss = nss; + if (link_sta->pub->rx_nss != nss) { + link_sta->pub->rx_nss = nss; sta_opmode.rx_nss = nss; changed |= IEEE80211_RC_NSS_CHANGED; sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED; @@ -617,34 +625,34 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80) - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; else - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; break; case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: /* legacy only, no longer used by newer spec */ - sta->link[link_id]->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; + link_sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; break; } - new_bw = ieee80211_sta_cur_vht_bw(sta, link_id); - if (new_bw != sta->sta.link[link_id]->bandwidth) { - sta->sta.link[link_id]->bandwidth = new_bw; - sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(sta, link_id); + new_bw = ieee80211_sta_cur_vht_bw(link_sta); + if (new_bw != link_sta->pub->bandwidth) { + link_sta->pub->bandwidth = new_bw; + sta_opmode.bw = ieee80211_sta_rx_bw_to_chan_width(link_sta); changed |= IEEE80211_RC_BW_CHANGED; sta_opmode.changed |= STA_OPMODE_MAX_BW_CHANGED; } if (sta_opmode.changed) - cfg80211_sta_opmode_change_notify(sdata->dev, sta->addr, + cfg80211_sta_opmode_change_notify(sdata->dev, link_sta->addr, &sta_opmode, GFP_KERNEL); return changed; @@ -689,18 +697,19 @@ void ieee80211_update_mu_groups(struct ieee80211_vif *vif, unsigned int link_id, EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups); void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, unsigned int link_id, + struct link_sta_info *link_sta, u8 opmode, enum nl80211_band band) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; - u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, link_id, + u32 changed = __ieee80211_vht_handle_opmode(sdata, link_sta, opmode, band); if (changed > 0) { ieee80211_recalc_min_chandef(sdata); - rate_control_rate_update(local, sband, sta, link_id, changed); + rate_control_rate_update(local, sband, link_sta->sta, + link_sta->link_id, changed); } } -- cgit v1.2.3 From efbabc11650040c64884ff3019b88c7bcc0ceb1d Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Wed, 8 Jun 2022 14:46:37 +0530 Subject: cfg80211: Indicate MLO connection info in connect and roam callbacks The MLO links used for connection with an MLD AP are decided by the driver in case of SME offloaded to driver. Add support for the drivers to indicate the information of links used for MLO connection in connect and roam callbacks, update the connected links information in wdev from connect/roam result sent by driver. Also, send the connected links information to userspace. Add a netlink flag attribute to indicate that userspace supports handling of MLO connection. Drivers must not do MLO connection when this flag is not set. This is to maintain backwards compatibility with older supplicant versions which doesn't have support for MLO connection. Signed-off-by: Veerendranath Jakkam Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 +- drivers/net/wireless/ath/wil6210/wmi.c | 4 +- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 6 +- drivers/net/wireless/rndis_wlan.c | 5 +- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 4 +- drivers/staging/wlan-ng/cfg80211.c | 2 +- include/net/cfg80211.h | 84 +++-- include/uapi/linux/nl80211.h | 6 + net/wireless/mlme.c | 4 +- net/wireless/nl80211.c | 120 ++++++- net/wireless/sme.c | 391 +++++++++++++++------ 11 files changed, 480 insertions(+), 148 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 33ed54738d47..e11c7e9accc0 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -807,7 +807,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, cfg80211_put_bss(ar->wiphy, bss); } else if (vif->sme_state == SME_CONNECTED) { struct cfg80211_roam_info roam_info = { - .bss = bss, + .links[0].bss = bss, .req_ie = assoc_req_ie, .req_ie_len = assoc_req_len, .resp_ie = assoc_resp_ie, diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 98b4c189eecc..ea7bd403e706 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1822,8 +1822,8 @@ wmi_evt_reassoc_status(struct wil6210_vif *vif, int id, void *d, int len) freq = ieee80211_channel_to_frequency(ch, NL80211_BAND_60GHZ); memset(&info, 0, sizeof(info)); - info.channel = ieee80211_get_channel(wiphy, freq); - info.bss = vif->bss; + info.links[0].channel = ieee80211_get_channel(wiphy, freq); + info.links[0].bss = vif->bss; info.req_ie = assoc_req_ie; info.req_ie_len = assoc_req_ie_len; info.resp_ie = assoc_resp_ie; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 11e1f07f83e0..3ae6779fe153 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6017,8 +6017,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, done: kfree(buf); - roam_info.channel = notify_channel; - roam_info.bssid = profile->bssid; + roam_info.links[0].channel = notify_channel; + roam_info.links[0].bssid = profile->bssid; roam_info.req_ie = conn_info->req_ie; roam_info.req_ie_len = conn_info->req_ie_len; roam_info.resp_ie = conn_info->resp_ie; @@ -6061,7 +6061,7 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, } else { conn_params.status = WLAN_STATUS_AUTH_TIMEOUT; } - conn_params.bssid = profile->bssid; + conn_params.links[0].bssid = profile->bssid; conn_params.req_ie = conn_info->req_ie; conn_params.req_ie_len = conn_info->req_ie_len; conn_params.resp_ie = conn_info->resp_ie; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index ff2448394a1e..05524291d60c 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2813,8 +2813,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) resp_ie_len, 0, GFP_KERNEL); } else { struct cfg80211_roam_info roam_info = { - .channel = get_current_channel(usbdev, NULL), - .bssid = bssid, + .links[0].channel = + get_current_channel(usbdev, NULL), + .links[0].bssid = bssid, .req_ie = req_ie, .req_ie_len = req_ie_len, .resp_ie = resp_ie, diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 349aa3c4b668..cf35125b7891 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -450,8 +450,8 @@ check_bss: notify_channel = ieee80211_get_channel(wiphy, freq); - roam_info.channel = notify_channel; - roam_info.bssid = cur_network->network.mac_address; + roam_info.links[0].channel = notify_channel; + roam_info.links[0].bssid = cur_network->network.mac_address; roam_info.req_ie = pmlmepriv->assoc_req+sizeof(struct ieee80211_hdr_3addr)+2; roam_info.req_ie_len = diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 87379edce9a8..b7b56d8406d1 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -645,7 +645,7 @@ void prism2_disconnected(struct wlandevice *wlandev) void prism2_roamed(struct wlandevice *wlandev) { struct cfg80211_roam_info roam_info = { - .bssid = wlandev->bssid, + .links[0].bssid = wlandev->bssid, }; cfg80211_roamed(wlandev->netdev, &roam_info, GFP_KERNEL); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5706f96b819a..996782c44838 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2763,6 +2763,9 @@ struct cfg80211_assoc_link { * request (connect callback). * @ASSOC_REQ_DISABLE_HE: Disable HE * @ASSOC_REQ_DISABLE_EHT: Disable EHT + * @CONNECT_REQ_MLO_SUPPORT: Userspace indicates support for handling MLD links. + * Drivers shall disable MLO features for the current association if this + * flag is not set. */ enum cfg80211_assoc_req_flags { ASSOC_REQ_DISABLE_HT = BIT(0), @@ -2771,6 +2774,7 @@ enum cfg80211_assoc_req_flags { CONNECT_REQ_EXTERNAL_AUTH_SUPPORT = BIT(3), ASSOC_REQ_DISABLE_HE = BIT(4), ASSOC_REQ_DISABLE_EHT = BIT(5), + CONNECT_REQ_MLO_SUPPORT = BIT(6), }; /** @@ -5780,12 +5784,13 @@ static inline void WARN_INVALID_LINK_ID(struct wireless_dev *wdev, !(wdev->valid_links & BIT(link_id))); } -#define for_each_valid_link(wdev, link_id) \ - for (link_id = 0; \ - link_id < ((wdev)->valid_links ? ARRAY_SIZE((wdev)->links) : 1); \ - link_id++) \ - if (!(wdev)->valid_links || \ - ((wdev)->valid_links & BIT(link_id))) +#define for_each_valid_link(link_info, link_id) \ + for (link_id = 0; \ + link_id < ((link_info)->valid_links ? \ + ARRAY_SIZE((link_info)->links) : 1); \ + link_id++) \ + if (!(link_info)->valid_links || \ + ((link_info)->valid_links & BIT(link_id))) /** * DOC: Utility functions @@ -7296,13 +7301,6 @@ struct cfg80211_fils_resp_params { * indicate that this is a failure, but without a status code. * @timeout_reason is used to report the reason for the timeout in that * case. - * @bssid: The BSSID of the AP (may be %NULL) - * @bss: Entry of bss to which STA got connected to, can be obtained through - * cfg80211_get_bss() (may be %NULL). But it is recommended to store the - * bss from the connect_request and hold a reference to it and return - * through this param to avoid a warning if the bss is expired during the - * connection, esp. for those drivers implementing connect op. - * Only one parameter among @bssid and @bss needs to be specified. * @req_ie: Association request IEs (may be %NULL) * @req_ie_len: Association request IEs length * @resp_ie: Association response IEs (may be %NULL) @@ -7314,17 +7312,41 @@ struct cfg80211_fils_resp_params { * not known. This value is used only if @status < 0 to indicate that the * failure is due to a timeout and not due to explicit rejection by the AP. * This value is ignored in other cases (@status >= 0). + * @valid_links: For MLO connection, BIT mask of the valid link ids. Otherwise + * zero. + * @ap_mld_addr: For MLO connection, MLD address of the AP. Otherwise %NULL. + * @links : For MLO connection, contains link info for the valid links indicated + * using @valid_links. For non-MLO connection, links[0] contains the + * connected AP info. + * @links.addr: For MLO connection, MAC address of the STA link. Otherwise + * %NULL. + * @links.bssid: For MLO connection, MAC address of the AP link. For non-MLO + * connection, links[0].bssid points to the BSSID of the AP (may be %NULL). + * @links.bss: For MLO connection, entry of bss to which STA link is connected. + * For non-MLO connection, links[0].bss points to entry of bss to which STA + * is connected. It can be obtained through cfg80211_get_bss() (may be + * %NULL). It is recommended to store the bss from the connect_request and + * hold a reference to it and return through this param to avoid a warning + * if the bss is expired during the connection, esp. for those drivers + * implementing connect op. Only one parameter among @bssid and @bss needs + * to be specified. */ struct cfg80211_connect_resp_params { int status; - const u8 *bssid; - struct cfg80211_bss *bss; const u8 *req_ie; size_t req_ie_len; const u8 *resp_ie; size_t resp_ie_len; struct cfg80211_fils_resp_params fils; enum nl80211_timeout_reason timeout_reason; + + const u8 *ap_mld_addr; + u16 valid_links; + struct { + const u8 *addr; + const u8 *bssid; + struct cfg80211_bss *bss; + } links[IEEE80211_MLD_MAX_NUM_LINKS]; }; /** @@ -7394,8 +7416,8 @@ cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, memset(¶ms, 0, sizeof(params)); params.status = status; - params.bssid = bssid; - params.bss = bss; + params.links[0].bssid = bssid; + params.links[0].bss = bss; params.req_ie = req_ie; params.req_ie_len = req_ie_len; params.resp_ie = resp_ie; @@ -7466,24 +7488,40 @@ cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid, /** * struct cfg80211_roam_info - driver initiated roaming information * - * @channel: the channel of the new AP - * @bss: entry of bss to which STA got roamed (may be %NULL if %bssid is set) - * @bssid: the BSSID of the new AP (may be %NULL if %bss is set) * @req_ie: association request IEs (maybe be %NULL) * @req_ie_len: association request IEs length * @resp_ie: association response IEs (may be %NULL) * @resp_ie_len: assoc response IEs length * @fils: FILS related roaming information. + * @valid_links: For MLO roaming, BIT mask of the new valid links is set. + * Otherwise zero. + * @ap_mld_addr: For MLO roaming, MLD address of the new AP. Otherwise %NULL. + * @links : For MLO roaming, contains new link info for the valid links set in + * @valid_links. For non-MLO roaming, links[0] contains the new AP info. + * @links.addr: For MLO roaming, MAC address of the STA link. Otherwise %NULL. + * @links.bssid: For MLO roaming, MAC address of the new AP link. For non-MLO + * roaming, links[0].bssid points to the BSSID of the new AP. May be + * %NULL if %links.bss is set. + * @links.channel: the channel of the new AP. + * @links.bss: For MLO roaming, entry of new bss to which STA link got + * roamed. For non-MLO roaming, links[0].bss points to entry of bss to + * which STA got roamed (may be %NULL if %links.bssid is set) */ struct cfg80211_roam_info { - struct ieee80211_channel *channel; - struct cfg80211_bss *bss; - const u8 *bssid; const u8 *req_ie; size_t req_ie_len; const u8 *resp_ie; size_t resp_ie_len; struct cfg80211_fils_resp_params fils; + + const u8 *ap_mld_addr; + u16 valid_links; + struct { + const u8 *addr; + const u8 *bssid; + struct ieee80211_channel *channel; + struct cfg80211_bss *bss; + } links[IEEE80211_MLD_MAX_NUM_LINKS]; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 60ad9a9f153d..89f64f46b98d 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2690,6 +2690,10 @@ enum nl80211_commands { * @NL80211_ATTR_MLD_ADDR: An MLD address, used with various commands such as * authenticate/associate. * + * @NL80211_ATTR_MLO_SUPPORT: Flag attribute to indicate user space supports MLO + * connection. Used with %NL80211_CMD_CONNECT. If this attribute is not + * included in NL80211_CMD_CONNECT drivers must not perform MLO connection. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3208,6 +3212,8 @@ enum nl80211_attrs { NL80211_ATTR_MLO_LINK_ID, NL80211_ATTR_MLD_ADDR, + NL80211_ATTR_MLO_SUPPORT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index d92eed0e52cd..8a84cf77667c 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -42,8 +42,8 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, memset(&cr, 0, sizeof(cr)); cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code); - cr.bssid = mgmt->bssid; - cr.bss = bss; + cr.links[0].bssid = mgmt->bssid; + cr.links[0].bss = bss; cr.req_ie = req_ies; cr.req_ie_len = req_ies_len; cr.resp_ie = resp_ie; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index aca799b9971e..6a45801c783c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -797,6 +797,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_MLO_LINK_ID] = NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS), [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN), + [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -11529,6 +11530,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) connect.flags |= CONNECT_REQ_EXTERNAL_AUTH_SUPPORT; } + if (nla_get_flag(info->attrs[NL80211_ATTR_MLO_SUPPORT])) + connect.flags |= CONNECT_REQ_MLO_SUPPORT; + wdev_lock(dev->ieee80211_ptr); err = cfg80211_connect(rdev, dev, &connect, connkeys, @@ -17304,10 +17308,29 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, { struct sk_buff *msg; void *hdr; + unsigned int link; + size_t link_info_size = 0; + const u8 *connected_addr = cr->valid_links ? + cr->ap_mld_addr : cr->links[0].bssid; + + if (cr->valid_links) { + for_each_valid_link(cr, link) { + /* Nested attribute header */ + link_info_size += NLA_HDRLEN; + /* Link ID */ + link_info_size += nla_total_size(sizeof(u8)); + link_info_size += cr->links[link].addr ? + nla_total_size(ETH_ALEN) : 0; + link_info_size += (cr->links[link].bssid || + cr->links[link].bss) ? + nla_total_size(ETH_ALEN) : 0; + } + } msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len + cr->fils.kek_len + cr->fils.pmk_len + - (cr->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp); + (cr->fils.pmkid ? WLAN_PMKID_LEN : 0) + link_info_size, + gfp); if (!msg) return; @@ -17319,8 +17342,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || - (cr->bssid && - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) || + (connected_addr && + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, connected_addr)) || nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE : cr->status) || @@ -17346,6 +17369,38 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->fils.pmkid))))) goto nla_put_failure; + if (cr->valid_links) { + int i = 1; + struct nlattr *nested; + + nested = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS); + if (!nested) + goto nla_put_failure; + + for_each_valid_link(cr, link) { + struct nlattr *nested_mlo_links; + const u8 *bssid = cr->links[link].bss ? + cr->links[link].bss->bssid : + cr->links[link].bssid; + + nested_mlo_links = nla_nest_start(msg, i); + if (!nested_mlo_links) + goto nla_put_failure; + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link) || + (bssid && + nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, bssid)) || + (cr->links[link].addr && + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, + cr->links[link].addr))) + goto nla_put_failure; + + nla_nest_end(msg, nested_mlo_links); + i++; + } + nla_nest_end(msg, nested); + } + genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, @@ -17362,11 +17417,32 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, { struct sk_buff *msg; void *hdr; - const u8 *bssid = info->bss ? info->bss->bssid : info->bssid; + size_t link_info_size = 0; + unsigned int link; + const u8 *connected_addr = info->ap_mld_addr ? + info->ap_mld_addr : + (info->links[0].bss ? + info->links[0].bss->bssid : + info->links[0].bssid); + + if (info->valid_links) { + for_each_valid_link(info, link) { + /* Nested attribute header */ + link_info_size += NLA_HDRLEN; + /* Link ID */ + link_info_size += nla_total_size(sizeof(u8)); + link_info_size += info->links[link].addr ? + nla_total_size(ETH_ALEN) : 0; + link_info_size += (info->links[link].bssid || + info->links[link].bss) ? + nla_total_size(ETH_ALEN) : 0; + } + } msg = nlmsg_new(100 + info->req_ie_len + info->resp_ie_len + info->fils.kek_len + info->fils.pmk_len + - (info->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp); + (info->fils.pmkid ? WLAN_PMKID_LEN : 0) + + link_info_size, gfp); if (!msg) return; @@ -17378,7 +17454,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, connected_addr) || (info->req_ie && nla_put(msg, NL80211_ATTR_REQ_IE, info->req_ie_len, info->req_ie)) || @@ -17397,6 +17473,38 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, info->fils.pmkid))) goto nla_put_failure; + if (info->valid_links) { + int i = 1; + struct nlattr *nested; + + nested = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS); + if (!nested) + goto nla_put_failure; + + for_each_valid_link(info, link) { + struct nlattr *nested_mlo_links; + const u8 *bssid = info->links[link].bss ? + info->links[link].bss->bssid : + info->links[link].bssid; + + nested_mlo_links = nla_nest_start(msg, i); + if (!nested_mlo_links) + goto nla_put_failure; + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link) || + (bssid && + nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, bssid)) || + (info->links[link].addr && + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, + info->links[link].addr))) + goto nla_put_failure; + + nla_nest_end(msg, nested_mlo_links); + i++; + } + nla_nest_end(msg, nested); + } + genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, diff --git a/net/wireless/sme.c b/net/wireless/sme.c index b3c6ce4f85ee..00be498aab2e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -275,7 +275,7 @@ void cfg80211_conn_work(struct work_struct *work) memset(&cr, 0, sizeof(cr)); cr.status = -1; - cr.bssid = bssid; + cr.links[0].bssid = bssid; cr.timeout_reason = treason; __cfg80211_connect_result(wdev->netdev, &cr, false); } @@ -384,7 +384,7 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) memset(&cr, 0, sizeof(cr)); cr.status = status_code; - cr.bssid = mgmt->bssid; + cr.links[0].bssid = mgmt->bssid; cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED; __cfg80211_connect_result(wdev->netdev, &cr, false); } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { @@ -698,6 +698,20 @@ static void disconnect_work(struct work_struct *work) DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); +static void +cfg80211_connect_result_release_bsses(struct wireless_dev *wdev, + struct cfg80211_connect_resp_params *cr) +{ + unsigned int link; + + for_each_valid_link(cr, link) { + if (!cr->links[link].bss) + continue; + cfg80211_unhold_bss(bss_from_pub(cr->links[link].bss)); + cfg80211_put_bss(wdev->wiphy, cr->links[link].bss); + } +} + /* * API calls for drivers implementing connect/disconnect and * SME event handling @@ -715,21 +729,33 @@ void __cfg80211_connect_result(struct net_device *dev, #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif + unsigned int link; + const u8 *connected_addr; + bool bss_not_found = false; ASSERT_WDEV_LOCK(wdev); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && - wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) { - cfg80211_put_bss(wdev->wiphy, cr->bss); - return; + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) + goto out; + + if (cr->valid_links) { + if (WARN_ON(!cr->ap_mld_addr)) + goto out; + + for_each_valid_link(cr, link) { + if (WARN_ON(!cr->links[link].addr)) + goto out; + } } wdev->unprot_beacon_reported = 0; nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr, GFP_KERNEL); + connected_addr = cr->valid_links ? cr->ap_mld_addr : cr->links[0].bssid; #ifdef CONFIG_CFG80211_WEXT - if (wextev) { + if (wextev && !cr->valid_links) { if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) { memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = cr->req_ie_len; @@ -746,23 +772,38 @@ void __cfg80211_connect_result(struct net_device *dev, memset(&wrqu, 0, sizeof(wrqu)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) { - memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN); - memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN); + if (connected_addr && cr->status == WLAN_STATUS_SUCCESS) { + memcpy(wrqu.ap_addr.sa_data, connected_addr, ETH_ALEN); + memcpy(wdev->wext.prev_bssid, connected_addr, ETH_ALEN); wdev->wext.prev_bssid_valid = true; } wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); } #endif - if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) { - WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); - cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid, - wdev->u.client.ssid, wdev->u.client.ssid_len, - wdev->conn_bss_type, - IEEE80211_PRIVACY_ANY); - if (cr->bss) - cfg80211_hold_bss(bss_from_pub(cr->bss)); + if (cr->status == WLAN_STATUS_SUCCESS) { + for_each_valid_link(cr, link) { + if (WARN_ON_ONCE(!cr->links[link].bss)) + break; + } + + for_each_valid_link(cr, link) { + if (cr->links[link].bss) + continue; + + cr->links[link].bss = + cfg80211_get_bss(wdev->wiphy, NULL, + cr->links[link].bssid, + wdev->u.client.ssid, + wdev->u.client.ssid_len, + wdev->conn_bss_type, + IEEE80211_PRIVACY_ANY); + if (!cr->links[link].bss) { + bss_not_found = true; + break; + } + cfg80211_hold_bss(bss_from_pub(cr->links[link].bss)); + } } cfg80211_wdev_release_bsses(wdev); @@ -772,26 +813,40 @@ void __cfg80211_connect_result(struct net_device *dev, wdev->connect_keys = NULL; wdev->u.client.ssid_len = 0; wdev->conn_owner_nlportid = 0; - if (cr->bss) { - cfg80211_unhold_bss(bss_from_pub(cr->bss)); - cfg80211_put_bss(wdev->wiphy, cr->bss); - } + cfg80211_connect_result_release_bsses(wdev, cr); cfg80211_sme_free(wdev); return; } - if (WARN_ON(!cr->bss)) + if (WARN_ON(bss_not_found)) { + cfg80211_connect_result_release_bsses(wdev, cr); return; + } - wdev->links[0].client.current_bss = bss_from_pub(cr->bss); + memset(wdev->links, 0, sizeof(wdev->links)); + wdev->valid_links = cr->valid_links; + for_each_valid_link(cr, link) + wdev->links[link].client.current_bss = + bss_from_pub(cr->links[link].bss); wdev->connected = true; - ether_addr_copy(wdev->u.client.connected_addr, cr->bss->bssid); + ether_addr_copy(wdev->u.client.connected_addr, connected_addr); + if (cr->valid_links) { + for_each_valid_link(cr, link) + memcpy(wdev->links[link].addr, cr->links[link].addr, + ETH_ALEN); + } if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) cfg80211_upload_connect_keys(wdev); rcu_read_lock(); - country_elem = ieee80211_bss_get_elem(cr->bss, WLAN_EID_COUNTRY); + for_each_valid_link(cr, link) { + country_elem = + ieee80211_bss_get_elem(cr->links[link].bss, + WLAN_EID_COUNTRY); + if (country_elem) + break; + } if (!country_elem) { rcu_read_unlock(); return; @@ -804,12 +859,60 @@ void __cfg80211_connect_result(struct net_device *dev, if (!country_data) return; - regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band, + regulatory_hint_country_ie(wdev->wiphy, + cr->links[link].bss->channel->band, country_data, country_datalen); kfree(country_data); + + return; +out: + for_each_valid_link(cr, link) + cfg80211_put_bss(wdev->wiphy, cr->links[link].bss); } -/* Consumes bss object one way or another */ +static void cfg80211_update_link_bss(struct wireless_dev *wdev, + struct cfg80211_bss **bss) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct cfg80211_internal_bss *ibss; + + if (!*bss) + return; + + ibss = bss_from_pub(*bss); + if (list_empty(&ibss->list)) { + struct cfg80211_bss *found = NULL, *tmp = *bss; + + found = cfg80211_get_bss(wdev->wiphy, NULL, + (*bss)->bssid, + wdev->u.client.ssid, + wdev->u.client.ssid_len, + wdev->conn_bss_type, + IEEE80211_PRIVACY_ANY); + if (found) { + /* The same BSS is already updated so use it + * instead, as it has latest info. + */ + *bss = found; + } else { + /* Update with BSS provided by driver, it will + * be freshly added and ref cnted, we can free + * the old one. + * + * signal_valid can be false, as we are not + * expecting the BSS to be found. + * + * keep the old timestamp to avoid confusion + */ + cfg80211_bss_update(rdev, ibss, false, + ibss->ts); + } + + cfg80211_put_bss(wdev->wiphy, tmp); + } +} + +/* Consumes bss object(s) one way or another */ void cfg80211_connect_done(struct net_device *dev, struct cfg80211_connect_resp_params *params, gfp_t gfp) @@ -819,55 +922,34 @@ void cfg80211_connect_done(struct net_device *dev, struct cfg80211_event *ev; unsigned long flags; u8 *next; + size_t link_info_size = 0; + unsigned int link; - if (params->bss) { - struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss); - - if (list_empty(&ibss->list)) { - struct cfg80211_bss *found = NULL, *tmp = params->bss; - - found = cfg80211_get_bss(wdev->wiphy, NULL, - params->bss->bssid, - wdev->u.client.ssid, wdev->u.client.ssid_len, - wdev->conn_bss_type, - IEEE80211_PRIVACY_ANY); - if (found) { - /* The same BSS is already updated so use it - * instead, as it has latest info. - */ - params->bss = found; - } else { - /* Update with BSS provided by driver, it will - * be freshly added and ref cnted, we can free - * the old one. - * - * signal_valid can be false, as we are not - * expecting the BSS to be found. - * - * keep the old timestamp to avoid confusion - */ - cfg80211_bss_update(rdev, ibss, false, - ibss->ts); - } - - cfg80211_put_bss(wdev->wiphy, tmp); - } + for_each_valid_link(params, link) { + cfg80211_update_link_bss(wdev, ¶ms->links[link].bss); + link_info_size += params->links[link].bssid ? ETH_ALEN : 0; + link_info_size += params->links[link].addr ? ETH_ALEN : 0; } - ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) + + ev = kzalloc(sizeof(*ev) + (params->ap_mld_addr ? ETH_ALEN : 0) + params->req_ie_len + params->resp_ie_len + params->fils.kek_len + params->fils.pmk_len + - (params->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp); + (params->fils.pmkid ? WLAN_PMKID_LEN : 0) + link_info_size, + gfp); + if (!ev) { - cfg80211_put_bss(wdev->wiphy, params->bss); + for_each_valid_link(params, link) + cfg80211_put_bss(wdev->wiphy, + params->links[link].bss); return; } ev->type = EVENT_CONNECT_RESULT; next = ((u8 *)ev) + sizeof(*ev); - if (params->bssid) { - ev->cr.bssid = next; - memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN); + if (params->ap_mld_addr) { + ev->cr.ap_mld_addr = next; + memcpy((void *)ev->cr.ap_mld_addr, params->ap_mld_addr, + ETH_ALEN); next += ETH_ALEN; } if (params->req_ie_len) { @@ -907,9 +989,28 @@ void cfg80211_connect_done(struct net_device *dev, ev->cr.fils.update_erp_next_seq_num = params->fils.update_erp_next_seq_num; if (params->fils.update_erp_next_seq_num) ev->cr.fils.erp_next_seq_num = params->fils.erp_next_seq_num; - if (params->bss) - cfg80211_hold_bss(bss_from_pub(params->bss)); - ev->cr.bss = params->bss; + ev->cr.valid_links = params->valid_links; + for_each_valid_link(params, link) { + if (params->links[link].bss) + cfg80211_hold_bss( + bss_from_pub(params->links[link].bss)); + ev->cr.links[link].bss = params->links[link].bss; + + if (params->links[link].addr) { + ev->cr.links[link].addr = next; + memcpy((void *)ev->cr.links[link].addr, + params->links[link].addr, + ETH_ALEN); + next += ETH_ALEN; + } + if (params->links[link].bssid) { + ev->cr.links[link].bssid = next; + memcpy((void *)ev->cr.links[link].bssid, + params->links[link].bssid, + ETH_ALEN); + next += ETH_ALEN; + } + } ev->cr.status = params->status; ev->cr.timeout_reason = params->timeout_reason; @@ -927,6 +1028,9 @@ void __cfg80211_roamed(struct wireless_dev *wdev, #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif + unsigned int link; + const u8 *connected_addr; + ASSERT_WDEV_LOCK(wdev); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && @@ -936,48 +1040,76 @@ void __cfg80211_roamed(struct wireless_dev *wdev, if (WARN_ON(!wdev->connected)) goto out; + if (info->valid_links) { + if (WARN_ON(!info->ap_mld_addr)) + goto out; + + for_each_valid_link(info, link) { + if (WARN_ON(!info->links[link].addr)) + goto out; + } + } + cfg80211_wdev_release_bsses(wdev); - if (WARN_ON(!info->bss)) - return; + for_each_valid_link(info, link) { + if (WARN_ON(!info->links[link].bss)) + goto out; + } - cfg80211_hold_bss(bss_from_pub(info->bss)); - wdev->links[0].client.current_bss = bss_from_pub(info->bss); - ether_addr_copy(wdev->u.client.connected_addr, info->bss->bssid); + memset(wdev->links, 0, sizeof(wdev->links)); + wdev->valid_links = info->valid_links; + for_each_valid_link(info, link) { + cfg80211_hold_bss(bss_from_pub(info->links[link].bss)); + wdev->links[link].client.current_bss = + bss_from_pub(info->links[link].bss); + } + connected_addr = info->valid_links ? + info->ap_mld_addr : + info->links[0].bss->bssid; + ether_addr_copy(wdev->u.client.connected_addr, connected_addr); + if (info->valid_links) { + for_each_valid_link(info, link) + memcpy(wdev->links[link].addr, info->links[link].addr, + ETH_ALEN); + } wdev->unprot_beacon_reported = 0; nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy), wdev->netdev, info, GFP_KERNEL); #ifdef CONFIG_CFG80211_WEXT - if (info->req_ie) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = info->req_ie_len; - wireless_send_event(wdev->netdev, IWEVASSOCREQIE, - &wrqu, info->req_ie); - } + if (!info->valid_links) { + if (info->req_ie) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = info->req_ie_len; + wireless_send_event(wdev->netdev, IWEVASSOCREQIE, + &wrqu, info->req_ie); + } + + if (info->resp_ie) { + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = info->resp_ie_len; + wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, + &wrqu, info->resp_ie); + } - if (info->resp_ie) { memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = info->resp_ie_len; - wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, - &wrqu, info->resp_ie); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu.ap_addr.sa_data, connected_addr, ETH_ALEN); + memcpy(wdev->wext.prev_bssid, connected_addr, ETH_ALEN); + wdev->wext.prev_bssid_valid = true; + wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); } - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu.ap_addr.sa_data, info->bss->bssid, ETH_ALEN); - memcpy(wdev->wext.prev_bssid, info->bss->bssid, ETH_ALEN); - wdev->wext.prev_bssid_valid = true; - wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); #endif return; out: - cfg80211_put_bss(wdev->wiphy, info->bss); + for_each_valid_link(info, link) + cfg80211_put_bss(wdev->wiphy, info->links[link].bss); } -/* Consumes info->bss object one way or another */ +/* Consumes info->links.bss object(s) one way or another */ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, gfp_t gfp) { @@ -986,25 +1118,41 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, struct cfg80211_event *ev; unsigned long flags; u8 *next; + unsigned int link; + size_t link_info_size = 0; + bool bss_not_found = false; + + for_each_valid_link(info, link) { + link_info_size += info->links[link].addr ? ETH_ALEN : 0; + link_info_size += info->links[link].bssid ? ETH_ALEN : 0; - if (!info->bss) { - info->bss = cfg80211_get_bss(wdev->wiphy, info->channel, - info->bssid, wdev->u.client.ssid, - wdev->u.client.ssid_len, - wdev->conn_bss_type, - IEEE80211_PRIVACY_ANY); + if (info->links[link].bss) + continue; + + info->links[link].bss = + cfg80211_get_bss(wdev->wiphy, + info->links[link].channel, + info->links[link].bssid, + wdev->u.client.ssid, + wdev->u.client.ssid_len, + wdev->conn_bss_type, + IEEE80211_PRIVACY_ANY); + + if (!info->links[link].bss) { + bss_not_found = true; + break; + } } - if (WARN_ON(!info->bss)) - return; + if (WARN_ON(bss_not_found)) + goto out; ev = kzalloc(sizeof(*ev) + info->req_ie_len + info->resp_ie_len + info->fils.kek_len + info->fils.pmk_len + - (info->fils.pmkid ? WLAN_PMKID_LEN : 0), gfp); - if (!ev) { - cfg80211_put_bss(wdev->wiphy, info->bss); - return; - } + (info->fils.pmkid ? WLAN_PMKID_LEN : 0) + + (info->ap_mld_addr ? ETH_ALEN : 0) + link_info_size, gfp); + if (!ev) + goto out; ev->type = EVENT_ROAMED; next = ((u8 *)ev) + sizeof(*ev); @@ -1044,12 +1192,43 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, ev->rm.fils.update_erp_next_seq_num = info->fils.update_erp_next_seq_num; if (info->fils.update_erp_next_seq_num) ev->rm.fils.erp_next_seq_num = info->fils.erp_next_seq_num; - ev->rm.bss = info->bss; + if (info->ap_mld_addr) { + ev->rm.ap_mld_addr = next; + memcpy((void *)ev->rm.ap_mld_addr, info->ap_mld_addr, + ETH_ALEN); + next += ETH_ALEN; + } + ev->rm.valid_links = info->valid_links; + for_each_valid_link(info, link) { + ev->rm.links[link].bss = info->links[link].bss; + + if (info->links[link].addr) { + ev->rm.links[link].addr = next; + memcpy((void *)ev->rm.links[link].addr, + info->links[link].addr, + ETH_ALEN); + next += ETH_ALEN; + } + + if (info->links[link].bssid) { + ev->rm.links[link].bssid = next; + memcpy((void *)ev->rm.links[link].bssid, + info->links[link].bssid, + ETH_ALEN); + next += ETH_ALEN; + } + } spin_lock_irqsave(&wdev->event_lock, flags); list_add_tail(&ev->list, &wdev->event_list); spin_unlock_irqrestore(&wdev->event_lock, flags); queue_work(cfg80211_wq, &rdev->event_work); + + return; +out: + for_each_valid_link(info, link) + cfg80211_put_bss(wdev->wiphy, info->links[link].bss); + } EXPORT_SYMBOL(cfg80211_roamed); -- cgit v1.2.3 From 394fb16954793d387e375b645d44fcfd8602bfda Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 25 May 2022 16:43:59 +0200 Subject: dt-bindings: interconnect: Add Qualcomm SM6350 NoC support Add bindings for Qualcomm SM6350 Network-On-Chip interconnect devices. As SM6350 has two pairs of NoCs sharing the same reg, allow this in the binding documentation, as was done for qcm2290. Signed-off-by: Luca Weiss Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220525144404.200390-4-luca.weiss@fairphone.com Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,sm6350-rpmh.yaml | 82 ++++++++++++ include/dt-bindings/interconnect/qcom,sm6350.h | 148 +++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,sm6350-rpmh.yaml create mode 100644 include/dt-bindings/interconnect/qcom,sm6350.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sm6350-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sm6350-rpmh.yaml new file mode 100644 index 000000000000..49eb156b08e0 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sm6350-rpmh.yaml @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sm6350-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM6350 RPMh Network-On-Chip Interconnect + +maintainers: + - Luca Weiss + +description: + Qualcomm RPMh-based interconnect provider on SM6350. + +allOf: + - $ref: qcom,rpmh-common.yaml# + +properties: + compatible: + enum: + - qcom,sm6350-aggre1-noc + - qcom,sm6350-aggre2-noc + - qcom,sm6350-config-noc + - qcom,sm6350-dc-noc + - qcom,sm6350-gem-noc + - qcom,sm6350-mmss-noc + - qcom,sm6350-npu-noc + - qcom,sm6350-system-noc + + reg: + maxItems: 1 + + '#interconnect-cells': true + +patternProperties: + '^interconnect-[a-z0-9\-]+$': + type: object + description: + The interconnect providers do not have a separate QoS register space, + but share parent's space. + $ref: qcom,rpmh-common.yaml# + + properties: + compatible: + enum: + - qcom,sm6350-clk-virt + - qcom,sm6350-compute-noc + + '#interconnect-cells': true + + required: + - compatible + + unevaluatedProperties: false + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + config_noc: interconnect@1500000 { + compatible = "qcom,sm6350-config-noc"; + reg = <0x01500000 0x28000>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + system_noc: interconnect@1620000 { + compatible = "qcom,sm6350-system-noc"; + reg = <0x01620000 0x17080>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + + clk_virt: interconnect-clk-virt { + compatible = "qcom,sm6350-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + }; diff --git a/include/dt-bindings/interconnect/qcom,sm6350.h b/include/dt-bindings/interconnect/qcom,sm6350.h new file mode 100644 index 000000000000..e662cede9aaa --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sm6350.h @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ +/* + * Qualcomm SM6350 interconnect IDs + * + * Copyright (C) 2022 Luca Weiss + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SM6350_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SM6350_H + +#define MASTER_A1NOC_CFG 0 +#define MASTER_QUP_0 1 +#define MASTER_EMMC 2 +#define MASTER_UFS_MEM 3 +#define A1NOC_SNOC_SLV 4 +#define SLAVE_SERVICE_A1NOC 5 + +#define MASTER_A2NOC_CFG 0 +#define MASTER_QDSS_BAM 1 +#define MASTER_QUP_1 2 +#define MASTER_CRYPTO_CORE_0 3 +#define MASTER_IPA 4 +#define MASTER_QDSS_ETR 5 +#define MASTER_SDCC_2 6 +#define MASTER_USB3 7 +#define A2NOC_SNOC_SLV 8 +#define SLAVE_SERVICE_A2NOC 9 + +#define MASTER_CAMNOC_HF0_UNCOMP 0 +#define MASTER_CAMNOC_ICP_UNCOMP 1 +#define MASTER_CAMNOC_SF_UNCOMP 2 +#define MASTER_QUP_CORE_0 3 +#define MASTER_QUP_CORE_1 4 +#define MASTER_LLCC 5 +#define SLAVE_CAMNOC_UNCOMP 6 +#define SLAVE_QUP_CORE_0 7 +#define SLAVE_QUP_CORE_1 8 +#define SLAVE_EBI_CH0 9 + +#define MASTER_NPU 0 +#define MASTER_NPU_PROC 1 +#define SLAVE_CDSP_GEM_NOC 2 + +#define SNOC_CNOC_MAS 0 +#define MASTER_QDSS_DAP 1 +#define SLAVE_A1NOC_CFG 2 +#define SLAVE_A2NOC_CFG 3 +#define SLAVE_AHB2PHY 4 +#define SLAVE_AHB2PHY_2 5 +#define SLAVE_AOSS 6 +#define SLAVE_BOOT_ROM 7 +#define SLAVE_CAMERA_CFG 8 +#define SLAVE_CAMERA_NRT_THROTTLE_CFG 9 +#define SLAVE_CAMERA_RT_THROTTLE_CFG 10 +#define SLAVE_CLK_CTL 11 +#define SLAVE_RBCPR_CX_CFG 12 +#define SLAVE_RBCPR_MX_CFG 13 +#define SLAVE_CRYPTO_0_CFG 14 +#define SLAVE_DCC_CFG 15 +#define SLAVE_CNOC_DDRSS 16 +#define SLAVE_DISPLAY_CFG 17 +#define SLAVE_DISPLAY_THROTTLE_CFG 18 +#define SLAVE_EMMC_CFG 19 +#define SLAVE_GLM 20 +#define SLAVE_GRAPHICS_3D_CFG 21 +#define SLAVE_IMEM_CFG 22 +#define SLAVE_IPA_CFG 23 +#define SLAVE_CNOC_MNOC_CFG 24 +#define SLAVE_CNOC_MSS 25 +#define SLAVE_NPU_CFG 26 +#define SLAVE_PDM 27 +#define SLAVE_PIMEM_CFG 28 +#define SLAVE_PRNG 29 +#define SLAVE_QDSS_CFG 30 +#define SLAVE_QM_CFG 31 +#define SLAVE_QM_MPU_CFG 32 +#define SLAVE_QUP_0 33 +#define SLAVE_QUP_1 34 +#define SLAVE_SDCC_2 35 +#define SLAVE_SECURITY 36 +#define SLAVE_SNOC_CFG 37 +#define SLAVE_TCSR 38 +#define SLAVE_UFS_MEM_CFG 39 +#define SLAVE_USB3 40 +#define SLAVE_VENUS_CFG 41 +#define SLAVE_VENUS_THROTTLE_CFG 42 +#define SLAVE_VSENSE_CTRL_CFG 43 +#define SLAVE_SERVICE_CNOC 44 + +#define MASTER_CNOC_DC_NOC 0 +#define SLAVE_GEM_NOC_CFG 1 +#define SLAVE_LLCC_CFG 2 + +#define MASTER_AMPSS_M0 0 +#define MASTER_SYS_TCU 1 +#define MASTER_GEM_NOC_CFG 2 +#define MASTER_COMPUTE_NOC 3 +#define MASTER_MNOC_HF_MEM_NOC 4 +#define MASTER_MNOC_SF_MEM_NOC 5 +#define MASTER_SNOC_GC_MEM_NOC 6 +#define MASTER_SNOC_SF_MEM_NOC 7 +#define MASTER_GRAPHICS_3D 8 +#define SLAVE_MCDMA_MS_MPU_CFG 9 +#define SLAVE_MSS_PROC_MS_MPU_CFG 10 +#define SLAVE_GEM_NOC_SNOC 11 +#define SLAVE_LLCC 12 +#define SLAVE_SERVICE_GEM_NOC 13 + +#define MASTER_CNOC_MNOC_CFG 0 +#define MASTER_VIDEO_P0 1 +#define MASTER_VIDEO_PROC 2 +#define MASTER_CAMNOC_HF 3 +#define MASTER_CAMNOC_ICP 4 +#define MASTER_CAMNOC_SF 5 +#define MASTER_MDP_PORT0 6 +#define SLAVE_MNOC_HF_MEM_NOC 7 +#define SLAVE_MNOC_SF_MEM_NOC 8 +#define SLAVE_SERVICE_MNOC 9 + +#define MASTER_NPU_SYS 0 +#define MASTER_NPU_NOC_CFG 1 +#define SLAVE_NPU_CAL_DP0 2 +#define SLAVE_NPU_CP 3 +#define SLAVE_NPU_INT_DMA_BWMON_CFG 4 +#define SLAVE_NPU_DPM 5 +#define SLAVE_ISENSE_CFG 6 +#define SLAVE_NPU_LLM_CFG 7 +#define SLAVE_NPU_TCM 8 +#define SLAVE_NPU_COMPUTE_NOC 9 +#define SLAVE_SERVICE_NPU_NOC 10 + +#define MASTER_SNOC_CFG 0 +#define A1NOC_SNOC_MAS 1 +#define A2NOC_SNOC_MAS 2 +#define MASTER_GEM_NOC_SNOC 3 +#define MASTER_PIMEM 4 +#define MASTER_GIC 5 +#define SLAVE_APPSS 6 +#define SNOC_CNOC_SLV 7 +#define SLAVE_SNOC_GEM_NOC_GC 8 +#define SLAVE_SNOC_GEM_NOC_SF 9 +#define SLAVE_OCIMEM 10 +#define SLAVE_PIMEM 11 +#define SLAVE_SERVICE_SNOC 12 +#define SLAVE_QDSS_STM 13 +#define SLAVE_TCU 14 + +#endif -- cgit v1.2.3 From cd268e309c29e9a8b15a47f684d848c1d57fe150 Mon Sep 17 00:00:00 2001 From: David Virag Date: Thu, 2 Jun 2022 01:37:39 +0200 Subject: dt-bindings: clock: Add bindings for Exynos7885 CMU_FSYS CMU_FSYS clock domain provides clocks for MMC (MMC_CARD, MMC_EMBD, MMC_SDIO), and USB30DRD. Add clock indices and bindings documentation for CMU_FSYS domain. Signed-off-by: David Virag Reviewed-by: Sylwester Nawrocki Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220601233743.56317-2-virag.david003@gmail.com Signed-off-by: Krzysztof Kozlowski --- .../bindings/clock/samsung,exynos7885-clock.yaml | 27 +++++++++++++++++++ include/dt-bindings/clock/exynos7885.h | 31 +++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos7885-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos7885-clock.yaml index 5073e569a47f..006d33a9e0f1 100644 --- a/Documentation/devicetree/bindings/clock/samsung,exynos7885-clock.yaml +++ b/Documentation/devicetree/bindings/clock/samsung,exynos7885-clock.yaml @@ -33,6 +33,7 @@ properties: enum: - samsung,exynos7885-cmu-top - samsung,exynos7885-cmu-core + - samsung,exynos7885-cmu-fsys - samsung,exynos7885-cmu-peri clocks: @@ -88,6 +89,32 @@ allOf: - const: dout_core_cci - const: dout_core_g3d + - if: + properties: + compatible: + contains: + const: samsung,exynos7885-cmu-fsys + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: CMU_FSYS bus clock (from CMU_TOP) + - description: MMC_CARD clock (from CMU_TOP) + - description: MMC_EMBD clock (from CMU_TOP) + - description: MMC_SDIO clock (from CMU_TOP) + - description: USB30DRD clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: dout_fsys_bus + - const: dout_fsys_mmc_card + - const: dout_fsys_mmc_embd + - const: dout_fsys_mmc_sdio + - const: dout_fsys_usb30drd + - if: properties: compatible: diff --git a/include/dt-bindings/clock/exynos7885.h b/include/dt-bindings/clock/exynos7885.h index 1f8701691d62..d2e1483f93e4 100644 --- a/include/dt-bindings/clock/exynos7885.h +++ b/include/dt-bindings/clock/exynos7885.h @@ -54,7 +54,22 @@ #define CLK_GOUT_PERI_USI0 43 #define CLK_GOUT_PERI_USI1 44 #define CLK_GOUT_PERI_USI2 45 -#define TOP_NR_CLK 46 +#define CLK_MOUT_FSYS_BUS 46 +#define CLK_MOUT_FSYS_MMC_CARD 47 +#define CLK_MOUT_FSYS_MMC_EMBD 48 +#define CLK_MOUT_FSYS_MMC_SDIO 49 +#define CLK_MOUT_FSYS_USB30DRD 50 +#define CLK_DOUT_FSYS_BUS 51 +#define CLK_DOUT_FSYS_MMC_CARD 52 +#define CLK_DOUT_FSYS_MMC_EMBD 53 +#define CLK_DOUT_FSYS_MMC_SDIO 54 +#define CLK_DOUT_FSYS_USB30DRD 55 +#define CLK_GOUT_FSYS_BUS 56 +#define CLK_GOUT_FSYS_MMC_CARD 57 +#define CLK_GOUT_FSYS_MMC_EMBD 58 +#define CLK_GOUT_FSYS_MMC_SDIO 59 +#define CLK_GOUT_FSYS_USB30DRD 60 +#define TOP_NR_CLK 61 /* CMU_CORE */ #define CLK_MOUT_CORE_BUS_USER 1 @@ -112,4 +127,18 @@ #define CLK_GOUT_WDT1_PCLK 43 #define PERI_NR_CLK 44 +/* CMU_FSYS */ +#define CLK_MOUT_FSYS_BUS_USER 1 +#define CLK_MOUT_FSYS_MMC_CARD_USER 2 +#define CLK_MOUT_FSYS_MMC_EMBD_USER 3 +#define CLK_MOUT_FSYS_MMC_SDIO_USER 4 +#define CLK_MOUT_FSYS_USB30DRD_USER 4 +#define CLK_GOUT_MMC_CARD_ACLK 5 +#define CLK_GOUT_MMC_CARD_SDCLKIN 6 +#define CLK_GOUT_MMC_EMBD_ACLK 7 +#define CLK_GOUT_MMC_EMBD_SDCLKIN 8 +#define CLK_GOUT_MMC_SDIO_ACLK 9 +#define CLK_GOUT_MMC_SDIO_SDCLKIN 10 +#define FSYS_NR_CLK 11 + #endif /* _DT_BINDINGS_CLOCK_EXYNOS_7885_H */ -- cgit v1.2.3 From e756e932a3a16418cd8bad757b028bfb337b4a51 Mon Sep 17 00:00:00 2001 From: David Virag Date: Thu, 2 Jun 2022 01:37:40 +0200 Subject: dt-bindings: clock: Add indices for Exynos7885 TREX clocks TREX D Core and P core clocks seem to be related to the BTS (Bus Traffic Shaper) inside the Exynos7885 SoC, and are needed for the SoC to function correctly. Add indices for these clocks. Signed-off-by: David Virag Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220601233743.56317-3-virag.david003@gmail.com Signed-off-by: Krzysztof Kozlowski --- include/dt-bindings/clock/exynos7885.h | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/dt-bindings/clock/exynos7885.h b/include/dt-bindings/clock/exynos7885.h index d2e1483f93e4..8256e7430b63 100644 --- a/include/dt-bindings/clock/exynos7885.h +++ b/include/dt-bindings/clock/exynos7885.h @@ -72,14 +72,21 @@ #define TOP_NR_CLK 61 /* CMU_CORE */ -#define CLK_MOUT_CORE_BUS_USER 1 -#define CLK_MOUT_CORE_CCI_USER 2 -#define CLK_MOUT_CORE_G3D_USER 3 -#define CLK_MOUT_CORE_GIC 4 -#define CLK_DOUT_CORE_BUSP 5 -#define CLK_GOUT_CCI_ACLK 6 -#define CLK_GOUT_GIC400_CLK 7 -#define CORE_NR_CLK 8 +#define CLK_MOUT_CORE_BUS_USER 1 +#define CLK_MOUT_CORE_CCI_USER 2 +#define CLK_MOUT_CORE_G3D_USER 3 +#define CLK_MOUT_CORE_GIC 4 +#define CLK_DOUT_CORE_BUSP 5 +#define CLK_GOUT_CCI_ACLK 6 +#define CLK_GOUT_GIC400_CLK 7 +#define CLK_GOUT_TREX_D_CORE_ACLK 8 +#define CLK_GOUT_TREX_D_CORE_GCLK 9 +#define CLK_GOUT_TREX_D_CORE_PCLK 10 +#define CLK_GOUT_TREX_P_CORE_ACLK_P_CORE 11 +#define CLK_GOUT_TREX_P_CORE_CCLK_P_CORE 12 +#define CLK_GOUT_TREX_P_CORE_PCLK 13 +#define CLK_GOUT_TREX_P_CORE_PCLK_P_CORE 14 +#define CORE_NR_CLK 15 /* CMU_PERI */ #define CLK_MOUT_PERI_BUS_USER 1 -- cgit v1.2.3 From 04919bed948dc22a0032a9da867b7dcb8aece4ca Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 15 Jun 2022 09:20:11 -0700 Subject: tcp: Introduce tcp_read_skb() This patch inroduces tcp_read_skb() based on tcp_read_sock(), a preparation for the next patch which actually introduces a new sock ops. TCP is special here, because it has tcp_read_sock() which is mainly used by splice(). tcp_read_sock() supports partial read and arbitrary offset, neither of them is needed for sockmap. Signed-off-by: Cong Wang Signed-off-by: Daniel Borkmann Reviewed-by: Eric Dumazet Reviewed-by: John Fastabend Link: https://lore.kernel.org/bpf/20220615162014.89193-2-xiyou.wangcong@gmail.com --- include/net/tcp.h | 2 ++ net/ipv4/tcp.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index c21a9b516f1e..7547d90fbb57 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -672,6 +672,8 @@ void tcp_get_info(struct sock *, struct tcp_info *); /* Read 'sendfile()'-style from a TCP socket */ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor); +int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor); void tcp_initialize_rcv_mss(struct sock *sk); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f7309452bdce..124f384f8695 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1734,6 +1734,53 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, } EXPORT_SYMBOL(tcp_read_sock); +int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, + sk_read_actor_t recv_actor) +{ + struct tcp_sock *tp = tcp_sk(sk); + u32 seq = tp->copied_seq; + struct sk_buff *skb; + int copied = 0; + u32 offset; + + if (sk->sk_state == TCP_LISTEN) + return -ENOTCONN; + + while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { + int used; + + __skb_unlink(skb, &sk->sk_receive_queue); + used = recv_actor(desc, skb, 0, skb->len); + if (used <= 0) { + if (!copied) + copied = used; + break; + } + seq += used; + copied += used; + + if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) { + consume_skb(skb); + ++seq; + break; + } + consume_skb(skb); + if (!desc->count) + break; + WRITE_ONCE(tp->copied_seq, seq); + } + WRITE_ONCE(tp->copied_seq, seq); + + tcp_rcv_space_adjust(sk); + + /* Clean up data we have read: This will do ACK frames. */ + if (copied > 0) + tcp_cleanup_rbuf(sk, copied); + + return copied; +} +EXPORT_SYMBOL(tcp_read_skb); + int tcp_peek_len(struct socket *sock) { return tcp_inq(sock->sk); -- cgit v1.2.3 From 965b57b469a589d64d81b1688b38dcb537011bb0 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 15 Jun 2022 09:20:12 -0700 Subject: net: Introduce a new proto_ops ->read_skb() Currently both splice() and sockmap use ->read_sock() to read skb from receive queue, but for sockmap we only read one entire skb at a time, so ->read_sock() is too conservative to use. Introduce a new proto_ops ->read_skb() which supports this sematic, with this we can finally pass the ownership of skb to recv actors. For non-TCP protocols, all ->read_sock() can be simply converted to ->read_skb(). Signed-off-by: Cong Wang Signed-off-by: Daniel Borkmann Reviewed-by: John Fastabend Link: https://lore.kernel.org/bpf/20220615162014.89193-3-xiyou.wangcong@gmail.com --- include/linux/net.h | 4 ++++ include/net/tcp.h | 3 +-- include/net/udp.h | 3 +-- net/core/skmsg.c | 20 +++++--------------- net/ipv4/af_inet.c | 3 ++- net/ipv4/tcp.c | 9 +++------ net/ipv4/udp.c | 10 ++++------ net/ipv6/af_inet6.c | 3 ++- net/unix/af_unix.c | 23 +++++++++-------------- 9 files changed, 31 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/include/linux/net.h b/include/linux/net.h index 12093f4db50c..a03485e8cbb2 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -152,6 +152,8 @@ struct module; struct sk_buff; typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, unsigned int, size_t); +typedef int (*skb_read_actor_t)(struct sock *, struct sk_buff *); + struct proto_ops { int family; @@ -214,6 +216,8 @@ struct proto_ops { */ int (*read_sock)(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor); + /* This is different from read_sock(), it reads an entire skb at a time. */ + int (*read_skb)(struct sock *sk, skb_read_actor_t recv_actor); int (*sendpage_locked)(struct sock *sk, struct page *page, int offset, size_t size, int flags); int (*sendmsg_locked)(struct sock *sk, struct msghdr *msg, diff --git a/include/net/tcp.h b/include/net/tcp.h index 7547d90fbb57..8e48dc56837b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -672,8 +672,7 @@ void tcp_get_info(struct sock *, struct tcp_info *); /* Read 'sendfile()'-style from a TCP socket */ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, sk_read_actor_t recv_actor); -int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); +int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor); void tcp_initialize_rcv_mss(struct sock *sk); diff --git a/include/net/udp.h b/include/net/udp.h index b60eea2e3fae..987f7fc7c0aa 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -306,8 +306,7 @@ struct sock *__udp6_lib_lookup(struct net *net, struct sk_buff *skb); struct sock *udp6_lib_lookup_skb(const struct sk_buff *skb, __be16 sport, __be16 dport); -int udp_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); +int udp_read_skb(struct sock *sk, skb_read_actor_t recv_actor); /* UDP uses skb->dev_scratch to cache as much information as possible and avoid * possibly multiple cache miss on dequeue() diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 7e03f96e441b..f7f63b7d990c 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -1160,21 +1160,17 @@ static void sk_psock_done_strp(struct sk_psock *psock) } #endif /* CONFIG_BPF_STREAM_PARSER */ -static int sk_psock_verdict_recv(read_descriptor_t *desc, struct sk_buff *skb, - unsigned int offset, size_t orig_len) +static int sk_psock_verdict_recv(struct sock *sk, struct sk_buff *skb) { - struct sock *sk = (struct sock *)desc->arg.data; struct sk_psock *psock; struct bpf_prog *prog; int ret = __SK_DROP; - int len = orig_len; + int len = skb->len; /* clone here so sk_eat_skb() in tcp_read_sock does not drop our data */ skb = skb_clone(skb, GFP_ATOMIC); - if (!skb) { - desc->error = -ENOMEM; + if (!skb) return 0; - } rcu_read_lock(); psock = sk_psock(sk); @@ -1204,16 +1200,10 @@ out: static void sk_psock_verdict_data_ready(struct sock *sk) { struct socket *sock = sk->sk_socket; - read_descriptor_t desc; - if (unlikely(!sock || !sock->ops || !sock->ops->read_sock)) + if (unlikely(!sock || !sock->ops || !sock->ops->read_skb)) return; - - desc.arg.data = sk; - desc.error = 0; - desc.count = 1; - - sock->ops->read_sock(sk, &desc, sk_psock_verdict_recv); + sock->ops->read_skb(sk, sk_psock_verdict_recv); } void sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index da81f56fdd1c..7abd652a558f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1040,6 +1040,7 @@ const struct proto_ops inet_stream_ops = { .sendpage = inet_sendpage, .splice_read = tcp_splice_read, .read_sock = tcp_read_sock, + .read_skb = tcp_read_skb, .sendmsg_locked = tcp_sendmsg_locked, .sendpage_locked = tcp_sendpage_locked, .peek_len = tcp_peek_len, @@ -1067,7 +1068,7 @@ const struct proto_ops inet_dgram_ops = { .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, .sendmsg = inet_sendmsg, - .read_sock = udp_read_sock, + .read_skb = udp_read_skb, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, .sendpage = inet_sendpage, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 124f384f8695..9d2fd3ced21b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1734,8 +1734,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, } EXPORT_SYMBOL(tcp_read_sock); -int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) +int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor) { struct tcp_sock *tp = tcp_sk(sk); u32 seq = tp->copied_seq; @@ -1750,7 +1749,7 @@ int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, int used; __skb_unlink(skb, &sk->sk_receive_queue); - used = recv_actor(desc, skb, 0, skb->len); + used = recv_actor(sk, skb); if (used <= 0) { if (!copied) copied = used; @@ -1765,9 +1764,7 @@ int tcp_read_skb(struct sock *sk, read_descriptor_t *desc, break; } consume_skb(skb); - if (!desc->count) - break; - WRITE_ONCE(tp->copied_seq, seq); + break; } WRITE_ONCE(tp->copied_seq, seq); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6172b4750a88..c660b0bc4d14 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1797,8 +1797,7 @@ busy_check: } EXPORT_SYMBOL(__skb_recv_udp); -int udp_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) +int udp_read_skb(struct sock *sk, skb_read_actor_t recv_actor) { int copied = 0; @@ -1820,7 +1819,7 @@ int udp_read_sock(struct sock *sk, read_descriptor_t *desc, continue; } - used = recv_actor(desc, skb, 0, skb->len); + used = recv_actor(sk, skb); if (used <= 0) { if (!copied) copied = used; @@ -1831,13 +1830,12 @@ int udp_read_sock(struct sock *sk, read_descriptor_t *desc, } kfree_skb(skb); - if (!desc->count) - break; + break; } return copied; } -EXPORT_SYMBOL(udp_read_sock); +EXPORT_SYMBOL(udp_read_skb); /* * This should be easy, if there is something there we diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 658823e91eca..0ee0770e79aa 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -702,6 +702,7 @@ const struct proto_ops inet6_stream_ops = { .sendpage_locked = tcp_sendpage_locked, .splice_read = tcp_splice_read, .read_sock = tcp_read_sock, + .read_skb = tcp_read_skb, .peek_len = tcp_peek_len, #ifdef CONFIG_COMPAT .compat_ioctl = inet6_compat_ioctl, @@ -727,7 +728,7 @@ const struct proto_ops inet6_dgram_ops = { .getsockopt = sock_common_getsockopt, /* ok */ .sendmsg = inet6_sendmsg, /* retpoline's sake */ .recvmsg = inet6_recvmsg, /* retpoline's sake */ - .read_sock = udp_read_sock, + .read_skb = udp_read_skb, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, .set_peek_off = sk_set_peek_off, diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3453e0053f76..1bed3739768c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -741,10 +741,8 @@ static ssize_t unix_stream_splice_read(struct socket *, loff_t *ppos, unsigned int flags); static int unix_dgram_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_dgram_recvmsg(struct socket *, struct msghdr *, size_t, int); -static int unix_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); -static int unix_stream_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); +static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor); +static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor); static int unix_dgram_connect(struct socket *, struct sockaddr *, int, int); static int unix_seqpacket_sendmsg(struct socket *, struct msghdr *, size_t); @@ -798,7 +796,7 @@ static const struct proto_ops unix_stream_ops = { .shutdown = unix_shutdown, .sendmsg = unix_stream_sendmsg, .recvmsg = unix_stream_recvmsg, - .read_sock = unix_stream_read_sock, + .read_skb = unix_stream_read_skb, .mmap = sock_no_mmap, .sendpage = unix_stream_sendpage, .splice_read = unix_stream_splice_read, @@ -823,7 +821,7 @@ static const struct proto_ops unix_dgram_ops = { .listen = sock_no_listen, .shutdown = unix_shutdown, .sendmsg = unix_dgram_sendmsg, - .read_sock = unix_read_sock, + .read_skb = unix_read_skb, .recvmsg = unix_dgram_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, @@ -2487,8 +2485,7 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, size_t si return __unix_dgram_recvmsg(sk, msg, size, flags); } -static int unix_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) +static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor) { int copied = 0; @@ -2503,7 +2500,7 @@ static int unix_read_sock(struct sock *sk, read_descriptor_t *desc, if (!skb) return err; - used = recv_actor(desc, skb, 0, skb->len); + used = recv_actor(sk, skb); if (used <= 0) { if (!copied) copied = used; @@ -2514,8 +2511,7 @@ static int unix_read_sock(struct sock *sk, read_descriptor_t *desc, } kfree_skb(skb); - if (!desc->count) - break; + break; } return copied; @@ -2650,13 +2646,12 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk, } #endif -static int unix_stream_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) +static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor) { if (unlikely(sk->sk_state != TCP_ESTABLISHED)) return -ENOTCONN; - return unix_read_sock(sk, desc, recv_actor); + return unix_read_skb(sk, recv_actor); } static int unix_stream_read_generic(struct unix_stream_read_state *state, -- cgit v1.2.3 From 414c12385d4741e35d88670c6cc2f40a77809734 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 13 Apr 2022 15:17:25 -0700 Subject: rcu: Provide a get_completed_synchronize_rcu() function It is currently up to the caller to handle stale return values from get_state_synchronize_rcu(). If poll_state_synchronize_rcu() returned true once, a grace period has elapsed, regardless of the fact that counter wrap might cause some future poll_state_synchronize_rcu() invocation to return false. For example, the caller might store a separate flag that indicates whether some previous call to poll_state_synchronize_rcu() determined that the relevant grace period had already ended. This approach works, but it requires extra storage and is easy to get wrong. This commit therefore introduces a get_completed_synchronize_rcu() that returns a cookie that causes poll_state_synchronize_rcu() to always return true. This already-completed cookie can be stored in place of the cookie that previously caused poll_state_synchronize_rcu() to return true. It can also be used to flag a given structure as not having been exposed to readers, and thus not requiring a grace period to elapse. This commit is in preparation for polled expedited grace periods. Link: https://lore.kernel.org/all/20220121142454.1994916-1-bfoster@redhat.com/ Link: https://docs.google.com/document/d/1RNKWW9jQyfjxw2E8dsXVTdvZYh0HnYeSHDKog9jhdN8/edit?usp=sharing Cc: Brian Foster Cc: Dave Chinner Cc: Al Viro Cc: Ian Kent Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 1 + kernel/rcu/rcu.h | 3 +++ kernel/rcu/tiny.c | 4 ++-- kernel/rcu/tree.c | 3 ++- kernel/rcu/update.c | 13 +++++++++++++ 5 files changed, 21 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 1a32036c918c..7f12daa4708b 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -41,6 +41,7 @@ void call_rcu(struct rcu_head *head, rcu_callback_t func); void rcu_barrier_tasks(void); void rcu_barrier_tasks_rude(void); void synchronize_rcu(void); +unsigned long get_completed_synchronize_rcu(void); #ifdef CONFIG_PREEMPT_RCU diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index 0adb55941aeb..32291f4eefde 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -23,6 +23,9 @@ #define RCU_SEQ_CTR_SHIFT 2 #define RCU_SEQ_STATE_MASK ((1 << RCU_SEQ_CTR_SHIFT) - 1) +/* Low-order bit definition for polled grace-period APIs. */ +#define RCU_GET_STATE_COMPLETED 0x1 + extern int sysctl_sched_rt_runtime; /* diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 340b3f8b090d..dbee6bea6726 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -58,7 +58,7 @@ void rcu_qs(void) rcu_ctrlblk.donetail = rcu_ctrlblk.curtail; raise_softirq_irqoff(RCU_SOFTIRQ); } - WRITE_ONCE(rcu_ctrlblk.gp_seq, rcu_ctrlblk.gp_seq + 1); + WRITE_ONCE(rcu_ctrlblk.gp_seq, rcu_ctrlblk.gp_seq + 2); local_irq_restore(flags); } @@ -213,7 +213,7 @@ EXPORT_SYMBOL_GPL(start_poll_synchronize_rcu); */ bool poll_state_synchronize_rcu(unsigned long oldstate) { - return READ_ONCE(rcu_ctrlblk.gp_seq) != oldstate; + return oldstate == RCU_GET_STATE_COMPLETED || READ_ONCE(rcu_ctrlblk.gp_seq) != oldstate; } EXPORT_SYMBOL_GPL(poll_state_synchronize_rcu); diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index ec28e259774e..46cfceea8784 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3924,7 +3924,8 @@ EXPORT_SYMBOL_GPL(start_poll_synchronize_rcu); */ bool poll_state_synchronize_rcu(unsigned long oldstate) { - if (rcu_seq_done_exact(&rcu_state.gp_seq, oldstate)) { + if (oldstate == RCU_GET_STATE_COMPLETED || + rcu_seq_done_exact(&rcu_state.gp_seq, oldstate)) { smp_mb(); /* Ensure GP ends before subsequent accesses. */ return true; } diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index fc7fef575606..2e93acad1e31 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -516,6 +516,19 @@ int rcu_cpu_stall_suppress_at_boot __read_mostly; // !0 = suppress boot stalls. EXPORT_SYMBOL_GPL(rcu_cpu_stall_suppress_at_boot); module_param(rcu_cpu_stall_suppress_at_boot, int, 0444); +/** + * get_completed_synchronize_rcu - Return a pre-completed polled state cookie + * + * Returns a value that will always be treated by functions like + * poll_state_synchronize_rcu() as a cookie whose grace period has already + * completed. + */ +unsigned long get_completed_synchronize_rcu(void) +{ + return RCU_GET_STATE_COMPLETED; +} +EXPORT_SYMBOL_GPL(get_completed_synchronize_rcu); + #ifdef CONFIG_PROVE_RCU /* -- cgit v1.2.3 From 3847b64570b1753e9863a4106aec03f4d68e7b17 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 23 May 2022 20:50:11 -0700 Subject: rcu-tasks: Merge state into .b.need_qs and atomically update This commit gets rid of the task_struct structure's ->trc_reader_checked field, making it instead be a bit within the task_struct structure's existing ->trc_reader_special.b.need_qs field. This commit also atomically loads, stores, and checks the resulting combination of the reader-checked and need-quiescent state flags. This will in turn allow significant simplification of the rcu_tasks_trace_postgp() function as well as elimination of the trc_n_readers_need_end counter in later commits. These changes will in turn simplify later elimination of the RCU Tasks Trace scan of the task list, which will make RCU Tasks Trace grace periods less CPU-intensive. [ paulmck: Apply kernel test robot feedback. ] Signed-off-by: Paul E. McKenney Cc: Neeraj Upadhyay Cc: Eric Dumazet Cc: Alexei Starovoitov Cc: Andrii Nakryiko Cc: Martin KaFai Lau Cc: KP Singh --- include/linux/rcupdate.h | 18 +++++---- include/linux/sched.h | 1 - kernel/rcu/tasks.h | 103 ++++++++++++++++++++++++++++++++--------------- 3 files changed, 82 insertions(+), 40 deletions(-) (limited to 'include') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 1a32036c918c..1e728d544fc1 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -169,13 +169,17 @@ void synchronize_rcu_tasks(void); # endif # ifdef CONFIG_TASKS_TRACE_RCU -# define rcu_tasks_trace_qs(t) \ - do { \ - if (!likely(READ_ONCE((t)->trc_reader_checked)) && \ - !unlikely(READ_ONCE((t)->trc_reader_nesting))) { \ - smp_store_release(&(t)->trc_reader_checked, true); \ - smp_mb(); /* Readers partitioned by store. */ \ - } \ +// Bits for ->trc_reader_special.b.need_qs field. +#define TRC_NEED_QS 0x1 // Task needs a quiescent state. +#define TRC_NEED_QS_CHECKED 0x2 // Task has been checked for needing quiescent state. + +u8 rcu_trc_cmpxchg_need_qs(struct task_struct *t, u8 old, u8 new); + +# define rcu_tasks_trace_qs(t) \ + do { \ + if (likely(!READ_ONCE((t)->trc_reader_special.b.need_qs)) && \ + likely(!READ_ONCE((t)->trc_reader_nesting))) \ + rcu_trc_cmpxchg_need_qs((t), 0, TRC_NEED_QS_CHECKED); \ } while (0) # else # define rcu_tasks_trace_qs(t) do { } while (0) diff --git a/include/linux/sched.h b/include/linux/sched.h index c46f3a63b758..e6eb5871593e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -843,7 +843,6 @@ struct task_struct { int trc_reader_nesting; int trc_ipi_to_cpu; union rcu_special trc_reader_special; - bool trc_reader_checked; struct list_head trc_holdout_list; #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */ diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h index bd9f2e24f5c7..7bdc62606816 100644 --- a/kernel/rcu/tasks.h +++ b/kernel/rcu/tasks.h @@ -1208,6 +1208,39 @@ void call_rcu_tasks_trace(struct rcu_head *rhp, rcu_callback_t func); DEFINE_RCU_TASKS(rcu_tasks_trace, rcu_tasks_wait_gp, call_rcu_tasks_trace, "RCU Tasks Trace"); +/* Load from ->trc_reader_special.b.need_qs with proper ordering. */ +static u8 rcu_ld_need_qs(struct task_struct *t) +{ + smp_mb(); // Enforce full grace-period ordering. + return smp_load_acquire(&t->trc_reader_special.b.need_qs); +} + +/* Store to ->trc_reader_special.b.need_qs with proper ordering. */ +static void rcu_st_need_qs(struct task_struct *t, u8 v) +{ + smp_store_release(&t->trc_reader_special.b.need_qs, v); + smp_mb(); // Enforce full grace-period ordering. +} + +/* + * Do a cmpxchg() on ->trc_reader_special.b.need_qs, allowing for + * the four-byte operand-size restriction of some platforms. + * Returns the old value, which is often ignored. + */ +u8 rcu_trc_cmpxchg_need_qs(struct task_struct *t, u8 old, u8 new) +{ + union rcu_special ret; + union rcu_special trs_old = READ_ONCE(t->trc_reader_special); + union rcu_special trs_new = trs_old; + + if (trs_old.b.need_qs != old) + return trs_old.b.need_qs; + trs_new.b.need_qs = new; + ret.s = cmpxchg(&t->trc_reader_special.s, trs_old.s, trs_new.s); + return ret.b.need_qs; +} +EXPORT_SYMBOL_GPL(rcu_trc_cmpxchg_need_qs); + /* * This irq_work handler allows rcu_read_unlock_trace() to be invoked * while the scheduler locks are held. @@ -1221,16 +1254,20 @@ static DEFINE_IRQ_WORK(rcu_tasks_trace_iw, rcu_read_unlock_iw); /* If we are the last reader, wake up the grace-period kthread. */ void rcu_read_unlock_trace_special(struct task_struct *t) { - int nq = READ_ONCE(t->trc_reader_special.b.need_qs); + int nqs = (rcu_ld_need_qs(t) == (TRC_NEED_QS_CHECKED | TRC_NEED_QS)); - if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB) && - t->trc_reader_special.b.need_mb) + if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB) && t->trc_reader_special.b.need_mb) smp_mb(); // Pairs with update-side barriers. // Update .need_qs before ->trc_reader_nesting for irq/NMI handlers. - if (nq) - WRITE_ONCE(t->trc_reader_special.b.need_qs, false); + if (nqs) { + u8 result = rcu_trc_cmpxchg_need_qs(t, TRC_NEED_QS_CHECKED | TRC_NEED_QS, + TRC_NEED_QS_CHECKED); + + WARN_ONCE(result != (TRC_NEED_QS_CHECKED | TRC_NEED_QS), + "%s: result = %d", __func__, result); + } WRITE_ONCE(t->trc_reader_nesting, 0); - if (nq && atomic_dec_and_test(&trc_n_readers_need_end)) + if (nqs && atomic_dec_and_test(&trc_n_readers_need_end)) irq_work_queue(&rcu_tasks_trace_iw); } EXPORT_SYMBOL_GPL(rcu_read_unlock_trace_special); @@ -1260,27 +1297,24 @@ static void trc_read_check_handler(void *t_in) struct task_struct *texp = t_in; // If the task is no longer running on this CPU, leave. - if (unlikely(texp != t)) { + if (unlikely(texp != t)) goto reset_ipi; // Already on holdout list, so will check later. - } // If the task is not in a read-side critical section, and // if this is the last reader, awaken the grace-period kthread. if (likely(!READ_ONCE(t->trc_reader_nesting))) { - WRITE_ONCE(t->trc_reader_checked, true); + rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED); goto reset_ipi; } // If we are racing with an rcu_read_unlock_trace(), try again later. if (unlikely(READ_ONCE(t->trc_reader_nesting) < 0)) goto reset_ipi; - WRITE_ONCE(t->trc_reader_checked, true); // Get here if the task is in a read-side critical section. Set // its state so that it will awaken the grace-period kthread upon // exit from that critical section. - atomic_inc(&trc_n_readers_need_end); // One more to wait on. - WARN_ON_ONCE(READ_ONCE(t->trc_reader_special.b.need_qs)); - WRITE_ONCE(t->trc_reader_special.b.need_qs, true); + if (!rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS | TRC_NEED_QS_CHECKED)) + atomic_inc(&trc_n_readers_need_end); // One more to wait on. reset_ipi: // Allow future IPIs to be sent on CPU and for task. @@ -1291,8 +1325,9 @@ reset_ipi: } /* Callback function for scheduler to check locked-down task. */ -static int trc_inspect_reader(struct task_struct *t, void *arg) +static int trc_inspect_reader(struct task_struct *t, void *bhp_in) { + struct list_head *bhp = bhp_in; int cpu = task_cpu(t); int nesting; bool ofl = cpu_is_offline(cpu); @@ -1323,16 +1358,19 @@ static int trc_inspect_reader(struct task_struct *t, void *arg) // If not exiting a read-side critical section, mark as checked // so that the grace-period kthread will remove it from the // holdout list. - t->trc_reader_checked = nesting >= 0; - if (nesting <= 0) + if (nesting <= 0) { + if (!nesting) + rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED); return nesting ? -EINVAL : 0; // If in QS, done, otherwise try again later. + } // The task is in a read-side critical section, so set up its // state so that it will awaken the grace-period kthread upon exit // from that critical section. - atomic_inc(&trc_n_readers_need_end); // One more to wait on. - WARN_ON_ONCE(READ_ONCE(t->trc_reader_special.b.need_qs)); - WRITE_ONCE(t->trc_reader_special.b.need_qs, true); + if (!rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS | TRC_NEED_QS_CHECKED)) { + atomic_inc(&trc_n_readers_need_end); // One more to wait on. + trc_add_holdout(t, bhp); + } return 0; } @@ -1348,14 +1386,14 @@ static void trc_wait_for_one_reader(struct task_struct *t, // The current task had better be in a quiescent state. if (t == current) { - t->trc_reader_checked = true; + rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED); WARN_ON_ONCE(READ_ONCE(t->trc_reader_nesting)); return; } // Attempt to nail down the task for inspection. get_task_struct(t); - if (!task_call_func(t, trc_inspect_reader, NULL)) { + if (!task_call_func(t, trc_inspect_reader, bhp)) { put_task_struct(t); return; } @@ -1419,8 +1457,7 @@ static void rcu_tasks_trace_pertask(struct task_struct *t, if (unlikely(t == NULL)) return; - WRITE_ONCE(t->trc_reader_special.b.need_qs, false); - WRITE_ONCE(t->trc_reader_checked, false); + rcu_st_need_qs(t, 0); t->trc_ipi_to_cpu = -1; trc_wait_for_one_reader(t, hop); } @@ -1442,7 +1479,8 @@ static void rcu_tasks_trace_postscan(struct list_head *hop) // Wait for late-stage exiting tasks to finish exiting. // These might have passed the call to exit_tasks_rcu_finish(). synchronize_rcu(); - // Any tasks that exit after this point will set ->trc_reader_checked. + // Any tasks that exit after this point will set + // TRC_NEED_QS_CHECKED in ->trc_reader_special.b.need_qs. } /* Communicate task state back to the RCU tasks trace stall warning request. */ @@ -1460,7 +1498,7 @@ static int trc_check_slow_task(struct task_struct *t, void *arg) return false; // It is running, so decline to inspect it. trc_rdrp->nesting = READ_ONCE(t->trc_reader_nesting); trc_rdrp->ipi_to_cpu = READ_ONCE(t->trc_ipi_to_cpu); - trc_rdrp->needqs = READ_ONCE(t->trc_reader_special.b.need_qs); + trc_rdrp->needqs = rcu_ld_need_qs(t); return true; } @@ -1514,12 +1552,12 @@ static void check_all_holdout_tasks_trace(struct list_head *hop, list_for_each_entry_safe(t, g, hop, trc_holdout_list) { // If safe and needed, try to check the current task. if (READ_ONCE(t->trc_ipi_to_cpu) == -1 && - !READ_ONCE(t->trc_reader_checked)) + !(rcu_ld_need_qs(t) & TRC_NEED_QS_CHECKED)) trc_wait_for_one_reader(t, hop); // If check succeeded, remove this task from the list. if (smp_load_acquire(&t->trc_ipi_to_cpu) == -1 && - READ_ONCE(t->trc_reader_checked)) + rcu_ld_need_qs(t) == TRC_NEED_QS_CHECKED) trc_del_holdout(t); else if (needreport) show_stalled_task_trace(t, firstreport); @@ -1574,12 +1612,12 @@ static void rcu_tasks_trace_postgp(struct rcu_tasks *rtp) // Stall warning time, so make a list of the offenders. rcu_read_lock(); for_each_process_thread(g, t) - if (READ_ONCE(t->trc_reader_special.b.need_qs)) + if (rcu_ld_need_qs(t) & TRC_NEED_QS) trc_add_holdout(t, &holdouts); rcu_read_unlock(); firstreport = true; list_for_each_entry_safe(t, g, &holdouts, trc_holdout_list) { - if (READ_ONCE(t->trc_reader_special.b.need_qs)) + if (rcu_ld_need_qs(t) & TRC_NEED_QS) show_stalled_task_trace(t, &firstreport); trc_del_holdout(t); // Release task_struct reference. } @@ -1595,11 +1633,12 @@ static void rcu_tasks_trace_postgp(struct rcu_tasks *rtp) /* Report any needed quiescent state for this exiting task. */ static void exit_tasks_rcu_finish_trace(struct task_struct *t) { - WRITE_ONCE(t->trc_reader_checked, true); + rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED); WARN_ON_ONCE(READ_ONCE(t->trc_reader_nesting)); - WRITE_ONCE(t->trc_reader_nesting, 0); - if (WARN_ON_ONCE(READ_ONCE(t->trc_reader_special.b.need_qs))) + if (WARN_ON_ONCE(rcu_ld_need_qs(t) & TRC_NEED_QS)) rcu_read_unlock_trace_special(t); + else + WRITE_ONCE(t->trc_reader_nesting, 0); } /** -- cgit v1.2.3 From 434c9eefb959c36331a93617ea95df903469b99f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 16 May 2022 17:56:16 -0700 Subject: rcu-tasks: Add data structures for lightweight grace periods This commit adds fields to task_struct and to rcu_tasks_percpu that will be used to avoid the task-list scan for RCU Tasks Trace grace periods, and also initializes these fields. Signed-off-by: Paul E. McKenney Cc: Neeraj Upadhyay Cc: Eric Dumazet Cc: Alexei Starovoitov Cc: Andrii Nakryiko Cc: Martin KaFai Lau Cc: KP Singh --- include/linux/sched.h | 2 ++ init/init_task.c | 1 + kernel/fork.c | 1 + kernel/rcu/tasks.h | 4 ++++ 4 files changed, 8 insertions(+) (limited to 'include') diff --git a/include/linux/sched.h b/include/linux/sched.h index e6eb5871593e..b88caf54e168 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -844,6 +844,8 @@ struct task_struct { int trc_ipi_to_cpu; union rcu_special trc_reader_special; struct list_head trc_holdout_list; + struct list_head trc_blkd_node; + int trc_blkd_cpu; #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */ struct sched_info sched_info; diff --git a/init/init_task.c b/init/init_task.c index 73cc8f03511a..ff6c4b9bfe6b 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -157,6 +157,7 @@ struct task_struct init_task .trc_reader_nesting = 0, .trc_reader_special.s = 0, .trc_holdout_list = LIST_HEAD_INIT(init_task.trc_holdout_list), + .trc_blkd_node = LIST_HEAD_INIT(init_task.trc_blkd_node), #endif #ifdef CONFIG_CPUSETS .mems_allowed_seq = SEQCNT_SPINLOCK_ZERO(init_task.mems_allowed_seq, diff --git a/kernel/fork.c b/kernel/fork.c index 9d44f2d46c69..1950eb870244 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1814,6 +1814,7 @@ static inline void rcu_copy_process(struct task_struct *p) p->trc_reader_nesting = 0; p->trc_reader_special.s = 0; INIT_LIST_HEAD(&p->trc_holdout_list); + INIT_LIST_HEAD(&p->trc_blkd_node); #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */ } diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h index 64eb4d7b142e..fd4508af055e 100644 --- a/kernel/rcu/tasks.h +++ b/kernel/rcu/tasks.h @@ -29,6 +29,7 @@ typedef void (*postgp_func_t)(struct rcu_tasks *rtp); * @rtp_work: Work queue for invoking callbacks. * @rtp_irq_work: IRQ work queue for deferred wakeups. * @barrier_q_head: RCU callback for barrier operation. + * @rtp_blkd_tasks: List of tasks blocked as readers. * @cpu: CPU number corresponding to this entry. * @rtpp: Pointer to the rcu_tasks structure. */ @@ -40,6 +41,7 @@ struct rcu_tasks_percpu { struct work_struct rtp_work; struct irq_work rtp_irq_work; struct rcu_head barrier_q_head; + struct list_head rtp_blkd_tasks; int cpu; struct rcu_tasks *rtpp; }; @@ -256,6 +258,8 @@ static void cblist_init_generic(struct rcu_tasks *rtp) INIT_WORK(&rtpcp->rtp_work, rcu_tasks_invoke_cbs_wq); rtpcp->cpu = cpu; rtpcp->rtpp = rtp; + if (!rtpcp->rtp_blkd_tasks.next) + INIT_LIST_HEAD(&rtpcp->rtp_blkd_tasks); raw_spin_unlock_rcu_node(rtpcp); // irqs remain disabled. } raw_spin_unlock_irqrestore(&rtp->cbs_gbl_lock, flags); -- cgit v1.2.3 From 0356d4e66214569de674ab2684f2e0b440a466ab Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 17 May 2022 11:30:32 -0700 Subject: rcu-tasks: Track blocked RCU Tasks Trace readers This commit places any task that has ever blocked within its current RCU Tasks Trace read-side critical section on a per-CPU list within the rcu_tasks_percpu structure. Tasks are removed from this list when they exit by the exit_tasks_rcu_finish_trace() function. The purpose of this commit is to provide the information needed to eliminate the current scan of the full task list. This commit offsets the INT_MIN value for ->trc_reader_nesting with the new nesting level in order to avoid queueing tasks that are exiting their read-side critical sections. [ paulmck: Apply kernel test robot feedback. ] [ paulmck: Apply feedback from syzbot+9bb26e7c5e8e4fa7e641@syzkaller.appspotmail.com ] Signed-off-by: Paul E. McKenney Tested-by: syzbot Tested-by: "Zhang, Qiang1" Cc: Peter Zijlstra Cc: Neeraj Upadhyay Cc: Eric Dumazet Cc: Alexei Starovoitov Cc: Andrii Nakryiko Cc: Martin KaFai Lau Cc: KP Singh --- include/linux/rcupdate.h | 11 +++++++++-- include/linux/rcupdate_trace.h | 2 +- kernel/rcu/tasks.h | 22 +++++++++++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 1e728d544fc1..ebdfeead44e5 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -174,12 +174,19 @@ void synchronize_rcu_tasks(void); #define TRC_NEED_QS_CHECKED 0x2 // Task has been checked for needing quiescent state. u8 rcu_trc_cmpxchg_need_qs(struct task_struct *t, u8 old, u8 new); +void rcu_tasks_trace_qs_blkd(struct task_struct *t); # define rcu_tasks_trace_qs(t) \ do { \ + int ___rttq_nesting = READ_ONCE((t)->trc_reader_nesting); \ + \ if (likely(!READ_ONCE((t)->trc_reader_special.b.need_qs)) && \ - likely(!READ_ONCE((t)->trc_reader_nesting))) \ + likely(!___rttq_nesting)) { \ rcu_trc_cmpxchg_need_qs((t), 0, TRC_NEED_QS_CHECKED); \ + } else if (___rttq_nesting && ___rttq_nesting != INT_MIN && \ + !READ_ONCE((t)->trc_reader_special.b.blocked)) { \ + rcu_tasks_trace_qs_blkd(t); \ + } \ } while (0) # else # define rcu_tasks_trace_qs(t) do { } while (0) @@ -188,7 +195,7 @@ u8 rcu_trc_cmpxchg_need_qs(struct task_struct *t, u8 old, u8 new); #define rcu_tasks_qs(t, preempt) \ do { \ rcu_tasks_classic_qs((t), (preempt)); \ - rcu_tasks_trace_qs((t)); \ + rcu_tasks_trace_qs(t); \ } while (0) # ifdef CONFIG_TASKS_RUDE_RCU diff --git a/include/linux/rcupdate_trace.h b/include/linux/rcupdate_trace.h index 6f9c35817398..9bc8cbb33340 100644 --- a/include/linux/rcupdate_trace.h +++ b/include/linux/rcupdate_trace.h @@ -75,7 +75,7 @@ static inline void rcu_read_unlock_trace(void) nesting = READ_ONCE(t->trc_reader_nesting) - 1; barrier(); // Critical section before disabling. // Disable IPI-based setting of .need_qs. - WRITE_ONCE(t->trc_reader_nesting, INT_MIN); + WRITE_ONCE(t->trc_reader_nesting, INT_MIN + nesting); if (likely(!READ_ONCE(t->trc_reader_special.s)) || nesting) { WRITE_ONCE(t->trc_reader_nesting, nesting); return; // We assume shallow reader nesting. diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h index fd4508af055e..bab75ec26bdb 100644 --- a/kernel/rcu/tasks.h +++ b/kernel/rcu/tasks.h @@ -1261,6 +1261,24 @@ void rcu_read_unlock_trace_special(struct task_struct *t) } EXPORT_SYMBOL_GPL(rcu_read_unlock_trace_special); +/* Add a newly blocked reader task to its CPU's list. */ +void rcu_tasks_trace_qs_blkd(struct task_struct *t) +{ + unsigned long flags; + struct rcu_tasks_percpu *rtpcp; + + local_irq_save(flags); + rtpcp = this_cpu_ptr(rcu_tasks_trace.rtpcpu); + raw_spin_lock_rcu_node(rtpcp); // irqs already disabled + t->trc_blkd_cpu = smp_processor_id(); + if (!rtpcp->rtp_blkd_tasks.next) + INIT_LIST_HEAD(&rtpcp->rtp_blkd_tasks); + list_add(&t->trc_blkd_node, &rtpcp->rtp_blkd_tasks); + t->trc_reader_special.b.blocked = true; + raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags); +} +EXPORT_SYMBOL_GPL(rcu_tasks_trace_qs_blkd); + /* Add a task to the holdout list, if it is not already on the list. */ static void trc_add_holdout(struct task_struct *t, struct list_head *bhp) { @@ -1586,9 +1604,11 @@ static void rcu_tasks_trace_postgp(struct rcu_tasks *rtp) /* Report any needed quiescent state for this exiting task. */ static void exit_tasks_rcu_finish_trace(struct task_struct *t) { + union rcu_special trs = READ_ONCE(t->trc_reader_special); + rcu_trc_cmpxchg_need_qs(t, 0, TRC_NEED_QS_CHECKED); WARN_ON_ONCE(READ_ONCE(t->trc_reader_nesting)); - if (WARN_ON_ONCE(rcu_ld_need_qs(t) & TRC_NEED_QS)) + if (WARN_ON_ONCE(rcu_ld_need_qs(t) & TRC_NEED_QS) || trs.b.blocked) rcu_read_unlock_trace_special(t); else WRITE_ONCE(t->trc_reader_nesting, 0); -- cgit v1.2.3 From 5f8a62af527ad8a615d68889d816b72c3f5f227f Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 8 Jun 2022 16:40:18 +0200 Subject: context_tracking: Remove unused context_tracking_in_user() This function is not used and CT_WARN_ON() coupled with ct_state() is the preferred way to assert context tracking state values. Reported-by: Nicolas Saenz Julienne Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Neeraj Upadhyay Cc: Uladzislau Rezki Cc: Joel Fernandes Cc: Boqun Feng Cc: Nicolas Saenz Julienne Cc: Marcelo Tosatti Cc: Xiongfeng Wang Cc: Yu Liao Cc: Phil Auld Cc: Paul Gortmaker Cc: Alex Belits Signed-off-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- include/linux/context_tracking_state.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'include') diff --git a/include/linux/context_tracking_state.h b/include/linux/context_tracking_state.h index ae1e63e26947..edc7b46376a6 100644 --- a/include/linux/context_tracking_state.h +++ b/include/linux/context_tracking_state.h @@ -41,12 +41,7 @@ static inline bool context_tracking_enabled_this_cpu(void) return context_tracking_enabled() && __this_cpu_read(context_tracking.active); } -static __always_inline bool context_tracking_in_user(void) -{ - return __this_cpu_read(context_tracking.state) == CONTEXT_USER; -} #else -static __always_inline bool context_tracking_in_user(void) { return false; } static __always_inline bool context_tracking_enabled(void) { return false; } static __always_inline bool context_tracking_enabled_cpu(int cpu) { return false; } static __always_inline bool context_tracking_enabled_this_cpu(void) { return false; } -- cgit v1.2.3 From 2f6fe93fede802acfe010752db461ccd34745745 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:10:03 +0200 Subject: ACPI: glue: Introduce acpi_find_child_by_adr() Rearrange the ACPI device lookup code used internally by acpi_find_child_device() so it can avoid extra checks after finding one object with a matching _ADR and use it for defining acpi_find_child_by_adr() that will allow the callers to find a given ACPI device's child matching a given bus address without doing any other checks in check_one_child(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/glue.c | 28 ++++++++++++++++++++++++---- include/acpi/acpi_bus.h | 2 ++ 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 5203a7c60daa..204fe94c7e45 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -119,6 +119,7 @@ struct find_child_walk_data { struct acpi_device *adev; u64 address; int score; + bool check_sta; bool check_children; }; @@ -131,9 +132,13 @@ static int check_one_child(struct acpi_device *adev, void *data) return 0; if (!wd->adev) { - /* This is the first matching object. Save it and continue. */ + /* + * This is the first matching object, so save it. If it is not + * necessary to look for any other matching objects, stop the + * search. + */ wd->adev = adev; - return 0; + return !(wd->check_sta || wd->check_children); } /* @@ -169,12 +174,14 @@ static int check_one_child(struct acpi_device *adev, void *data) return 0; } -struct acpi_device *acpi_find_child_device(struct acpi_device *parent, - u64 address, bool check_children) +static struct acpi_device *acpi_find_child(struct acpi_device *parent, + u64 address, bool check_children, + bool check_sta) { struct find_child_walk_data wd = { .address = address, .check_children = check_children, + .check_sta = check_sta, .adev = NULL, .score = 0, }; @@ -184,8 +191,21 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, return wd.adev; } + +struct acpi_device *acpi_find_child_device(struct acpi_device *parent, + u64 address, bool check_children) +{ + return acpi_find_child(parent, address, check_children, true); +} EXPORT_SYMBOL_GPL(acpi_find_child_device); +struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev, + acpi_bus_address adr) +{ + return acpi_find_child(adev, adr, false, false); +} +EXPORT_SYMBOL_GPL(acpi_find_child_by_adr); + static void acpi_physnode_link_name(char *buf, unsigned int node_id) { if (node_id > 0) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0dc1ea0b52f5..597961969ca1 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -622,6 +622,8 @@ static inline int acpi_dma_configure(struct device *dev, } struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); +struct acpi_device *acpi_find_child_by_adr(struct acpi_device *adev, + acpi_bus_address adr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); -- cgit v1.2.3 From ff32e59947c87b01dc25a8b5763d609c1a8f56eb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Jun 2022 20:26:47 +0200 Subject: ACPI: bus: Introduce acpi_dev_for_each_child_reverse() Make it possible to walk the children of an ACPI device in the revese order by defining acpi_dev_for_each_child_reverse() in analogy with acpi_dev_for_each_child(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- drivers/acpi/bus.c | 12 ++++++++++++ include/acpi/acpi_bus.h | 3 +++ 2 files changed, 15 insertions(+) (limited to 'include') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 7027ff2edfba..4d7c51a33b01 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1115,6 +1115,18 @@ int acpi_dev_for_each_child(struct acpi_device *adev, return device_for_each_child(&adev->dev, &adwc, acpi_dev_for_one_check); } +int acpi_dev_for_each_child_reverse(struct acpi_device *adev, + int (*fn)(struct acpi_device *, void *), + void *data) +{ + struct acpi_dev_walk_context adwc = { + .fn = fn, + .data = data, + }; + + return device_for_each_child_reverse(&adev->dev, &adwc, acpi_dev_for_one_check); +} + /* -------------------------------------------------------------------------- Initialization/Cleanup -------------------------------------------------------------------------- */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 597961969ca1..76de1aa5d221 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -483,6 +483,9 @@ extern struct bus_type acpi_bus_type; int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data); int acpi_dev_for_each_child(struct acpi_device *adev, int (*fn)(struct acpi_device *, void *), void *data); +int acpi_dev_for_each_child_reverse(struct acpi_device *adev, + int (*fn)(struct acpi_device *, void *), + void *data); /* * Events -- cgit v1.2.3 From e6445be4f549a0342cd9b8672b82e3b1d85d017f Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Sat, 11 Jun 2022 22:14:08 +0800 Subject: media: uapi: Add some RGB bus formats for i.MX8qm/qxp pixel combiner This patch adds RGB666_1X30_CPADLO, RGB888_1X30_CPADLO, RGB666_1X36_CPADLO and RGB888_1X36_CPADLO bus formats used by i.MX8qm/qxp pixel combiner. The RGB pixels with padding low per component are transmitted on a 30-bit input bus(10-bit per component) from a display controller or a 36-bit output bus(12-bit per component) to a pixel link. Reviewed-by: Robert Foss Reviewed-by: Laurent Pinchart Signed-off-by: Liu Ying Acked-by: Sakari Ailus Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220611141421.718743-2-victor.liu@nxp.com --- include/uapi/linux/media-bus-format.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 0dfc11ee243a..ec3323dbb927 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -34,7 +34,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x101e */ +/* RGB - next is 0x1022 */ #define MEDIA_BUS_FMT_RGB444_1X12 0x1016 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 @@ -59,9 +59,13 @@ #define MEDIA_BUS_FMT_RGB888_3X8_DELTA 0x101d #define MEDIA_BUS_FMT_RGB888_1X7X4_SPWG 0x1011 #define MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA 0x1012 +#define MEDIA_BUS_FMT_RGB666_1X30_CPADLO 0x101e +#define MEDIA_BUS_FMT_RGB888_1X30_CPADLO 0x101f #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d #define MEDIA_BUS_FMT_RGB888_1X32_PADHI 0x100f #define MEDIA_BUS_FMT_RGB101010_1X30 0x1018 +#define MEDIA_BUS_FMT_RGB666_1X36_CPADLO 0x1020 +#define MEDIA_BUS_FMT_RGB888_1X36_CPADLO 0x1021 #define MEDIA_BUS_FMT_RGB121212_1X36 0x1019 #define MEDIA_BUS_FMT_RGB161616_1X48 0x101a -- cgit v1.2.3 From 255490f9150da7c6dabe468f3a877b92fd0f02c1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 14 Jun 2022 12:02:45 +0300 Subject: drm: Drop drm_edid.h from drm_crtc.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_crtc.h has no need for drm_edid.h, so don't include it. Avoids useless rebuilds of the entire universe when touching drm_edid.h. Quite a few placs do currently depend on drm_edid.h without actually including it directly. All of those need to be fixed up. v2: Fix up i915 and msm some more v3: Fix alphabetical ordering (Sam) Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20220614090245.30283-1-ville.syrjala@linux.intel.com Acked-by: Sam Ravnborg Acked-by: Jani Nikula --- drivers/gpu/drm/arm/malidp_mw.c | 1 + drivers/gpu/drm/aspeed/aspeed_gfx_out.c | 1 + drivers/gpu/drm/ast/ast_mode.c | 1 + drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 1 + drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 1 + drivers/gpu/drm/bridge/lontium-lt8912b.c | 1 + drivers/gpu/drm/bridge/parade-ps8640.c | 1 + drivers/gpu/drm/bridge/simple-bridge.c | 1 + drivers/gpu/drm/bridge/ti-tfp410.c | 1 + drivers/gpu/drm/display/drm_dp_helper.c | 1 + drivers/gpu/drm/display/drm_dp_mst_topology.c | 1 + drivers/gpu/drm/drm_client_modeset.c | 1 + drivers/gpu/drm/drm_kms_helper_common.c | 1 + drivers/gpu/drm/drm_modes.c | 1 + drivers/gpu/drm/exynos/exynos_mixer.c | 1 + drivers/gpu/drm/gma500/cdv_intel_dp.c | 1 + drivers/gpu/drm/gma500/oaktrail_hdmi.c | 1 + drivers/gpu/drm/gma500/oaktrail_lvds.c | 1 + drivers/gpu/drm/gma500/psb_intel_modes.c | 2 ++ drivers/gpu/drm/gud/gud_connector.c | 1 + drivers/gpu/drm/i915/display/intel_bios.c | 1 + drivers/gpu/drm/i915/display/intel_dp.c | 1 + drivers/gpu/drm/i915/display/intel_lspcon.c | 1 + drivers/gpu/drm/i915/display/intel_opregion.c | 2 ++ drivers/gpu/drm/imx/imx-ldb.c | 1 + drivers/gpu/drm/imx/imx-tve.c | 1 + drivers/gpu/drm/imx/parallel-display.c | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c | 2 ++ drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 1 + drivers/gpu/drm/omapdrm/dss/hdmi4.c | 1 + drivers/gpu/drm/omapdrm/dss/hdmi5.c | 1 + drivers/gpu/drm/panel/panel-edp.c | 1 + drivers/gpu/drm/panel/panel-simple.c | 1 + drivers/gpu/drm/qxl/qxl_display.c | 1 + drivers/gpu/drm/rcar-du/rcar_du_writeback.c | 1 + drivers/gpu/drm/rockchip/rk3066_hdmi.c | 1 + drivers/gpu/drm/solomon/ssd130x.c | 1 + drivers/gpu/drm/stm/ltdc.c | 1 + drivers/gpu/drm/tiny/arcpgu.c | 1 + drivers/gpu/drm/tiny/bochs.c | 1 + drivers/gpu/drm/tiny/cirrus.c | 1 + drivers/gpu/drm/tiny/gm12u320.c | 1 + drivers/gpu/drm/udl/udl_connector.c | 1 + drivers/gpu/drm/vboxvideo/vbox_mode.c | 1 + drivers/gpu/drm/virtio/virtgpu_display.c | 1 + drivers/gpu/drm/virtio/virtgpu_vq.c | 2 ++ drivers/gpu/drm/vkms/vkms_output.c | 1 + drivers/gpu/drm/vkms/vkms_writeback.c | 1 + include/drm/drm_crtc.h | 1 - 49 files changed, 52 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c index 204c869d9fe2..5985ba99b9e4 100644 --- a/drivers/gpu/drm/arm/malidp_mw.c +++ b/drivers/gpu/drm/arm/malidp_mw.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c index 6759cb88415a..4f2187025a21 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_out.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_out.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "aspeed_gfx.h" diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index db2010a55674..3eb9afecd9d4 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 01c8b80e34ec..8aadcc0aa90b 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 67f0f444b4e8..ba5f695703dc 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index c92515834ff2..6a7a6983e796 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -11,6 +11,7 @@ #include #include +#include #include #include diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index ff4227f6d800..45b235a74a12 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index d974282c12b2..2c5c5211bdab 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 756b3e6e776b..4541126a45ea 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index e7c22c2ca90c..8eb3172b4b36 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 18f2b6075b78..a57f09560b14 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index 48e6ce16439f..bbc535cc50dd 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c index 8be20080cd8d..0bf0fc1abf54 100644 --- a/drivers/gpu/drm/drm_kms_helper_common.c +++ b/drivers/gpu/drm/drm_kms_helper_common.c @@ -27,6 +27,7 @@ #include +#include #include #include "drm_crtc_helper_internal.h" diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 40b7b245e98c..a2542254233e 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -41,6 +41,7 @@ #include #include +#include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e5204be86093..de06ac647284 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 9ee99a7d4fbe..bb2e9d64018a 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "gma_display.h" diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index b5946a1cdcd5..95b7cb099e63 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -27,6 +27,7 @@ #include #include +#include #include #include "psb_drv.h" diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index 9c9ebf8e29c4..4d98df189e10 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -13,6 +13,7 @@ #include +#include #include #include "intel_bios.h" diff --git a/drivers/gpu/drm/gma500/psb_intel_modes.c b/drivers/gpu/drm/gma500/psb_intel_modes.c index 60306780e16c..8be0ec340de5 100644 --- a/drivers/gpu/drm/gma500/psb_intel_modes.c +++ b/drivers/gpu/drm/gma500/psb_intel_modes.c @@ -7,6 +7,8 @@ #include +#include + #include "psb_intel_drv.h" /** diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c index ae051133e050..d0addd478815 100644 --- a/drivers/gpu/drm/gud/gud_connector.c +++ b/drivers/gpu/drm/gud/gud_connector.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 0c5638f5b72b..96cd1f0b9d32 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -25,6 +25,7 @@ * */ +#include #include #include diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index e4a79c11fd25..7c96088d80c7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include "g4x_dp.h" diff --git a/drivers/gpu/drm/i915/display/intel_lspcon.c b/drivers/gpu/drm/i915/display/intel_lspcon.c index 7fbc8031a5aa..15d59de8810e 100644 --- a/drivers/gpu/drm/i915/display/intel_lspcon.c +++ b/drivers/gpu/drm/i915/display/intel_lspcon.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "intel_de.h" #include "intel_display_types.h" diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index f31e8c3f8ce0..3aea4e42d55e 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -30,6 +30,8 @@ #include #include +#include + #include "i915_drv.h" #include "intel_acpi.h" #include "intel_backlight.h" diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 14a058a42854..8bf885137977 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index 2b1fdf2cbbce..6b34fac3f73a 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -18,6 +18,7 @@ #include