From f5c27da4e3c8a2e42fb4f41a0c685debcb9af294 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 3 Nov 2022 16:57:44 +0100 Subject: HID: initial BPF implementation Declare an entry point that can use fmod_ret BPF programs, and also an API to access and change the incoming data. A simpler implementation would consist in just calling hid_bpf_device_event() for any incoming event and let users deal with the fact that they will be called for any event of any device. The goal of HID-BPF is to partially replace drivers, so this situation can be problematic because we might have programs which will step on each other toes. For that, we add a new API hid_bpf_attach_prog() that can be called from a syscall and we manually deal with a jump table in hid-bpf. Whenever we add a program to the jump table (in other words, when we attach a program to a HID device), we keep the number of time we added this program in the jump table so we can release it whenever there are no other users. HID devices have an RCU protected list of available programs in the jump table, and those programs are called one after the other thanks to bpf_tail_call(). To achieve the detection of users losing their fds on the programs we attached, we add 2 tracing facilities on bpf_prog_release() (for when a fd is closed) and bpf_free_inode() (for when a pinned program gets unpinned). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- include/linux/hid.h | 5 +++ include/linux/hid_bpf.h | 117 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 include/linux/hid_bpf.h (limited to 'include') diff --git a/include/linux/hid.h b/include/linux/hid.h index 8677ae38599e..cd3c52fae7b1 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -26,6 +26,7 @@ #include #include #include +#include /* * We parse each description item into this structure. Short items data @@ -651,6 +652,10 @@ struct hid_device { /* device report descriptor */ wait_queue_head_t debug_wait; unsigned int id; /* system unique id */ + +#ifdef CONFIG_BPF + struct hid_bpf bpf; /* hid-bpf data */ +#endif /* CONFIG_BPF */ }; #define to_hid_device(pdev) \ diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h new file mode 100644 index 000000000000..de3fb1c376d2 --- /dev/null +++ b/include/linux/hid_bpf.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef __HID_BPF_H +#define __HID_BPF_H + +#include +#include + +struct hid_device; + +/* + * The following is the user facing HID BPF API. + * + * Extra care should be taken when editing this part, as + * it might break existing out of the tree bpf programs. + */ + +/** + * struct hid_bpf_ctx - User accessible data for all HID programs + * + * ``data`` is not directly accessible from the context. We need to issue + * a call to ``hid_bpf_get_data()`` in order to get a pointer to that field. + * + * All of these fields are currently read-only. + * + * @index: program index in the jump table. No special meaning (a smaller index + * doesn't mean the program will be executed before another program with + * a bigger index). + * @hid: the ``struct hid_device`` representing the device itself + * @report_type: used for ``hid_bpf_device_event()`` + * @size: Valid data in the data field. + * + * Programs can get the available valid size in data by fetching this field. + */ +struct hid_bpf_ctx { + __u32 index; + const struct hid_device *hid; + enum hid_report_type report_type; + __s32 size; +}; + +/** + * enum hid_bpf_attach_flags - flags used when attaching a HIF-BPF program + * + * @HID_BPF_FLAG_NONE: no specific flag is used, the kernel choses where to + * insert the program + * @HID_BPF_FLAG_INSERT_HEAD: insert the given program before any other program + * currently attached to the device. This doesn't + * guarantee that this program will always be first + * @HID_BPF_FLAG_MAX: sentinel value, not to be used by the callers + */ +enum hid_bpf_attach_flags { + HID_BPF_FLAG_NONE = 0, + HID_BPF_FLAG_INSERT_HEAD = _BITUL(0), + HID_BPF_FLAG_MAX, +}; + +/* Following functions are tracepoints that BPF programs can attach to */ +int hid_bpf_device_event(struct hid_bpf_ctx *ctx); + +/* Following functions are kfunc that we export to BPF programs */ +/* only available in tracing */ +__u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz); + +/* only available in syscall */ +int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags); + +/* + * Below is HID internal + */ + +/* internal function to call eBPF programs, not to be used by anybody */ +int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx); + +#define HID_BPF_MAX_PROGS_PER_DEV 64 +#define HID_BPF_FLAG_MASK (((HID_BPF_FLAG_MAX - 1) << 1) - 1) + +/* types of HID programs to attach to */ +enum hid_bpf_prog_type { + HID_BPF_PROG_TYPE_UNDEF = -1, + HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */ + HID_BPF_PROG_TYPE_MAX, +}; + +struct hid_bpf_ops { + struct module *owner; + struct bus_type *bus_type; +}; + +extern struct hid_bpf_ops *hid_bpf_ops; + +struct hid_bpf_prog_list { + u16 prog_idx[HID_BPF_MAX_PROGS_PER_DEV]; + u8 prog_cnt; +}; + +/* stored in each device */ +struct hid_bpf { + struct hid_bpf_prog_list __rcu *progs[HID_BPF_PROG_TYPE_MAX]; /* attached BPF progs */ + bool destroyed; /* prevents the assignment of any progs */ + + spinlock_t progs_lock; /* protects RCU update of progs */ +}; + +#ifdef CONFIG_HID_BPF +int dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, + u32 size, int interrupt); +void hid_bpf_destroy_device(struct hid_device *hid); +void hid_bpf_device_init(struct hid_device *hid); +#else /* CONFIG_HID_BPF */ +static inline int dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, + u8 *data, u32 size, int interrupt) { return 0; } +static inline void hid_bpf_destroy_device(struct hid_device *hid) {} +static inline void hid_bpf_device_init(struct hid_device *hid) {} +#endif /* CONFIG_HID_BPF */ + +#endif /* __HID_BPF_H */ -- cgit v1.2.3 From 658ee5a64fcfbbf758447fa3af425729eaabb0dc Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 3 Nov 2022 16:57:47 +0100 Subject: HID: bpf: allocate data memory for device_event BPF programs We need to also be able to change the size of the report. Reducing it is easy, because we already have the incoming buffer that is big enough, but extending it is harder. Pre-allocate a buffer that is big enough to handle all reports of the device, and use that as the primary buffer for BPF programs. To be able to change the size of the buffer, we change the device_event API and request it to return the size of the buffer. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/bpf/hid_bpf_dispatch.c | 116 ++++++++++++++++++++++++++++++++---- drivers/hid/bpf/hid_bpf_jmp_table.c | 4 +- drivers/hid/hid-core.c | 12 +++- include/linux/hid_bpf.h | 37 ++++++++++-- 4 files changed, 151 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 0ef99caf937a..efd4e4b4a615 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -28,8 +28,9 @@ EXPORT_SYMBOL(hid_bpf_ops); * * @ctx: The HID-BPF context * - * @return %0 on success and keep processing; a negative error code to interrupt - * the processing of this event + * @return %0 on success and keep processing; a positive value to change the + * incoming size buffer; a negative error code to interrupt the processing + * of this event * * Declare an %fmod_ret tracing bpf program to this function and attach this * program through hid_bpf_attach_prog() to have this helper called for @@ -44,23 +45,43 @@ __weak noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx) } ALLOW_ERROR_INJECTION(hid_bpf_device_event, ERRNO); -int +u8 * dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data, - u32 size, int interrupt) + u32 *size, int interrupt) { struct hid_bpf_ctx_kern ctx_kern = { .ctx = { .hid = hdev, .report_type = type, - .size = size, + .allocated_size = hdev->bpf.allocated_data, + .size = *size, }, - .data = data, + .data = hdev->bpf.device_data, }; + int ret; if (type >= HID_REPORT_TYPES) - return -EINVAL; + return ERR_PTR(-EINVAL); + + /* no program has been attached yet */ + if (!hdev->bpf.device_data) + return data; + + memset(ctx_kern.data, 0, hdev->bpf.allocated_data); + memcpy(ctx_kern.data, data, *size); + + ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern); + if (ret < 0) + return ERR_PTR(ret); + + if (ret) { + if (ret > ctx_kern.ctx.allocated_size) + return ERR_PTR(-EINVAL); - return hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern); + *size = ret; + } + + return ctx_kern.data; } EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event); @@ -83,7 +104,7 @@ hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); - if (rdwr_buf_size + offset > ctx->size) + if (rdwr_buf_size + offset > ctx->allocated_size) return NULL; return ctx_kern->data + offset; @@ -110,6 +131,51 @@ static int device_match_id(struct device *dev, const void *id) return hdev->id == *(int *)id; } +static int __hid_bpf_allocate_data(struct hid_device *hdev, u8 **data, u32 *size) +{ + u8 *alloc_data; + unsigned int i, j, max_report_len = 0; + size_t alloc_size = 0; + + /* compute the maximum report length for this device */ + for (i = 0; i < HID_REPORT_TYPES; i++) { + struct hid_report_enum *report_enum = hdev->report_enum + i; + + for (j = 0; j < HID_MAX_IDS; j++) { + struct hid_report *report = report_enum->report_id_hash[j]; + + if (report) + max_report_len = max(max_report_len, hid_report_len(report)); + } + } + + /* + * Give us a little bit of extra space and some predictability in the + * buffer length we create. This way, we can tell users that they can + * work on chunks of 64 bytes of memory without having the bpf verifier + * scream at them. + */ + alloc_size = DIV_ROUND_UP(max_report_len, 64) * 64; + + alloc_data = kzalloc(alloc_size, GFP_KERNEL); + if (!alloc_data) + return -ENOMEM; + + *data = alloc_data; + *size = alloc_size; + + return 0; +} + +static int hid_bpf_allocate_event_data(struct hid_device *hdev) +{ + /* hdev->bpf.device_data is already allocated, abort */ + if (hdev->bpf.device_data) + return 0; + + return __hid_bpf_allocate_data(hdev, &hdev->bpf.device_data, &hdev->bpf.allocated_data); +} + /** * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device * @@ -125,7 +191,7 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) { struct hid_device *hdev; struct device *dev; - int prog_type = hid_bpf_get_prog_attach_type(prog_fd); + int err, prog_type = hid_bpf_get_prog_attach_type(prog_fd); if (!hid_bpf_ops) return -EINVAL; @@ -145,6 +211,12 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) hdev = to_hid_device(dev); + if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) { + err = hid_bpf_allocate_event_data(hdev); + if (err) + return err; + } + return __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags); } @@ -158,6 +230,30 @@ static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = { .set = &hid_bpf_syscall_kfunc_ids, }; +int hid_bpf_connect_device(struct hid_device *hdev) +{ + struct hid_bpf_prog_list *prog_list; + + rcu_read_lock(); + prog_list = rcu_dereference(hdev->bpf.progs[HID_BPF_PROG_TYPE_DEVICE_EVENT]); + rcu_read_unlock(); + + /* only allocate BPF data if there are programs attached */ + if (!prog_list) + return 0; + + return hid_bpf_allocate_event_data(hdev); +} +EXPORT_SYMBOL_GPL(hid_bpf_connect_device); + +void hid_bpf_disconnect_device(struct hid_device *hdev) +{ + kfree(hdev->bpf.device_data); + hdev->bpf.device_data = NULL; + hdev->bpf.allocated_data = 0; +} +EXPORT_SYMBOL_GPL(hid_bpf_disconnect_device); + void hid_bpf_destroy_device(struct hid_device *hdev) { if (!hdev) diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c index e5f171ab480c..bfcdd7b805a9 100644 --- a/drivers/hid/bpf/hid_bpf_jmp_table.c +++ b/drivers/hid/bpf/hid_bpf_jmp_table.c @@ -122,8 +122,10 @@ int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type, ctx_kern->ctx.index = idx; err = __hid_bpf_tail_call(&ctx_kern->ctx); - if (err) + if (err < 0) break; + if (err) + ctx_kern->ctx.retval = err; } out_unlock: diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 1098c49b5d2e..400a7b8133c6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2040,9 +2040,11 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data report_enum = hid->report_enum + type; hdrv = hid->driver; - ret = dispatch_hid_bpf_device_event(hid, type, data, size, interrupt); - if (ret) + data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt); + if (IS_ERR(data)) { + ret = PTR_ERR(data); goto unlock; + } if (!size) { dbg_hid("empty report\n"); @@ -2158,6 +2160,10 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) int len; int ret; + ret = hid_bpf_connect_device(hdev); + if (ret) + return ret; + if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE) connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV); if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE) @@ -2259,6 +2265,8 @@ void hid_disconnect(struct hid_device *hdev) if (hdev->claimed & HID_CLAIMED_HIDRAW) hidraw_disconnect(hdev); hdev->claimed = 0; + + hid_bpf_disconnect_device(hdev); } EXPORT_SYMBOL_GPL(hid_disconnect); diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index de3fb1c376d2..b3de462ef3a6 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -28,15 +28,32 @@ struct hid_device; * a bigger index). * @hid: the ``struct hid_device`` representing the device itself * @report_type: used for ``hid_bpf_device_event()`` + * @allocated_size: Allocated size of data. + * + * This is how much memory is available and can be requested + * by the HID program. + * Note that for ``HID_BPF_RDESC_FIXUP``, that memory is set to + * ``4096`` (4 KB) * @size: Valid data in the data field. * * Programs can get the available valid size in data by fetching this field. + * Programs can also change this value by returning a positive number in the + * program. + * To discard the event, return a negative error code. + * + * ``size`` must always be less or equal than ``allocated_size`` (it is enforced + * once all BPF programs have been run). + * @retval: Return value of the previous program. */ struct hid_bpf_ctx { __u32 index; const struct hid_device *hid; + __u32 allocated_size; enum hid_report_type report_type; - __s32 size; + union { + __s32 retval; + __s32 size; + }; }; /** @@ -96,6 +113,12 @@ struct hid_bpf_prog_list { /* stored in each device */ struct hid_bpf { + u8 *device_data; /* allocated when a bpf program of type + * SEC(f.../hid_bpf_device_event) has been attached + * to this HID device + */ + u32 allocated_data; + struct hid_bpf_prog_list __rcu *progs[HID_BPF_PROG_TYPE_MAX]; /* attached BPF progs */ bool destroyed; /* prevents the assignment of any progs */ @@ -103,13 +126,17 @@ struct hid_bpf { }; #ifdef CONFIG_HID_BPF -int dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, - u32 size, int interrupt); +u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, + u32 *size, int interrupt); +int hid_bpf_connect_device(struct hid_device *hdev); +void hid_bpf_disconnect_device(struct hid_device *hdev); void hid_bpf_destroy_device(struct hid_device *hid); void hid_bpf_device_init(struct hid_device *hid); #else /* CONFIG_HID_BPF */ -static inline int dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 size, int interrupt) { return 0; } +static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, + u8 *data, u32 *size, int interrupt) { return NULL; } +static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } +static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} static inline void hid_bpf_device_init(struct hid_device *hid) {} #endif /* CONFIG_HID_BPF */ -- cgit v1.2.3 From 91a7f802d1852f60139712bdcfa98db547ce0531 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 3 Nov 2022 16:57:49 +0100 Subject: HID: bpf: introduce hid_hw_request() This function can not be called under IRQ, thus it is only available while in SEC("syscall"). For consistency, this function requires a HID-BPF context to work with, and so we also provide a helper to create one based on the HID unique ID. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Benjamin Tissoires -- changes in v12: - variable dereferenced before check 'ctx' |Reported-by: kernel test robot |Reported-by: Dan Carpenter no changes in v11 no changes in v10 changes in v9: - fixed kfunc declaration aaccording to latest upstream changes no changes in v8 changes in v7: - hid_bpf_allocate_context: remove unused variable - ensures buf is not NULL changes in v6: - rename parameter size into buf__sz to teach the verifier about the actual buffer size used by the call - remove the allocated data in the user created context, it's not used new-ish in v5 Signed-off-by: Jiri Kosina --- drivers/hid/bpf/hid_bpf_dispatch.c | 134 +++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 2 + include/linux/hid_bpf.h | 13 +++- 3 files changed, 148 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index efd4e4b4a615..0fe856d67f12 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -220,9 +220,143 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) return __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags); } +/** + * hid_bpf_allocate_context - Allocate a context to the given HID device + * + * @hid_id: the system unique identifier of the HID device + * + * @returns A pointer to &struct hid_bpf_ctx on success, %NULL on error. + */ +noinline struct hid_bpf_ctx * +hid_bpf_allocate_context(unsigned int hid_id) +{ + struct hid_device *hdev; + struct hid_bpf_ctx_kern *ctx_kern = NULL; + struct device *dev; + + if (!hid_bpf_ops) + return NULL; + + dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id); + if (!dev) + return NULL; + + hdev = to_hid_device(dev); + + ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL); + if (!ctx_kern) + return NULL; + + ctx_kern->ctx.hid = hdev; + + return &ctx_kern->ctx; +} + +/** + * hid_bpf_release_context - Release the previously allocated context @ctx + * + * @ctx: the HID-BPF context to release + * + */ +noinline void +hid_bpf_release_context(struct hid_bpf_ctx *ctx) +{ + struct hid_bpf_ctx_kern *ctx_kern; + + if (!ctx) + return; + + ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx); + + kfree(ctx_kern); +} + +/** + * hid_bpf_hw_request - Communicate with a HID device + * + * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context() + * @buf: a %PTR_TO_MEM buffer + * @buf__sz: the size of the data to transfer + * @rtype: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT) + * @reqtype: the type of the request (%HID_REQ_GET_REPORT, %HID_REQ_SET_REPORT, ...) + * + * @returns %0 on success, a negative error code otherwise. + */ +noinline int +hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, + enum hid_report_type rtype, enum hid_class_request reqtype) +{ + struct hid_device *hdev; + struct hid_report *report; + struct hid_report_enum *report_enum; + u8 *dma_data; + u32 report_len; + int ret; + + /* check arguments */ + if (!ctx || !hid_bpf_ops || !buf) + return -EINVAL; + + switch (rtype) { + case HID_INPUT_REPORT: + case HID_OUTPUT_REPORT: + case HID_FEATURE_REPORT: + break; + default: + return -EINVAL; + } + + switch (reqtype) { + case HID_REQ_GET_REPORT: + case HID_REQ_GET_IDLE: + case HID_REQ_GET_PROTOCOL: + case HID_REQ_SET_REPORT: + case HID_REQ_SET_IDLE: + case HID_REQ_SET_PROTOCOL: + break; + default: + return -EINVAL; + } + + if (buf__sz < 1) + return -EINVAL; + + hdev = (struct hid_device *)ctx->hid; /* discard const */ + + report_enum = hdev->report_enum + rtype; + report = hid_bpf_ops->hid_get_report(report_enum, buf); + if (!report) + return -EINVAL; + + report_len = hid_report_len(report); + + if (buf__sz > report_len) + buf__sz = report_len; + + dma_data = kmemdup(buf, buf__sz, GFP_KERNEL); + if (!dma_data) + return -ENOMEM; + + ret = hid_bpf_ops->hid_hw_raw_request(hdev, + dma_data[0], + dma_data, + buf__sz, + rtype, + reqtype); + + if (ret > 0) + memcpy(buf, dma_data, ret); + + kfree(dma_data); + return ret; +} + /* for syscall HID-BPF */ BTF_SET8_START(hid_bpf_syscall_kfunc_ids) BTF_ID_FLAGS(func, hid_bpf_attach_prog) +BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE) +BTF_ID_FLAGS(func, hid_bpf_hw_request) BTF_SET8_END(hid_bpf_syscall_kfunc_ids) static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = { diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 400a7b8133c6..6bf47e352f23 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2919,6 +2919,8 @@ EXPORT_SYMBOL_GPL(hid_check_keys_pressed); #ifdef CONFIG_HID_BPF static struct hid_bpf_ops hid_ops = { + .hid_get_report = hid_get_report, + .hid_hw_raw_request = hid_hw_raw_request, .owner = THIS_MODULE, .bus_type = &hid_bus_type, }; diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index b3de462ef3a6..1d24b72059bc 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -76,11 +76,15 @@ enum hid_bpf_attach_flags { int hid_bpf_device_event(struct hid_bpf_ctx *ctx); /* Following functions are kfunc that we export to BPF programs */ -/* only available in tracing */ +/* available everywhere in HID-BPF */ __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz); /* only available in syscall */ int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags); +int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, + enum hid_report_type rtype, enum hid_class_request reqtype); +struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id); +void hid_bpf_release_context(struct hid_bpf_ctx *ctx); /* * Below is HID internal @@ -99,7 +103,14 @@ enum hid_bpf_prog_type { HID_BPF_PROG_TYPE_MAX, }; +struct hid_report_enum; + struct hid_bpf_ops { + struct hid_report *(*hid_get_report)(struct hid_report_enum *report_enum, const u8 *data); + int (*hid_hw_raw_request)(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, + size_t len, enum hid_report_type rtype, + enum hid_class_request reqtype); struct module *owner; struct bus_type *bus_type; }; -- cgit v1.2.3 From ad190df11a024c1214fbc8dcaab72c592c79d9b5 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 3 Nov 2022 16:57:51 +0100 Subject: HID: bpf: allow to change the report descriptor Add a new tracepoint hid_bpf_rdesc_fixup() so we can trigger a report descriptor fixup in the bpf world. Whenever the program gets attached/detached, the device is reconnected meaning that userspace will see it disappearing and reappearing with the new report descriptor. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/bpf/hid_bpf_dispatch.c | 80 ++++++++++++++++++++++++++++++++++++- drivers/hid/bpf/hid_bpf_dispatch.h | 1 + drivers/hid/bpf/hid_bpf_jmp_table.c | 7 ++++ drivers/hid/hid-core.c | 3 +- include/linux/hid_bpf.h | 8 ++++ 5 files changed, 97 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 0fe856d67f12..c3920c7964dc 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include "hid_bpf_dispatch.h" @@ -85,6 +86,65 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type } EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event); +/** + * hid_bpf_rdesc_fixup - Called when the probe function parses the report + * descriptor of the HID device + * + * @ctx: The HID-BPF context + * + * @return 0 on success and keep processing; a positive value to change the + * incoming size buffer; a negative error code to interrupt the processing + * of this event + * + * Declare an %fmod_ret tracing bpf program to this function and attach this + * program through hid_bpf_attach_prog() to have this helper called before any + * parsing of the report descriptor by HID. + */ +/* never used by the kernel but declared so we can load and attach a tracepoint */ +__weak noinline int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx) +{ + return 0; +} +ALLOW_ERROR_INJECTION(hid_bpf_rdesc_fixup, ERRNO); + +u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size) +{ + int ret; + struct hid_bpf_ctx_kern ctx_kern = { + .ctx = { + .hid = hdev, + .size = *size, + .allocated_size = HID_MAX_DESCRIPTOR_SIZE, + }, + }; + + ctx_kern.data = kzalloc(ctx_kern.ctx.allocated_size, GFP_KERNEL); + if (!ctx_kern.data) + goto ignore_bpf; + + memcpy(ctx_kern.data, rdesc, min_t(unsigned int, *size, HID_MAX_DESCRIPTOR_SIZE)); + + ret = hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_RDESC_FIXUP, &ctx_kern); + if (ret < 0) + goto ignore_bpf; + + if (ret) { + if (ret > ctx_kern.ctx.allocated_size) + goto ignore_bpf; + + *size = ret; + } + + rdesc = krealloc(ctx_kern.data, *size, GFP_KERNEL); + + return rdesc; + + ignore_bpf: + kfree(ctx_kern.data); + return kmemdup(rdesc, *size, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup); + /** * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx * @@ -176,6 +236,14 @@ static int hid_bpf_allocate_event_data(struct hid_device *hdev) return __hid_bpf_allocate_data(hdev, &hdev->bpf.device_data, &hdev->bpf.allocated_data); } +int hid_bpf_reconnect(struct hid_device *hdev) +{ + if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) + return device_reprobe(&hdev->dev); + + return 0; +} + /** * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device * @@ -217,7 +285,17 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags) return err; } - return __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags); + err = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags); + if (err) + return err; + + if (prog_type == HID_BPF_PROG_TYPE_RDESC_FIXUP) { + err = hid_bpf_reconnect(hdev); + if (err) + return err; + } + + return 0; } /** diff --git a/drivers/hid/bpf/hid_bpf_dispatch.h b/drivers/hid/bpf/hid_bpf_dispatch.h index e2d64faa3932..2eeab1f746dd 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.h +++ b/drivers/hid/bpf/hid_bpf_dispatch.h @@ -18,6 +18,7 @@ int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_t void __hid_bpf_destroy_device(struct hid_device *hdev); int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type, struct hid_bpf_ctx_kern *ctx_kern); +int hid_bpf_reconnect(struct hid_device *hdev); struct bpf_prog; diff --git a/drivers/hid/bpf/hid_bpf_jmp_table.c b/drivers/hid/bpf/hid_bpf_jmp_table.c index bfcdd7b805a9..579a6c06906e 100644 --- a/drivers/hid/bpf/hid_bpf_jmp_table.c +++ b/drivers/hid/bpf/hid_bpf_jmp_table.c @@ -58,12 +58,15 @@ static DECLARE_WORK(release_work, hid_bpf_release_progs); BTF_ID_LIST(hid_bpf_btf_ids) BTF_ID(func, hid_bpf_device_event) /* HID_BPF_PROG_TYPE_DEVICE_EVENT */ +BTF_ID(func, hid_bpf_rdesc_fixup) /* HID_BPF_PROG_TYPE_RDESC_FIXUP */ static int hid_bpf_max_programs(enum hid_bpf_prog_type type) { switch (type) { case HID_BPF_PROG_TYPE_DEVICE_EVENT: return HID_BPF_MAX_PROGS_PER_DEV; + case HID_BPF_PROG_TYPE_RDESC_FIXUP: + return 1; default: return -EINVAL; } @@ -233,6 +236,10 @@ static void hid_bpf_release_progs(struct work_struct *work) if (next->hdev == hdev && next->type == type) next->hdev = NULL; } + + /* if type was rdesc fixup, reconnect device */ + if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP) + hid_bpf_reconnect(hdev); } } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6bf47e352f23..fa4436b8101e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1218,7 +1218,8 @@ int hid_open_report(struct hid_device *device) return -ENODEV; size = device->dev_rsize; - buf = kmemdup(start, size, GFP_KERNEL); + /* call_hid_bpf_rdesc_fixup() ensures we work on a copy of rdesc */ + buf = call_hid_bpf_rdesc_fixup(device, start, &size); if (buf == NULL) return -ENOMEM; diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 1d24b72059bc..9b11f8f25ad5 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -74,6 +74,7 @@ enum hid_bpf_attach_flags { /* Following functions are tracepoints that BPF programs can attach to */ int hid_bpf_device_event(struct hid_bpf_ctx *ctx); +int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx); /* Following functions are kfunc that we export to BPF programs */ /* available everywhere in HID-BPF */ @@ -100,6 +101,7 @@ int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx); enum hid_bpf_prog_type { HID_BPF_PROG_TYPE_UNDEF = -1, HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */ + HID_BPF_PROG_TYPE_RDESC_FIXUP, HID_BPF_PROG_TYPE_MAX, }; @@ -143,6 +145,7 @@ int hid_bpf_connect_device(struct hid_device *hdev); void hid_bpf_disconnect_device(struct hid_device *hdev); void hid_bpf_destroy_device(struct hid_device *hid); void hid_bpf_device_init(struct hid_device *hid); +u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size); #else /* CONFIG_HID_BPF */ static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 *size, int interrupt) { return NULL; } @@ -150,6 +153,11 @@ static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} static inline void hid_bpf_device_init(struct hid_device *hid) {} +static inline u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size) +{ + return kmemdup(rdesc, *size, GFP_KERNEL); +} + #endif /* CONFIG_HID_BPF */ #endif /* __HID_BPF_H */ -- cgit v1.2.3 From 576e619ba4a47329bf55ada2d184e72529793fbd Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 16 Nov 2022 11:31:10 +0100 Subject: HID: bpf: return non NULL data pointer when CONFIG_HID_BPF is not set dispatch_hid_bpf_device_event() is supposed to return either an error, or a valid pointer to memory containing the data. Returning NULL simply makes a segfault when CONFIG_HID_BPF is not set for any processed event. Fixes: 658ee5a64fcfbbf ("HID: bpf: allocate data memory for device_event BPF program") Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- include/linux/hid_bpf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h index 9b11f8f25ad5..3ca85ab91325 100644 --- a/include/linux/hid_bpf.h +++ b/include/linux/hid_bpf.h @@ -148,7 +148,7 @@ void hid_bpf_device_init(struct hid_device *hid); u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size); #else /* CONFIG_HID_BPF */ static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 *size, int interrupt) { return NULL; } + u8 *data, u32 *size, int interrupt) { return data; } static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {} -- cgit v1.2.3 From d878d3dc126db05b075147456644bd2d2ab1fb5e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 9 Dec 2022 16:07:22 +0100 Subject: wifi: mt76: mt7915: get rid of wed rx_buf_ring page_frag_cache Since wed rx_buf_ring page_frag_cache is no longer used in a hot path, remove it and rely on page allocation APIs in mt7915_mmio_wed_init_rx_buf() and mt7915_mmio_wed_release_rx_buf() Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 25 +++++++++++------------- include/linux/soc/mediatek/mtk_wed.h | 1 - 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index afa558c9a930..1a2e4df8d1b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -594,10 +594,13 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) { struct mt7915_dev *dev; - struct page *page; + u32 length; int i; dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + length = SKB_DATA_ALIGN(NET_SKB_PAD + wed->wlan.rx_size + + sizeof(struct skb_shared_info)); + for (i = 0; i < dev->mt76.rx_token_size; i++) { struct mt76_txwi_cache *t; @@ -607,18 +610,11 @@ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) dma_unmap_single(dev->mt76.dma_dev, t->dma_addr, wed->wlan.rx_size, DMA_FROM_DEVICE); - skb_free_frag(t->ptr); + __free_pages(virt_to_page(t->ptr), get_order(length)); t->ptr = NULL; mt76_put_rxwi(&dev->mt76, t); } - - if (!wed->rx_buf_ring.rx_page.va) - return; - - page = virt_to_page(wed->rx_buf_ring.rx_page.va); - __page_frag_cache_drain(page, wed->rx_buf_ring.rx_page.pagecnt_bias); - memset(&wed->rx_buf_ring.rx_page, 0, sizeof(wed->rx_buf_ring.rx_page)); } static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) @@ -635,19 +631,20 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) for (i = 0; i < size; i++) { struct mt76_txwi_cache *t = mt76_get_rxwi(&dev->mt76); dma_addr_t phy_addr; + struct page *page; int token; void *ptr; - ptr = page_frag_alloc(&wed->rx_buf_ring.rx_page, length, - GFP_KERNEL); - if (!ptr) + page = __dev_alloc_pages(GFP_KERNEL, get_order(length)); + if (!page) goto unmap; + ptr = page_address(page); phy_addr = dma_map_single(dev->mt76.dma_dev, ptr, wed->wlan.rx_size, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev->mt76.dev, phy_addr))) { - skb_free_frag(ptr); + __free_pages(page, get_order(length)); goto unmap; } @@ -656,7 +653,7 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) if (token < 0) { dma_unmap_single(dev->mt76.dma_dev, phy_addr, wed->wlan.rx_size, DMA_TO_DEVICE); - skb_free_frag(ptr); + __free_pages(page, get_order(length)); goto unmap; } diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h index beb190449704..7293259dc1f8 100644 --- a/include/linux/soc/mediatek/mtk_wed.h +++ b/include/linux/soc/mediatek/mtk_wed.h @@ -103,7 +103,6 @@ struct mtk_wed_device { struct { int size; - struct page_frag_cache rx_page; struct mtk_rxbm_desc *desc; dma_addr_t desc_phys; } rx_buf_ring; -- cgit v1.2.3 From 78aa1cc9404399a15d2a1205329c6a06236f5378 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 15 Dec 2022 22:44:28 +0100 Subject: bpf: Add struct for bin_args arg in bpf_bprintf_prepare Adding struct bpf_bprintf_data to hold bin_args argument for bpf_bprintf_prepare function. We will add another return argument to bpf_bprintf_prepare and pass the struct to bpf_bprintf_cleanup for proper cleanup in following changes. Signed-off-by: Jiri Olsa Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20221215214430.1336195-2-jolsa@kernel.org --- include/linux/bpf.h | 7 ++++++- kernel/bpf/helpers.c | 24 +++++++++++++----------- kernel/bpf/verifier.c | 3 ++- kernel/trace/bpf_trace.c | 34 ++++++++++++++++++++-------------- 4 files changed, 41 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 3de24cfb7a3d..cc390ba32e70 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2796,8 +2796,13 @@ bool btf_id_set_contains(const struct btf_id_set *set, u32 id); #define MAX_BPRINTF_VARARGS 12 +struct bpf_bprintf_data { + u32 *bin_args; + bool get_bin_args; +}; + int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, - u32 **bin_buf, u32 num_args); + u32 num_args, struct bpf_bprintf_data *data); void bpf_bprintf_cleanup(void); /* the implementation of the opaque uapi struct bpf_dynptr */ diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index af30c6cbd65d..7dbf6bb72cad 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -798,16 +798,16 @@ void bpf_bprintf_cleanup(void) * Returns a negative value if fmt is an invalid format string or 0 otherwise. * * This can be used in two ways: - * - Format string verification only: when bin_args is NULL + * - Format string verification only: when data->get_bin_args is false * - Arguments preparation: in addition to the above verification, it writes in - * bin_args a binary representation of arguments usable by bstr_printf where - * pointers from BPF have been sanitized. + * data->bin_args a binary representation of arguments usable by bstr_printf + * where pointers from BPF have been sanitized. * * In argument preparation mode, if 0 is returned, safe temporary buffers are * allocated and bpf_bprintf_cleanup should be called to free them after use. */ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, - u32 **bin_args, u32 num_args) + u32 num_args, struct bpf_bprintf_data *data) { char *unsafe_ptr = NULL, *tmp_buf = NULL, *tmp_buf_end, *fmt_end; size_t sizeof_cur_arg, sizeof_cur_ip; @@ -820,12 +820,12 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, return -EINVAL; fmt_size = fmt_end - fmt; - if (bin_args) { + if (data->get_bin_args) { if (num_args && try_get_fmt_tmp_buf(&tmp_buf)) return -EBUSY; tmp_buf_end = tmp_buf + MAX_BPRINTF_BUF_LEN; - *bin_args = (u32 *)tmp_buf; + data->bin_args = (u32 *)tmp_buf; } for (i = 0; i < fmt_size; i++) { @@ -1026,24 +1026,26 @@ out: } BPF_CALL_5(bpf_snprintf, char *, str, u32, str_size, char *, fmt, - const void *, data, u32, data_len) + const void *, args, u32, data_len) { + struct bpf_bprintf_data data = { + .get_bin_args = true, + }; int err, num_args; - u32 *bin_args; if (data_len % 8 || data_len > MAX_BPRINTF_VARARGS * 8 || - (data_len && !data)) + (data_len && !args)) return -EINVAL; num_args = data_len / 8; /* ARG_PTR_TO_CONST_STR guarantees that fmt is zero-terminated so we * can safely give an unbounded size. */ - err = bpf_bprintf_prepare(fmt, UINT_MAX, data, &bin_args, num_args); + err = bpf_bprintf_prepare(fmt, UINT_MAX, args, num_args, &data); if (err < 0) return err; - err = bstr_printf(str, str_size, fmt, bin_args); + err = bstr_printf(str, str_size, fmt, data.bin_args); bpf_bprintf_cleanup(); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a5255a0dcbb6..faa358b3d5d7 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -7612,6 +7612,7 @@ static int check_bpf_snprintf_call(struct bpf_verifier_env *env, struct bpf_reg_state *fmt_reg = ®s[BPF_REG_3]; struct bpf_reg_state *data_len_reg = ®s[BPF_REG_5]; struct bpf_map *fmt_map = fmt_reg->map_ptr; + struct bpf_bprintf_data data = {}; int err, fmt_map_off, num_args; u64 fmt_addr; char *fmt; @@ -7636,7 +7637,7 @@ static int check_bpf_snprintf_call(struct bpf_verifier_env *env, /* We are also guaranteed that fmt+fmt_map_off is NULL terminated, we * can focus on validating the format specifiers. */ - err = bpf_bprintf_prepare(fmt, UINT_MAX, NULL, NULL, num_args); + err = bpf_bprintf_prepare(fmt, UINT_MAX, NULL, num_args, &data); if (err < 0) verbose(env, "Invalid format string\n"); diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 3bbd3f0c810c..3e849c3a7cc8 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -378,18 +378,20 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, u64, arg2, u64, arg3) { u64 args[MAX_TRACE_PRINTK_VARARGS] = { arg1, arg2, arg3 }; - u32 *bin_args; + struct bpf_bprintf_data data = { + .get_bin_args = true, + }; static char buf[BPF_TRACE_PRINTK_SIZE]; unsigned long flags; int ret; - ret = bpf_bprintf_prepare(fmt, fmt_size, args, &bin_args, - MAX_TRACE_PRINTK_VARARGS); + ret = bpf_bprintf_prepare(fmt, fmt_size, args, + MAX_TRACE_PRINTK_VARARGS, &data); if (ret < 0) return ret; raw_spin_lock_irqsave(&trace_printk_lock, flags); - ret = bstr_printf(buf, sizeof(buf), fmt, bin_args); + ret = bstr_printf(buf, sizeof(buf), fmt, data.bin_args); trace_bpf_trace_printk(buf); raw_spin_unlock_irqrestore(&trace_printk_lock, flags); @@ -427,25 +429,27 @@ const struct bpf_func_proto *bpf_get_trace_printk_proto(void) return &bpf_trace_printk_proto; } -BPF_CALL_4(bpf_trace_vprintk, char *, fmt, u32, fmt_size, const void *, data, +BPF_CALL_4(bpf_trace_vprintk, char *, fmt, u32, fmt_size, const void *, args, u32, data_len) { + struct bpf_bprintf_data data = { + .get_bin_args = true, + }; static char buf[BPF_TRACE_PRINTK_SIZE]; unsigned long flags; int ret, num_args; - u32 *bin_args; if (data_len & 7 || data_len > MAX_BPRINTF_VARARGS * 8 || - (data_len && !data)) + (data_len && !args)) return -EINVAL; num_args = data_len / 8; - ret = bpf_bprintf_prepare(fmt, fmt_size, data, &bin_args, num_args); + ret = bpf_bprintf_prepare(fmt, fmt_size, args, num_args, &data); if (ret < 0) return ret; raw_spin_lock_irqsave(&trace_printk_lock, flags); - ret = bstr_printf(buf, sizeof(buf), fmt, bin_args); + ret = bstr_printf(buf, sizeof(buf), fmt, data.bin_args); trace_bpf_trace_printk(buf); raw_spin_unlock_irqrestore(&trace_printk_lock, flags); @@ -472,21 +476,23 @@ const struct bpf_func_proto *bpf_get_trace_vprintk_proto(void) } BPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size, - const void *, data, u32, data_len) + const void *, args, u32, data_len) { + struct bpf_bprintf_data data = { + .get_bin_args = true, + }; int err, num_args; - u32 *bin_args; if (data_len & 7 || data_len > MAX_BPRINTF_VARARGS * 8 || - (data_len && !data)) + (data_len && !args)) return -EINVAL; num_args = data_len / 8; - err = bpf_bprintf_prepare(fmt, fmt_size, data, &bin_args, num_args); + err = bpf_bprintf_prepare(fmt, fmt_size, args, num_args, &data); if (err < 0) return err; - seq_bprintf(m, fmt, bin_args); + seq_bprintf(m, fmt, data.bin_args); bpf_bprintf_cleanup(); -- cgit v1.2.3 From f19a4050455aad847fb93f18dc1fe502eb60f989 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 15 Dec 2022 22:44:29 +0100 Subject: bpf: Do cleanup in bpf_bprintf_cleanup only when needed Currently we always cleanup/decrement bpf_bprintf_nest_level variable in bpf_bprintf_cleanup if it's > 0. There's possible scenario where this could cause a problem, when bpf_bprintf_prepare does not get bin_args buffer (because num_args is 0) and following bpf_bprintf_cleanup call decrements bpf_bprintf_nest_level variable, like: in task context: bpf_bprintf_prepare(num_args != 0) increments 'bpf_bprintf_nest_level = 1' -> first irq : bpf_bprintf_prepare(num_args == 0) bpf_bprintf_cleanup decrements 'bpf_bprintf_nest_level = 0' -> second irq: bpf_bprintf_prepare(num_args != 0) bpf_bprintf_nest_level = 1 gets same buffer as task context above Adding check to bpf_bprintf_cleanup and doing the real cleanup only if we got bin_args data in the first place. Signed-off-by: Jiri Olsa Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20221215214430.1336195-3-jolsa@kernel.org --- include/linux/bpf.h | 2 +- kernel/bpf/helpers.c | 16 +++++++++------- kernel/trace/bpf_trace.c | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index cc390ba32e70..656879385fbf 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2803,7 +2803,7 @@ struct bpf_bprintf_data { int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, u32 num_args, struct bpf_bprintf_data *data); -void bpf_bprintf_cleanup(void); +void bpf_bprintf_cleanup(struct bpf_bprintf_data *data); /* the implementation of the opaque uapi struct bpf_dynptr */ struct bpf_dynptr_kern { diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 7dbf6bb72cad..9cca02e13f2e 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -784,12 +784,14 @@ static int try_get_fmt_tmp_buf(char **tmp_buf) return 0; } -void bpf_bprintf_cleanup(void) +void bpf_bprintf_cleanup(struct bpf_bprintf_data *data) { - if (this_cpu_read(bpf_bprintf_nest_level)) { - this_cpu_dec(bpf_bprintf_nest_level); - preempt_enable(); - } + if (!data->bin_args) + return; + if (WARN_ON_ONCE(this_cpu_read(bpf_bprintf_nest_level) == 0)) + return; + this_cpu_dec(bpf_bprintf_nest_level); + preempt_enable(); } /* @@ -1021,7 +1023,7 @@ nocopy_fmt: err = 0; out: if (err) - bpf_bprintf_cleanup(); + bpf_bprintf_cleanup(data); return err; } @@ -1047,7 +1049,7 @@ BPF_CALL_5(bpf_snprintf, char *, str, u32, str_size, char *, fmt, err = bstr_printf(str, str_size, fmt, data.bin_args); - bpf_bprintf_cleanup(); + bpf_bprintf_cleanup(&data); return err + 1; } diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 3e849c3a7cc8..2129f7c68bb5 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -396,7 +396,7 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, trace_bpf_trace_printk(buf); raw_spin_unlock_irqrestore(&trace_printk_lock, flags); - bpf_bprintf_cleanup(); + bpf_bprintf_cleanup(&data); return ret; } @@ -454,7 +454,7 @@ BPF_CALL_4(bpf_trace_vprintk, char *, fmt, u32, fmt_size, const void *, args, trace_bpf_trace_printk(buf); raw_spin_unlock_irqrestore(&trace_printk_lock, flags); - bpf_bprintf_cleanup(); + bpf_bprintf_cleanup(&data); return ret; } @@ -494,7 +494,7 @@ BPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size, seq_bprintf(m, fmt, data.bin_args); - bpf_bprintf_cleanup(); + bpf_bprintf_cleanup(&data); return seq_has_overflowed(m) ? -EOVERFLOW : 0; } -- cgit v1.2.3 From e2bb9e01d589f7fa82573aedd2765ff9b277816a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 15 Dec 2022 22:44:30 +0100 Subject: bpf: Remove trace_printk_lock Both bpf_trace_printk and bpf_trace_vprintk helpers use static buffer guarded with trace_printk_lock spin lock. The spin lock contention causes issues with bpf programs attached to contention_begin tracepoint [1][2]. Andrii suggested we could get rid of the contention by using trylock, but we could actually get rid of the spinlock completely by using percpu buffers the same way as for bin_args in bpf_bprintf_prepare function. Adding new return 'buf' argument to struct bpf_bprintf_data and making bpf_bprintf_prepare to return also the buffer for printk helpers. [1] https://lore.kernel.org/bpf/CACkBjsakT_yWxnSWr4r-0TpPvbKm9-OBmVUhJb7hV3hY8fdCkw@mail.gmail.com/ [2] https://lore.kernel.org/bpf/CACkBjsaCsTovQHFfkqJKto6S4Z8d02ud1D7MPESrHa1cVNNTrw@mail.gmail.com/ Reported-by: Hao Sun Suggested-by: Andrii Nakryiko Signed-off-by: Jiri Olsa Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20221215214430.1336195-4-jolsa@kernel.org --- include/linux/bpf.h | 3 +++ kernel/bpf/helpers.c | 31 +++++++++++++++++++------------ kernel/trace/bpf_trace.c | 20 ++++++-------------- 3 files changed, 28 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 656879385fbf..5fec2d1be6d7 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2795,10 +2795,13 @@ struct btf_id_set; bool btf_id_set_contains(const struct btf_id_set *set, u32 id); #define MAX_BPRINTF_VARARGS 12 +#define MAX_BPRINTF_BUF 1024 struct bpf_bprintf_data { u32 *bin_args; + char *buf; bool get_bin_args; + bool get_buf; }; int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 9cca02e13f2e..23aa8cf8fd1a 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -756,19 +756,20 @@ static int bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype, /* Per-cpu temp buffers used by printf-like helpers to store the bprintf binary * arguments representation. */ -#define MAX_BPRINTF_BUF_LEN 512 +#define MAX_BPRINTF_BIN_ARGS 512 /* Support executing three nested bprintf helper calls on a given CPU */ #define MAX_BPRINTF_NEST_LEVEL 3 struct bpf_bprintf_buffers { - char tmp_bufs[MAX_BPRINTF_NEST_LEVEL][MAX_BPRINTF_BUF_LEN]; + char bin_args[MAX_BPRINTF_BIN_ARGS]; + char buf[MAX_BPRINTF_BUF]; }; -static DEFINE_PER_CPU(struct bpf_bprintf_buffers, bpf_bprintf_bufs); + +static DEFINE_PER_CPU(struct bpf_bprintf_buffers[MAX_BPRINTF_NEST_LEVEL], bpf_bprintf_bufs); static DEFINE_PER_CPU(int, bpf_bprintf_nest_level); -static int try_get_fmt_tmp_buf(char **tmp_buf) +static int try_get_buffers(struct bpf_bprintf_buffers **bufs) { - struct bpf_bprintf_buffers *bufs; int nest_level; preempt_disable(); @@ -778,15 +779,14 @@ static int try_get_fmt_tmp_buf(char **tmp_buf) preempt_enable(); return -EBUSY; } - bufs = this_cpu_ptr(&bpf_bprintf_bufs); - *tmp_buf = bufs->tmp_bufs[nest_level - 1]; + *bufs = this_cpu_ptr(&bpf_bprintf_bufs[nest_level - 1]); return 0; } void bpf_bprintf_cleanup(struct bpf_bprintf_data *data) { - if (!data->bin_args) + if (!data->bin_args && !data->buf) return; if (WARN_ON_ONCE(this_cpu_read(bpf_bprintf_nest_level) == 0)) return; @@ -811,7 +811,9 @@ void bpf_bprintf_cleanup(struct bpf_bprintf_data *data) int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, u32 num_args, struct bpf_bprintf_data *data) { + bool get_buffers = (data->get_bin_args && num_args) || data->get_buf; char *unsafe_ptr = NULL, *tmp_buf = NULL, *tmp_buf_end, *fmt_end; + struct bpf_bprintf_buffers *buffers = NULL; size_t sizeof_cur_arg, sizeof_cur_ip; int err, i, num_spec = 0; u64 cur_arg; @@ -822,14 +824,19 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args, return -EINVAL; fmt_size = fmt_end - fmt; - if (data->get_bin_args) { - if (num_args && try_get_fmt_tmp_buf(&tmp_buf)) - return -EBUSY; + if (get_buffers && try_get_buffers(&buffers)) + return -EBUSY; - tmp_buf_end = tmp_buf + MAX_BPRINTF_BUF_LEN; + if (data->get_bin_args) { + if (num_args) + tmp_buf = buffers->bin_args; + tmp_buf_end = tmp_buf + MAX_BPRINTF_BIN_ARGS; data->bin_args = (u32 *)tmp_buf; } + if (data->get_buf) + data->buf = buffers->buf; + for (i = 0; i < fmt_size; i++) { if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) { err = -EINVAL; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 2129f7c68bb5..23ce498bca97 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -369,8 +369,6 @@ static const struct bpf_func_proto *bpf_get_probe_write_proto(void) return &bpf_probe_write_user_proto; } -static DEFINE_RAW_SPINLOCK(trace_printk_lock); - #define MAX_TRACE_PRINTK_VARARGS 3 #define BPF_TRACE_PRINTK_SIZE 1024 @@ -380,9 +378,8 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, u64 args[MAX_TRACE_PRINTK_VARARGS] = { arg1, arg2, arg3 }; struct bpf_bprintf_data data = { .get_bin_args = true, + .get_buf = true, }; - static char buf[BPF_TRACE_PRINTK_SIZE]; - unsigned long flags; int ret; ret = bpf_bprintf_prepare(fmt, fmt_size, args, @@ -390,11 +387,9 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, if (ret < 0) return ret; - raw_spin_lock_irqsave(&trace_printk_lock, flags); - ret = bstr_printf(buf, sizeof(buf), fmt, data.bin_args); + ret = bstr_printf(data.buf, MAX_BPRINTF_BUF, fmt, data.bin_args); - trace_bpf_trace_printk(buf); - raw_spin_unlock_irqrestore(&trace_printk_lock, flags); + trace_bpf_trace_printk(data.buf); bpf_bprintf_cleanup(&data); @@ -434,9 +429,8 @@ BPF_CALL_4(bpf_trace_vprintk, char *, fmt, u32, fmt_size, const void *, args, { struct bpf_bprintf_data data = { .get_bin_args = true, + .get_buf = true, }; - static char buf[BPF_TRACE_PRINTK_SIZE]; - unsigned long flags; int ret, num_args; if (data_len & 7 || data_len > MAX_BPRINTF_VARARGS * 8 || @@ -448,11 +442,9 @@ BPF_CALL_4(bpf_trace_vprintk, char *, fmt, u32, fmt_size, const void *, args, if (ret < 0) return ret; - raw_spin_lock_irqsave(&trace_printk_lock, flags); - ret = bstr_printf(buf, sizeof(buf), fmt, data.bin_args); + ret = bstr_printf(data.buf, MAX_BPRINTF_BUF, fmt, data.bin_args); - trace_bpf_trace_printk(buf); - raw_spin_unlock_irqrestore(&trace_printk_lock, flags); + trace_bpf_trace_printk(data.buf); bpf_bprintf_cleanup(&data); -- cgit v1.2.3 From e26aa600ba6a62fe84659f1df497a381bab6d07e Mon Sep 17 00:00:00 2001 From: Christian Ehrig Date: Sun, 18 Dec 2022 06:17:31 +0100 Subject: bpf: Add flag BPF_F_NO_TUNNEL_KEY to bpf_skb_set_tunnel_key() This patch allows to remove TUNNEL_KEY from the tunnel flags bitmap when using bpf_skb_set_tunnel_key by providing a BPF_F_NO_TUNNEL_KEY flag. On egress, the resulting tunnel header will not contain a tunnel key if the protocol and implementation supports it. At the moment bpf_tunnel_key wants a user to specify a numeric tunnel key. This will wrap the inner packet into a tunnel header with the key bit and value set accordingly. This is problematic when using a tunnel protocol that supports optional tunnel keys and a receiving tunnel device that is not expecting packets with the key bit set. The receiver won't decapsulate and drop the packet. RFC 2890 and RFC 2784 GRE tunnels are examples where this flag is useful. It allows for generating packets, that can be decapsulated by a GRE tunnel device not operating in collect metadata mode or not expecting the key bit set. Signed-off-by: Christian Ehrig Signed-off-by: Daniel Borkmann Reviewed-by: Jakub Sitnicki Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20221218051734.31411-1-cehrig@cloudflare.com --- include/uapi/linux/bpf.h | 4 ++++ net/core/filter.c | 5 ++++- tools/include/uapi/linux/bpf.h | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 464ca3f01fe7..bc1a3d232ae4 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -2001,6 +2001,9 @@ union bpf_attr { * sending the packet. This flag was added for GRE * encapsulation, but might be used with other protocols * as well in the future. + * **BPF_F_NO_TUNNEL_KEY** + * Add a flag to tunnel metadata indicating that no tunnel + * key should be set in the resulting tunnel header. * * Here is a typical usage on the transmit path: * @@ -5764,6 +5767,7 @@ enum { BPF_F_ZERO_CSUM_TX = (1ULL << 1), BPF_F_DONT_FRAGMENT = (1ULL << 2), BPF_F_SEQ_NUMBER = (1ULL << 3), + BPF_F_NO_TUNNEL_KEY = (1ULL << 4), }; /* BPF_FUNC_skb_get_tunnel_key flags. */ diff --git a/net/core/filter.c b/net/core/filter.c index 929358677183..c746e4d77214 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4615,7 +4615,8 @@ BPF_CALL_4(bpf_skb_set_tunnel_key, struct sk_buff *, skb, struct ip_tunnel_info *info; if (unlikely(flags & ~(BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX | - BPF_F_DONT_FRAGMENT | BPF_F_SEQ_NUMBER))) + BPF_F_DONT_FRAGMENT | BPF_F_SEQ_NUMBER | + BPF_F_NO_TUNNEL_KEY))) return -EINVAL; if (unlikely(size != sizeof(struct bpf_tunnel_key))) { switch (size) { @@ -4653,6 +4654,8 @@ BPF_CALL_4(bpf_skb_set_tunnel_key, struct sk_buff *, skb, info->key.tun_flags &= ~TUNNEL_CSUM; if (flags & BPF_F_SEQ_NUMBER) info->key.tun_flags |= TUNNEL_SEQ; + if (flags & BPF_F_NO_TUNNEL_KEY) + info->key.tun_flags &= ~TUNNEL_KEY; info->key.tun_id = cpu_to_be64(from->tunnel_id); info->key.tos = from->tunnel_tos; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 464ca3f01fe7..bc1a3d232ae4 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -2001,6 +2001,9 @@ union bpf_attr { * sending the packet. This flag was added for GRE * encapsulation, but might be used with other protocols * as well in the future. + * **BPF_F_NO_TUNNEL_KEY** + * Add a flag to tunnel metadata indicating that no tunnel + * key should be set in the resulting tunnel header. * * Here is a typical usage on the transmit path: * @@ -5764,6 +5767,7 @@ enum { BPF_F_ZERO_CSUM_TX = (1ULL << 1), BPF_F_DONT_FRAGMENT = (1ULL << 2), BPF_F_SEQ_NUMBER = (1ULL << 3), + BPF_F_NO_TUNNEL_KEY = (1ULL << 4), }; /* BPF_FUNC_skb_get_tunnel_key flags. */ -- cgit v1.2.3 From 98c062e8245199fa9121141a0bf1035dc45ae90e Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Fri, 25 Nov 2022 00:38:38 +0100 Subject: HID: hid-sensor-custom: Allow more custom iio sensors The known LUID table for established/known custom HID sensors was limited to sensors with "INTEL" as manufacturer. But some vendors such as Lenovo also include fairly standard iio sensors (e.g. ambient light) in their custom sensors. Expand the known custom sensors table by a tag used for the platform device name and match sensors based on the LUID as well as optionally on model and manufacturer properties. Signed-off-by: Philipp Jungkamp Reviewed-by: Jonathan Cameron Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-custom.c | 210 ++++++++++++++++++++++++++-------------- include/linux/hid-sensor-ids.h | 1 + 2 files changed, 139 insertions(+), 72 deletions(-) (limited to 'include') diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c index f444e63e9f36..e6aa2cdcbc47 100644 --- a/drivers/hid/hid-sensor-custom.c +++ b/drivers/hid/hid-sensor-custom.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -750,114 +751,179 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom } -/* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */ -static const char *const known_sensor_luid[] = { "020B000000000000" }; +/* + * Match a known custom sensor. + * tag and luid is mandatory. + */ +struct hid_sensor_custom_match { + const char *tag; + const char *luid; + const char *model; + const char *manufacturer; + bool check_dmi; + struct dmi_system_id dmi; +}; -static int get_luid_table_index(unsigned char *usage_str) -{ - int i; +/* + * Custom sensor properties used for matching. + */ +struct hid_sensor_custom_properties { + u16 serial_num[HID_CUSTOM_MAX_FEATURE_BYTES]; + u16 model[HID_CUSTOM_MAX_FEATURE_BYTES]; + u16 manufacturer[HID_CUSTOM_MAX_FEATURE_BYTES]; +}; - for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) { - if (!strncmp(usage_str, known_sensor_luid[i], - strlen(known_sensor_luid[i]))) - return i; +static const struct hid_sensor_custom_match hid_sensor_custom_known_table[] = { + /* + * Intel Integrated Sensor Hub (ISH) + */ + { /* Intel ISH hinge */ + .tag = "INT", + .luid = "020B000000000000", + .manufacturer = "INTEL", + }, + {} +}; + +static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match, + size_t count) +{ + while (count-- && *prop && *match) { + if (*prop != (u16) *match) + return false; + prop++; + match++; } - return -ENODEV; + return (count == -1) || *prop == (u16)*match; } -static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev) +static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev, + u32 prop_usage_id, size_t prop_size, + u16 *prop) { - struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 }; - struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 }; - int report_size; + struct hid_sensor_hub_attribute_info prop_attr = { 0 }; int ret; - static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES]; - static char buf[HID_CUSTOM_MAX_FEATURE_BYTES]; - int i; - memset(w_buf, 0, sizeof(w_buf)); - memset(buf, 0, sizeof(buf)); + memset(prop, 0, prop_size); - /* get manufacturer info */ - ret = sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, hsdev->usage, - HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer); + ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, + hsdev->usage, prop_usage_id, + &prop_attr); if (ret < 0) return ret; - report_size = - sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id, - sensor_manufacturer.index, sizeof(w_buf), - w_buf); - if (report_size <= 0) { - hid_err(hsdev->hdev, - "Failed to get sensor manufacturer info %d\n", - report_size); - return -ENODEV; + ret = sensor_hub_get_feature(hsdev, prop_attr.report_id, + prop_attr.index, prop_size, prop); + if (ret < 0) { + hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n", + prop_usage_id, ret); + return ret; } - /* convert from wide char to char */ - for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) - buf[i] = (char)w_buf[i]; + return 0; +} + +static bool +hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev, + const struct hid_sensor_custom_match *match, + const struct hid_sensor_custom_properties *prop) +{ + struct dmi_system_id dmi[] = { match->dmi, { 0 } }; + + if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) || + !hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid, + HID_CUSTOM_MAX_FEATURE_BYTES - 5)) + return false; + + if (match->model && + !hid_sensor_custom_prop_match_str(prop->model, match->model, + HID_CUSTOM_MAX_FEATURE_BYTES)) + return false; + + if (match->manufacturer && + !hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer, + HID_CUSTOM_MAX_FEATURE_BYTES)) + return false; - /* ensure it's ISH sensor */ - if (strncmp(buf, "INTEL", strlen("INTEL"))) - return -ENODEV; + if (match->check_dmi && !dmi_check_system(dmi)) + return false; - memset(w_buf, 0, sizeof(w_buf)); - memset(buf, 0, sizeof(buf)); + return true; +} - /* get real usage id */ - ret = sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, hsdev->usage, - HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info); +static int +hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev, + struct hid_sensor_custom_properties *prop) +{ + int ret; + + ret = hid_sensor_custom_get_prop(hsdev, + HID_USAGE_SENSOR_PROP_SERIAL_NUM, + HID_CUSTOM_MAX_FEATURE_BYTES, + prop->serial_num); if (ret < 0) return ret; - report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id, - sensor_luid_info.index, sizeof(w_buf), - w_buf); - if (report_size <= 0) { - hid_err(hsdev->hdev, "Failed to get real usage info %d\n", - report_size); - return -ENODEV; - } + /* + * Ignore errors on the following model and manufacturer properties. + * Because these are optional, it is not an error if they are missing. + */ + + hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL, + HID_CUSTOM_MAX_FEATURE_BYTES, + prop->model); - /* convert from wide char to char */ - for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) - buf[i] = (char)w_buf[i]; + hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER, + HID_CUSTOM_MAX_FEATURE_BYTES, + prop->manufacturer); - if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) { - hid_err(hsdev->hdev, - "%s luid length not match %zu != (%zu + 5)\n", __func__, - strlen(buf), strlen(known_sensor_luid[0])); - return -ENODEV; + return 0; +} + +static int +hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev, + const struct hid_sensor_custom_match **known) +{ + int ret; + const struct hid_sensor_custom_match *match = + hid_sensor_custom_known_table; + struct hid_sensor_custom_properties prop; + + ret = hid_sensor_custom_properties_get(hsdev, &prop); + if (ret < 0) + return ret; + + while (match->tag) { + if (hid_sensor_custom_do_match(hsdev, match, &prop)) { + *known = match; + return 0; + } + match++; } - /* get table index with luid (not matching 'LUID: ' in luid) */ - return get_luid_table_index(&buf[5]); + return -ENODATA; } static struct platform_device * hid_sensor_register_platform_device(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - int index) + const struct hid_sensor_custom_match *match) { - char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 }; + char real_usage[HID_SENSOR_USAGE_LENGTH]; struct platform_device *custom_pdev; const char *dev_name; char *c; - /* copy real usage id */ - memcpy(real_usage, known_sensor_luid[index], 4); + memcpy(real_usage, match->luid, 4); /* usage id are all lowcase */ for (c = real_usage; *c != '\0'; c++) *c = tolower(*c); - /* HID-SENSOR-INT-REAL_USAGE_ID */ - dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage); + /* HID-SENSOR-TAG-REAL_USAGE_ID */ + dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s", + match->tag, real_usage); if (!dev_name) return ERR_PTR(-ENOMEM); @@ -873,7 +939,7 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) struct hid_sensor_custom *sensor_inst; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; int ret; - int index; + const struct hid_sensor_custom_match *match; sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst), GFP_KERNEL); @@ -888,10 +954,10 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) mutex_init(&sensor_inst->mutex); platform_set_drvdata(pdev, sensor_inst); - index = get_known_custom_sensor_index(hsdev); - if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) { + ret = hid_sensor_custom_get_known(hsdev, &match); + if (!ret) { sensor_inst->custom_pdev = - hid_sensor_register_platform_device(pdev, hsdev, index); + hid_sensor_register_platform_device(pdev, hsdev, match); ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev); if (ret) { diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index ac631159403a..13b1e65fbdcc 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -132,6 +132,7 @@ #define HID_USAGE_SENSOR_PROP_FRIENDLY_NAME 0x200301 #define HID_USAGE_SENSOR_PROP_SERIAL_NUM 0x200307 #define HID_USAGE_SENSOR_PROP_MANUFACTURER 0x200305 +#define HID_USAGE_SENSOR_PROP_MODEL 0x200306 #define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E #define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F #define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310 -- cgit v1.2.3 From a608dc1c06397dc50ab773498433432fb5938f92 Mon Sep 17 00:00:00 2001 From: José Expósito Date: Thu, 24 Nov 2022 18:59:37 +0100 Subject: HID: input: map battery system charging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HID descriptors with Battery System (0x85) Charging (0x44) usage are ignored and POWER_SUPPLY_STATUS_DISCHARGING is always reported to user space, even when the device is charging. Map this usage and when it is reported set the right charging status. In addition, add KUnit tests to make sure that the charging status is correctly set and reported. They can be run with the usual command: $ ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/hid Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/.kunitconfig | 1 + drivers/hid/Kconfig | 1 + drivers/hid/hid-input-test.c | 80 ++++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-input.c | 36 ++++++++++++++++++-- include/linux/hid.h | 2 ++ 5 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 drivers/hid/hid-input-test.c (limited to 'include') diff --git a/drivers/hid/.kunitconfig b/drivers/hid/.kunitconfig index 04daeff5c970..675a8209c7ae 100644 --- a/drivers/hid/.kunitconfig +++ b/drivers/hid/.kunitconfig @@ -1,5 +1,6 @@ CONFIG_KUNIT=y CONFIG_USB=y CONFIG_USB_HID=y +CONFIG_HID_BATTERY_STRENGTH=y CONFIG_HID_UCLOGIC=y CONFIG_HID_KUNIT_TEST=y diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 17cce4c50e8d..1aa7b6614c20 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1264,6 +1264,7 @@ config HID_MCP2221 config HID_KUNIT_TEST tristate "KUnit tests for HID" if !KUNIT_ALL_TESTS depends on KUNIT=y + depends on HID_BATTERY_STRENGTH depends on HID_UCLOGIC default KUNIT_ALL_TESTS help diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c new file mode 100644 index 000000000000..77c2d45ac62a --- /dev/null +++ b/drivers/hid/hid-input-test.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HID to Linux Input mapping + * + * Copyright (c) 2022 José Expósito + */ + +#include + +static void hid_test_input_set_battery_charge_status(struct kunit *test) +{ + struct hid_device *dev; + bool handled; + + dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0); + KUNIT_EXPECT_FALSE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN); + + handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0); + KUNIT_EXPECT_TRUE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING); + + handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1); + KUNIT_EXPECT_TRUE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING); +} + +static void hid_test_input_get_battery_property(struct kunit *test) +{ + struct power_supply *psy; + struct hid_device *dev; + union power_supply_propval val; + int ret; + + dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + dev->battery_avoid_query = true; + + psy = kunit_kzalloc(test, sizeof(*psy), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, psy); + psy->drv_data = dev; + + dev->battery_status = HID_BATTERY_UNKNOWN; + dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING; + ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_UNKNOWN); + + dev->battery_status = HID_BATTERY_REPORTED; + dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING; + ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_CHARGING); + + dev->battery_status = HID_BATTERY_REPORTED; + dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING; + ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_DISCHARGING); +} + +static struct kunit_case hid_input_tests[] = { + KUNIT_CASE(hid_test_input_set_battery_charge_status), + KUNIT_CASE(hid_test_input_get_battery_property), + { } +}; + +static struct kunit_suite hid_input_test_suite = { + .name = "hid_input", + .test_cases = hid_input_tests, +}; + +kunit_test_suite(hid_input_test_suite); + +MODULE_DESCRIPTION("HID input KUnit tests"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("José Expósito "); diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 3a93cf04147d..796930ac18f8 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -480,7 +480,7 @@ static int hidinput_get_battery_property(struct power_supply *psy, if (dev->battery_status == HID_BATTERY_UNKNOWN) val->intval = POWER_SUPPLY_STATUS_UNKNOWN; else - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + val->intval = dev->battery_charge_status; break; case POWER_SUPPLY_PROP_SCOPE: @@ -548,6 +548,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, dev->battery_max = max; dev->battery_report_type = report_type; dev->battery_report_id = field->report->id; + dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING; /* * Stylus is normally not connected to the device and thus we @@ -614,6 +615,20 @@ static void hidinput_update_battery(struct hid_device *dev, int value) power_supply_changed(dev->battery); } } + +static bool hidinput_set_battery_charge_status(struct hid_device *dev, + unsigned int usage, int value) +{ + switch (usage) { + case HID_BAT_CHARGING: + dev->battery_charge_status = value ? + POWER_SUPPLY_STATUS_CHARGING : + POWER_SUPPLY_STATUS_DISCHARGING; + return true; + } + + return false; +} #else /* !CONFIG_HID_BATTERY_STRENGTH */ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field, bool is_percentage) @@ -628,6 +643,12 @@ static void hidinput_cleanup_battery(struct hid_device *dev) static void hidinput_update_battery(struct hid_device *dev, int value) { } + +static bool hidinput_set_battery_charge_status(struct hid_device *dev, + unsigned int usage, int value) +{ + return false; +} #endif /* CONFIG_HID_BATTERY_STRENGTH */ static bool hidinput_field_in_collection(struct hid_device *device, struct hid_field *field, @@ -1217,6 +1238,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel hidinput_setup_battery(device, HID_INPUT_REPORT, field, true); usage->type = EV_PWR; return; + case HID_BAT_CHARGING: + usage->type = EV_PWR; + return; } goto unknown; @@ -1459,7 +1483,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; if (usage->type == EV_PWR) { - hidinput_update_battery(hid, value); + bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value); + + if (!handled) + hidinput_update_battery(hid, value); + return; } @@ -2315,3 +2343,7 @@ void hidinput_disconnect(struct hid_device *hid) cancel_work_sync(&hid->led_work); } EXPORT_SYMBOL_GPL(hidinput_disconnect); + +#ifdef CONFIG_HID_KUNIT_TEST +#include "hid-input-test.c" +#endif diff --git a/include/linux/hid.h b/include/linux/hid.h index 8677ae38599e..1eb5408599cd 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -312,6 +312,7 @@ struct hid_item { #define HID_DG_LATENCYMODE 0x000d0060 #define HID_BAT_ABSOLUTESTATEOFCHARGE 0x00850065 +#define HID_BAT_CHARGING 0x00850044 #define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076 @@ -611,6 +612,7 @@ struct hid_device { /* device report descriptor */ __s32 battery_max; __s32 battery_report_type; __s32 battery_report_id; + __s32 battery_charge_status; enum hid_battery_status battery_status; bool battery_avoid_query; ktime_t battery_ratelimit_time; -- cgit v1.2.3 From be2b81b519d7121290cfecc5fdfb4907ecc41c39 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Wed, 14 Dec 2022 19:54:59 +0100 Subject: ASoC: Intel: avs: Parse control tuples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add callback to handle loading of kcontrol and linking it to active widget. In order to link kcontrol to specific modules add additional field to module data, as well as specify control id in kcontrol data. Co-authored-by: Cezary Rojewski Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20221214185500.3896902-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/intel/avs/tokens.h | 4 ++ sound/soc/intel/avs/control.c | 10 +++++ sound/soc/intel/avs/topology.c | 76 +++++++++++++++++++++++++++++++++++ sound/soc/intel/avs/topology.h | 3 ++ 4 files changed, 93 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/intel/avs/tokens.h b/include/uapi/sound/intel/avs/tokens.h index 754f02b2f444..4ffe546aa409 100644 --- a/include/uapi/sound/intel/avs/tokens.h +++ b/include/uapi/sound/intel/avs/tokens.h @@ -108,6 +108,7 @@ enum avs_tplg_token { AVS_TKN_MOD_CORE_ID_U8 = 1704, AVS_TKN_MOD_PROC_DOMAIN_U8 = 1705, AVS_TKN_MOD_MODCFG_EXT_ID_U32 = 1706, + AVS_TKN_MOD_KCONTROL_ID_U32 = 1707, /* struct avs_tplg_path_template */ AVS_TKN_PATH_TMPL_ID_U32 = 1801, @@ -121,6 +122,9 @@ enum avs_tplg_token { AVS_TKN_PIN_FMT_INDEX_U32 = 2201, AVS_TKN_PIN_FMT_IOBS_U32 = 2202, AVS_TKN_PIN_FMT_AFMT_ID_U32 = 2203, + + /* struct avs_tplg_kcontrol */ + AVS_TKN_KCONTROL_ID_U32 = 2301, }; #endif diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c index 92b3aad0baca..a8b14b784f8a 100644 --- a/sound/soc/intel/avs/control.c +++ b/sound/soc/intel/avs/control.c @@ -23,6 +23,16 @@ static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol) static struct avs_path_module *avs_get_kcontrol_module(struct avs_dev *adev, u32 id) { + struct avs_path *path; + struct avs_path_pipeline *ppl; + struct avs_path_module *mod; + + list_for_each_entry(path, &adev->path_list, node) + list_for_each_entry(ppl, &path->ppl_list, node) + list_for_each_entry(mod, &ppl->mod_list, node) + if (mod->template->ctl_id && mod->template->ctl_id == id) + return mod; + return NULL; } diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index e845eaf0a1e7..5fee7a8ec06a 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -13,6 +13,7 @@ #include #include #include "avs.h" +#include "control.h" #include "topology.h" /* Get pointer to vendor array at the specified offset. */ @@ -1070,6 +1071,12 @@ static const struct avs_tplg_token_parser module_parsers[] = { .offset = offsetof(struct avs_tplg_module, cfg_ext), .parse = avs_parse_modcfg_ext_ptr, }, + { + .token = AVS_TKN_MOD_KCONTROL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_module, ctl_id), + .parse = avs_parse_byte_token, + }, }; static struct avs_tplg_module * @@ -1435,6 +1442,16 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, return 0; } +static int avs_widget_ready(struct snd_soc_component *comp, int index, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *dw) +{ + struct avs_tplg_path_template *template = w->priv; + + template->w = w; + return 0; +} + static int avs_dai_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) @@ -1586,9 +1603,68 @@ static int avs_manifest(struct snd_soc_component *comp, int index, return avs_tplg_parse_bindings(comp, tuples, remaining); } +#define AVS_CONTROL_OPS_VOLUME 257 + +static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = { + { + .id = AVS_CONTROL_OPS_VOLUME, + .get = avs_control_volume_get, + .put = avs_control_volume_put, + }, +}; + +static const struct avs_tplg_token_parser control_parsers[] = { + { + .token = AVS_TKN_KCONTROL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_control_data, id), + .parse = avs_parse_word_token, + }, +}; + +static int +avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_new *ctmpl, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_soc_tplg_vendor_array *tuples; + struct snd_soc_tplg_mixer_control *tmc; + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + size_t block_size; + int ret; + + switch (hdr->type) { + case SND_SOC_TPLG_TYPE_MIXER: + tmc = container_of(hdr, typeof(*tmc), hdr); + tuples = tmc->priv.array; + block_size = le32_to_cpu(tmc->priv.size); + break; + default: + return -EINVAL; + } + + ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL); + if (!ctl_data) + return -ENOMEM; + + ret = parse_dictionary_entries(comp, tuples, block_size, ctl_data, 1, sizeof(*ctl_data), + AVS_TKN_KCONTROL_ID_U32, control_parsers, + ARRAY_SIZE(control_parsers)); + if (ret) + return ret; + + mc = (struct soc_mixer_control *)ctmpl->private_value; + mc->dobj.private = ctl_data; + return 0; +} + static struct snd_soc_tplg_ops avs_tplg_ops = { + .io_ops = avs_control_ops, + .io_ops_count = ARRAY_SIZE(avs_control_ops), + .control_load = avs_control_load, .dapm_route_load = avs_route_load, .widget_load = avs_widget_load, + .widget_ready = avs_widget_ready, .dai_load = avs_dai_load, .link_load = avs_link_load, .manifest = avs_manifest, diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 68e5f6312353..6e1c8e9b2496 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -138,6 +138,8 @@ struct avs_tplg_path_template_id { struct avs_tplg_path_template { u32 id; + struct snd_soc_dapm_widget *w; + struct list_head path_list; struct avs_tplg *owner; @@ -180,6 +182,7 @@ struct avs_tplg_module { u8 core_id; u8 domain; struct avs_tplg_modcfg_ext *cfg_ext; + u32 ctl_id; struct avs_tplg_pipeline *owner; /* Pipeline modules management. */ -- cgit v1.2.3 From 0985cd52087d55cc7a85db1cbc48bf4ad3c3b475 Mon Sep 17 00:00:00 2001 From: Tam Nguyen Date: Tue, 29 Nov 2022 18:03:03 +0100 Subject: dt-bindings: power: r8a779g0: Add missing A3DUL power domain Add the power domain index for the A3DUL domain, as described in the R-Car V4H Series Hardware User's Manual Rev. 0.51 and later. Signed-off-by: Tam Nguyen [geert: Manual reference] Signed-off-by: Geert Uytterhoeven Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/d61cf54b58629a76e007b9505dac7c2beb3b30db.1669740926.git.geert+renesas@glider.be --- include/dt-bindings/power/r8a779g0-sysc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/dt-bindings/power/r8a779g0-sysc.h b/include/dt-bindings/power/r8a779g0-sysc.h index 7daa70f1814e..c7b139fb075f 100644 --- a/include/dt-bindings/power/r8a779g0-sysc.h +++ b/include/dt-bindings/power/r8a779g0-sysc.h @@ -38,6 +38,7 @@ #define R8A779G0_PD_A3VIP2 58 #define R8A779G0_PD_A3ISP0 60 #define R8A779G0_PD_A3ISP1 61 +#define R8A779G0_PD_A3DUL 62 /* Always-on power area */ #define R8A779G0_PD_ALWAYS_ON 64 -- cgit v1.2.3 From 317c8194e6aeb8b3b573ad139fc2a0635856498e Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 22 Nov 2022 15:39:04 -0500 Subject: rseq: Introduce feature size and alignment ELF auxiliary vector entries Export the rseq feature size supported by the kernel as well as the required allocation alignment for the rseq per-thread area to user-space through ELF auxiliary vector entries. This is part of the extensible rseq ABI. Signed-off-by: Mathieu Desnoyers Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20221122203932.231377-3-mathieu.desnoyers@efficios.com --- fs/binfmt_elf.c | 5 +++++ include/uapi/linux/auxvec.h | 2 ++ include/uapi/linux/rseq.h | 5 +++++ 3 files changed, 12 insertions(+) (limited to 'include') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index de63572a9404..0ba86f0b1477 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -288,6 +289,10 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, if (bprm->have_execfd) { NEW_AUX_ENT(AT_EXECFD, bprm->execfd); } +#ifdef CONFIG_RSEQ + NEW_AUX_ENT(AT_RSEQ_FEATURE_SIZE, offsetof(struct rseq, end)); + NEW_AUX_ENT(AT_RSEQ_ALIGN, __alignof__(struct rseq)); +#endif #undef NEW_AUX_ENT /* AT_NULL is zero; clear the rest too */ memset(elf_info, 0, (char *)mm->saved_auxv + diff --git a/include/uapi/linux/auxvec.h b/include/uapi/linux/auxvec.h index c7e502bf5a6f..6991c4b8ab18 100644 --- a/include/uapi/linux/auxvec.h +++ b/include/uapi/linux/auxvec.h @@ -30,6 +30,8 @@ * differ from AT_PLATFORM. */ #define AT_RANDOM 25 /* address of 16 random bytes */ #define AT_HWCAP2 26 /* extension of AT_HWCAP */ +#define AT_RSEQ_FEATURE_SIZE 27 /* rseq supported feature size */ +#define AT_RSEQ_ALIGN 28 /* rseq allocation alignment */ #define AT_EXECFN 31 /* filename of program */ diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h index 77ee207623a9..05d3c4cdeb40 100644 --- a/include/uapi/linux/rseq.h +++ b/include/uapi/linux/rseq.h @@ -130,6 +130,11 @@ struct rseq { * this thread. */ __u32 flags; + + /* + * Flexible array member at end of structure, after last feature field. + */ + char end[]; } __attribute__((aligned(4 * sizeof(__u64)))); #endif /* _UAPI_LINUX_RSEQ_H */ -- cgit v1.2.3 From ee3e3ac05c2631ce1f12d88c9cc9a092f8fe947a Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 22 Nov 2022 15:39:05 -0500 Subject: rseq: Introduce extensible rseq ABI Introduce the extensible rseq ABI, where the feature size supported by the kernel and the required alignment are communicated to user-space through ELF auxiliary vectors. This allows user-space to call rseq registration with a rseq_len of either 32 bytes for the original struct rseq size (which includes padding), or larger. If rseq_len is larger than 32 bytes, then it must be large enough to contain the feature size communicated to user-space through ELF auxiliary vectors. Signed-off-by: Mathieu Desnoyers Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20221122203932.231377-4-mathieu.desnoyers@efficios.com --- include/linux/sched.h | 4 ++++ kernel/ptrace.c | 2 +- kernel/rseq.c | 37 ++++++++++++++++++++++++++++++------- 3 files changed, 35 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/sched.h b/include/linux/sched.h index 853d08f7562b..e0bc020a63a9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1302,6 +1302,7 @@ struct task_struct { #ifdef CONFIG_RSEQ struct rseq __user *rseq; + u32 rseq_len; u32 rseq_sig; /* * RmW on rseq_event_mask must be performed atomically @@ -2352,10 +2353,12 @@ static inline void rseq_fork(struct task_struct *t, unsigned long clone_flags) { if (clone_flags & CLONE_VM) { t->rseq = NULL; + t->rseq_len = 0; t->rseq_sig = 0; t->rseq_event_mask = 0; } else { t->rseq = current->rseq; + t->rseq_len = current->rseq_len; t->rseq_sig = current->rseq_sig; t->rseq_event_mask = current->rseq_event_mask; } @@ -2364,6 +2367,7 @@ static inline void rseq_fork(struct task_struct *t, unsigned long clone_flags) static inline void rseq_execve(struct task_struct *t) { t->rseq = NULL; + t->rseq_len = 0; t->rseq_sig = 0; t->rseq_event_mask = 0; } diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 54482193e1ed..0786450074c1 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -813,7 +813,7 @@ static long ptrace_get_rseq_configuration(struct task_struct *task, { struct ptrace_rseq_configuration conf = { .rseq_abi_pointer = (u64)(uintptr_t)task->rseq, - .rseq_abi_size = sizeof(*task->rseq), + .rseq_abi_size = task->rseq_len, .signature = task->rseq_sig, .flags = 0, }; diff --git a/kernel/rseq.c b/kernel/rseq.c index d38ab944105d..7962738455c9 100644 --- a/kernel/rseq.c +++ b/kernel/rseq.c @@ -18,6 +18,9 @@ #define CREATE_TRACE_POINTS #include +/* The original rseq structure size (including padding) is 32 bytes. */ +#define ORIG_RSEQ_SIZE 32 + #define RSEQ_CS_NO_RESTART_FLAGS (RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT | \ RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL | \ RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE) @@ -87,10 +90,15 @@ static int rseq_update_cpu_id(struct task_struct *t) u32 cpu_id = raw_smp_processor_id(); struct rseq __user *rseq = t->rseq; - if (!user_write_access_begin(rseq, sizeof(*rseq))) + if (!user_write_access_begin(rseq, t->rseq_len)) goto efault; unsafe_put_user(cpu_id, &rseq->cpu_id_start, efault_end); unsafe_put_user(cpu_id, &rseq->cpu_id, efault_end); + /* + * Additional feature fields added after ORIG_RSEQ_SIZE + * need to be conditionally updated only if + * t->rseq_len != ORIG_RSEQ_SIZE. + */ user_write_access_end(); trace_rseq_update(t); return 0; @@ -117,6 +125,11 @@ static int rseq_reset_rseq_cpu_id(struct task_struct *t) */ if (put_user(cpu_id, &t->rseq->cpu_id)) return -EFAULT; + /* + * Additional feature fields added after ORIG_RSEQ_SIZE + * need to be conditionally reset only if + * t->rseq_len != ORIG_RSEQ_SIZE. + */ return 0; } @@ -344,7 +357,7 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, /* Unregister rseq for current thread. */ if (current->rseq != rseq || !current->rseq) return -EINVAL; - if (rseq_len != sizeof(*rseq)) + if (rseq_len != current->rseq_len) return -EINVAL; if (current->rseq_sig != sig) return -EPERM; @@ -353,6 +366,7 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, return ret; current->rseq = NULL; current->rseq_sig = 0; + current->rseq_len = 0; return 0; } @@ -365,7 +379,7 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, * the provided address differs from the prior * one. */ - if (current->rseq != rseq || rseq_len != sizeof(*rseq)) + if (current->rseq != rseq || rseq_len != current->rseq_len) return -EINVAL; if (current->rseq_sig != sig) return -EPERM; @@ -374,15 +388,24 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, } /* - * If there was no rseq previously registered, - * ensure the provided rseq is properly aligned and valid. + * If there was no rseq previously registered, ensure the provided rseq + * is properly aligned, as communcated to user-space through the ELF + * auxiliary vector AT_RSEQ_ALIGN. If rseq_len is the original rseq + * size, the required alignment is the original struct rseq alignment. + * + * In order to be valid, rseq_len is either the original rseq size, or + * large enough to contain all supported fields, as communicated to + * user-space through the ELF auxiliary vector AT_RSEQ_FEATURE_SIZE. */ - if (!IS_ALIGNED((unsigned long)rseq, __alignof__(*rseq)) || - rseq_len != sizeof(*rseq)) + if (rseq_len < ORIG_RSEQ_SIZE || + (rseq_len == ORIG_RSEQ_SIZE && !IS_ALIGNED((unsigned long)rseq, ORIG_RSEQ_SIZE)) || + (rseq_len != ORIG_RSEQ_SIZE && (!IS_ALIGNED((unsigned long)rseq, __alignof__(*rseq)) || + rseq_len < offsetof(struct rseq, end)))) return -EINVAL; if (!access_ok(rseq, rseq_len)) return -EFAULT; current->rseq = rseq; + current->rseq_len = rseq_len; current->rseq_sig = sig; /* * If rseq was previously inactive, and has just been -- cgit v1.2.3 From cbae6bac29a8c5cf2f1cb5c6bce35af00cec164b Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 22 Nov 2022 15:39:06 -0500 Subject: rseq: Extend struct rseq with numa node id Adding the NUMA node id to struct rseq is a straightforward thing to do, and a good way to figure out if anything in the user-space ecosystem prevents extending struct rseq. This NUMA node id field allows memory allocators such as tcmalloc to take advantage of fast access to the current NUMA node id to perform NUMA-aware memory allocation. It can also be useful for implementing fast-paths for NUMA-aware user-space mutexes. It also allows implementing getcpu(2) purely in user-space. Signed-off-by: Mathieu Desnoyers Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20221122203932.231377-5-mathieu.desnoyers@efficios.com --- include/trace/events/rseq.h | 4 +++- include/uapi/linux/rseq.h | 8 ++++++++ kernel/rseq.c | 19 +++++++++++++------ 3 files changed, 24 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/trace/events/rseq.h b/include/trace/events/rseq.h index a04a64bc1a00..dde7a359b4ef 100644 --- a/include/trace/events/rseq.h +++ b/include/trace/events/rseq.h @@ -16,13 +16,15 @@ TRACE_EVENT(rseq_update, TP_STRUCT__entry( __field(s32, cpu_id) + __field(s32, node_id) ), TP_fast_assign( __entry->cpu_id = raw_smp_processor_id(); + __entry->node_id = cpu_to_node(__entry->cpu_id); ), - TP_printk("cpu_id=%d", __entry->cpu_id) + TP_printk("cpu_id=%d node_id=%d", __entry->cpu_id, __entry->node_id) ); TRACE_EVENT(rseq_ip_fixup, diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h index 05d3c4cdeb40..1cb90a435c5c 100644 --- a/include/uapi/linux/rseq.h +++ b/include/uapi/linux/rseq.h @@ -131,6 +131,14 @@ struct rseq { */ __u32 flags; + /* + * Restartable sequences node_id field. Updated by the kernel. Read by + * user-space with single-copy atomicity semantics. This field should + * only be read by the thread which registered this data structure. + * Aligned on 32-bit. Contains the current NUMA node ID. + */ + __u32 node_id; + /* * Flexible array member at end of structure, after last feature field. */ diff --git a/kernel/rseq.c b/kernel/rseq.c index 7962738455c9..193cfcc94ddc 100644 --- a/kernel/rseq.c +++ b/kernel/rseq.c @@ -85,15 +85,17 @@ * F1. */ -static int rseq_update_cpu_id(struct task_struct *t) +static int rseq_update_cpu_node_id(struct task_struct *t) { - u32 cpu_id = raw_smp_processor_id(); struct rseq __user *rseq = t->rseq; + u32 cpu_id = raw_smp_processor_id(); + u32 node_id = cpu_to_node(cpu_id); if (!user_write_access_begin(rseq, t->rseq_len)) goto efault; unsafe_put_user(cpu_id, &rseq->cpu_id_start, efault_end); unsafe_put_user(cpu_id, &rseq->cpu_id, efault_end); + unsafe_put_user(node_id, &rseq->node_id, efault_end); /* * Additional feature fields added after ORIG_RSEQ_SIZE * need to be conditionally updated only if @@ -109,9 +111,9 @@ efault: return -EFAULT; } -static int rseq_reset_rseq_cpu_id(struct task_struct *t) +static int rseq_reset_rseq_cpu_node_id(struct task_struct *t) { - u32 cpu_id_start = 0, cpu_id = RSEQ_CPU_ID_UNINITIALIZED; + u32 cpu_id_start = 0, cpu_id = RSEQ_CPU_ID_UNINITIALIZED, node_id = 0; /* * Reset cpu_id_start to its initial state (0). @@ -125,6 +127,11 @@ static int rseq_reset_rseq_cpu_id(struct task_struct *t) */ if (put_user(cpu_id, &t->rseq->cpu_id)) return -EFAULT; + /* + * Reset node_id to its initial state (0). + */ + if (put_user(node_id, &t->rseq->node_id)) + return -EFAULT; /* * Additional feature fields added after ORIG_RSEQ_SIZE * need to be conditionally reset only if @@ -314,7 +321,7 @@ void __rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs) if (unlikely(ret < 0)) goto error; } - if (unlikely(rseq_update_cpu_id(t))) + if (unlikely(rseq_update_cpu_node_id(t))) goto error; return; @@ -361,7 +368,7 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, return -EINVAL; if (current->rseq_sig != sig) return -EPERM; - ret = rseq_reset_rseq_cpu_id(current); + ret = rseq_reset_rseq_cpu_node_id(current); if (ret) return ret; current->rseq = NULL; -- cgit v1.2.3 From af7f588d8f7355bc4298dd1962d7826358fc95f0 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 22 Nov 2022 15:39:09 -0500 Subject: sched: Introduce per-memory-map concurrency ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This feature allows the scheduler to expose a per-memory map concurrency ID to user-space. This concurrency ID is within the possible cpus range, and is temporarily (and uniquely) assigned while threads are actively running within a memory map. If a memory map has fewer threads than cores, or is limited to run on few cores concurrently through sched affinity or cgroup cpusets, the concurrency IDs will be values close to 0, thus allowing efficient use of user-space memory for per-cpu data structures. This feature is meant to be exposed by a new rseq thread area field. The primary purpose of this feature is to do the heavy-lifting needed by memory allocators to allow them to use per-cpu data structures efficiently in the following situations: - Single-threaded applications, - Multi-threaded applications on large systems (many cores) with limited cpu affinity mask, - Multi-threaded applications on large systems (many cores) with restricted cgroup cpuset per container. One of the key concern from scheduler maintainers is the overhead associated with additional spin locks or atomic operations in the scheduler fast-path. This is why the following optimization is implemented. On context switch between threads belonging to the same memory map, transfer the mm_cid from prev to next without any atomic ops. This takes care of use-cases involving frequent context switch between threads belonging to the same memory map. Additional optimizations can be done if the spin locks added when context switching between threads belonging to different memory maps end up being a performance bottleneck. Those are left out of this patch though. A performance impact would have to be clearly demonstrated to justify the added complexity. The credit goes to Paul Turner (Google) for the original virtual cpu id idea. This feature is implemented based on the discussions with Paul Turner and Peter Oskolkov (Google), but I took the liberty to implement scheduler fast-path optimizations and my own NUMA-awareness scheme. The rumor has it that Google have been running a rseq vcpu_id extension internally in production for a year. The tcmalloc source code indeed has comments hinting at a vcpu_id prototype extension to the rseq system call [1]. The following benchmarks do not show any significant overhead added to the scheduler context switch by this feature: * perf bench sched messaging (process) Baseline: 86.5±0.3 ms With mm_cid: 86.7±2.6 ms * perf bench sched messaging (threaded) Baseline: 84.3±3.0 ms With mm_cid: 84.7±2.6 ms * hackbench (process) Baseline: 82.9±2.7 ms With mm_cid: 82.9±2.9 ms * hackbench (threaded) Baseline: 85.2±2.6 ms With mm_cid: 84.4±2.9 ms [1] https://github.com/google/tcmalloc/blob/master/tcmalloc/internal/linux_syscall_support.h#L26 Signed-off-by: Mathieu Desnoyers Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20221122203932.231377-8-mathieu.desnoyers@efficios.com --- fs/exec.c | 4 ++++ include/linux/mm.h | 25 +++++++++++++++++++++ include/linux/mm_types.h | 43 ++++++++++++++++++++++++++++++++++- include/linux/sched.h | 5 +++++ init/Kconfig | 4 ++++ kernel/fork.c | 8 ++++++- kernel/sched/core.c | 51 ++++++++++++++++++++++++++++++++++++++++++ kernel/sched/sched.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ kernel/signal.c | 2 ++ 9 files changed, 198 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/fs/exec.c b/fs/exec.c index ab913243a367..58f16312b983 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1010,6 +1010,7 @@ static int exec_mmap(struct mm_struct *mm) active_mm = tsk->active_mm; tsk->active_mm = mm; tsk->mm = mm; + mm_init_cid(mm); /* * This prevents preemption while active_mm is being loaded and * it and mm are being updated, which could cause problems for @@ -1822,6 +1823,7 @@ static int bprm_execve(struct linux_binprm *bprm, */ check_unsafe_exec(bprm); current->in_execve = 1; + sched_mm_cid_before_execve(current); file = do_open_execat(fd, filename, flags); retval = PTR_ERR(file); @@ -1852,6 +1854,7 @@ static int bprm_execve(struct linux_binprm *bprm, if (retval < 0) goto out; + sched_mm_cid_after_execve(current); /* execve succeeded */ current->fs->in_exec = 0; current->in_execve = 0; @@ -1871,6 +1874,7 @@ out: force_fatal_sig(SIGSEGV); out_unmark: + sched_mm_cid_after_execve(current); current->fs->in_exec = 0; current->in_execve = 0; diff --git a/include/linux/mm.h b/include/linux/mm.h index f3f196e4d66d..cf008c26a883 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1976,6 +1976,31 @@ struct zap_details { /* Set in unmap_vmas() to indicate a final unmap call. Only used by hugetlb */ #define ZAP_FLAG_UNMAP ((__force zap_flags_t) BIT(1)) +#ifdef CONFIG_SCHED_MM_CID +void sched_mm_cid_before_execve(struct task_struct *t); +void sched_mm_cid_after_execve(struct task_struct *t); +void sched_mm_cid_fork(struct task_struct *t); +void sched_mm_cid_exit_signals(struct task_struct *t); +static inline int task_mm_cid(struct task_struct *t) +{ + return t->mm_cid; +} +#else +static inline void sched_mm_cid_before_execve(struct task_struct *t) { } +static inline void sched_mm_cid_after_execve(struct task_struct *t) { } +static inline void sched_mm_cid_fork(struct task_struct *t) { } +static inline void sched_mm_cid_exit_signals(struct task_struct *t) { } +static inline int task_mm_cid(struct task_struct *t) +{ + /* + * Use the processor id as a fall-back when the mm cid feature is + * disabled. This provides functional per-cpu data structure accesses + * in user-space, althrough it won't provide the memory usage benefits. + */ + return raw_smp_processor_id(); +} +#endif + #ifdef CONFIG_MMU extern bool can_do_mlock(void); #else diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 3b8475007734..1c3bf76063d2 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -645,7 +645,18 @@ struct mm_struct { * &struct mm_struct is freed. */ atomic_t mm_count; - +#ifdef CONFIG_SCHED_MM_CID + /** + * @cid_lock: Protect cid bitmap updates vs lookups. + * + * Prevent situations where updates to the cid bitmap happen + * concurrently with lookups. Those can lead to situations + * where a lookup cannot find a free bit simply because it was + * unlucky enough to load, non-atomically, bitmap words as they + * were being concurrently updated by the updaters. + */ + raw_spinlock_t cid_lock; +#endif #ifdef CONFIG_MMU atomic_long_t pgtables_bytes; /* PTE page table pages */ #endif @@ -909,6 +920,36 @@ static inline void vma_iter_init(struct vma_iterator *vmi, vmi->mas.node = MAS_START; } +#ifdef CONFIG_SCHED_MM_CID +/* Accessor for struct mm_struct's cidmask. */ +static inline cpumask_t *mm_cidmask(struct mm_struct *mm) +{ + unsigned long cid_bitmap = (unsigned long)mm; + + cid_bitmap += offsetof(struct mm_struct, cpu_bitmap); + /* Skip cpu_bitmap */ + cid_bitmap += cpumask_size(); + return (struct cpumask *)cid_bitmap; +} + +static inline void mm_init_cid(struct mm_struct *mm) +{ + raw_spin_lock_init(&mm->cid_lock); + cpumask_clear(mm_cidmask(mm)); +} + +static inline unsigned int mm_cid_size(void) +{ + return cpumask_size(); +} +#else /* CONFIG_SCHED_MM_CID */ +static inline void mm_init_cid(struct mm_struct *mm) { } +static inline unsigned int mm_cid_size(void) +{ + return 0; +} +#endif /* CONFIG_SCHED_MM_CID */ + struct mmu_gather; extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm); extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm); diff --git a/include/linux/sched.h b/include/linux/sched.h index e0bc020a63a9..4df2b3e76b30 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1311,6 +1311,11 @@ struct task_struct { unsigned long rseq_event_mask; #endif +#ifdef CONFIG_SCHED_MM_CID + int mm_cid; /* Current cid in mm */ + int mm_cid_active; /* Whether cid bitmap is active */ +#endif + struct tlbflush_unmap_batch tlb_ubc; union { diff --git a/init/Kconfig b/init/Kconfig index 7e5c3ddc341d..1ce960aa453e 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1041,6 +1041,10 @@ config RT_GROUP_SCHED endif #CGROUP_SCHED +config SCHED_MM_CID + def_bool y + depends on SMP && RSEQ + config UCLAMP_TASK_GROUP bool "Utilization clamping per group of tasks" depends on CGROUP_SCHED diff --git a/kernel/fork.c b/kernel/fork.c index 9f7fe3541897..82b2b5846aae 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1060,6 +1060,10 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) tsk->reported_split_lock = 0; #endif +#ifdef CONFIG_SCHED_MM_CID + tsk->mm_cid = -1; + tsk->mm_cid_active = 0; +#endif return tsk; free_stack: @@ -1169,6 +1173,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, mm->user_ns = get_user_ns(user_ns); lru_gen_init_mm(mm); + mm_init_cid(mm); return mm; fail_pcpu: @@ -1601,6 +1606,7 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk) tsk->mm = mm; tsk->active_mm = mm; + sched_mm_cid_fork(tsk); return 0; } @@ -3034,7 +3040,7 @@ void __init mm_cache_init(void) * dynamically sized based on the maximum CPU number this system * can have, taking hotplug into account (nr_cpu_ids). */ - mm_size = sizeof(struct mm_struct) + cpumask_size(); + mm_size = sizeof(struct mm_struct) + cpumask_size() + mm_cid_size(); mm_cachep = kmem_cache_create_usercopy("mm_struct", mm_size, ARCH_MIN_MMSTRUCT_ALIGN, diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 25b582b6ee5f..75830b7dee8f 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5052,6 +5052,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, sched_info_switch(rq, prev, next); perf_event_task_sched_out(prev, next); rseq_preempt(prev); + switch_mm_cid(prev, next); fire_sched_out_preempt_notifiers(prev, next); kmap_local_sched_out(); prepare_task(next); @@ -11305,3 +11306,53 @@ void call_trace_sched_update_nr_running(struct rq *rq, int count) { trace_sched_update_nr_running_tp(rq, count); } + +#ifdef CONFIG_SCHED_MM_CID +void sched_mm_cid_exit_signals(struct task_struct *t) +{ + struct mm_struct *mm = t->mm; + unsigned long flags; + + if (!mm) + return; + local_irq_save(flags); + mm_cid_put(mm, t->mm_cid); + t->mm_cid = -1; + t->mm_cid_active = 0; + local_irq_restore(flags); +} + +void sched_mm_cid_before_execve(struct task_struct *t) +{ + struct mm_struct *mm = t->mm; + unsigned long flags; + + if (!mm) + return; + local_irq_save(flags); + mm_cid_put(mm, t->mm_cid); + t->mm_cid = -1; + t->mm_cid_active = 0; + local_irq_restore(flags); +} + +void sched_mm_cid_after_execve(struct task_struct *t) +{ + struct mm_struct *mm = t->mm; + unsigned long flags; + + WARN_ON_ONCE((t->flags & PF_KTHREAD) || !t->mm); + + local_irq_save(flags); + t->mm_cid = mm_cid_get(mm); + t->mm_cid_active = 1; + local_irq_restore(flags); + rseq_set_notify_resume(t); +} + +void sched_mm_cid_fork(struct task_struct *t) +{ + WARN_ON_ONCE((t->flags & PF_KTHREAD) || !t->mm || t->mm_cid != -1); + t->mm_cid_active = 1; +} +#endif diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index b3d6e819127c..c2d7467fdde1 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -3269,4 +3269,62 @@ static inline void update_current_exec_runtime(struct task_struct *curr, cgroup_account_cputime(curr, delta_exec); } +#ifdef CONFIG_SCHED_MM_CID +static inline int __mm_cid_get(struct mm_struct *mm) +{ + struct cpumask *cpumask; + int cid; + + cpumask = mm_cidmask(mm); + cid = cpumask_first_zero(cpumask); + if (cid >= nr_cpu_ids) + return -1; + __cpumask_set_cpu(cid, cpumask); + return cid; +} + +static inline void mm_cid_put(struct mm_struct *mm, int cid) +{ + lockdep_assert_irqs_disabled(); + if (cid < 0) + return; + raw_spin_lock(&mm->cid_lock); + __cpumask_clear_cpu(cid, mm_cidmask(mm)); + raw_spin_unlock(&mm->cid_lock); +} + +static inline int mm_cid_get(struct mm_struct *mm) +{ + int ret; + + lockdep_assert_irqs_disabled(); + raw_spin_lock(&mm->cid_lock); + ret = __mm_cid_get(mm); + raw_spin_unlock(&mm->cid_lock); + return ret; +} + +static inline void switch_mm_cid(struct task_struct *prev, struct task_struct *next) +{ + if (prev->mm_cid_active) { + if (next->mm_cid_active && next->mm == prev->mm) { + /* + * Context switch between threads in same mm, hand over + * the mm_cid from prev to next. + */ + next->mm_cid = prev->mm_cid; + prev->mm_cid = -1; + return; + } + mm_cid_put(prev->mm, prev->mm_cid); + prev->mm_cid = -1; + } + if (next->mm_cid_active) + next->mm_cid = mm_cid_get(next->mm); +} + +#else +static inline void switch_mm_cid(struct task_struct *prev, struct task_struct *next) { } +#endif + #endif /* _KERNEL_SCHED_SCHED_H */ diff --git a/kernel/signal.c b/kernel/signal.c index ae26da61c4d9..8cb28f1df294 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2951,6 +2951,7 @@ void exit_signals(struct task_struct *tsk) cgroup_threadgroup_change_begin(tsk); if (thread_group_empty(tsk) || (tsk->signal->flags & SIGNAL_GROUP_EXIT)) { + sched_mm_cid_exit_signals(tsk); tsk->flags |= PF_EXITING; cgroup_threadgroup_change_end(tsk); return; @@ -2961,6 +2962,7 @@ void exit_signals(struct task_struct *tsk) * From now this task is not visible for group-wide signals, * see wants_signal(), do_signal_stop(). */ + sched_mm_cid_exit_signals(tsk); tsk->flags |= PF_EXITING; cgroup_threadgroup_change_end(tsk); -- cgit v1.2.3 From f7b01bb0b57f994a44ea6368536b59062b796381 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 22 Nov 2022 15:39:10 -0500 Subject: rseq: Extend struct rseq with per-memory-map concurrency ID If a memory map has fewer threads than there are cores on the system, or is limited to run on few cores concurrently through sched affinity or cgroup cpusets, the concurrency IDs will be values close to 0, thus allowing efficient use of user-space memory for per-cpu data structures. Signed-off-by: Mathieu Desnoyers Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20221122203932.231377-9-mathieu.desnoyers@efficios.com --- include/uapi/linux/rseq.h | 9 +++++++++ kernel/rseq.c | 11 ++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h index 1cb90a435c5c..c233aae5eac9 100644 --- a/include/uapi/linux/rseq.h +++ b/include/uapi/linux/rseq.h @@ -139,6 +139,15 @@ struct rseq { */ __u32 node_id; + /* + * Restartable sequences mm_cid field. Updated by the kernel. Read by + * user-space with single-copy atomicity semantics. This field should + * only be read by the thread which registered this data structure. + * Aligned on 32-bit. Contains the current thread's concurrency ID + * (allocated uniquely within a memory map). + */ + __u32 mm_cid; + /* * Flexible array member at end of structure, after last feature field. */ diff --git a/kernel/rseq.c b/kernel/rseq.c index 193cfcc94ddc..9de6e35fe679 100644 --- a/kernel/rseq.c +++ b/kernel/rseq.c @@ -90,12 +90,15 @@ static int rseq_update_cpu_node_id(struct task_struct *t) struct rseq __user *rseq = t->rseq; u32 cpu_id = raw_smp_processor_id(); u32 node_id = cpu_to_node(cpu_id); + u32 mm_cid = task_mm_cid(t); + WARN_ON_ONCE((int) mm_cid < 0); if (!user_write_access_begin(rseq, t->rseq_len)) goto efault; unsafe_put_user(cpu_id, &rseq->cpu_id_start, efault_end); unsafe_put_user(cpu_id, &rseq->cpu_id, efault_end); unsafe_put_user(node_id, &rseq->node_id, efault_end); + unsafe_put_user(mm_cid, &rseq->mm_cid, efault_end); /* * Additional feature fields added after ORIG_RSEQ_SIZE * need to be conditionally updated only if @@ -113,7 +116,8 @@ efault: static int rseq_reset_rseq_cpu_node_id(struct task_struct *t) { - u32 cpu_id_start = 0, cpu_id = RSEQ_CPU_ID_UNINITIALIZED, node_id = 0; + u32 cpu_id_start = 0, cpu_id = RSEQ_CPU_ID_UNINITIALIZED, node_id = 0, + mm_cid = 0; /* * Reset cpu_id_start to its initial state (0). @@ -132,6 +136,11 @@ static int rseq_reset_rseq_cpu_node_id(struct task_struct *t) */ if (put_user(node_id, &t->rseq->node_id)) return -EFAULT; + /* + * Reset mm_cid to its initial state (0). + */ + if (put_user(mm_cid, &t->rseq->mm_cid)) + return -EFAULT; /* * Additional feature fields added after ORIG_RSEQ_SIZE * need to be conditionally reset only if -- cgit v1.2.3 From 14a8644d4f76fb4afdfcc46e9193af867241bd42 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 22 Nov 2022 15:39:23 -0500 Subject: tracing/rseq: Add mm_cid field to rseq_update Add the mm_cid field to the rseq_update event, allowing tracers to follow which mm_cid is observed by user-space, and whether negative mm_cid values are visible in case of internal scheduler implementation issues. Signed-off-by: Mathieu Desnoyers Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/r/20221122203932.231377-22-mathieu.desnoyers@efficios.com --- include/trace/events/rseq.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/trace/events/rseq.h b/include/trace/events/rseq.h index dde7a359b4ef..823b47d1ba1e 100644 --- a/include/trace/events/rseq.h +++ b/include/trace/events/rseq.h @@ -17,14 +17,17 @@ TRACE_EVENT(rseq_update, TP_STRUCT__entry( __field(s32, cpu_id) __field(s32, node_id) + __field(s32, mm_cid) ), TP_fast_assign( __entry->cpu_id = raw_smp_processor_id(); __entry->node_id = cpu_to_node(__entry->cpu_id); + __entry->mm_cid = task_mm_cid(t); ), - TP_printk("cpu_id=%d node_id=%d", __entry->cpu_id, __entry->node_id) + TP_printk("cpu_id=%d node_id=%d mm_cid=%d", __entry->cpu_id, + __entry->node_id, __entry->mm_cid) ); TRACE_EVENT(rseq_ip_fixup, -- cgit v1.2.3 From c89970202a1153b2fc230e89f90c180bd5bcbcef Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Dec 2022 17:07:05 +1000 Subject: cputime: remove cputime_to_nsecs fallback The archs that use cputime_to_nsecs() internally provide their own definition and don't need the fallback. cputime_to_usecs() unused except in this fallback, and is not defined anywhere. This removes the final remnant of the cputime_t code from the kernel. Signed-off-by: Nicholas Piggin Signed-off-by: Peter Zijlstra (Intel) Acked-by: Alexander Gordeev Link: https://lore.kernel.org/r/20221220070705.2958959-1-npiggin@gmail.com --- arch/s390/kernel/idle.c | 2 +- arch/s390/kernel/vtime.c | 2 +- include/linux/sched/cputime.h | 9 --------- kernel/sched/cputime.c | 4 ++++ 4 files changed, 6 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c index 4bf1ee293f2b..a6bbceaf7616 100644 --- a/arch/s390/kernel/idle.c +++ b/arch/s390/kernel/idle.c @@ -12,9 +12,9 @@ #include #include #include -#include #include #include +#include #include #include #include "entry.h" diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 9436f3053b88..e0a88dcaf5cb 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -7,13 +7,13 @@ */ #include -#include #include #include #include #include #include #include +#include #include #include #include diff --git a/include/linux/sched/cputime.h b/include/linux/sched/cputime.h index ce3c58286062..5f8fd5b24a2e 100644 --- a/include/linux/sched/cputime.h +++ b/include/linux/sched/cputime.h @@ -8,15 +8,6 @@ * cputime accounting APIs: */ -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE -#include - -#ifndef cputime_to_nsecs -# define cputime_to_nsecs(__ct) \ - (cputime_to_usecs(__ct) * NSEC_PER_USEC) -#endif -#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ - #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN extern bool task_cputime(struct task_struct *t, u64 *utime, u64 *stime); diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 95fc77853743..af7952f12e6c 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -3,6 +3,10 @@ * Simple CPU accounting cgroup controller */ +#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE + #include +#endif + #ifdef CONFIG_IRQ_TIME_ACCOUNTING /* -- cgit v1.2.3 From 031bc3a9f9decd25cc29a27dcdcf893949f4e26a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 26 Dec 2022 06:21:39 +0200 Subject: dt-bindings: clock: qcom: gcc-qcs404: add two GDSC entries On QCS404 platform the Global Clock Controller supports two GDSCs: MDSS (display) and OXILI (GPU). Add corresponding indices. Acked-by: Krzysztof Kozlowski Signed-off-by: Dmitry Baryshkov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20221226042154.2666748-2-dmitry.baryshkov@linaro.org --- include/dt-bindings/clock/qcom,gcc-qcs404.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/dt-bindings/clock/qcom,gcc-qcs404.h b/include/dt-bindings/clock/qcom,gcc-qcs404.h index bc3051543347..126a51898571 100644 --- a/include/dt-bindings/clock/qcom,gcc-qcs404.h +++ b/include/dt-bindings/clock/qcom,gcc-qcs404.h @@ -177,4 +177,8 @@ #define GCC_PCIE_0_PIPE_ARES 21 #define GCC_WDSP_RESTART 22 +/* Indexes for GDSCs */ +#define MDSS_GDSC 0 +#define OXILI_GDSC 1 + #endif -- cgit v1.2.3 From a73bf9f2d969cbb04d5ca778f2a224060cda1027 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 22 Dec 2022 21:49:16 -0800 Subject: bpf: reorganize struct bpf_reg_state fields Move id and ref_obj_id fields after scalar data section (var_off and ranges). This is necessary to simplify next patch which will change regsafe()'s logic to be safer, as it makes the contents that has to be an exact match (type-specific parts, off, type, and var_off+ranges) a single sequential block of memory, while id and ref_obj_id should always be remapped and thus can't be memcp()'ed. There are few places that assume that var_off is after id/ref_obj_id to clear out id/ref_obj_id with the single memset(0). These are changed to explicitly zero-out id/ref_obj_id fields. Other places are adjusted to preserve exact byte-by-byte comparison behavior. No functional changes. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20221223054921.958283-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 40 ++++++++++++++++++++-------------------- kernel/bpf/verifier.c | 17 ++++++++--------- 2 files changed, 28 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 53d175cbaa02..127058cfec47 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -92,6 +92,26 @@ struct bpf_reg_state { u32 subprogno; /* for PTR_TO_FUNC */ }; + /* For scalar types (SCALAR_VALUE), this represents our knowledge of + * the actual value. + * For pointer types, this represents the variable part of the offset + * from the pointed-to object, and is shared with all bpf_reg_states + * with the same id as us. + */ + struct tnum var_off; + /* Used to determine if any memory access using this register will + * result in a bad access. + * These refer to the same value as var_off, not necessarily the actual + * contents of the register. + */ + s64 smin_value; /* minimum possible (s64)value */ + s64 smax_value; /* maximum possible (s64)value */ + u64 umin_value; /* minimum possible (u64)value */ + u64 umax_value; /* maximum possible (u64)value */ + s32 s32_min_value; /* minimum possible (s32)value */ + s32 s32_max_value; /* maximum possible (s32)value */ + u32 u32_min_value; /* minimum possible (u32)value */ + u32 u32_max_value; /* maximum possible (u32)value */ /* For PTR_TO_PACKET, used to find other pointers with the same variable * offset, so they can share range knowledge. * For PTR_TO_MAP_VALUE_OR_NULL this is used to share which map value we @@ -144,26 +164,6 @@ struct bpf_reg_state { * allowed and has the same effect as bpf_sk_release(sk). */ u32 ref_obj_id; - /* For scalar types (SCALAR_VALUE), this represents our knowledge of - * the actual value. - * For pointer types, this represents the variable part of the offset - * from the pointed-to object, and is shared with all bpf_reg_states - * with the same id as us. - */ - struct tnum var_off; - /* Used to determine if any memory access using this register will - * result in a bad access. - * These refer to the same value as var_off, not necessarily the actual - * contents of the register. - */ - s64 smin_value; /* minimum possible (s64)value */ - s64 smax_value; /* maximum possible (s64)value */ - u64 umin_value; /* minimum possible (u64)value */ - u64 umax_value; /* maximum possible (u64)value */ - s32 s32_min_value; /* minimum possible (s32)value */ - s32 s32_max_value; /* maximum possible (s32)value */ - u32 u32_min_value; /* minimum possible (u32)value */ - u32 u32_max_value; /* maximum possible (u32)value */ /* parentage chain for liveness checking */ struct bpf_reg_state *parent; /* Inside the callee two registers can be both PTR_TO_STACK like diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ab8337f6a576..e419e6024251 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1402,9 +1402,11 @@ static void ___mark_reg_known(struct bpf_reg_state *reg, u64 imm) */ static void __mark_reg_known(struct bpf_reg_state *reg, u64 imm) { - /* Clear id, off, and union(map_ptr, range) */ + /* Clear off and union(map_ptr, range) */ memset(((u8 *)reg) + sizeof(reg->type), 0, offsetof(struct bpf_reg_state, var_off) - sizeof(reg->type)); + reg->id = 0; + reg->ref_obj_id = 0; ___mark_reg_known(reg, imm); } @@ -1750,11 +1752,13 @@ static void __mark_reg_unknown(const struct bpf_verifier_env *env, struct bpf_reg_state *reg) { /* - * Clear type, id, off, and union(map_ptr, range) and + * Clear type, off, and union(map_ptr, range) and * padding between 'type' and union */ memset(reg, 0, offsetof(struct bpf_reg_state, var_off)); reg->type = SCALAR_VALUE; + reg->id = 0; + reg->ref_obj_id = 0; reg->var_off = tnum_unknown; reg->frameno = 0; reg->precise = !env->bpf_capable; @@ -13104,7 +13108,7 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, if (type_may_be_null(rold->type)) { if (!type_may_be_null(rcur->type)) return false; - if (memcmp(rold, rcur, offsetof(struct bpf_reg_state, id))) + if (memcmp(rold, rcur, offsetof(struct bpf_reg_state, var_off))) return false; /* Check our ids match any regs they're supposed to */ return check_ids(rold->id, rcur->id, idmap); @@ -13112,13 +13116,8 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, /* If the new min/max/var_off satisfy the old ones and * everything else matches, we are OK. - * 'id' is not compared, since it's only used for maps with - * bpf_spin_lock inside map element and in such cases if - * the rest of the prog is valid for one map element then - * it's valid for all map elements regardless of the key - * used in bpf_map_lookup() */ - return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 && + return memcmp(rold, rcur, offsetof(struct bpf_reg_state, var_off)) == 0 && range_within(rold, rcur) && tnum_in(rold->var_off, rcur->var_off) && check_ids(rold->id, rcur->id, idmap); -- cgit v1.2.3 From e873d4329ccb891bf3b17f1e0d44396de943e92d Mon Sep 17 00:00:00 2001 From: Joy Zou Date: Tue, 15 Nov 2022 17:38:23 +0800 Subject: dmaengine: imx-sdma: support hdmi in sdma The hdmi script already supported in sdma firmware. So add support hdmi in sdma driver. The design of hdmi script is different from common script such as sai. There is no need to config buffer descriptor for HDMI. The cyclic capability is achieved by the hdmi script. The slave config is so simple, only config src_addr, dts_addr and direction DMA_TRANS_NONE. Signed-off-by: Joy Zou Reviewed-by: Sascha Hauer Link: https://lore.kernel.org/r/20221115093823.2879128-3-joy.zou@nxp.com Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 38 ++++++++++++++++++++++++++++++-------- include/linux/dma/imx-dma.h | 1 + 2 files changed, 31 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index fbea5f62dd98..ab877ceeac3f 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -954,7 +954,10 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id) desc = sdmac->desc; if (desc) { if (sdmac->flags & IMX_DMA_SG_LOOP) { - sdma_update_channel_loop(sdmac); + if (sdmac->peripheral_type != IMX_DMATYPE_HDMI) + sdma_update_channel_loop(sdmac); + else + vchan_cyclic_callback(&desc->vd); } else { mxc_sdma_handle_channel_normal(sdmac); vchan_cookie_complete(&desc->vd); @@ -1074,6 +1077,10 @@ static int sdma_get_pc(struct sdma_channel *sdmac, per_2_emi = sdma->script_addrs->sai_2_mcu_addr; emi_2_per = sdma->script_addrs->mcu_2_sai_addr; break; + case IMX_DMATYPE_HDMI: + emi_2_per = sdma->script_addrs->hdmi_dma_addr; + sdmac->is_ram_script = true; + break; default: dev_err(sdma->dev, "Unsupported transfer type %d\n", peripheral_type); @@ -1125,11 +1132,16 @@ static int sdma_load_context(struct sdma_channel *sdmac) /* Send by context the event mask,base address for peripheral * and watermark level */ - context->gReg[0] = sdmac->event_mask[1]; - context->gReg[1] = sdmac->event_mask[0]; - context->gReg[2] = sdmac->per_addr; - context->gReg[6] = sdmac->shp_addr; - context->gReg[7] = sdmac->watermark_level; + if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) { + context->gReg[4] = sdmac->per_addr; + context->gReg[6] = sdmac->shp_addr; + } else { + context->gReg[0] = sdmac->event_mask[1]; + context->gReg[1] = sdmac->event_mask[0]; + context->gReg[2] = sdmac->per_addr; + context->gReg[6] = sdmac->shp_addr; + context->gReg[7] = sdmac->watermark_level; + } bd0->mode.command = C0_SETDM; bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD; @@ -1513,7 +1525,7 @@ static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac, desc->sdmac = sdmac; desc->num_bd = bds; - if (sdma_alloc_bd(desc)) + if (bds && sdma_alloc_bd(desc)) goto err_desc_out; /* No slave_config called in MEMCPY case, so do here */ @@ -1678,13 +1690,16 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( { struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; - int num_periods = buf_len / period_len; + int num_periods = 0; int channel = sdmac->channel; int i = 0, buf = 0; struct sdma_desc *desc; dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel); + if (sdmac->peripheral_type != IMX_DMATYPE_HDMI) + num_periods = buf_len / period_len; + sdma_config_write(chan, &sdmac->slave_config, direction); desc = sdma_transfer_init(sdmac, direction, num_periods); @@ -1701,6 +1716,9 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( goto err_bd_out; } + if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) + return vchan_tx_prep(&sdmac->vc, &desc->vd, flags); + while (buf < buf_len) { struct sdma_buffer_descriptor *bd = &desc->bd[i]; int param; @@ -1761,6 +1779,10 @@ static int sdma_config_write(struct dma_chan *chan, sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16) & SDMA_WATERMARK_LEVEL_HWML; sdmac->word_size = dmaengine_cfg->dst_addr_width; + } else if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) { + sdmac->per_address = dmaengine_cfg->dst_addr; + sdmac->per_address2 = dmaengine_cfg->src_addr; + sdmac->watermark_level = 0; } else { sdmac->per_address = dmaengine_cfg->dst_addr; sdmac->watermark_level = dmaengine_cfg->dst_maxburst * diff --git a/include/linux/dma/imx-dma.h b/include/linux/dma/imx-dma.h index f487a4fa103a..cfec5f946e23 100644 --- a/include/linux/dma/imx-dma.h +++ b/include/linux/dma/imx-dma.h @@ -40,6 +40,7 @@ enum sdma_peripheral_type { IMX_DMATYPE_ASRC_SP, /* Shared ASRC */ IMX_DMATYPE_SAI, /* SAI */ IMX_DMATYPE_MULTI_SAI, /* MULTI FIFOs For Audio */ + IMX_DMATYPE_HDMI, /* HDMI Audio */ }; enum imx_dma_prio { -- cgit v1.2.3 From a5ac24ba17590866cf1ff8fe44cd2738c003d52f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 7 Dec 2022 03:27:59 +0200 Subject: arm64: dts: qcom: sm8450: add RPMH_REGULATOR_LEVEL_LOW_SVS_D1 Add another power saving state used on SM8450. Unfortunately adding it in proper place causes renumbering of all the opp states in sm8450.dtsi Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20221207012803.114959-2-dmitry.baryshkov@linaro.org --- arch/arm64/boot/dts/qcom/sm8450.dtsi | 20 ++++++++++++-------- include/dt-bindings/power/qcom-rpmpd.h | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index 570475040d95..1b48d776aa2c 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -3580,35 +3580,39 @@ opp-level = ; }; - rpmhpd_opp_low_svs: opp3 { + rpmhpd_opp_low_svs_d1: opp3 { + opp-level = ; + }; + + rpmhpd_opp_low_svs: opp4 { opp-level = ; }; - rpmhpd_opp_svs: opp4 { + rpmhpd_opp_svs: opp5 { opp-level = ; }; - rpmhpd_opp_svs_l1: opp5 { + rpmhpd_opp_svs_l1: opp6 { opp-level = ; }; - rpmhpd_opp_nom: opp6 { + rpmhpd_opp_nom: opp7 { opp-level = ; }; - rpmhpd_opp_nom_l1: opp7 { + rpmhpd_opp_nom_l1: opp8 { opp-level = ; }; - rpmhpd_opp_nom_l2: opp8 { + rpmhpd_opp_nom_l2: opp9 { opp-level = ; }; - rpmhpd_opp_turbo: opp9 { + rpmhpd_opp_turbo: opp10 { opp-level = ; }; - rpmhpd_opp_turbo_l1: opp10 { + rpmhpd_opp_turbo_l1: opp11 { opp-level = ; }; }; diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index 1e19e258a74d..278de6df425e 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -190,6 +190,7 @@ /* SDM845 Power Domain performance levels */ #define RPMH_REGULATOR_LEVEL_RETENTION 16 #define RPMH_REGULATOR_LEVEL_MIN_SVS 48 +#define RPMH_REGULATOR_LEVEL_LOW_SVS_D1 56 #define RPMH_REGULATOR_LEVEL_LOW_SVS 64 #define RPMH_REGULATOR_LEVEL_SVS 128 #define RPMH_REGULATOR_LEVEL_SVS_L0 144 -- cgit v1.2.3 From 08f01cc1d6e240092a6d9bfa21652622657f38f0 Mon Sep 17 00:00:00 2001 From: Gerald Loacker Date: Thu, 1 Dec 2022 08:22:18 +0100 Subject: iio: add struct declaration for iio types Add struct for iio type arrays such as IIO_AVAIL_LIST which can be used instead of int arrays. Signed-off-by: Gerald Loacker Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20221201072220.402585-2-gerald.loacker@wolfvision.net Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 8e0afaaa3f75..81413cd3a3e7 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -381,6 +381,11 @@ s64 iio_get_time_ns(const struct iio_dev *indio_dev); #define INDIO_MAX_RAW_ELEMENTS 4 +struct iio_val_int_plus_micro { + int integer; + int micro; +}; + struct iio_trigger; /* forward declaration */ /** -- cgit v1.2.3 From 1f5e408f6a000be980872b8065e547e2dbef6acc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 7 Dec 2022 21:03:44 +0200 Subject: iio: light: tsl2563: Drop legacy platform data code There is no in-kernel user for legacy platform data. Otherwise, a new one can use software nodes instead. Hence, drop legacy platform data code. Signed-off-by: Andy Shevchenko Tested-by: Ferry Toth Link: https://lore.kernel.org/r/20221207190348.9347-7-andriy.shevchenko@linux.intel.com Signed-off-by: Jonathan Cameron --- drivers/iio/light/tsl2563.c | 12 ++---------- include/linux/platform_data/tsl2563.h | 9 --------- 2 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 include/linux/platform_data/tsl2563.h (limited to 'include') diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index cce044556293..ed193a3da91e 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -29,7 +29,6 @@ #include #include #include -#include /* Use this many bits for fraction part. */ #define ADC_FRAC_BITS 14 @@ -698,7 +697,6 @@ static int tsl2563_probe(struct i2c_client *client) struct device *dev = &client->dev; struct iio_dev *indio_dev; struct tsl2563_chip *chip; - struct tsl2563_platform_data *pdata = client->dev.platform_data; unsigned long irq_flags; u8 id = 0; int err; @@ -730,14 +728,8 @@ static int tsl2563_probe(struct i2c_client *client) chip->calib0 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS); chip->calib1 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS); - if (pdata) { - chip->cover_comp_gain = pdata->cover_comp_gain; - } else { - err = device_property_read_u32(&client->dev, "amstaos,cover-comp-gain", - &chip->cover_comp_gain); - if (err) - chip->cover_comp_gain = 1; - } + chip->cover_comp_gain = 1; + device_property_read_u32(dev, "amstaos,cover-comp-gain", &chip->cover_comp_gain); dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f); indio_dev->name = client->name; diff --git a/include/linux/platform_data/tsl2563.h b/include/linux/platform_data/tsl2563.h deleted file mode 100644 index 9cf9309c3f24..000000000000 --- a/include/linux/platform_data/tsl2563.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LINUX_TSL2563_H -#define __LINUX_TSL2563_H - -struct tsl2563_platform_data { - int cover_comp_gain; -}; - -#endif /* __LINUX_TSL2563_H */ -- cgit v1.2.3 From ba796801d2474a4773a6a0ebb94c53c96a294426 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 9 Dec 2022 18:48:37 +0200 Subject: dt-bindings: clocks: qcom: rpmcc: add LN_BB_CLK_PIN clocks Add pin-controlled Low-Noise BB clock definition. Signed-off-by: Dmitry Baryshkov Reviewed-by: Alex Elder Acked-by: Krzysztof Kozlowski Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20221209164855.128798-2-dmitry.baryshkov@linaro.org --- include/dt-bindings/clock/qcom,rpmcc.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/dt-bindings/clock/qcom,rpmcc.h b/include/dt-bindings/clock/qcom,rpmcc.h index c0ad624e930e..46309c9953b2 100644 --- a/include/dt-bindings/clock/qcom,rpmcc.h +++ b/include/dt-bindings/clock/qcom,rpmcc.h @@ -168,5 +168,7 @@ #define RPM_SMD_MSS_CFG_AHB_CLK 122 #define RPM_SMD_MSS_CFG_AHB_A_CLK 123 #define RPM_SMD_BIMC_FREQ_LOG 124 +#define RPM_SMD_LN_BB_CLK_PIN 125 +#define RPM_SMD_LN_BB_A_CLK_PIN 126 #endif -- cgit v1.2.3 From c941b98781b348bd63fb8f8b5307b10fde2af0c1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 9 Dec 2022 18:48:39 +0200 Subject: clk: qcom: smd-rpm: remove duplication between MMXI and MMAXI defines The commit 644c42295592 ("clk: qcom: smd: Add SM6375 clocks") added a duplicate of the existing define QCOM_SMD_RPM_MMAXI_CLK, drop it now. Fixes: 644c42295592 ("clk: qcom: smd: Add SM6375 clocks") Reviewed-by: Alex Elder Signed-off-by: Dmitry Baryshkov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20221209164855.128798-4-dmitry.baryshkov@linaro.org --- drivers/clk/qcom/clk-smd-rpm.c | 4 ++-- include/linux/soc/qcom/smd-rpm.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 3082f38513fa..ccc54913eca5 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -1122,8 +1122,8 @@ static const struct rpm_smd_clk_desc rpm_clk_sm6115 = { }; /* SM6375 */ -DEFINE_CLK_SMD_RPM(sm6375, mmnrt_clk, mmnrt_a_clk, QCOM_SMD_RPM_MMXI_CLK, 0); -DEFINE_CLK_SMD_RPM(sm6375, mmrt_clk, mmrt_a_clk, QCOM_SMD_RPM_MMXI_CLK, 1); +DEFINE_CLK_SMD_RPM(sm6375, mmnrt_clk, mmnrt_a_clk, QCOM_SMD_RPM_MMAXI_CLK, 0); +DEFINE_CLK_SMD_RPM(sm6375, mmrt_clk, mmrt_a_clk, QCOM_SMD_RPM_MMAXI_CLK, 1); DEFINE_CLK_SMD_RPM(qcm2290, hwkm_clk, hwkm_a_clk, QCOM_SMD_RPM_HWKM_CLK, 0); DEFINE_CLK_SMD_RPM(qcm2290, pka_clk, pka_a_clk, QCOM_SMD_RPM_PKA_CLK, 0); DEFINE_CLK_SMD_RPM_BRANCH(sm6375, bimc_freq_log, bimc_freq_log_a, QCOM_SMD_RPM_MISC_CLK, 4, 1); diff --git a/include/linux/soc/qcom/smd-rpm.h b/include/linux/soc/qcom/smd-rpm.h index 62de54992e49..2990f425fdef 100644 --- a/include/linux/soc/qcom/smd-rpm.h +++ b/include/linux/soc/qcom/smd-rpm.h @@ -43,7 +43,6 @@ struct qcom_smd_rpm; #define QCOM_SMD_RPM_HWKM_CLK 0x6d6b7768 #define QCOM_SMD_RPM_PKA_CLK 0x616b70 #define QCOM_SMD_RPM_MCFG_CLK 0x6766636d -#define QCOM_SMD_RPM_MMXI_CLK 0x69786d6d int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm, int state, -- cgit v1.2.3 From 7afc1f6977d0b0d1b722aaedf6d9796df9a82325 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 13 Dec 2022 16:26:15 +0100 Subject: dt-bindings: clock: add QCOM SM6350 camera clock bindings Add device tree bindings for camera clock controller for Qualcomm Technology Inc's SM6350 SoC. Signed-off-by: Konrad Dybcio Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20221213152617.296426-1-konrad.dybcio@linaro.org --- .../bindings/clock/qcom,sm6350-camcc.yaml | 49 +++++++++ include/dt-bindings/clock/qcom,sm6350-camcc.h | 109 +++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sm6350-camcc.yaml create mode 100644 include/dt-bindings/clock/qcom,sm6350-camcc.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/qcom,sm6350-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm6350-camcc.yaml new file mode 100644 index 000000000000..fd6658cb793d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm6350-camcc.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm6350-camcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Camera Clock & Reset Controller on SM6350 + +maintainers: + - Konrad Dybcio + +description: | + Qualcomm camera clock control module provides the clocks, resets and power + domains on SM6350. + + See also:: include/dt-bindings/clock/qcom,sm6350-camcc.h + +properties: + compatible: + const: qcom,sm6350-camcc + + clocks: + items: + - description: Board XO source + + reg: + maxItems: 1 + +required: + - compatible + - clocks + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@ad00000 { + compatible = "qcom,sm6350-camcc"; + reg = <0x0ad00000 0x16000>; + clocks = <&rpmhcc RPMH_CXO_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/include/dt-bindings/clock/qcom,sm6350-camcc.h b/include/dt-bindings/clock/qcom,sm6350-camcc.h new file mode 100644 index 000000000000..c6bcdc8fd485 --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm6350-camcc.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Linaro Limited + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_CAMCC_SM6350_H +#define _DT_BINDINGS_CLK_QCOM_CAMCC_SM6350_H + +/* CAMCC clocks */ +#define CAMCC_PLL2_OUT_EARLY 0 +#define CAMCC_PLL0 1 +#define CAMCC_PLL0_OUT_EVEN 2 +#define CAMCC_PLL1 3 +#define CAMCC_PLL1_OUT_EVEN 4 +#define CAMCC_PLL2 5 +#define CAMCC_PLL2_OUT_MAIN 6 +#define CAMCC_PLL3 7 +#define CAMCC_BPS_AHB_CLK 8 +#define CAMCC_BPS_AREG_CLK 9 +#define CAMCC_BPS_AXI_CLK 10 +#define CAMCC_BPS_CLK 11 +#define CAMCC_BPS_CLK_SRC 12 +#define CAMCC_CAMNOC_ATB_CLK 13 +#define CAMCC_CAMNOC_AXI_CLK 14 +#define CAMCC_CCI_0_CLK 15 +#define CAMCC_CCI_0_CLK_SRC 16 +#define CAMCC_CCI_1_CLK 17 +#define CAMCC_CCI_1_CLK_SRC 18 +#define CAMCC_CORE_AHB_CLK 19 +#define CAMCC_CPAS_AHB_CLK 20 +#define CAMCC_CPHY_RX_CLK_SRC 21 +#define CAMCC_CSI0PHYTIMER_CLK 22 +#define CAMCC_CSI0PHYTIMER_CLK_SRC 23 +#define CAMCC_CSI1PHYTIMER_CLK 24 +#define CAMCC_CSI1PHYTIMER_CLK_SRC 25 +#define CAMCC_CSI2PHYTIMER_CLK 26 +#define CAMCC_CSI2PHYTIMER_CLK_SRC 27 +#define CAMCC_CSI3PHYTIMER_CLK 28 +#define CAMCC_CSI3PHYTIMER_CLK_SRC 29 +#define CAMCC_CSIPHY0_CLK 30 +#define CAMCC_CSIPHY1_CLK 31 +#define CAMCC_CSIPHY2_CLK 32 +#define CAMCC_CSIPHY3_CLK 33 +#define CAMCC_FAST_AHB_CLK_SRC 34 +#define CAMCC_ICP_APB_CLK 35 +#define CAMCC_ICP_ATB_CLK 36 +#define CAMCC_ICP_CLK 37 +#define CAMCC_ICP_CLK_SRC 38 +#define CAMCC_ICP_CTI_CLK 39 +#define CAMCC_ICP_TS_CLK 40 +#define CAMCC_IFE_0_AXI_CLK 41 +#define CAMCC_IFE_0_CLK 42 +#define CAMCC_IFE_0_CLK_SRC 43 +#define CAMCC_IFE_0_CPHY_RX_CLK 44 +#define CAMCC_IFE_0_CSID_CLK 45 +#define CAMCC_IFE_0_CSID_CLK_SRC 46 +#define CAMCC_IFE_0_DSP_CLK 47 +#define CAMCC_IFE_1_AXI_CLK 48 +#define CAMCC_IFE_1_CLK 49 +#define CAMCC_IFE_1_CLK_SRC 50 +#define CAMCC_IFE_1_CPHY_RX_CLK 51 +#define CAMCC_IFE_1_CSID_CLK 52 +#define CAMCC_IFE_1_CSID_CLK_SRC 53 +#define CAMCC_IFE_1_DSP_CLK 54 +#define CAMCC_IFE_2_AXI_CLK 55 +#define CAMCC_IFE_2_CLK 56 +#define CAMCC_IFE_2_CLK_SRC 57 +#define CAMCC_IFE_2_CPHY_RX_CLK 58 +#define CAMCC_IFE_2_CSID_CLK 59 +#define CAMCC_IFE_2_CSID_CLK_SRC 60 +#define CAMCC_IFE_2_DSP_CLK 61 +#define CAMCC_IFE_LITE_CLK 62 +#define CAMCC_IFE_LITE_CLK_SRC 63 +#define CAMCC_IFE_LITE_CPHY_RX_CLK 64 +#define CAMCC_IFE_LITE_CSID_CLK 65 +#define CAMCC_IFE_LITE_CSID_CLK_SRC 66 +#define CAMCC_IPE_0_AHB_CLK 67 +#define CAMCC_IPE_0_AREG_CLK 68 +#define CAMCC_IPE_0_AXI_CLK 69 +#define CAMCC_IPE_0_CLK 70 +#define CAMCC_IPE_0_CLK_SRC 71 +#define CAMCC_JPEG_CLK 72 +#define CAMCC_JPEG_CLK_SRC 73 +#define CAMCC_LRME_CLK 74 +#define CAMCC_LRME_CLK_SRC 75 +#define CAMCC_MCLK0_CLK 76 +#define CAMCC_MCLK0_CLK_SRC 77 +#define CAMCC_MCLK1_CLK 78 +#define CAMCC_MCLK1_CLK_SRC 79 +#define CAMCC_MCLK2_CLK 80 +#define CAMCC_MCLK2_CLK_SRC 81 +#define CAMCC_MCLK3_CLK 82 +#define CAMCC_MCLK3_CLK_SRC 83 +#define CAMCC_MCLK4_CLK 84 +#define CAMCC_MCLK4_CLK_SRC 85 +#define CAMCC_SLOW_AHB_CLK_SRC 86 +#define CAMCC_SOC_AHB_CLK 87 +#define CAMCC_SYS_TMR_CLK 88 + +/* GDSCs */ +#define BPS_GDSC 0 +#define IPE_0_GDSC 1 +#define IFE_0_GDSC 2 +#define IFE_1_GDSC 3 +#define IFE_2_GDSC 4 +#define TITAN_TOP_GDSC 5 + +#endif -- cgit v1.2.3 From 30465003ad776a922c32b2dac58db14f120f037e Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Sat, 17 Dec 2022 00:24:57 -0800 Subject: bpf: rename list_head -> graph_root in field info types Many of the structs recently added to track field info for linked-list head are useful as-is for rbtree root. So let's do a mechanical renaming of list_head-related types and fields: include/linux/bpf.h: struct btf_field_list_head -> struct btf_field_graph_root list_head -> graph_root in struct btf_field union kernel/bpf/btf.c: list_head -> graph_root in struct btf_field_info This is a nonfunctional change, functionality to actually use these fields for rbtree will be added in further patches. Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20221217082506.1570898-5-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 4 ++-- kernel/bpf/btf.c | 21 +++++++++++---------- kernel/bpf/helpers.c | 4 ++-- kernel/bpf/verifier.c | 21 +++++++++++---------- 4 files changed, 26 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 5fec2d1be6d7..1697bd87fc06 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -189,7 +189,7 @@ struct btf_field_kptr { u32 btf_id; }; -struct btf_field_list_head { +struct btf_field_graph_root { struct btf *btf; u32 value_btf_id; u32 node_offset; @@ -201,7 +201,7 @@ struct btf_field { enum btf_field_type type; union { struct btf_field_kptr kptr; - struct btf_field_list_head list_head; + struct btf_field_graph_root graph_root; }; }; diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index f7dd8af06413..578cee398550 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -3228,7 +3228,7 @@ struct btf_field_info { struct { const char *node_name; u32 value_btf_id; - } list_head; + } graph_root; }; }; @@ -3335,8 +3335,8 @@ static int btf_find_list_head(const struct btf *btf, const struct btf_type *pt, return -EINVAL; info->type = BPF_LIST_HEAD; info->off = off; - info->list_head.value_btf_id = id; - info->list_head.node_name = list_node; + info->graph_root.value_btf_id = id; + info->graph_root.node_name = list_node; return BTF_FIELD_FOUND; } @@ -3604,13 +3604,14 @@ static int btf_parse_list_head(const struct btf *btf, struct btf_field *field, u32 offset; int i; - t = btf_type_by_id(btf, info->list_head.value_btf_id); + t = btf_type_by_id(btf, info->graph_root.value_btf_id); /* We've already checked that value_btf_id is a struct type. We * just need to figure out the offset of the list_node, and * verify its type. */ for_each_member(i, t, member) { - if (strcmp(info->list_head.node_name, __btf_name_by_offset(btf, member->name_off))) + if (strcmp(info->graph_root.node_name, + __btf_name_by_offset(btf, member->name_off))) continue; /* Invalid BTF, two members with same name */ if (n) @@ -3627,9 +3628,9 @@ static int btf_parse_list_head(const struct btf *btf, struct btf_field *field, if (offset % __alignof__(struct bpf_list_node)) return -EINVAL; - field->list_head.btf = (struct btf *)btf; - field->list_head.value_btf_id = info->list_head.value_btf_id; - field->list_head.node_offset = offset; + field->graph_root.btf = (struct btf *)btf; + field->graph_root.value_btf_id = info->graph_root.value_btf_id; + field->graph_root.node_offset = offset; } if (!n) return -ENOENT; @@ -3736,11 +3737,11 @@ int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec) if (!(rec->fields[i].type & BPF_LIST_HEAD)) continue; - btf_id = rec->fields[i].list_head.value_btf_id; + btf_id = rec->fields[i].graph_root.value_btf_id; meta = btf_find_struct_meta(btf, btf_id); if (!meta) return -EFAULT; - rec->fields[i].list_head.value_rec = meta->record; + rec->fields[i].graph_root.value_rec = meta->record; if (!(rec->field_mask & BPF_LIST_NODE)) continue; diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 23aa8cf8fd1a..458db2db2f81 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1756,12 +1756,12 @@ unlock: while (head != orig_head) { void *obj = head; - obj -= field->list_head.node_offset; + obj -= field->graph_root.node_offset; head = head->next; /* The contained type can also have resources, including a * bpf_list_head which needs to be freed. */ - bpf_obj_free_fields(field->list_head.value_rec, obj); + bpf_obj_free_fields(field->graph_root.value_rec, obj); /* bpf_mem_free requires migrate_disable(), since we can be * called from map free path as well apart from BPF program (as * part of map ops doing bpf_obj_free_fields). diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b23812d2bb49..4a25375ebb0d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8776,21 +8776,22 @@ static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env, field = meta->arg_list_head.field; - et = btf_type_by_id(field->list_head.btf, field->list_head.value_btf_id); + et = btf_type_by_id(field->graph_root.btf, field->graph_root.value_btf_id); t = btf_type_by_id(reg->btf, reg->btf_id); - if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, 0, field->list_head.btf, - field->list_head.value_btf_id, true)) { + if (!btf_struct_ids_match(&env->log, reg->btf, reg->btf_id, 0, field->graph_root.btf, + field->graph_root.value_btf_id, true)) { verbose(env, "operation on bpf_list_head expects arg#1 bpf_list_node at offset=%d " "in struct %s, but arg is at offset=%d in struct %s\n", - field->list_head.node_offset, btf_name_by_offset(field->list_head.btf, et->name_off), + field->graph_root.node_offset, + btf_name_by_offset(field->graph_root.btf, et->name_off), list_node_off, btf_name_by_offset(reg->btf, t->name_off)); return -EINVAL; } - if (list_node_off != field->list_head.node_offset) { + if (list_node_off != field->graph_root.node_offset) { verbose(env, "arg#1 offset=%d, but expected bpf_list_node at offset=%d in struct %s\n", - list_node_off, field->list_head.node_offset, - btf_name_by_offset(field->list_head.btf, et->name_off)); + list_node_off, field->graph_root.node_offset, + btf_name_by_offset(field->graph_root.btf, et->name_off)); return -EINVAL; } /* Set arg#1 for expiration after unlock */ @@ -9232,9 +9233,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, mark_reg_known_zero(env, regs, BPF_REG_0); regs[BPF_REG_0].type = PTR_TO_BTF_ID | MEM_ALLOC; - regs[BPF_REG_0].btf = field->list_head.btf; - regs[BPF_REG_0].btf_id = field->list_head.value_btf_id; - regs[BPF_REG_0].off = field->list_head.node_offset; + regs[BPF_REG_0].btf = field->graph_root.btf; + regs[BPF_REG_0].btf_id = field->graph_root.value_btf_id; + regs[BPF_REG_0].off = field->graph_root.node_offset; } else if (meta.func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) { mark_reg_known_zero(env, regs, BPF_REG_0); regs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_TRUSTED; -- cgit v1.2.3 From 66773faf054b9d8c11e126f47e24b1dabdadb4d8 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Sat, 3 Dec 2022 01:20:53 +0200 Subject: dt-bindings: interconnect: Add Qualcomm SM8550 The Qualcomm SM8550 SoC has several bus fabrics that could be controlled and tuned dynamically according to the bandwidth demand. Signed-off-by: Abel Vesa Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20221202232054.2666830-2-abel.vesa@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,sm8550-rpmh.yaml | 139 +++++++++++++++ .../dt-bindings/interconnect/qcom,sm8550-rpmh.h | 189 +++++++++++++++++++++ 2 files changed, 328 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,sm8550-rpmh.yaml create mode 100644 include/dt-bindings/interconnect/qcom,sm8550-rpmh.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sm8550-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sm8550-rpmh.yaml new file mode 100644 index 000000000000..716bd21f6041 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sm8550-rpmh.yaml @@ -0,0 +1,139 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sm8550-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on SM8550 + +maintainers: + - Abel Vesa + - Neil Armstrong + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also:: include/dt-bindings/interconnect/qcom,sm8550-rpmh.h + +properties: + compatible: + enum: + - qcom,sm8550-aggre1-noc + - qcom,sm8550-aggre2-noc + - qcom,sm8550-clk-virt + - qcom,sm8550-cnoc-main + - qcom,sm8550-config-noc + - qcom,sm8550-gem-noc + - qcom,sm8550-lpass-ag-noc + - qcom,sm8550-lpass-lpiaon-noc + - qcom,sm8550-lpass-lpicx-noc + - qcom,sm8550-mc-virt + - qcom,sm8550-mmss-noc + - qcom,sm8550-nsp-noc + - qcom,sm8550-pcie-anoc + - qcom,sm8550-system-noc + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8550-clk-virt + - qcom,sm8550-mc-virt + then: + properties: + reg: false + else: + required: + - reg + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8550-pcie-anoc + then: + properties: + clocks: + items: + - description: aggre-NOC PCIe AXI clock + - description: cfg-NOC PCIe a-NOC AHB clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8550-aggre1-noc + then: + properties: + clocks: + items: + - description: aggre UFS PHY AXI clock + - description: aggre USB3 PRIM AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8550-aggre2-noc + then: + properties: + clocks: + items: + - description: RPMH CC IPA clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8550-aggre1-noc + - qcom,sm8550-aggre2-noc + - qcom,sm8550-pcie-anoc + then: + required: + - clocks + else: + properties: + clocks: false + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + + clk_virt: interconnect-0 { + compatible = "qcom,sm8550-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,sm8550-aggre1-noc"; + reg = <0x016e0000 0x14400>; + #interconnect-cells = <2>; + clocks = <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/include/dt-bindings/interconnect/qcom,sm8550-rpmh.h b/include/dt-bindings/interconnect/qcom,sm8550-rpmh.h new file mode 100644 index 000000000000..b38d0da7886f --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sm8550-rpmh.h @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Linaro Limited + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SM8550_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SM8550_H + +#define MASTER_QSPI_0 0 +#define MASTER_QUP_1 1 +#define MASTER_SDCC_4 2 +#define MASTER_UFS_MEM 3 +#define MASTER_USB3_0 4 +#define SLAVE_A1NOC_SNOC 5 + +#define MASTER_QDSS_BAM 0 +#define MASTER_QUP_2 1 +#define MASTER_CRYPTO 2 +#define MASTER_IPA 3 +#define MASTER_SP 4 +#define MASTER_QDSS_ETR 5 +#define MASTER_QDSS_ETR_1 6 +#define MASTER_SDCC_2 7 +#define SLAVE_A2NOC_SNOC 8 + +#define MASTER_QUP_CORE_0 0 +#define MASTER_QUP_CORE_1 1 +#define MASTER_QUP_CORE_2 2 +#define SLAVE_QUP_CORE_0 3 +#define SLAVE_QUP_CORE_1 4 +#define SLAVE_QUP_CORE_2 5 + +#define MASTER_CNOC_CFG 0 +#define SLAVE_AHB2PHY_SOUTH 1 +#define SLAVE_AHB2PHY_NORTH 2 +#define SLAVE_APPSS 3 +#define SLAVE_CAMERA_CFG 4 +#define SLAVE_CLK_CTL 5 +#define SLAVE_RBCPR_CX_CFG 6 +#define SLAVE_RBCPR_MMCX_CFG 7 +#define SLAVE_RBCPR_MXA_CFG 8 +#define SLAVE_RBCPR_MXC_CFG 9 +#define SLAVE_CPR_NSPCX 10 +#define SLAVE_CRYPTO_0_CFG 11 +#define SLAVE_CX_RDPM 12 +#define SLAVE_DISPLAY_CFG 13 +#define SLAVE_GFX3D_CFG 14 +#define SLAVE_I2C 15 +#define SLAVE_IMEM_CFG 16 +#define SLAVE_IPA_CFG 17 +#define SLAVE_IPC_ROUTER_CFG 18 +#define SLAVE_CNOC_MSS 19 +#define SLAVE_MX_RDPM 20 +#define SLAVE_PCIE_0_CFG 21 +#define SLAVE_PCIE_1_CFG 22 +#define SLAVE_PDM 23 +#define SLAVE_PIMEM_CFG 24 +#define SLAVE_PRNG 25 +#define SLAVE_QDSS_CFG 26 +#define SLAVE_QSPI_0 27 +#define SLAVE_QUP_1 28 +#define SLAVE_QUP_2 29 +#define SLAVE_SDCC_2 30 +#define SLAVE_SDCC_4 31 +#define SLAVE_SPSS_CFG 32 +#define SLAVE_TCSR 33 +#define SLAVE_TLMM 34 +#define SLAVE_UFS_MEM_CFG 35 +#define SLAVE_USB3_0 36 +#define SLAVE_VENUS_CFG 37 +#define SLAVE_VSENSE_CTRL_CFG 38 +#define SLAVE_LPASS_QTB_CFG 39 +#define SLAVE_CNOC_MNOC_CFG 40 +#define SLAVE_NSP_QTB_CFG 41 +#define SLAVE_PCIE_ANOC_CFG 42 +#define SLAVE_QDSS_STM 43 +#define SLAVE_TCU 44 + +#define MASTER_GEM_NOC_CNOC 0 +#define MASTER_GEM_NOC_PCIE_SNOC 1 +#define SLAVE_AOSS 2 +#define SLAVE_TME_CFG 3 +#define SLAVE_CNOC_CFG 4 +#define SLAVE_DDRSS_CFG 5 +#define SLAVE_BOOT_IMEM 6 +#define SLAVE_IMEM 7 +#define SLAVE_PCIE_0 8 +#define SLAVE_PCIE_1 9 + +#define MASTER_GPU_TCU 0 +#define MASTER_SYS_TCU 1 +#define MASTER_APPSS_PROC 2 +#define MASTER_GFX3D 3 +#define MASTER_LPASS_GEM_NOC 4 +#define MASTER_MSS_PROC 5 +#define MASTER_MNOC_HF_MEM_NOC 6 +#define MASTER_MNOC_SF_MEM_NOC 7 +#define MASTER_COMPUTE_NOC 8 +#define MASTER_ANOC_PCIE_GEM_NOC 9 +#define MASTER_SNOC_GC_MEM_NOC 10 +#define MASTER_SNOC_SF_MEM_NOC 11 +#define SLAVE_GEM_NOC_CNOC 12 +#define SLAVE_LLCC 13 +#define SLAVE_MEM_NOC_PCIE_SNOC 14 +#define MASTER_MNOC_HF_MEM_NOC_DISP 15 +#define MASTER_ANOC_PCIE_GEM_NOC_DISP 16 +#define SLAVE_LLCC_DISP 17 +#define MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0 18 +#define MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0 19 +#define MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0 20 +#define SLAVE_LLCC_CAM_IFE_0 21 +#define MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1 22 +#define MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1 23 +#define MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1 24 +#define SLAVE_LLCC_CAM_IFE_1 25 +#define MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2 26 +#define MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2 27 +#define MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2 28 +#define SLAVE_LLCC_CAM_IFE_2 29 + +#define MASTER_LPIAON_NOC 0 +#define SLAVE_LPASS_GEM_NOC 1 + +#define MASTER_LPASS_LPINOC 0 +#define SLAVE_LPIAON_NOC_LPASS_AG_NOC 1 + +#define MASTER_LPASS_PROC 0 +#define SLAVE_LPICX_NOC_LPIAON_NOC 1 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 +#define MASTER_LLCC_DISP 2 +#define SLAVE_EBI1_DISP 3 +#define MASTER_LLCC_CAM_IFE_0 4 +#define SLAVE_EBI1_CAM_IFE_0 5 +#define MASTER_LLCC_CAM_IFE_1 6 +#define SLAVE_EBI1_CAM_IFE_1 7 +#define MASTER_LLCC_CAM_IFE_2 8 +#define SLAVE_EBI1_CAM_IFE_2 9 + +#define MASTER_CAMNOC_HF 0 +#define MASTER_CAMNOC_ICP 1 +#define MASTER_CAMNOC_SF 2 +#define MASTER_MDP 3 +#define MASTER_CDSP_HCP 4 +#define MASTER_VIDEO 5 +#define MASTER_VIDEO_CV_PROC 6 +#define MASTER_VIDEO_PROC 7 +#define MASTER_VIDEO_V_PROC 8 +#define MASTER_CNOC_MNOC_CFG 9 +#define SLAVE_MNOC_HF_MEM_NOC 10 +#define SLAVE_MNOC_SF_MEM_NOC 11 +#define SLAVE_SERVICE_MNOC 12 +#define MASTER_MDP_DISP 13 +#define SLAVE_MNOC_HF_MEM_NOC_DISP 14 +#define MASTER_CAMNOC_HF_CAM_IFE_0 15 +#define MASTER_CAMNOC_ICP_CAM_IFE_0 16 +#define MASTER_CAMNOC_SF_CAM_IFE_0 17 +#define SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0 18 +#define SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 19 +#define MASTER_CAMNOC_HF_CAM_IFE_1 20 +#define MASTER_CAMNOC_ICP_CAM_IFE_1 21 +#define MASTER_CAMNOC_SF_CAM_IFE_1 22 +#define SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1 23 +#define SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 24 +#define MASTER_CAMNOC_HF_CAM_IFE_2 25 +#define MASTER_CAMNOC_ICP_CAM_IFE_2 26 +#define MASTER_CAMNOC_SF_CAM_IFE_2 27 +#define SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2 28 +#define SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 29 + +#define MASTER_CDSP_PROC 0 +#define SLAVE_CDSP_MEM_NOC 1 + +#define MASTER_PCIE_ANOC_CFG 0 +#define MASTER_PCIE_0 1 +#define MASTER_PCIE_1 2 +#define SLAVE_ANOC_PCIE_GEM_NOC 3 +#define SLAVE_SERVICE_PCIE_ANOC 4 + +#define MASTER_GIC_AHB 0 +#define MASTER_A1NOC_SNOC 1 +#define MASTER_A2NOC_SNOC 2 +#define MASTER_GIC 3 +#define SLAVE_SNOC_GEM_NOC_GC 4 +#define SLAVE_SNOC_GEM_NOC_SF 5 + +#endif -- cgit v1.2.3 From 26c48aea147cbf3dcec1df67d0684457ddf00fea Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 29 Dec 2022 18:38:35 +0800 Subject: spi: altera: switch to use modern name Change legacy name master/slave to modern name host/target or controller. No functional changed. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20221229103837.4192759-2-yangyingliang@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-altera-core.c | 30 +++++++++++++++--------------- drivers/spi/spi-altera-dfl.c | 2 +- drivers/spi/spi-altera-platform.c | 2 +- include/linux/spi/altera.h | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/spi/spi-altera-core.c b/drivers/spi/spi-altera-core.c index de4d31c530d9..94fe6bf1b9a6 100644 --- a/drivers/spi/spi-altera-core.c +++ b/drivers/spi/spi-altera-core.c @@ -24,7 +24,7 @@ #define ALTERA_SPI_TXDATA 4 #define ALTERA_SPI_STATUS 8 #define ALTERA_SPI_CONTROL 12 -#define ALTERA_SPI_SLAVE_SEL 20 +#define ALTERA_SPI_TARGET_SEL 20 #define ALTERA_SPI_STATUS_ROE_MSK 0x8 #define ALTERA_SPI_STATUS_TOE_MSK 0x10 @@ -67,7 +67,7 @@ static int altr_spi_readl(struct altera_spi *hw, unsigned int reg, static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev) { - return spi_master_get_devdata(sdev->master); + return spi_controller_get_devdata(sdev->controller); } static void altera_spi_set_cs(struct spi_device *spi, bool is_high) @@ -77,9 +77,9 @@ static void altera_spi_set_cs(struct spi_device *spi, bool is_high) if (is_high) { hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK; altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); - altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, 0); + altr_spi_writel(hw, ALTERA_SPI_TARGET_SEL, 0); } else { - altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, + altr_spi_writel(hw, ALTERA_SPI_TARGET_SEL, BIT(spi->chip_select)); hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK; altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); @@ -139,10 +139,10 @@ static void altera_spi_rx_word(struct altera_spi *hw) hw->count++; } -static int altera_spi_txrx(struct spi_master *master, +static int altera_spi_txrx(struct spi_controller *host, struct spi_device *spi, struct spi_transfer *t) { - struct altera_spi *hw = spi_master_get_devdata(master); + struct altera_spi *hw = spi_controller_get_devdata(host); u32 val; hw->tx = t->tx_buf; @@ -175,15 +175,15 @@ static int altera_spi_txrx(struct spi_master *master, altera_spi_rx_word(hw); } - spi_finalize_current_transfer(master); + spi_finalize_current_transfer(host); return 0; } irqreturn_t altera_spi_irq(int irq, void *dev) { - struct spi_master *master = dev; - struct altera_spi *hw = spi_master_get_devdata(master); + struct spi_controller *host = dev; + struct altera_spi *hw = spi_controller_get_devdata(host); altera_spi_rx_word(hw); @@ -194,20 +194,20 @@ irqreturn_t altera_spi_irq(int irq, void *dev) hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK; altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr); - spi_finalize_current_transfer(master); + spi_finalize_current_transfer(host); } return IRQ_HANDLED; } EXPORT_SYMBOL_GPL(altera_spi_irq); -void altera_spi_init_master(struct spi_master *master) +void altera_spi_init_host(struct spi_controller *host) { - struct altera_spi *hw = spi_master_get_devdata(master); + struct altera_spi *hw = spi_controller_get_devdata(host); u32 val; - master->transfer_one = altera_spi_txrx; - master->set_cs = altera_spi_set_cs; + host->transfer_one = altera_spi_txrx; + host->set_cs = altera_spi_set_cs; /* program defaults into the registers */ hw->imr = 0; /* disable spi interrupts */ @@ -217,6 +217,6 @@ void altera_spi_init_master(struct spi_master *master) if (val & ALTERA_SPI_STATUS_RRDY_MSK) altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */ } -EXPORT_SYMBOL_GPL(altera_spi_init_master); +EXPORT_SYMBOL_GPL(altera_spi_init_host); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-altera-dfl.c b/drivers/spi/spi-altera-dfl.c index 596e181ae136..0b3302a29989 100644 --- a/drivers/spi/spi-altera-dfl.c +++ b/drivers/spi/spi-altera-dfl.c @@ -156,7 +156,7 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) hw->irq = -EINVAL; - altera_spi_init_master(master); + altera_spi_init_host(master); err = devm_spi_register_master(dev, master); if (err) diff --git a/drivers/spi/spi-altera-platform.c b/drivers/spi/spi-altera-platform.c index 65147aae82a1..cde12c4b9cbc 100644 --- a/drivers/spi/spi-altera-platform.c +++ b/drivers/spi/spi-altera-platform.c @@ -107,7 +107,7 @@ static int altera_spi_probe(struct platform_device *pdev) } } - altera_spi_init_master(master); + altera_spi_init_host(master); /* irq is optional */ hw->irq = platform_get_irq(pdev, 0); diff --git a/include/linux/spi/altera.h b/include/linux/spi/altera.h index 2e2a622e56da..3b74c3750caf 100644 --- a/include/linux/spi/altera.h +++ b/include/linux/spi/altera.h @@ -14,7 +14,7 @@ /** * struct altera_spi_platform_data - Platform data of the Altera SPI driver - * @mode_bits: Mode bits of SPI master. + * @mode_bits: Mode bits of SPI host. * @num_chipselect: Number of chipselects. * @bits_per_word_mask: bitmask of supported bits_per_word for transfers. * @num_devices: Number of devices that shall be added when the driver @@ -46,5 +46,5 @@ struct altera_spi { }; extern irqreturn_t altera_spi_irq(int irq, void *dev); -extern void altera_spi_init_master(struct spi_master *master); +extern void altera_spi_init_host(struct spi_controller *host); #endif /* __LINUX_SPI_ALTERA_H */ -- cgit v1.2.3 From 63a1bd8ad1ac9e4e8bfcd5914c8899606e04898d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 30 Nov 2022 23:08:53 +0000 Subject: KVM: Drop arch hardware (un)setup hooks Drop kvm_arch_hardware_setup() and kvm_arch_hardware_unsetup() now that all implementations are nops. No functional change intended. Signed-off-by: Sean Christopherson Reviewed-by: Eric Farman # s390 Acked-by: Anup Patel Message-Id: <20221130230934.1014142-10-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/include/asm/kvm_host.h | 1 - arch/arm64/kvm/arm.c | 5 ----- arch/mips/include/asm/kvm_host.h | 1 - arch/mips/kvm/mips.c | 5 ----- arch/powerpc/include/asm/kvm_host.h | 1 - arch/powerpc/kvm/powerpc.c | 5 ----- arch/riscv/include/asm/kvm_host.h | 1 - arch/riscv/kvm/main.c | 5 ----- arch/s390/kvm/kvm-s390.c | 10 ---------- arch/x86/kvm/x86.c | 10 ---------- include/linux/kvm_host.h | 2 -- virt/kvm/kvm_main.c | 7 ------- 12 files changed, 53 deletions(-) (limited to 'include') diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 35a159d131b5..f50951c51d3b 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -943,7 +943,6 @@ static inline bool kvm_system_needs_idmapped_vectors(void) void kvm_arm_vcpu_ptrauth_trap(struct kvm_vcpu *vcpu); -static inline void kvm_arch_hardware_unsetup(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 9c5573bc4614..e6c21b804c13 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -63,11 +63,6 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE; } -int kvm_arch_hardware_setup(void *opaque) -{ - return 0; -} - int kvm_arch_check_processor_compat(void *opaque) { return 0; diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 5cedb28e8a40..28f0ba97db71 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -888,7 +888,6 @@ extern unsigned long kvm_mips_get_ramsize(struct kvm *kvm); extern int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_mips_interrupt *irq); -static inline void kvm_arch_hardware_unsetup(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) {} diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index a25e0b73ee70..af29490d9740 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -135,11 +135,6 @@ void kvm_arch_hardware_disable(void) kvm_mips_callbacks->hardware_disable(); } -int kvm_arch_hardware_setup(void *opaque) -{ - return 0; -} - int kvm_arch_check_processor_compat(void *opaque) { return 0; diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index caea15dcb91d..5d2c3a487e73 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -877,7 +877,6 @@ struct kvm_vcpu_arch { #define __KVM_HAVE_CREATE_DEVICE static inline void kvm_arch_hardware_disable(void) {} -static inline void kvm_arch_hardware_unsetup(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {} diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 04494a4fb37a..5faf69421f13 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -440,11 +440,6 @@ int kvm_arch_hardware_enable(void) return 0; } -int kvm_arch_hardware_setup(void *opaque) -{ - return 0; -} - int kvm_arch_check_processor_compat(void *opaque) { return kvmppc_core_check_processor_compat(); diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 93f43a3e7886..a79b7d1514db 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -230,7 +230,6 @@ struct kvm_vcpu_arch { bool pause; }; -static inline void kvm_arch_hardware_unsetup(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index 58c5489d3031..afd6400a9e80 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -25,11 +25,6 @@ int kvm_arch_check_processor_compat(void *opaque) return 0; } -int kvm_arch_hardware_setup(void *opaque) -{ - return 0; -} - int kvm_arch_hardware_enable(void) { unsigned long hideleg, hedeleg; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 97c7ccd189eb..829e6e046003 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -329,16 +329,6 @@ static struct notifier_block kvm_clock_notifier = { .notifier_call = kvm_clock_sync, }; -int kvm_arch_hardware_setup(void *opaque) -{ - return 0; -} - -void kvm_arch_hardware_unsetup(void) -{ - -} - static void allow_cpu_feat(unsigned long nr) { set_bit_inv(nr, kvm_s390_available_cpu_feat); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4e7a71cab828..089f0eeea850 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12033,16 +12033,6 @@ void kvm_arch_hardware_disable(void) drop_user_return_notifiers(); } -int kvm_arch_hardware_setup(void *opaque) -{ - return 0; -} - -void kvm_arch_hardware_unsetup(void) -{ - -} - int kvm_arch_check_processor_compat(void *opaque) { struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 4f26b244f6d0..7c1009c0e66d 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1447,8 +1447,6 @@ static inline void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) {} int kvm_arch_hardware_enable(void); void kvm_arch_hardware_disable(void); -int kvm_arch_hardware_setup(void *opaque); -void kvm_arch_hardware_unsetup(void); int kvm_arch_check_processor_compat(void *opaque); int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu); bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 70264378da41..8393347fd35f 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -5931,10 +5931,6 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, if (r) return r; - r = kvm_arch_hardware_setup(opaque); - if (r < 0) - goto err_hw_setup; - if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) { r = -ENOMEM; goto err_hw_enabled; @@ -6027,8 +6023,6 @@ out_free_3: out_free_2: free_cpumask_var(cpus_hardware_enabled); err_hw_enabled: - kvm_arch_hardware_unsetup(); -err_hw_setup: kvm_arch_exit(); return r; } @@ -6057,7 +6051,6 @@ void kvm_exit(void) on_each_cpu(hardware_disable_nolock, NULL, 1); kvm_irqfd_exit(); free_cpumask_var(cpus_hardware_enabled); - kvm_arch_hardware_unsetup(); kvm_arch_exit(); } EXPORT_SYMBOL_GPL(kvm_exit); -- cgit v1.2.3 From 466d27e48d7cd2542710309817cff1e91cd2e10a Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 30 Nov 2022 23:09:00 +0000 Subject: KVM: arm64: Simplify the CPUHP logic For a number of historical reasons, the KVM/arm64 hotplug setup is pretty complicated, and we have two extra CPUHP notifiers for vGIC and timers. It looks pretty pointless, and gets in the way of further changes. So let's just expose some helpers that can be called from the core CPUHP callback, and get rid of everything else. This gives us the opportunity to drop a useless notifier entry, as well as tidy-up the timer enable/disable, which was a bit odd. Signed-off-by: Marc Zyngier Signed-off-by: Isaku Yamahata Signed-off-by: Sean Christopherson Message-Id: <20221130230934.1014142-17-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/arch_timer.c | 27 ++++++++++----------------- arch/arm64/kvm/arm.c | 13 +++++++++++++ arch/arm64/kvm/vgic/vgic-init.c | 19 ++----------------- include/kvm/arm_arch_timer.h | 4 ++++ include/kvm/arm_vgic.h | 4 ++++ include/linux/cpuhotplug.h | 3 --- 6 files changed, 33 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index bb24a76b4224..33fca1a691a5 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -811,10 +811,18 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) ptimer->host_timer_irq_flags = host_ptimer_irq_flags; } -static void kvm_timer_init_interrupt(void *info) +void kvm_timer_cpu_up(void) { enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags); - enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags); + if (host_ptimer_irq) + enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags); +} + +void kvm_timer_cpu_down(void) +{ + disable_percpu_irq(host_vtimer_irq); + if (host_ptimer_irq) + disable_percpu_irq(host_ptimer_irq); } int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) @@ -976,18 +984,6 @@ void kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu, preempt_enable(); } -static int kvm_timer_starting_cpu(unsigned int cpu) -{ - kvm_timer_init_interrupt(NULL); - return 0; -} - -static int kvm_timer_dying_cpu(unsigned int cpu) -{ - disable_percpu_irq(host_vtimer_irq); - return 0; -} - static int timer_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) { if (vcpu) @@ -1185,9 +1181,6 @@ int kvm_timer_hyp_init(bool has_gic) goto out_free_irq; } - cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING, - "kvm/arm/timer:starting", kvm_timer_starting_cpu, - kvm_timer_dying_cpu); return 0; out_free_irq: free_percpu_irq(host_vtimer_irq, kvm_get_running_vcpus()); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index e6c21b804c13..b572c78f3c23 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1677,7 +1677,15 @@ static void _kvm_arch_hardware_enable(void *discard) int kvm_arch_hardware_enable(void) { + int was_enabled = __this_cpu_read(kvm_arm_hardware_enabled); + _kvm_arch_hardware_enable(NULL); + + if (!was_enabled) { + kvm_vgic_cpu_up(); + kvm_timer_cpu_up(); + } + return 0; } @@ -1691,6 +1699,11 @@ static void _kvm_arch_hardware_disable(void *discard) void kvm_arch_hardware_disable(void) { + if (__this_cpu_read(kvm_arm_hardware_enabled)) { + kvm_timer_cpu_down(); + kvm_vgic_cpu_down(); + } + if (!is_protected_kvm_enabled()) _kvm_arch_hardware_disable(NULL); } diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index f6d4f4052555..6c7f6ae21ec0 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -465,17 +465,15 @@ out: /* GENERIC PROBE */ -static int vgic_init_cpu_starting(unsigned int cpu) +void kvm_vgic_cpu_up(void) { enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0); - return 0; } -static int vgic_init_cpu_dying(unsigned int cpu) +void kvm_vgic_cpu_down(void) { disable_percpu_irq(kvm_vgic_global_state.maint_irq); - return 0; } static irqreturn_t vgic_maintenance_handler(int irq, void *data) @@ -584,19 +582,6 @@ int kvm_vgic_hyp_init(void) return ret; } - ret = cpuhp_setup_state(CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING, - "kvm/arm/vgic:starting", - vgic_init_cpu_starting, vgic_init_cpu_dying); - if (ret) { - kvm_err("Cannot register vgic CPU notifier\n"); - goto out_free_irq; - } - kvm_info("vgic interrupt IRQ%d\n", kvm_vgic_global_state.maint_irq); return 0; - -out_free_irq: - free_percpu_irq(kvm_vgic_global_state.maint_irq, - kvm_get_running_vcpus()); - return ret; } diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index cd6d8f260eab..1638418f72dd 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h @@ -104,4 +104,8 @@ void kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu, u32 timer_get_ctl(struct arch_timer_context *ctxt); u64 timer_get_cval(struct arch_timer_context *ctxt); +/* CPU HP callbacks */ +void kvm_timer_cpu_up(void); +void kvm_timer_cpu_down(void); + #endif diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 9270cd87da3f..0629e3532ad0 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -432,4 +432,8 @@ int vgic_v4_load(struct kvm_vcpu *vcpu); void vgic_v4_commit(struct kvm_vcpu *vcpu); int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db); +/* CPU HP callbacks */ +void kvm_vgic_cpu_up(void); +void kvm_vgic_cpu_down(void); + #endif /* __KVM_ARM_VGIC_H */ diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 6c6859bfc454..5cae6bd22f7f 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -188,9 +188,6 @@ enum cpuhp_state { CPUHP_AP_TI_GP_TIMER_STARTING, CPUHP_AP_HYPERV_TIMER_STARTING, CPUHP_AP_KVM_STARTING, - CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING, - CPUHP_AP_KVM_ARM_VGIC_STARTING, - CPUHP_AP_KVM_ARM_TIMER_STARTING, /* Must be the last timer callback */ CPUHP_AP_DUMMY_TIMER_STARTING, CPUHP_AP_ARM_XEN_STARTING, -- cgit v1.2.3 From a578a0a9e3526483ad1904fac019d95e7089fb34 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 30 Nov 2022 23:09:13 +0000 Subject: KVM: Drop kvm_arch_{init,exit}() hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop kvm_arch_init() and kvm_arch_exit() now that all implementations are nops. No functional change intended. Signed-off-by: Sean Christopherson Reviewed-by: Eric Farman # s390 Reviewed-by: Philippe Mathieu-Daudé Acked-by: Anup Patel Message-Id: <20221130230934.1014142-30-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/arm.c | 11 ----------- arch/mips/kvm/mips.c | 10 ---------- arch/powerpc/include/asm/kvm_host.h | 1 - arch/powerpc/kvm/powerpc.c | 5 ----- arch/riscv/kvm/main.c | 9 --------- arch/s390/kvm/kvm-s390.c | 10 ---------- arch/x86/kvm/x86.c | 10 ---------- include/linux/kvm_host.h | 3 --- virt/kvm/kvm_main.c | 19 ++----------------- 9 files changed, 2 insertions(+), 76 deletions(-) (limited to 'include') diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index ea8057fa113f..04ed741f7b9d 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -2301,17 +2301,6 @@ out_err: return err; } -int kvm_arch_init(void *opaque) -{ - return 0; -} - -/* NOP: Compiling as a module not supported */ -void kvm_arch_exit(void) -{ - -} - static int __init early_kvm_mode_cfg(char *arg) { if (!arg) diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index ae7a24342fdf..3cade648827a 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -1010,16 +1010,6 @@ long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) return r; } -int kvm_arch_init(void *opaque) -{ - return 0; -} - -void kvm_arch_exit(void) -{ - -} - int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 5d2c3a487e73..0a80e80c7b9e 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -881,7 +881,6 @@ static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} -static inline void kvm_arch_exit(void) {} static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index d44b85ba8cef..01d0f9935e6c 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -2539,11 +2539,6 @@ void kvmppc_init_lpid(unsigned long nr_lpids_param) } EXPORT_SYMBOL_GPL(kvmppc_init_lpid); -int kvm_arch_init(void *opaque) -{ - return 0; -} - EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ppc_instr); void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry) diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index 1cd220e96c26..be951feee27a 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -65,15 +65,6 @@ void kvm_arch_hardware_disable(void) csr_write(CSR_HIDELEG, 0); } -int kvm_arch_init(void *opaque) -{ - return 0; -} - -void kvm_arch_exit(void) -{ -} - static int __init riscv_kvm_init(void) { const char *str; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 66d162723d21..25b08b956888 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -541,16 +541,6 @@ static void __kvm_s390_exit(void) debug_unregister(kvm_s390_dbf_uv); } -int kvm_arch_init(void *opaque) -{ - return 0; -} - -void kvm_arch_exit(void) -{ - -} - /* Section: device related */ long kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 78cb6a46dd50..accf5a7ab8df 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9292,16 +9292,6 @@ static inline void kvm_ops_update(struct kvm_x86_init_ops *ops) kvm_pmu_ops_update(ops->pmu_ops); } -int kvm_arch_init(void *opaque) -{ - return 0; -} - -void kvm_arch_exit(void) -{ - -} - static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) { u64 host_pat; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 7c1009c0e66d..62d977bb1448 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1423,9 +1423,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg); int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu); -int kvm_arch_init(void *opaque); -void kvm_arch_exit(void); - void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu); void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 8393347fd35f..597ff734b312 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -5921,20 +5921,8 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, int r; int cpu; - /* - * FIXME: Get rid of kvm_arch_init(), vendor code should call arch code - * directly. Note, kvm_arch_init() _must_ be called before anything - * else as x86 relies on checks buried in kvm_arch_init() to guard - * against multiple calls to kvm_init(). - */ - r = kvm_arch_init(opaque); - if (r) - return r; - - if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) { - r = -ENOMEM; - goto err_hw_enabled; - } + if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) + return -ENOMEM; c.ret = &r; c.opaque = opaque; @@ -6022,8 +6010,6 @@ out_free_3: cpuhp_remove_state_nocalls(CPUHP_AP_KVM_STARTING); out_free_2: free_cpumask_var(cpus_hardware_enabled); -err_hw_enabled: - kvm_arch_exit(); return r; } EXPORT_SYMBOL_GPL(kvm_init); @@ -6051,7 +6037,6 @@ void kvm_exit(void) on_each_cpu(hardware_disable_nolock, NULL, 1); kvm_irqfd_exit(); free_cpumask_var(cpus_hardware_enabled); - kvm_arch_exit(); } EXPORT_SYMBOL_GPL(kvm_exit); -- cgit v1.2.3 From 81a1cf9f89a6b71e71bfd7d43837ce9235e70b38 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 30 Nov 2022 23:09:16 +0000 Subject: KVM: Drop kvm_arch_check_processor_compat() hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop kvm_arch_check_processor_compat() and its support code now that all architecture implementations are nops. Signed-off-by: Sean Christopherson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Eric Farman # s390 Acked-by: Anup Patel Reviewed-by: Kai Huang Message-Id: <20221130230934.1014142-33-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/arm.c | 7 +------ arch/mips/kvm/mips.c | 7 +------ arch/powerpc/kvm/book3s.c | 2 +- arch/powerpc/kvm/e500.c | 2 +- arch/powerpc/kvm/e500mc.c | 2 +- arch/powerpc/kvm/powerpc.c | 5 ----- arch/riscv/kvm/main.c | 7 +------ arch/s390/kvm/kvm-s390.c | 7 +------ arch/x86/kvm/svm/svm.c | 4 ++-- arch/x86/kvm/vmx/vmx.c | 4 ++-- arch/x86/kvm/x86.c | 5 ----- include/linux/kvm_host.h | 4 +--- virt/kvm/kvm_main.c | 24 +----------------------- 13 files changed, 13 insertions(+), 67 deletions(-) (limited to 'include') diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 04ed741f7b9d..698787ed87e9 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -63,11 +63,6 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE; } -int kvm_arch_check_processor_compat(void *opaque) -{ - return 0; -} - int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) { @@ -2285,7 +2280,7 @@ static __init int kvm_arm_init(void) * FIXME: Do something reasonable if kvm_init() fails after pKVM * hypervisor protection is finalized. */ - err = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); + err = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (err) goto out_subs; diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 3cade648827a..36c8991b5d39 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -135,11 +135,6 @@ void kvm_arch_hardware_disable(void) kvm_mips_callbacks->hardware_disable(); } -int kvm_arch_check_processor_compat(void *opaque) -{ - return 0; -} - extern void kvm_init_loongson_ipi(struct kvm *kvm); int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) @@ -1636,7 +1631,7 @@ static int __init kvm_mips_init(void) register_die_notifier(&kvm_mips_csr_die_notifier); - ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); + ret = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (ret) { unregister_die_notifier(&kvm_mips_csr_die_notifier); return ret; diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 87283a0e33d8..57f4e7896d67 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -1052,7 +1052,7 @@ static int kvmppc_book3s_init(void) { int r; - r = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); + r = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (r) return r; #ifdef CONFIG_KVM_BOOK3S_32_HANDLER diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index 0ea61190ec04..b0f695428733 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c @@ -531,7 +531,7 @@ static int __init kvmppc_e500_init(void) flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers + ivor[max_ivor] + handler_len); - r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); + r = kvm_init(sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); if (r) goto err_out; kvm_ops_e500.owner = THIS_MODULE; diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c index 795667f7ebf0..611532a0dedc 100644 --- a/arch/powerpc/kvm/e500mc.c +++ b/arch/powerpc/kvm/e500mc.c @@ -404,7 +404,7 @@ static int __init kvmppc_e500mc_init(void) */ kvmppc_init_lpid(KVMPPC_NR_LPIDS/threads_per_core); - r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); + r = kvm_init(sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); if (r) goto err_out; kvm_ops_e500mc.owner = THIS_MODULE; diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 01d0f9935e6c..f5b4ff6bfc89 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -440,11 +440,6 @@ int kvm_arch_hardware_enable(void) return 0; } -int kvm_arch_check_processor_compat(void *opaque) -{ - return 0; -} - int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { struct kvmppc_ops *kvm_ops = NULL; diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index be951feee27a..e2da56ed9069 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -20,11 +20,6 @@ long kvm_arch_dev_ioctl(struct file *filp, return -EINVAL; } -int kvm_arch_check_processor_compat(void *opaque) -{ - return 0; -} - int kvm_arch_hardware_enable(void) { unsigned long hideleg, hedeleg; @@ -110,7 +105,7 @@ static int __init riscv_kvm_init(void) kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits()); - return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); + return kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); } module_init(riscv_kvm_init); diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 25b08b956888..7ad8252e92c2 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -262,11 +262,6 @@ int kvm_arch_hardware_enable(void) return 0; } -int kvm_arch_check_processor_compat(void *opaque) -{ - return 0; -} - /* forward declarations */ static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start, unsigned long end); @@ -5716,7 +5711,7 @@ static int __init kvm_s390_init(void) if (r) return r; - r = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); + r = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (r) { __kvm_s390_exit(); return r; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index e55f8e54e25a..6db44797e85e 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5109,8 +5109,8 @@ static int __init svm_init(void) * Common KVM initialization _must_ come last, after this, /dev/kvm is * exposed to userspace! */ - r = kvm_init(NULL, sizeof(struct vcpu_svm), - __alignof__(struct vcpu_svm), THIS_MODULE); + r = kvm_init(sizeof(struct vcpu_svm), __alignof__(struct vcpu_svm), + THIS_MODULE); if (r) goto err_kvm_init; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e996034809de..3df6b771d816 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8635,8 +8635,8 @@ static int __init vmx_init(void) * Common KVM initialization _must_ come last, after this, /dev/kvm is * exposed to userspace! */ - r = kvm_init(NULL, sizeof(struct vcpu_vmx), - __alignof__(struct vcpu_vmx), THIS_MODULE); + r = kvm_init(sizeof(struct vcpu_vmx), __alignof__(struct vcpu_vmx), + THIS_MODULE); if (r) goto err_kvm_init; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d94e6e8692cc..17cbd17c9077 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12084,11 +12084,6 @@ void kvm_arch_hardware_disable(void) drop_user_return_notifiers(); } -int kvm_arch_check_processor_compat(void *opaque) -{ - return 0; -} - bool kvm_vcpu_is_reset_bsp(struct kvm_vcpu *vcpu) { return vcpu->kvm->arch.bsp_vcpu_id == vcpu->vcpu_id; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 62d977bb1448..20e207e4c6c1 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -956,8 +956,7 @@ static inline void kvm_irqfd_exit(void) { } #endif -int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, - struct module *module); +int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module); void kvm_exit(void); void kvm_get_kvm(struct kvm *kvm); @@ -1444,7 +1443,6 @@ static inline void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) {} int kvm_arch_hardware_enable(void); void kvm_arch_hardware_disable(void); -int kvm_arch_check_processor_compat(void *opaque); int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu); bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu); int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 597ff734b312..e13b369cfc1b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -5902,36 +5902,14 @@ void kvm_unregister_perf_callbacks(void) } #endif -struct kvm_cpu_compat_check { - void *opaque; - int *ret; -}; - -static void check_processor_compat(void *data) +int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module) { - struct kvm_cpu_compat_check *c = data; - - *c->ret = kvm_arch_check_processor_compat(c->opaque); -} - -int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, - struct module *module) -{ - struct kvm_cpu_compat_check c; int r; int cpu; if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) return -ENOMEM; - c.ret = &r; - c.opaque = opaque; - for_each_online_cpu(cpu) { - smp_call_function_single(cpu, check_processor_compat, &c, 1); - if (r < 0) - goto out_free_2; - } - r = cpuhp_setup_state_nocalls(CPUHP_AP_KVM_STARTING, "kvm/cpu:starting", kvm_starting_cpu, kvm_dying_cpu); if (r) -- cgit v1.2.3 From 8d20bd6381670382669d9bb39b5fd566a84cdbef Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 30 Nov 2022 23:09:18 +0000 Subject: KVM: x86: Unify pr_fmt to use module name for all KVM modules Define pr_fmt using KBUILD_MODNAME for all KVM x86 code so that printks use consistent formatting across common x86, Intel, and AMD code. In addition to providing consistent print formatting, using KBUILD_MODNAME, e.g. kvm_amd and kvm_intel, allows referencing SVM and VMX (and SEV and SGX and ...) as technologies without generating weird messages, and without causing naming conflicts with other kernel code, e.g. "SEV: ", "tdx: ", "sgx: " etc.. are all used by the kernel for non-KVM subsystems. Opportunistically move away from printk() for prints that need to be modified anyways, e.g. to drop a manual "kvm: " prefix. Opportunistically convert a few SGX WARNs that are similarly modified to WARN_ONCE; in the very unlikely event that the WARNs fire, odds are good that they would fire repeatedly and spam the kernel log without providing unique information in each print. Note, defining pr_fmt yields undesirable results for code that uses KVM's printk wrappers, e.g. vcpu_unimpl(). But, that's a pre-existing problem as SVM/kvm_amd already defines a pr_fmt, and thankfully use of KVM's wrappers is relatively limited in KVM x86 code. Signed-off-by: Sean Christopherson Reviewed-by: Paul Durrant Message-Id: <20221130230934.1014142-35-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/include/asm/kvm_host.h | 14 +++++++------- arch/arm64/include/asm/kvm_mmu.h | 4 ++-- arch/arm64/kvm/arch_timer.c | 2 +- arch/arm64/kvm/mmu.c | 12 ++++++------ arch/arm64/kvm/reset.c | 8 ++++---- arch/arm64/kvm/sys_regs.c | 6 +++--- arch/arm64/kvm/vmid.c | 6 +++--- arch/x86/kvm/cpuid.c | 1 + arch/x86/kvm/debugfs.c | 2 ++ arch/x86/kvm/emulate.c | 1 + arch/x86/kvm/hyperv.c | 1 + arch/x86/kvm/i8254.c | 4 ++-- arch/x86/kvm/i8259.c | 4 +++- arch/x86/kvm/ioapic.c | 1 + arch/x86/kvm/irq.c | 1 + arch/x86/kvm/irq_comm.c | 7 ++++--- arch/x86/kvm/kvm_onhyperv.c | 1 + arch/x86/kvm/lapic.c | 8 ++++---- arch/x86/kvm/mmu/mmu.c | 6 +++--- arch/x86/kvm/mmu/page_track.c | 1 + arch/x86/kvm/mmu/spte.c | 4 ++-- arch/x86/kvm/mmu/spte.h | 4 ++-- arch/x86/kvm/mmu/tdp_iter.c | 1 + arch/x86/kvm/mmu/tdp_mmu.c | 1 + arch/x86/kvm/mtrr.c | 1 + arch/x86/kvm/pmu.c | 1 + arch/x86/kvm/smm.c | 1 + arch/x86/kvm/svm/avic.c | 2 +- arch/x86/kvm/svm/nested.c | 2 +- arch/x86/kvm/svm/pmu.c | 2 ++ arch/x86/kvm/svm/sev.c | 1 + arch/x86/kvm/svm/svm.c | 10 +++++----- arch/x86/kvm/svm/svm_onhyperv.c | 1 + arch/x86/kvm/svm/svm_onhyperv.h | 4 ++-- arch/x86/kvm/vmx/hyperv.c | 3 +-- arch/x86/kvm/vmx/hyperv.h | 4 +--- arch/x86/kvm/vmx/nested.c | 3 ++- arch/x86/kvm/vmx/pmu_intel.c | 5 +++-- arch/x86/kvm/vmx/posted_intr.c | 2 ++ arch/x86/kvm/vmx/sgx.c | 5 +++-- arch/x86/kvm/vmx/vmcs12.c | 1 + arch/x86/kvm/vmx/vmx.c | 40 +++++++++++++++++++-------------------- arch/x86/kvm/vmx/vmx_ops.h | 4 ++-- arch/x86/kvm/x86.c | 28 ++++++++++++++------------- arch/x86/kvm/xen.c | 1 + include/kvm/arm_arch_timer.h | 2 +- 46 files changed, 124 insertions(+), 99 deletions(-) (limited to 'include') diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index f50951c51d3b..113e20fdbb56 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -66,8 +66,8 @@ enum kvm_mode kvm_get_mode(void); DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use); -extern unsigned int kvm_sve_max_vl; -int kvm_arm_init_sve(void); +extern unsigned int __ro_after_init kvm_sve_max_vl; +int __init kvm_arm_init_sve(void); u32 __attribute_const__ kvm_target_cpu(void); int kvm_reset_vcpu(struct kvm_vcpu *vcpu); @@ -877,7 +877,7 @@ int kvm_handle_cp10_id(struct kvm_vcpu *vcpu); void kvm_reset_sys_regs(struct kvm_vcpu *vcpu); -int kvm_sys_reg_table_init(void); +int __init kvm_sys_reg_table_init(void); /* MMIO helpers */ void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data); @@ -908,9 +908,9 @@ int kvm_arm_pvtime_get_attr(struct kvm_vcpu *vcpu, int kvm_arm_pvtime_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); -extern unsigned int kvm_arm_vmid_bits; -int kvm_arm_vmid_alloc_init(void); -void kvm_arm_vmid_alloc_free(void); +extern unsigned int __ro_after_init kvm_arm_vmid_bits; +int __init kvm_arm_vmid_alloc_init(void); +void __init kvm_arm_vmid_alloc_free(void); void kvm_arm_vmid_update(struct kvm_vmid *kvm_vmid); void kvm_arm_vmid_clear_active(void); @@ -993,7 +993,7 @@ static inline void kvm_clr_pmu_events(u32 clr) {} void kvm_vcpu_load_sysregs_vhe(struct kvm_vcpu *vcpu); void kvm_vcpu_put_sysregs_vhe(struct kvm_vcpu *vcpu); -int kvm_set_ipa_limit(void); +int __init kvm_set_ipa_limit(void); #define __KVM_HAVE_ARCH_VM_ALLOC struct kvm *kvm_arch_alloc_vm(void); diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index e4a7e6369499..7f7c1231679e 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -163,7 +163,7 @@ int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size, void __iomem **haddr); int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size, void **haddr); -void free_hyp_pgds(void); +void __init free_hyp_pgds(void); void stage2_unmap_vm(struct kvm *kvm); int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long type); @@ -175,7 +175,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu); phys_addr_t kvm_mmu_get_httbr(void); phys_addr_t kvm_get_idmap_vector(void); -int kvm_mmu_init(u32 *hyp_va_bits); +int __init kvm_mmu_init(u32 *hyp_va_bits); static inline void *__kvm_vector_slot2addr(void *base, enum arm64_hyp_spectre_vector slot) diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 33fca1a691a5..23346585a294 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -1113,7 +1113,7 @@ static int kvm_irq_init(struct arch_timer_kvm_info *info) return 0; } -int kvm_timer_hyp_init(bool has_gic) +int __init kvm_timer_hyp_init(bool has_gic) { struct arch_timer_kvm_info *info; int err; diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 31d7fa4c7c14..d6c41043b5af 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -25,11 +25,11 @@ static struct kvm_pgtable *hyp_pgtable; static DEFINE_MUTEX(kvm_hyp_pgd_mutex); -static unsigned long hyp_idmap_start; -static unsigned long hyp_idmap_end; -static phys_addr_t hyp_idmap_vector; +static unsigned long __ro_after_init hyp_idmap_start; +static unsigned long __ro_after_init hyp_idmap_end; +static phys_addr_t __ro_after_init hyp_idmap_vector; -static unsigned long io_map_base; +static unsigned long __ro_after_init io_map_base; static phys_addr_t stage2_range_addr_end(phys_addr_t addr, phys_addr_t end) { @@ -280,7 +280,7 @@ static void stage2_flush_vm(struct kvm *kvm) /** * free_hyp_pgds - free Hyp-mode page tables */ -void free_hyp_pgds(void) +void __init free_hyp_pgds(void) { mutex_lock(&kvm_hyp_pgd_mutex); if (hyp_pgtable) { @@ -1665,7 +1665,7 @@ static struct kvm_pgtable_mm_ops kvm_hyp_mm_ops = { .virt_to_phys = kvm_host_pa, }; -int kvm_mmu_init(u32 *hyp_va_bits) +int __init kvm_mmu_init(u32 *hyp_va_bits) { int err; u32 idmap_bits; diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index e0267f672b8a..2bc74739a6df 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -30,7 +30,7 @@ #include /* Maximum phys_shift supported for any VM on this host */ -static u32 kvm_ipa_limit; +static u32 __ro_after_init kvm_ipa_limit; /* * ARMv8 Reset Values @@ -41,9 +41,9 @@ static u32 kvm_ipa_limit; #define VCPU_RESET_PSTATE_SVC (PSR_AA32_MODE_SVC | PSR_AA32_A_BIT | \ PSR_AA32_I_BIT | PSR_AA32_F_BIT) -unsigned int kvm_sve_max_vl; +unsigned int __ro_after_init kvm_sve_max_vl; -int kvm_arm_init_sve(void) +int __init kvm_arm_init_sve(void) { if (system_supports_sve()) { kvm_sve_max_vl = sve_max_virtualisable_vl(); @@ -352,7 +352,7 @@ u32 get_kvm_ipa_limit(void) return kvm_ipa_limit; } -int kvm_set_ipa_limit(void) +int __init kvm_set_ipa_limit(void) { unsigned int parange; u64 mmfr0; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index d5ee52d6bf73..1225e9faac06 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -82,7 +82,7 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg) } /* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */ -static u32 cache_levels; +static u32 __ro_after_init cache_levels; /* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */ #define CSSELR_MAX 14 @@ -2733,7 +2733,7 @@ static void get_ctr_el0(struct kvm_vcpu *v, const struct sys_reg_desc *r) } /* ->val is filled in by kvm_sys_reg_table_init() */ -static struct sys_reg_desc invariant_sys_regs[] = { +static struct sys_reg_desc invariant_sys_regs[] __ro_after_init = { { SYS_DESC(SYS_MIDR_EL1), NULL, get_midr_el1 }, { SYS_DESC(SYS_REVIDR_EL1), NULL, get_revidr_el1 }, { SYS_DESC(SYS_CLIDR_EL1), NULL, get_clidr_el1 }, @@ -3057,7 +3057,7 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) return write_demux_regids(uindices); } -int kvm_sys_reg_table_init(void) +int __init kvm_sys_reg_table_init(void) { bool valid = true; unsigned int i; diff --git a/arch/arm64/kvm/vmid.c b/arch/arm64/kvm/vmid.c index d78ae63d7c15..08978d0672e7 100644 --- a/arch/arm64/kvm/vmid.c +++ b/arch/arm64/kvm/vmid.c @@ -16,7 +16,7 @@ #include #include -unsigned int kvm_arm_vmid_bits; +unsigned int __ro_after_init kvm_arm_vmid_bits; static DEFINE_RAW_SPINLOCK(cpu_vmid_lock); static atomic64_t vmid_generation; @@ -172,7 +172,7 @@ void kvm_arm_vmid_update(struct kvm_vmid *kvm_vmid) /* * Initialize the VMID allocator */ -int kvm_arm_vmid_alloc_init(void) +int __init kvm_arm_vmid_alloc_init(void) { kvm_arm_vmid_bits = kvm_get_vmid_bits(); @@ -190,7 +190,7 @@ int kvm_arm_vmid_alloc_init(void) return 0; } -void kvm_arm_vmid_alloc_free(void) +void __init kvm_arm_vmid_alloc_free(void) { kfree(vmid_map); } diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 69768e4d53a6..4ca16b18a086 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -8,6 +8,7 @@ * Copyright 2011 Red Hat, Inc. and/or its affiliates. * Copyright IBM Corporation, 2008 */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/debugfs.c b/arch/x86/kvm/debugfs.c index c1390357126a..ee8c4c3496ed 100644 --- a/arch/x86/kvm/debugfs.c +++ b/arch/x86/kvm/debugfs.c @@ -4,6 +4,8 @@ * * Copyright 2016 Red Hat, Inc. and/or its affiliates. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include "lapic.h" diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5cc3efa0e21c..c3443045cd93 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -17,6 +17,7 @@ * * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include "kvm_cache_regs.h" diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 80d082ecd5c5..71aff0edc0ed 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -17,6 +17,7 @@ * Ben-Ami Yassour * Andrey Smetanin */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "x86.h" #include "lapic.h" diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index e0a7a0e7a73c..cd57a517d04a 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -30,7 +30,7 @@ * Based on QEMU and Xen. */ -#define pr_fmt(fmt) "pit: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -351,7 +351,7 @@ static void create_pit_timer(struct kvm_pit *pit, u32 val, int is_period) if (ps->period < min_period) { pr_info_ratelimited( - "kvm: requested %lld ns " + "requested %lld ns " "i8254 timer period limited to %lld ns\n", ps->period, min_period); ps->period = min_period; diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index e1bb6218bb96..4756bcb5724f 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -26,6 +26,8 @@ * Yaozu (Eddie) Dong * Port from Qemu. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -35,7 +37,7 @@ #include "trace.h" #define pr_pic_unimpl(fmt, ...) \ - pr_err_ratelimited("kvm: pic: " fmt, ## __VA_ARGS__) + pr_err_ratelimited("pic: " fmt, ## __VA_ARGS__) static void pic_irq_request(struct kvm *kvm, int level); diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 765943d7cfa5..042dee556125 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -26,6 +26,7 @@ * Yaozu (Eddie) Dong * Based on Xen 3.1 code. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index a70952eca905..b2c397dd2bc6 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -7,6 +7,7 @@ * Authors: * Yaozu (Eddie) Dong */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 3742d9adacfc..16d076a1b91a 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -8,6 +8,7 @@ * * Copyright 2010 Red Hat, Inc. and/or its affiliates. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -56,7 +57,7 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, if (irq->dest_mode == APIC_DEST_PHYSICAL && irq->dest_id == 0xff && kvm_lowest_prio_delivery(irq)) { - printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n"); + pr_info("apic: phys broadcast and lowest prio\n"); irq->delivery_mode = APIC_DM_FIXED; } @@ -199,7 +200,7 @@ int kvm_request_irq_source_id(struct kvm *kvm) irq_source_id = find_first_zero_bit(bitmap, BITS_PER_LONG); if (irq_source_id >= BITS_PER_LONG) { - printk(KERN_WARNING "kvm: exhaust allocatable IRQ sources!\n"); + pr_warn("exhausted allocatable IRQ sources!\n"); irq_source_id = -EFAULT; goto unlock; } @@ -221,7 +222,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) mutex_lock(&kvm->irq_lock); if (irq_source_id < 0 || irq_source_id >= BITS_PER_LONG) { - printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); + pr_err("IRQ source ID out of range!\n"); goto unlock; } clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); diff --git a/arch/x86/kvm/kvm_onhyperv.c b/arch/x86/kvm/kvm_onhyperv.c index ee4f696a0782..482d6639ef88 100644 --- a/arch/x86/kvm/kvm_onhyperv.c +++ b/arch/x86/kvm/kvm_onhyperv.c @@ -2,6 +2,7 @@ /* * KVM L1 hypervisor optimizations on Hyper-V. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 4efdb4a4d72c..cfaf1d8c64ca 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -15,6 +15,7 @@ * * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -941,8 +942,7 @@ static void kvm_apic_disabled_lapic_found(struct kvm *kvm) { if (!kvm->arch.disabled_lapic_found) { kvm->arch.disabled_lapic_found = true; - printk(KERN_INFO - "Disabled LAPIC found during irq injection\n"); + pr_info("Disabled LAPIC found during irq injection\n"); } } @@ -1560,7 +1560,7 @@ static void limit_periodic_timer_frequency(struct kvm_lapic *apic) if (apic->lapic_timer.period < min_period) { pr_info_ratelimited( - "kvm: vcpu %i: requested %lld ns " + "vcpu %i: requested %lld ns " "lapic timer period limited to %lld ns\n", apic->vcpu->vcpu_id, apic->lapic_timer.period, min_period); @@ -1845,7 +1845,7 @@ static bool set_target_expiration(struct kvm_lapic *apic, u32 count_reg) deadline = apic->lapic_timer.period; else if (unlikely(deadline > apic->lapic_timer.period)) { pr_info_ratelimited( - "kvm: vcpu %i: requested lapic timer restore with " + "vcpu %i: requested lapic timer restore with " "starting count register %#x=%u (%lld ns) > initial count (%lld ns). " "Using initial count to start timer.\n", apic->vcpu->vcpu_id, diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 9c7198544195..aeb240b339f5 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -14,6 +14,7 @@ * Yaniv Kamay * Avi Kivity */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "irq.h" #include "ioapic.h" @@ -3456,8 +3457,7 @@ static int fast_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) } if (++retry_count > 4) { - printk_once(KERN_WARNING - "kvm: Fast #PF retrying more than 4 times.\n"); + pr_warn_once("Fast #PF retrying more than 4 times.\n"); break; } @@ -6647,7 +6647,7 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen) * zap all shadow pages. */ if (unlikely(gen == 0)) { - kvm_debug_ratelimited("kvm: zapping shadow pages for mmio generation wraparound\n"); + kvm_debug_ratelimited("zapping shadow pages for mmio generation wraparound\n"); kvm_mmu_zap_all_fast(kvm); } } diff --git a/arch/x86/kvm/mmu/page_track.c b/arch/x86/kvm/mmu/page_track.c index 2e09d1b6249f..0a2ac438d647 100644 --- a/arch/x86/kvm/mmu/page_track.c +++ b/arch/x86/kvm/mmu/page_track.c @@ -10,6 +10,7 @@ * Author: * Xiao Guangrong */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index c0fd7e049b4e..fce6f047399f 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -7,7 +7,7 @@ * Copyright (C) 2006 Qumranet, Inc. * Copyright 2020 Red Hat, Inc. and/or its affiliates. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include "mmu.h" @@ -352,7 +352,7 @@ u64 mark_spte_for_access_track(u64 spte) WARN_ONCE(spte & (SHADOW_ACC_TRACK_SAVED_BITS_MASK << SHADOW_ACC_TRACK_SAVED_BITS_SHIFT), - "kvm: Access Tracking saved bit locations are not zero\n"); + "Access Tracking saved bit locations are not zero\n"); spte |= (spte & SHADOW_ACC_TRACK_SAVED_BITS_MASK) << SHADOW_ACC_TRACK_SAVED_BITS_SHIFT; diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index 6f54dc9409c9..0d8deefee66c 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -435,11 +435,11 @@ static inline void check_spte_writable_invariants(u64 spte) { if (spte & shadow_mmu_writable_mask) WARN_ONCE(!(spte & shadow_host_writable_mask), - "kvm: MMU-writable SPTE is not Host-writable: %llx", + KBUILD_MODNAME ": MMU-writable SPTE is not Host-writable: %llx", spte); else WARN_ONCE(is_writable_pte(spte), - "kvm: Writable SPTE is not MMU-writable: %llx", spte); + KBUILD_MODNAME ": Writable SPTE is not MMU-writable: %llx", spte); } static inline bool is_mmu_writable_spte(u64 spte) diff --git a/arch/x86/kvm/mmu/tdp_iter.c b/arch/x86/kvm/mmu/tdp_iter.c index 39b48e7d7d1a..e26e744df1d1 100644 --- a/arch/x86/kvm/mmu/tdp_iter.c +++ b/arch/x86/kvm/mmu/tdp_iter.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "mmu_internal.h" #include "tdp_iter.h" diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index cc1fb9a65620..bba33aea0fb0 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "mmu.h" #include "mmu_internal.h" diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c index a8502e02f479..9fac1ec03463 100644 --- a/arch/x86/kvm/mtrr.c +++ b/arch/x86/kvm/mtrr.c @@ -13,6 +13,7 @@ * Paolo Bonzini * Xiao Guangrong */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index eb594620dd75..d939d3b84e6f 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -9,6 +9,7 @@ * Gleb Natapov * Wei Huang */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c index a9c1c2af8d94..cc43638d48a3 100644 --- a/arch/x86/kvm/smm.c +++ b/arch/x86/kvm/smm.c @@ -1,4 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include "x86.h" diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 6919dee69f18..f52f5e0dd465 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -12,7 +12,7 @@ * Avi Kivity */ -#define pr_fmt(fmt) "SVM: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index bc9cd7086fa9..3bfbcb607d80 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -12,7 +12,7 @@ * Avi Kivity */ -#define pr_fmt(fmt) "SVM: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 0e313fbae055..1ff068f23841 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -9,6 +9,8 @@ * * Implementation is based on pmu_intel.c file */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 86d6897f4806..273cba809328 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -6,6 +6,7 @@ * * Copyright 2010 Red Hat, Inc. and/or its affiliates. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 2bb62c3db3b3..f7192a14fc89 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1,4 +1,4 @@ -#define pr_fmt(fmt) "SVM: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -2076,7 +2076,7 @@ static void svm_handle_mce(struct kvm_vcpu *vcpu) * Erratum 383 triggered. Guest state is corrupt so kill the * guest. */ - pr_err("KVM: Guest triggered AMD Erratum 383\n"); + pr_err("Guest triggered AMD Erratum 383\n"); kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); @@ -4629,7 +4629,7 @@ static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type, smap = cr4 & X86_CR4_SMAP; is_user = svm_get_cpl(vcpu) == 3; if (smap && (!smep || is_user)) { - pr_err_ratelimited("KVM: SEV Guest triggered AMD Erratum 1096\n"); + pr_err_ratelimited("SEV Guest triggered AMD Erratum 1096\n"); /* * If the fault occurred in userspace, arbitrarily inject #GP @@ -4978,7 +4978,7 @@ static __init int svm_hardware_setup(void) } if (nested) { - printk(KERN_INFO "kvm: Nested Virtualization enabled\n"); + pr_info("Nested Virtualization enabled\n"); kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE); } @@ -4996,7 +4996,7 @@ static __init int svm_hardware_setup(void) /* Force VM NPT level equal to the host's paging level */ kvm_configure_mmu(npt_enabled, get_npt_level(), get_npt_level(), PG_LEVEL_1G); - pr_info("kvm: Nested Paging %sabled\n", npt_enabled ? "en" : "dis"); + pr_info("Nested Paging %sabled\n", npt_enabled ? "en" : "dis"); /* Setup shadow_me_value and shadow_me_mask */ kvm_mmu_set_me_spte_mask(sme_me_mask, sme_me_mask); diff --git a/arch/x86/kvm/svm/svm_onhyperv.c b/arch/x86/kvm/svm/svm_onhyperv.c index 26a89d0da93e..7af8422d3382 100644 --- a/arch/x86/kvm/svm/svm_onhyperv.c +++ b/arch/x86/kvm/svm/svm_onhyperv.c @@ -2,6 +2,7 @@ /* * KVM L1 hypervisor optimizations on Hyper-V for SVM. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include diff --git a/arch/x86/kvm/svm/svm_onhyperv.h b/arch/x86/kvm/svm/svm_onhyperv.h index 45faf84476ce..6981c1e9a809 100644 --- a/arch/x86/kvm/svm/svm_onhyperv.h +++ b/arch/x86/kvm/svm/svm_onhyperv.h @@ -34,7 +34,7 @@ static inline void svm_hv_hardware_setup(void) { if (npt_enabled && ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB) { - pr_info("kvm: Hyper-V enlightened NPT TLB flush enabled\n"); + pr_info(KBUILD_MODNAME ": Hyper-V enlightened NPT TLB flush enabled\n"); svm_x86_ops.tlb_remote_flush = hv_remote_flush_tlb; svm_x86_ops.tlb_remote_flush_with_range = hv_remote_flush_tlb_with_range; @@ -43,7 +43,7 @@ static inline void svm_hv_hardware_setup(void) if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) { int cpu; - pr_info("kvm: Hyper-V Direct TLB Flush enabled\n"); + pr_info(KBUILD_MODNAME ": Hyper-V Direct TLB Flush enabled\n"); for_each_online_cpu(cpu) { struct hv_vp_assist_page *vp_ap = hv_get_vp_assist_page(cpu); diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c index f773450fba6e..2a26a0f27d48 100644 --- a/arch/x86/kvm/vmx/hyperv.c +++ b/arch/x86/kvm/vmx/hyperv.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 - -#define pr_fmt(fmt) "kvm/hyper-v: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h index 883102d567c3..e03692958408 100644 --- a/arch/x86/kvm/vmx/hyperv.h +++ b/arch/x86/kvm/vmx/hyperv.h @@ -179,9 +179,7 @@ static __always_inline int get_evmcs_offset(unsigned long field, { int offset = evmcs_field_offset(field, clean_field); - WARN_ONCE(offset < 0, "KVM: accessing unsupported EVMCS field %lx\n", - field); - + WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field); return offset; } diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index d93c715cda6a..557b9c468734 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -203,7 +204,7 @@ static void nested_vmx_abort(struct kvm_vcpu *vcpu, u32 indicator) { /* TODO: not to reset guest simply here. */ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); - pr_debug_ratelimited("kvm: nested vmx abort, indicator %d\n", indicator); + pr_debug_ratelimited("nested vmx abort, indicator %d\n", indicator); } static inline bool vmx_control_verify(u32 control, u32 low, u32 high) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index e5cec07ca8d9..efce9ad70e4e 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -8,6 +8,8 @@ * Avi Kivity * Gleb Natapov */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -762,8 +764,7 @@ void vmx_passthrough_lbr_msrs(struct kvm_vcpu *vcpu) return; warn: - pr_warn_ratelimited("kvm: vcpu-%d: fail to passthrough LBR.\n", - vcpu->vcpu_id); + pr_warn_ratelimited("vcpu-%d: fail to passthrough LBR.\n", vcpu->vcpu_id); } static void intel_pmu_cleanup(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx/posted_intr.c b/arch/x86/kvm/vmx/posted_intr.c index 1b56c5e5c9fb..94c38bea60e7 100644 --- a/arch/x86/kvm/vmx/posted_intr.c +++ b/arch/x86/kvm/vmx/posted_intr.c @@ -1,4 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c index b12da2a6dec9..aa53c98034bf 100644 --- a/arch/x86/kvm/vmx/sgx.c +++ b/arch/x86/kvm/vmx/sgx.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2021 Intel Corporation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -164,7 +165,7 @@ static int __handle_encls_ecreate(struct kvm_vcpu *vcpu, if (!vcpu->kvm->arch.sgx_provisioning_allowed && (attributes & SGX_ATTR_PROVISIONKEY)) { if (sgx_12_1->eax & SGX_ATTR_PROVISIONKEY) - pr_warn_once("KVM: SGX PROVISIONKEY advertised but not allowed\n"); + pr_warn_once("SGX PROVISIONKEY advertised but not allowed\n"); kvm_inject_gp(vcpu, 0); return 1; } @@ -381,7 +382,7 @@ int handle_encls(struct kvm_vcpu *vcpu) return handle_encls_ecreate(vcpu); if (leaf == EINIT) return handle_encls_einit(vcpu); - WARN(1, "KVM: unexpected exit on ENCLS[%u]", leaf); + WARN_ONCE(1, "unexpected exit on ENCLS[%u]", leaf); vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; vcpu->run->hw.hardware_exit_reason = EXIT_REASON_ENCLS; return 0; diff --git a/arch/x86/kvm/vmx/vmcs12.c b/arch/x86/kvm/vmx/vmcs12.c index 2251b60920f8..106a72c923ca 100644 --- a/arch/x86/kvm/vmx/vmcs12.c +++ b/arch/x86/kvm/vmx/vmcs12.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "vmcs12.h" diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index daab447d311c..58eb4dbf64a3 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -12,6 +12,7 @@ * Avi Kivity * Yaniv Kamay */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -444,36 +445,36 @@ void vmread_error(unsigned long field, bool fault) if (fault) kvm_spurious_fault(); else - vmx_insn_failed("kvm: vmread failed: field=%lx\n", field); + vmx_insn_failed("vmread failed: field=%lx\n", field); } noinline void vmwrite_error(unsigned long field, unsigned long value) { - vmx_insn_failed("kvm: vmwrite failed: field=%lx val=%lx err=%u\n", + vmx_insn_failed("vmwrite failed: field=%lx val=%lx err=%u\n", field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); } noinline void vmclear_error(struct vmcs *vmcs, u64 phys_addr) { - vmx_insn_failed("kvm: vmclear failed: %p/%llx err=%u\n", + vmx_insn_failed("vmclear failed: %p/%llx err=%u\n", vmcs, phys_addr, vmcs_read32(VM_INSTRUCTION_ERROR)); } noinline void vmptrld_error(struct vmcs *vmcs, u64 phys_addr) { - vmx_insn_failed("kvm: vmptrld failed: %p/%llx err=%u\n", + vmx_insn_failed("vmptrld failed: %p/%llx err=%u\n", vmcs, phys_addr, vmcs_read32(VM_INSTRUCTION_ERROR)); } noinline void invvpid_error(unsigned long ext, u16 vpid, gva_t gva) { - vmx_insn_failed("kvm: invvpid failed: ext=0x%lx vpid=%u gva=0x%lx\n", + vmx_insn_failed("invvpid failed: ext=0x%lx vpid=%u gva=0x%lx\n", ext, vpid, gva); } noinline void invept_error(unsigned long ext, u64 eptp, gpa_t gpa) { - vmx_insn_failed("kvm: invept failed: ext=0x%lx eptp=%llx gpa=0x%llx\n", + vmx_insn_failed("invept failed: ext=0x%lx eptp=%llx gpa=0x%llx\n", ext, eptp, gpa); } @@ -577,7 +578,7 @@ static __init void hv_init_evmcs(void) } if (enlightened_vmcs) { - pr_info("KVM: vmx: using Hyper-V Enlightened VMCS\n"); + pr_info("Using Hyper-V Enlightened VMCS\n"); static_branch_enable(&enable_evmcs); } @@ -1680,8 +1681,8 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu) if (!instr_len) goto rip_updated; - WARN(exit_reason.enclave_mode, - "KVM: skipping instruction after SGX enclave VM-Exit"); + WARN_ONCE(exit_reason.enclave_mode, + "skipping instruction after SGX enclave VM-Exit"); orig_rip = kvm_rip_read(vcpu); rip = orig_rip + instr_len; @@ -3024,9 +3025,8 @@ static void fix_rmode_seg(int seg, struct kvm_segment *save) var.type = 0x3; var.avl = 0; if (save->base & 0xf) - printk_once(KERN_WARNING "kvm: segment base is not " - "paragraph aligned when entering " - "protected mode (seg=%d)", seg); + pr_warn_once("segment base is not paragraph aligned " + "when entering protected mode (seg=%d)", seg); } vmcs_write16(sf->selector, var.selector); @@ -3056,8 +3056,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu) * vcpu. Warn the user that an update is overdue. */ if (!kvm_vmx->tss_addr) - printk_once(KERN_WARNING "kvm: KVM_SET_TSS_ADDR need to be " - "called before entering vcpu\n"); + pr_warn_once("KVM_SET_TSS_ADDR needs to be called before running vCPU\n"); vmx_segment_cache_clear(vmx); @@ -6925,7 +6924,7 @@ static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu) gate_desc *desc = (gate_desc *)host_idt_base + vector; if (KVM_BUG(!is_external_intr(intr_info), vcpu->kvm, - "KVM: unexpected VM-Exit interrupt info: 0x%x", intr_info)) + "unexpected VM-Exit interrupt info: 0x%x", intr_info)) return; handle_interrupt_nmi_irqoff(vcpu, gate_offset(desc)); @@ -7530,7 +7529,7 @@ static int __init vmx_check_processor_compat(void) if (!this_cpu_has(X86_FEATURE_MSR_IA32_FEAT_CTL) || !this_cpu_has(X86_FEATURE_VMX)) { - pr_err("kvm: VMX is disabled on CPU %d\n", smp_processor_id()); + pr_err("VMX is disabled on CPU %d\n", smp_processor_id()); return -EIO; } @@ -7539,8 +7538,7 @@ static int __init vmx_check_processor_compat(void) if (nested) nested_vmx_setup_ctls_msrs(&vmcs_conf, vmx_cap.ept); if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) { - printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n", - smp_processor_id()); + pr_err("CPU %d feature inconsistency!\n", smp_processor_id()); return -EIO; } return 0; @@ -8365,7 +8363,7 @@ static __init int hardware_setup(void) return -EIO; if (cpu_has_perf_global_ctrl_bug()) - pr_warn_once("kvm: VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL " + pr_warn_once("VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL " "does not work properly. Using workaround\n"); if (boot_cpu_has(X86_FEATURE_NX)) @@ -8373,7 +8371,7 @@ static __init int hardware_setup(void) if (boot_cpu_has(X86_FEATURE_MPX)) { rdmsrl(MSR_IA32_BNDCFGS, host_bndcfgs); - WARN_ONCE(host_bndcfgs, "KVM: BNDCFGS in host will be lost"); + WARN_ONCE(host_bndcfgs, "BNDCFGS in host will be lost"); } if (!cpu_has_vmx_mpx()) @@ -8392,7 +8390,7 @@ static __init int hardware_setup(void) /* NX support is required for shadow paging. */ if (!enable_ept && !boot_cpu_has(X86_FEATURE_NX)) { - pr_err_ratelimited("kvm: NX (Execute Disable) not supported\n"); + pr_err_ratelimited("NX (Execute Disable) not supported\n"); return -EOPNOTSUPP; } diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h index 842dc898c972..a5282014616c 100644 --- a/arch/x86/kvm/vmx/vmx_ops.h +++ b/arch/x86/kvm/vmx/vmx_ops.h @@ -100,8 +100,8 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field) return value; do_fail: - WARN_ONCE(1, "kvm: vmread failed: field=%lx\n", field); - pr_warn_ratelimited("kvm: vmread failed: field=%lx\n", field); + WARN_ONCE(1, KBUILD_MODNAME ": vmread failed: field=%lx\n", field); + pr_warn_ratelimited(KBUILD_MODNAME ": vmread failed: field=%lx\n", field); return 0; do_exception: diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 17cbd17c9077..4c40bbec372a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -15,6 +15,7 @@ * Amit Shah * Ben-Ami Yassour */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include "irq.h" @@ -2087,7 +2088,7 @@ static int kvm_emulate_monitor_mwait(struct kvm_vcpu *vcpu, const char *insn) !guest_cpuid_has(vcpu, X86_FEATURE_MWAIT)) return kvm_handle_invalid_op(vcpu); - pr_warn_once("kvm: %s instruction emulated as NOP!\n", insn); + pr_warn_once("%s instruction emulated as NOP!\n", insn); return kvm_emulate_as_nop(vcpu); } int kvm_emulate_mwait(struct kvm_vcpu *vcpu) @@ -2434,7 +2435,8 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) thresh_lo = adjust_tsc_khz(tsc_khz, -tsc_tolerance_ppm); thresh_hi = adjust_tsc_khz(tsc_khz, tsc_tolerance_ppm); if (user_tsc_khz < thresh_lo || user_tsc_khz > thresh_hi) { - pr_debug("kvm: requested TSC rate %u falls outside tolerance [%u,%u]\n", user_tsc_khz, thresh_lo, thresh_hi); + pr_debug("requested TSC rate %u falls outside tolerance [%u,%u]\n", + user_tsc_khz, thresh_lo, thresh_hi); use_scaling = 1; } return set_tsc_khz(vcpu, user_tsc_khz, use_scaling); @@ -7702,7 +7704,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, return X86EMUL_CONTINUE; emul_write: - printk_once(KERN_WARNING "kvm: emulating exchange as write\n"); + pr_warn_once("emulating exchange as write\n"); return emulator_write_emulated(ctxt, addr, new, bytes, exception); } @@ -8263,7 +8265,7 @@ static struct x86_emulate_ctxt *alloc_emulate_ctxt(struct kvm_vcpu *vcpu) ctxt = kmem_cache_zalloc(x86_emulator_cache, GFP_KERNEL_ACCOUNT); if (!ctxt) { - pr_err("kvm: failed to allocate vcpu's emulator\n"); + pr_err("failed to allocate vcpu's emulator\n"); return NULL; } @@ -9324,17 +9326,17 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) int r, cpu; if (kvm_x86_ops.hardware_enable) { - pr_err("kvm: already loaded vendor module '%s'\n", kvm_x86_ops.name); + pr_err("already loaded vendor module '%s'\n", kvm_x86_ops.name); return -EEXIST; } if (!ops->cpu_has_kvm_support()) { - pr_err_ratelimited("kvm: no hardware support for '%s'\n", + pr_err_ratelimited("no hardware support for '%s'\n", ops->runtime_ops->name); return -EOPNOTSUPP; } if (ops->disabled_by_bios()) { - pr_err_ratelimited("kvm: support for '%s' disabled by bios\n", + pr_err_ratelimited("support for '%s' disabled by bios\n", ops->runtime_ops->name); return -EOPNOTSUPP; } @@ -9345,7 +9347,7 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) * vCPU's FPU state as a fxregs_state struct. */ if (!boot_cpu_has(X86_FEATURE_FPU) || !boot_cpu_has(X86_FEATURE_FXSR)) { - printk(KERN_ERR "kvm: inadequate fpu\n"); + pr_err("inadequate fpu\n"); return -EOPNOTSUPP; } @@ -9363,19 +9365,19 @@ static int __kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) */ if (rdmsrl_safe(MSR_IA32_CR_PAT, &host_pat) || (host_pat & GENMASK(2, 0)) != 6) { - pr_err("kvm: host PAT[0] is not WB\n"); + pr_err("host PAT[0] is not WB\n"); return -EIO; } x86_emulator_cache = kvm_alloc_emulator_cache(); if (!x86_emulator_cache) { - pr_err("kvm: failed to allocate cache for x86 emulator\n"); + pr_err("failed to allocate cache for x86 emulator\n"); return -ENOMEM; } user_return_msrs = alloc_percpu(struct kvm_user_return_msrs); if (!user_return_msrs) { - printk(KERN_ERR "kvm: failed to allocate percpu kvm_user_return_msrs\n"); + pr_err("failed to allocate percpu kvm_user_return_msrs\n"); r = -ENOMEM; goto out_free_x86_emulator_cache; } @@ -11647,7 +11649,7 @@ static int sync_regs(struct kvm_vcpu *vcpu) int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) { if (kvm_check_tsc_unstable() && kvm->created_vcpus) - pr_warn_once("kvm: SMP vm created on host with unstable TSC; " + pr_warn_once("SMP vm created on host with unstable TSC; " "guest TSC will not be reliable\n"); if (!kvm->arch.max_vcpu_ids) @@ -11724,7 +11726,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) goto free_wbinvd_dirty_mask; if (!fpu_alloc_guest_fpstate(&vcpu->arch.guest_fpu)) { - pr_err("kvm: failed to allocate vcpu's fpu\n"); + pr_err("failed to allocate vcpu's fpu\n"); goto free_emulate_ctxt; } diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 2e29bdc2949c..0bd5d171df57 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -5,6 +5,7 @@ * * KVM Xen emulation */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "x86.h" #include "xen.h" diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index 1638418f72dd..71916de7c6c4 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h @@ -60,7 +60,7 @@ struct arch_timer_cpu { bool enabled; }; -int kvm_timer_hyp_init(bool); +int __init kvm_timer_hyp_init(bool has_gic); int kvm_timer_enable(struct kvm_vcpu *vcpu); int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu); void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu); -- cgit v1.2.3 From aaf12a7b4323eb7d94677bcefc286ff6b772ed1c Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Wed, 30 Nov 2022 23:09:25 +0000 Subject: KVM: Rename and move CPUHP_AP_KVM_STARTING to ONLINE section The CPU STARTING section doesn't allow callbacks to fail. Move KVM's hotplug callback to ONLINE section so that it can abort onlining a CPU in certain cases to avoid potentially breaking VMs running on existing CPUs. For example, when KVM fails to enable hardware virtualization on the hotplugged CPU. Place KVM's hotplug state before CPUHP_AP_SCHED_WAIT_EMPTY as it ensures when offlining a CPU, all user tasks and non-pinned kernel tasks have left the CPU, i.e. there cannot be a vCPU task around. So, it is safe for KVM's CPU offline callback to disable hardware virtualization at that point. Likewise, KVM's online callback can enable hardware virtualization before any vCPU task gets a chance to run on hotplugged CPUs. Drop kvm_x86_check_processor_compatibility()'s WARN that IRQs are disabled, as the ONLINE section runs with IRQs disabled. The WARN wasn't intended to be a requirement, e.g. disabling preemption is sufficient, the IRQ thing was purely an aggressive sanity check since the helper was only ever invoked via SMP function call. Rename KVM's CPU hotplug callbacks accordingly. Suggested-by: Thomas Gleixner Signed-off-by: Chao Gao Signed-off-by: Isaku Yamahata Reviewed-by: Yuan Yao [sean: drop WARN that IRQs are disabled] Signed-off-by: Sean Christopherson Message-Id: <20221130230934.1014142-42-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 2 -- include/linux/cpuhotplug.h | 2 +- virt/kvm/kvm_main.c | 30 ++++++++++++++++++++++-------- 3 files changed, 23 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6575d9e7b9b6..f2971821ec26 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9298,8 +9298,6 @@ static int kvm_x86_check_processor_compatibility(void) { struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); - WARN_ON(!irqs_disabled()); - if (__cr4_reserved_bits(cpu_has, c) != __cr4_reserved_bits(cpu_has, &boot_cpu_data)) return -EIO; diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 5cae6bd22f7f..5b2f8147d1ae 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -187,7 +187,6 @@ enum cpuhp_state { CPUHP_AP_CSKY_TIMER_STARTING, CPUHP_AP_TI_GP_TIMER_STARTING, CPUHP_AP_HYPERV_TIMER_STARTING, - CPUHP_AP_KVM_STARTING, /* Must be the last timer callback */ CPUHP_AP_DUMMY_TIMER_STARTING, CPUHP_AP_ARM_XEN_STARTING, @@ -202,6 +201,7 @@ enum cpuhp_state { /* Online section invoked on the hotplugged CPU from the hotplug thread */ CPUHP_AP_ONLINE_IDLE, + CPUHP_AP_KVM_ONLINE, CPUHP_AP_SCHED_WAIT_EMPTY, CPUHP_AP_SMPBOOT_THREADS, CPUHP_AP_X86_VDSO_VMA_ONLINE, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e13b369cfc1b..ee1005cb99e1 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -5114,13 +5114,27 @@ static void hardware_enable_nolock(void *junk) } } -static int kvm_starting_cpu(unsigned int cpu) +static int kvm_online_cpu(unsigned int cpu) { + int ret = 0; + + /* + * Abort the CPU online process if hardware virtualization cannot + * be enabled. Otherwise running VMs would encounter unrecoverable + * errors when scheduled to this CPU. + */ raw_spin_lock(&kvm_count_lock); - if (kvm_usage_count) + if (kvm_usage_count) { + WARN_ON_ONCE(atomic_read(&hardware_enable_failed)); + hardware_enable_nolock(NULL); + if (atomic_read(&hardware_enable_failed)) { + atomic_set(&hardware_enable_failed, 0); + ret = -EIO; + } + } raw_spin_unlock(&kvm_count_lock); - return 0; + return ret; } static void hardware_disable_nolock(void *junk) @@ -5133,7 +5147,7 @@ static void hardware_disable_nolock(void *junk) kvm_arch_hardware_disable(); } -static int kvm_dying_cpu(unsigned int cpu) +static int kvm_offline_cpu(unsigned int cpu) { raw_spin_lock(&kvm_count_lock); if (kvm_usage_count) @@ -5910,8 +5924,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module) if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) return -ENOMEM; - r = cpuhp_setup_state_nocalls(CPUHP_AP_KVM_STARTING, "kvm/cpu:starting", - kvm_starting_cpu, kvm_dying_cpu); + r = cpuhp_setup_state_nocalls(CPUHP_AP_KVM_ONLINE, "kvm/cpu:online", + kvm_online_cpu, kvm_offline_cpu); if (r) goto out_free_2; register_reboot_notifier(&kvm_reboot_notifier); @@ -5985,7 +5999,7 @@ out_free_4: kmem_cache_destroy(kvm_vcpu_cache); out_free_3: unregister_reboot_notifier(&kvm_reboot_notifier); - cpuhp_remove_state_nocalls(CPUHP_AP_KVM_STARTING); + cpuhp_remove_state_nocalls(CPUHP_AP_KVM_ONLINE); out_free_2: free_cpumask_var(cpus_hardware_enabled); return r; @@ -6011,7 +6025,7 @@ void kvm_exit(void) kvm_async_pf_deinit(); unregister_syscore_ops(&kvm_syscore_ops); unregister_reboot_notifier(&kvm_reboot_notifier); - cpuhp_remove_state_nocalls(CPUHP_AP_KVM_STARTING); + cpuhp_remove_state_nocalls(CPUHP_AP_KVM_ONLINE); on_each_cpu(hardware_disable_nolock, NULL, 1); kvm_irqfd_exit(); free_cpumask_var(cpus_hardware_enabled); -- cgit v1.2.3 From 441f7bfa99fe2b8a7e504aa72047e20579e88a5d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 30 Nov 2022 23:09:33 +0000 Subject: KVM: Opt out of generic hardware enabling on s390 and PPC Allow architectures to opt out of the generic hardware enabling logic, and opt out on both s390 and PPC, which don't need to manually enable virtualization as it's always on (when available). In addition to letting s390 and PPC drop a bit of dead code, this will hopefully also allow ARM to clean up its related code, e.g. ARM has its own per-CPU flag to track which CPUs have enable hardware due to the need to keep hardware enabled indefinitely when pKVM is enabled. Signed-off-by: Sean Christopherson Acked-by: Anup Patel Message-Id: <20221130230934.1014142-50-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/Kconfig | 1 + arch/mips/kvm/Kconfig | 1 + arch/powerpc/include/asm/kvm_host.h | 1 - arch/powerpc/kvm/powerpc.c | 5 ----- arch/riscv/kvm/Kconfig | 1 + arch/s390/include/asm/kvm_host.h | 1 - arch/s390/kvm/kvm-s390.c | 6 ------ arch/x86/kvm/Kconfig | 1 + include/linux/kvm_host.h | 4 ++++ virt/kvm/Kconfig | 3 +++ virt/kvm/kvm_main.c | 30 ++++++++++++++++++++++++------ 11 files changed, 35 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 05da3c8f7e88..ca6eadeb7d1a 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -21,6 +21,7 @@ if VIRTUALIZATION menuconfig KVM bool "Kernel-based Virtual Machine (KVM) support" depends on HAVE_KVM + select KVM_GENERIC_HARDWARE_ENABLING select MMU_NOTIFIER select PREEMPT_NOTIFIERS select HAVE_KVM_CPU_RELAX_INTERCEPT diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig index 91d197bee9c0..29e51649203b 100644 --- a/arch/mips/kvm/Kconfig +++ b/arch/mips/kvm/Kconfig @@ -28,6 +28,7 @@ config KVM select MMU_NOTIFIER select SRCU select INTERVAL_TREE + select KVM_GENERIC_HARDWARE_ENABLING help Support for hosting Guest kernels. diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 0a80e80c7b9e..959f566a455c 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -876,7 +876,6 @@ struct kvm_vcpu_arch { #define __KVM_HAVE_ARCH_WQP #define __KVM_HAVE_CREATE_DEVICE -static inline void kvm_arch_hardware_disable(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {} diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index f5b4ff6bfc89..4c5405fc5538 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -435,11 +435,6 @@ int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, } EXPORT_SYMBOL_GPL(kvmppc_ld); -int kvm_arch_hardware_enable(void) -{ - return 0; -} - int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { struct kvmppc_ops *kvm_ops = NULL; diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig index f36a737d5f96..d5a658a047a7 100644 --- a/arch/riscv/kvm/Kconfig +++ b/arch/riscv/kvm/Kconfig @@ -20,6 +20,7 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support (EXPERIMENTAL)" depends on RISCV_SBI && MMU + select KVM_GENERIC_HARDWARE_ENABLING select MMU_NOTIFIER select PREEMPT_NOTIFIERS select KVM_MMIO diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index d67ce719d16a..2bbc3d54959d 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -1031,7 +1031,6 @@ extern char sie_exit; extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc); extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc); -static inline void kvm_arch_hardware_disable(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arch_free_memslot(struct kvm *kvm, diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 7ad8252e92c2..bd25076aa19b 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -256,12 +256,6 @@ debug_info_t *kvm_s390_dbf; debug_info_t *kvm_s390_dbf_uv; /* Section: not file related */ -int kvm_arch_hardware_enable(void) -{ - /* every s390 is virtualization enabled ;-) */ - return 0; -} - /* forward declarations */ static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start, unsigned long end); diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index fbeaa9ddef59..8e578311ca9d 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -49,6 +49,7 @@ config KVM select SRCU select INTERVAL_TREE select HAVE_KVM_PM_NOTIFIER if PM + select KVM_GENERIC_HARDWARE_ENABLING help Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 20e207e4c6c1..109b18e2789c 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1441,8 +1441,10 @@ void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_ static inline void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) {} #endif +#ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING int kvm_arch_hardware_enable(void); void kvm_arch_hardware_disable(void); +#endif int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu); bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu); int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu); @@ -2074,7 +2076,9 @@ static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu) } } +#ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING extern bool kvm_rebooting; +#endif extern unsigned int halt_poll_ns; extern unsigned int halt_poll_ns_grow; diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 9fb1ff6f19e5..b74916de5183 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -92,3 +92,6 @@ config KVM_XFER_TO_GUEST_WORK config HAVE_KVM_PM_NOTIFIER bool + +config KVM_GENERIC_HARDWARE_ENABLING + bool diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 6c0bd9a8e27e..3d0678579c5e 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -102,9 +102,6 @@ EXPORT_SYMBOL_GPL(halt_poll_ns_shrink); DEFINE_MUTEX(kvm_lock); LIST_HEAD(vm_list); -static DEFINE_PER_CPU(bool, hardware_enabled); -static int kvm_usage_count; - static struct kmem_cache *kvm_vcpu_cache; static __read_mostly struct preempt_ops kvm_preempt_ops; @@ -146,9 +143,6 @@ static void hardware_disable_all(void); static void kvm_io_bus_destroy(struct kvm_io_bus *bus); -__visible bool kvm_rebooting; -EXPORT_SYMBOL_GPL(kvm_rebooting); - #define KVM_EVENT_CREATE_VM 0 #define KVM_EVENT_DESTROY_VM 1 static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm); @@ -5093,6 +5087,13 @@ static struct miscdevice kvm_dev = { &kvm_chardev_ops, }; +#ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING +__visible bool kvm_rebooting; +EXPORT_SYMBOL_GPL(kvm_rebooting); + +static DEFINE_PER_CPU(bool, hardware_enabled); +static int kvm_usage_count; + static int __hardware_enable_nolock(void) { if (__this_cpu_read(hardware_enabled)) @@ -5254,6 +5255,17 @@ static struct syscore_ops kvm_syscore_ops = { .suspend = kvm_suspend, .resume = kvm_resume, }; +#else /* CONFIG_KVM_GENERIC_HARDWARE_ENABLING */ +static int hardware_enable_all(void) +{ + return 0; +} + +static void hardware_disable_all(void) +{ + +} +#endif /* CONFIG_KVM_GENERIC_HARDWARE_ENABLING */ static void kvm_io_bus_destroy(struct kvm_io_bus *bus) { @@ -5942,6 +5954,7 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module) int r; int cpu; +#ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING r = cpuhp_setup_state_nocalls(CPUHP_AP_KVM_ONLINE, "kvm/cpu:online", kvm_online_cpu, kvm_offline_cpu); if (r) @@ -5949,6 +5962,7 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module) register_reboot_notifier(&kvm_reboot_notifier); register_syscore_ops(&kvm_syscore_ops); +#endif /* A kmem cache lets us meet the alignment requirements of fx_save. */ if (!vcpu_align) @@ -6016,9 +6030,11 @@ out_free_4: free_cpumask_var(per_cpu(cpu_kick_mask, cpu)); kmem_cache_destroy(kvm_vcpu_cache); out_free_3: +#ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING unregister_syscore_ops(&kvm_syscore_ops); unregister_reboot_notifier(&kvm_reboot_notifier); cpuhp_remove_state_nocalls(CPUHP_AP_KVM_ONLINE); +#endif return r; } EXPORT_SYMBOL_GPL(kvm_init); @@ -6040,9 +6056,11 @@ void kvm_exit(void) kmem_cache_destroy(kvm_vcpu_cache); kvm_vfio_ops_exit(); kvm_async_pf_deinit(); +#ifdef CONFIG_KVM_GENERIC_HARDWARE_ENABLING unregister_syscore_ops(&kvm_syscore_ops); unregister_reboot_notifier(&kvm_reboot_notifier); cpuhp_remove_state_nocalls(CPUHP_AP_KVM_ONLINE); +#endif kvm_irqfd_exit(); } EXPORT_SYMBOL_GPL(kvm_exit); -- cgit v1.2.3 From 443a0a0f0cf4f432c7af6654b7f2f920d411d379 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 19 Dec 2022 14:42:33 +0200 Subject: pinctrl: Introduce struct pinfunction and PINCTRL_PINFUNCTION() macro There are many pin control drivers define their own data type for pin function representation which is the same or embed the same data as newly introduced one. Provide the data type and convenient macro for all pin control drivers. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Acked-by: Mika Westerberg --- 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 a0d39b303431..4d252ea00ed1 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -206,6 +206,26 @@ extern int pinctrl_get_group_pins(struct pinctrl_dev *pctldev, const char *pin_group, const unsigned **pins, unsigned *num_pins); +/** + * struct pinfunction - Description about a function + * @name: Name of the function + * @groups: An array of groups for this function + * @ngroups: Number of groups in @groups + */ +struct pinfunction { + const char *name; + const char * const *groups; + size_t ngroups; +}; + +/* Convenience macro to define a single named pinfunction */ +#define PINCTRL_PINFUNCTION(_name, _groups, _ngroups) \ +(struct pinfunction) { \ + .name = (_name), \ + .groups = (_groups), \ + .ngroups = (_ngroups), \ + } + #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_PINCTRL) extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np); #else -- cgit v1.2.3 From aa9695157f65c55e5c85a1c194859d3c03e68018 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 13 Dec 2022 17:13:10 +0100 Subject: crypto: scatterwalk - use kmap_local() not kmap_atomic() kmap_atomic() is used to create short-lived mappings of pages that may not be accessible via the kernel direct map. This is only needed on 32-bit architectures that implement CONFIG_HIGHMEM, but it can be used on 64-bit other architectures too, where the returned mapping is simply the kernel direct address of the page. However, kmap_atomic() does not support migration on CONFIG_HIGHMEM configurations, due to the use of per-CPU kmap slots, and so it disables preemption on all architectures, not just the 32-bit ones. This implies that all scatterwalk based crypto routines essentially execute with preemption disabled all the time, which is less than ideal. So let's switch scatterwalk_map/_unmap and the shash/ahash routines to kmap_local() instead, which serves a similar purpose, but without the resulting impact on preemption on architectures that have no need for CONFIG_HIGHMEM. Cc: Eric Biggers Cc: Herbert Xu Cc: "Elliott, Robert (Servers)" Signed-off-by: Ard Biesheuvel Signed-off-by: Herbert Xu --- crypto/ahash.c | 4 ++-- crypto/shash.c | 4 ++-- include/crypto/scatterwalk.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/crypto/ahash.c b/crypto/ahash.c index c2ca631a111f..4b089f1b770f 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -45,7 +45,7 @@ static int hash_walk_next(struct crypto_hash_walk *walk) unsigned int nbytes = min(walk->entrylen, ((unsigned int)(PAGE_SIZE)) - offset); - walk->data = kmap_atomic(walk->pg); + walk->data = kmap_local_page(walk->pg); walk->data += offset; if (offset & alignmask) { @@ -95,7 +95,7 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) } } - kunmap_atomic(walk->data); + kunmap_local(walk->data); crypto_yield(walk->flags); if (err) diff --git a/crypto/shash.c b/crypto/shash.c index 868b6ba2b3b7..58b46f198449 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -320,10 +320,10 @@ int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) nbytes <= min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset))) { void *data; - data = kmap_atomic(sg_page(sg)); + data = kmap_local_page(sg_page(sg)); err = crypto_shash_digest(desc, data + offset, nbytes, req->result); - kunmap_atomic(data); + kunmap_local(data); } else err = crypto_shash_init(desc) ?: shash_ahash_finup(req, desc); diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h index f2c42b4111b1..32fc4473175b 100644 --- a/include/crypto/scatterwalk.h +++ b/include/crypto/scatterwalk.h @@ -53,7 +53,7 @@ static inline struct page *scatterwalk_page(struct scatter_walk *walk) static inline void scatterwalk_unmap(void *vaddr) { - kunmap_atomic(vaddr); + kunmap_local(vaddr); } static inline void scatterwalk_start(struct scatter_walk *walk, @@ -65,7 +65,7 @@ static inline void scatterwalk_start(struct scatter_walk *walk, static inline void *scatterwalk_map(struct scatter_walk *walk) { - return kmap_atomic(scatterwalk_page(walk)) + + return kmap_local_page(scatterwalk_page(walk)) + offset_in_page(walk->offset); } -- cgit v1.2.3 From ffebb38efee3e6bbcccd0b7babf0ede8890794cd Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 14 Dec 2022 21:38:05 +0800 Subject: scsi: libsas: Change the coding style of sas_discover_sata() The coding style where calling this interface is inconsistent with other interfaces for SATA devices. The standard style for other SATA interfaces is like: #ifdefine CONFIG_SCSI_SAS_ATA void sas_ata_task_abort(struct sas_task *task); #else static inline void sas_ata_task_abort(struct sas_task *task) { } #endif And the callers does not have to do things like "#ifdefine CONFIG_SCSI_SAS_ATA" and may call the interface directly. So follow the standard style here. Cc: John Garry Signed-off-by: Jason Yan Reviewed-by: Jack Wang Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_discover.c | 6 ------ include/scsi/libsas.h | 1 - include/scsi/sas_ata.h | 11 +++++++++++ 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index d5bc1314c341..72fdb2e5d047 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -455,14 +455,8 @@ static void sas_discover_domain(struct work_struct *work) break; case SAS_SATA_DEV: case SAS_SATA_PM: -#ifdef CONFIG_SCSI_SAS_ATA error = sas_discover_sata(dev); break; -#else - pr_notice("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n"); - fallthrough; -#endif - /* Fall through - only for the #else condition above. */ default: error = -ENXIO; pr_err("unhandled device %d\n", dev->dev_type); diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 1aee3d0ebbb2..159823e0afbf 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -735,7 +735,6 @@ void sas_unregister_domain_devices(struct asd_sas_port *port, int gone); void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *); void sas_discover_event(struct asd_sas_port *, enum discover_event ev); -int sas_discover_sata(struct domain_device *); int sas_discover_end_dev(struct domain_device *); void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *); diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h index 9c927d46f136..606b4496ecaf 100644 --- a/include/scsi/sas_ata.h +++ b/include/scsi/sas_ata.h @@ -36,8 +36,13 @@ void sas_ata_device_link_abort(struct domain_device *dev, bool force_reset); int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id); int smp_ata_check_ready_type(struct ata_link *link); +int sas_discover_sata(struct domain_device *dev); #else +static inline void sas_ata_disabled_notice(void) +{ + pr_notice_once("ATA device seen but CONFIG_SCSI_SAS_ATA=N\n"); +} static inline int dev_is_sata(struct domain_device *dev) { @@ -103,6 +108,12 @@ static inline int smp_ata_check_ready_type(struct ata_link *link) { return 0; } + +static inline int sas_discover_sata(struct domain_device *dev) +{ + sas_ata_disabled_notice(); + return -ENXIO; +} #endif #endif /* _SAS_ATA_H_ */ -- cgit v1.2.3 From 7cc7646b4b24430437e0cff104fadeafd470a7ce Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Wed, 14 Dec 2022 21:38:07 +0800 Subject: scsi: libsas: Factor out sas_ata_add_dev() Factor out sas_ata_add_dev() and put it in sas_ata.c since it is a SATA related interface. Also follow the standard coding style to define an inline empty function when CONFIG_SCSI_SAS_ATA is not enabled. Cc: John Garry Signed-off-by: Jason Yan Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_ata.c | 62 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/libsas/sas_expander.c | 54 ++------------------------------- include/scsi/sas_ata.h | 9 ++++++ 3 files changed, 73 insertions(+), 52 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index de3439ae358d..13fbb8629057 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -675,6 +675,68 @@ void sas_probe_sata(struct asd_sas_port *port) } +int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, + struct domain_device *child, int phy_id) +{ + struct sas_rphy *rphy; + int ret; + + if (child->linkrate > parent->min_linkrate) { + struct sas_phy *cphy = child->phy; + enum sas_linkrate min_prate = cphy->minimum_linkrate, + parent_min_lrate = parent->min_linkrate, + min_linkrate = (min_prate > parent_min_lrate) ? + parent_min_lrate : 0; + struct sas_phy_linkrates rates = { + .maximum_linkrate = parent->min_linkrate, + .minimum_linkrate = min_linkrate, + }; + + pr_notice("ex %016llx phy%02d SATA device linkrate > min pathway connection rate, attempting to lower device linkrate\n", + SAS_ADDR(child->sas_addr), phy_id); + ret = sas_smp_phy_control(parent, phy_id, + PHY_FUNC_LINK_RESET, &rates); + if (ret) { + pr_err("ex %016llx phy%02d SATA device could not set linkrate (%d)\n", + SAS_ADDR(child->sas_addr), phy_id, ret); + return ret; + } + pr_notice("ex %016llx phy%02d SATA device set linkrate successfully\n", + SAS_ADDR(child->sas_addr), phy_id); + child->linkrate = child->min_linkrate; + } + ret = sas_get_ata_info(child, phy); + if (ret) + return ret; + + sas_init_dev(child); + ret = sas_ata_init(child); + if (ret) + return ret; + + rphy = sas_end_device_alloc(phy->port); + if (!rphy) + return ret; + + rphy->identify.phy_identifier = phy_id; + child->rphy = rphy; + get_device(&rphy->dev); + + list_add_tail(&child->disco_list_node, &parent->port->disco_list); + + ret = sas_discover_sata(child); + if (ret) { + pr_notice("sas_discover_sata() for device %16llx at %016llx:%02d returned 0x%x\n", + SAS_ADDR(child->sas_addr), + SAS_ADDR(parent->sas_addr), phy_id, ret); + sas_rphy_free(child->rphy); + list_del(&child->disco_list_node); + return ret; + } + + return 0; +} + static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func) { struct domain_device *dev, *n; diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 29e1b93b0964..0e4e09a0286a 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -785,61 +785,11 @@ static struct domain_device *sas_ex_discover_end_dev( sas_ex_get_linkrate(parent, child, phy); sas_device_set_phy(child, phy->port); -#ifdef CONFIG_SCSI_SAS_ATA if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { - if (child->linkrate > parent->min_linkrate) { - struct sas_phy *cphy = child->phy; - enum sas_linkrate min_prate = cphy->minimum_linkrate, - parent_min_lrate = parent->min_linkrate, - min_linkrate = (min_prate > parent_min_lrate) ? - parent_min_lrate : 0; - struct sas_phy_linkrates rates = { - .maximum_linkrate = parent->min_linkrate, - .minimum_linkrate = min_linkrate, - }; - int ret; - - pr_notice("ex %016llx phy%02d SATA device linkrate > min pathway connection rate, attempting to lower device linkrate\n", - SAS_ADDR(child->sas_addr), phy_id); - ret = sas_smp_phy_control(parent, phy_id, - PHY_FUNC_LINK_RESET, &rates); - if (ret) { - pr_err("ex %016llx phy%02d SATA device could not set linkrate (%d)\n", - SAS_ADDR(child->sas_addr), phy_id, ret); - goto out_free; - } - pr_notice("ex %016llx phy%02d SATA device set linkrate successfully\n", - SAS_ADDR(child->sas_addr), phy_id); - child->linkrate = child->min_linkrate; - } - res = sas_get_ata_info(child, phy); - if (res) - goto out_free; - - sas_init_dev(child); - res = sas_ata_init(child); + res = sas_ata_add_dev(parent, phy, child, phy_id); if (res) goto out_free; - rphy = sas_end_device_alloc(phy->port); - if (!rphy) - goto out_free; - rphy->identify.phy_identifier = phy_id; - - child->rphy = rphy; - get_device(&rphy->dev); - - list_add_tail(&child->disco_list_node, &parent->port->disco_list); - - res = sas_discover_sata(child); - if (res) { - pr_notice("sas_discover_sata() for device %16llx at %016llx:%02d returned 0x%x\n", - SAS_ADDR(child->sas_addr), - SAS_ADDR(parent->sas_addr), phy_id, res); - goto out_list_del; - } - } else -#endif - if (phy->attached_tproto & SAS_PROTOCOL_SSP) { + } else if (phy->attached_tproto & SAS_PROTOCOL_SSP) { child->dev_type = SAS_END_DEVICE; rphy = sas_end_device_alloc(phy->port); /* FIXME: error handling */ diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h index 606b4496ecaf..2f8c719840a6 100644 --- a/include/scsi/sas_ata.h +++ b/include/scsi/sas_ata.h @@ -37,6 +37,8 @@ int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id); int smp_ata_check_ready_type(struct ata_link *link); int sas_discover_sata(struct domain_device *dev); +int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, + struct domain_device *child, int phy_id); #else static inline void sas_ata_disabled_notice(void) @@ -114,6 +116,13 @@ static inline int sas_discover_sata(struct domain_device *dev) sas_ata_disabled_notice(); return -ENXIO; } + +static inline int sas_ata_add_dev(struct domain_device *parent, struct ex_phy *phy, + struct domain_device *child, int phy_id) +{ + sas_ata_disabled_notice(); + return -ENODEV; +} #endif #endif /* _SAS_ATA_H_ */ -- cgit v1.2.3 From 6ad90f71129219f9b87ce181189817bcbcde34b8 Mon Sep 17 00:00:00 2001 From: Stuart Hayes Date: Thu, 8 Dec 2022 17:25:36 -0600 Subject: ACPI: tables: Add support for NBFT Add support for the NVMe Boot Firmware Table (NBFT) to facilitate booting from NVM Express namespaces which are accessed via NVMe over Fabrics (NVMe-oF). Signed-off-by: Stuart Hayes Reviewed-by: John Meneghini Signed-off-by: Rafael J. Wysocki --- drivers/acpi/tables.c | 3 ++- include/acpi/actbl1.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 5fbc32b802d0..7b4680da57d7 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -555,7 +555,8 @@ static const char table_sigs[][ACPI_NAMESEG_SIZE] __initconst = { ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, - ACPI_SIG_NHLT, ACPI_SIG_AEST, ACPI_SIG_CEDT, ACPI_SIG_AGDI }; + ACPI_SIG_NHLT, ACPI_SIG_AEST, ACPI_SIG_CEDT, ACPI_SIG_AGDI, + ACPI_SIG_NBFT }; #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 4175dce3967c..72884efc0d86 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -50,6 +50,8 @@ #define ACPI_SIG_S3PT "S3PT" /* S3 Performance (sub)Table */ #define ACPI_SIG_PCCS "PCC" /* PCC Shared Memory Region */ +#define ACPI_SIG_NBFT "NBFT" /* NVMe Boot Firmware Table */ + /* Reserved table signatures */ #define ACPI_SIG_MATR "MATR" /* Memory Address Translation Table */ -- cgit v1.2.3 From 91fdb91ccca2b48572a1ccf1d382fd599e3e1237 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 20 Dec 2022 17:01:26 +0200 Subject: ACPICA: Constify pathname argument for acpi_get_handle() acpi_get_handle() uses the pathname argument to find a handle related to that pathname but it does not need to modify it. Make it const, in order to be able to pass const pathname to it. Link: https://github.com/acpica/acpica/pull/773 Signed-off-by: Sakari Ailus Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsxfname.c | 2 +- include/acpi/acpixf.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index b2cfdfef3194..a0592d15dd37 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -44,7 +44,7 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, acpi_status acpi_get_handle(acpi_handle parent, - acpi_string pathname, acpi_handle *ret_handle) + const char *pathname, acpi_handle *ret_handle) { acpi_status status; struct acpi_namespace_node *node = NULL; diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 9778408f8db4..8e364cbdd14a 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -526,7 +526,7 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status struct acpi_buffer *ret_path_ptr)) ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_get_handle(acpi_handle parent, - acpi_string pathname, + const char *pathname, acpi_handle *ret_handle)) ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_attach_data(acpi_handle object, -- cgit v1.2.3 From a3c1f066e1c514ac819f5dae288cc8a59c384158 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Mon, 19 Dec 2022 23:46:15 +0800 Subject: thermal/intel: Introduce Intel TCC library There are several different drivers that accesses the Intel TCC (thermal control circuitry) MSRs, and each of them has its own implementation for the same functionalities, e.g. getting the current temperature, getting the tj_max, and getting/setting the tj_max offset. Introduce a library to unify the code for Intel CPU TCC MSR access. At the same time, ensure the temperature is got based on the updated tjmax value because tjmax can be changed at runtime for cases like the Intel SST-PP (Intel Speed Select Technology - Performance Profile) level change. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/Kconfig | 4 ++ drivers/thermal/intel/Makefile | 1 + drivers/thermal/intel/intel_tcc.c | 139 ++++++++++++++++++++++++++++++++++++++ include/linux/intel_tcc.h | 18 +++++ 4 files changed, 162 insertions(+) create mode 100644 drivers/thermal/intel/intel_tcc.c create mode 100644 include/linux/intel_tcc.h (limited to 'include') diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index f0c845679250..6b938c040d6e 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -12,6 +12,10 @@ config X86_THERMAL_VECTOR def_bool y depends on X86 && CPU_SUP_INTEL && X86_LOCAL_APIC +config INTEL_TCC + bool + depends on X86 + config X86_PKG_TEMP_THERMAL tristate "X86 package temperature thermal driver" depends on X86_THERMAL_VECTOR diff --git a/drivers/thermal/intel/Makefile b/drivers/thermal/intel/Makefile index 9a8d8054f316..5d8833c82ab6 100644 --- a/drivers/thermal/intel/Makefile +++ b/drivers/thermal/intel/Makefile @@ -2,6 +2,7 @@ # # Makefile for various Intel thermal drivers. +obj-$(CONFIG_INTEL_TCC) += intel_tcc.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o diff --git a/drivers/thermal/intel/intel_tcc.c b/drivers/thermal/intel/intel_tcc.c new file mode 100644 index 000000000000..2e5c741c41ca --- /dev/null +++ b/drivers/thermal/intel/intel_tcc.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * intel_tcc.c - Library for Intel TCC (thermal control circuitry) MSR access + * Copyright (c) 2022, Intel Corporation. + */ + +#include +#include +#include + +/** + * intel_tcc_get_tjmax() - returns the default TCC activation Temperature + * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * + * Get the TjMax value, which is the default thermal throttling or TCC + * activation temperature in degrees C. + * + * Return: Tjmax value in degrees C on success, negative error code otherwise. + */ +int intel_tcc_get_tjmax(int cpu) +{ + u32 low, high; + int val, err; + + if (cpu < 0) + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); + else + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high); + if (err) + return err; + + val = (low >> 16) & 0xff; + + return val ? val : -ENODATA; +} +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, INTEL_TCC); + +/** + * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax + * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * + * Get the TCC offset value to Tjmax. The effective thermal throttling or TCC + * activation temperature equals "Tjmax" - "TCC Offset", in degrees C. + * + * Return: Tcc offset value in degrees C on success, negative error code otherwise. + */ +int intel_tcc_get_offset(int cpu) +{ + u32 low, high; + int err; + + if (cpu < 0) + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); + else + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high); + if (err) + return err; + + return (low >> 24) & 0x3f; +} +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC); + +/** + * intel_tcc_set_offset() - set the TCC offset value to Tjmax + * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * @offset: TCC offset value in degree C + * + * Set the TCC Offset value to Tjmax. The effective thermal throttling or TCC + * activation temperature equals "Tjmax" - "TCC Offset", in degree C. + * + * Return: On success returns 0, negative error code otherwise. + */ + +int intel_tcc_set_offset(int cpu, int offset) +{ + u32 low, high; + int err; + + if (offset < 0 || offset > 0x3f) + return -EINVAL; + + if (cpu < 0) + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &low, &high); + else + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &low, &high); + if (err) + return err; + + /* MSR Locked */ + if (low & BIT(31)) + return -EPERM; + + low &= ~(0x3f << 24); + low |= offset << 24; + + if (cpu < 0) + return wrmsr_safe(MSR_IA32_TEMPERATURE_TARGET, low, high); + else + return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, low, high); +} +EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC); + +/** + * intel_tcc_get_temp() - returns the current temperature + * @cpu: cpu that the MSR should be run on, nagative value means any cpu. + * @pkg: true: Package Thermal Sensor. false: Core Thermal Sensor. + * + * Get the current temperature returned by the CPU core/package level + * thermal sensor, in degrees C. + * + * Return: Temperature in degrees C on success, negative error code otherwise. + */ +int intel_tcc_get_temp(int cpu, bool pkg) +{ + u32 low, high; + u32 msr = pkg ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS; + int tjmax, temp, err; + + tjmax = intel_tcc_get_tjmax(cpu); + if (tjmax < 0) + return tjmax; + + if (cpu < 0) + err = rdmsr_safe(msr, &low, &high); + else + err = rdmsr_safe_on_cpu(cpu, msr, &low, &high); + if (err) + return err; + + /* Temperature is beyond the valid thermal sensor range */ + if (!(low & BIT(31))) + return -ENODATA; + + temp = tjmax - ((low >> 16) & 0x7f); + + /* Do not allow negative CPU temperature */ + return temp >= 0 ? temp : -ENODATA; +} +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC); diff --git a/include/linux/intel_tcc.h b/include/linux/intel_tcc.h new file mode 100644 index 000000000000..f422612c28d6 --- /dev/null +++ b/include/linux/intel_tcc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * header for Intel TCC (thermal control circuitry) library + * + * Copyright (C) 2022 Intel Corporation. + */ + +#ifndef __INTEL_TCC_H__ +#define __INTEL_TCC_H__ + +#include + +int intel_tcc_get_tjmax(int cpu); +int intel_tcc_get_offset(int cpu); +int intel_tcc_set_offset(int cpu, int offset); +int intel_tcc_get_temp(int cpu, bool pkg); + +#endif /* __INTEL_TCC_H__ */ -- cgit v1.2.3 From 3f5145a6152388ca612461ca96db4f995fa816d2 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Thu, 1 Dec 2022 15:04:31 +0100 Subject: scsi: ufs: bsg: Let result in struct ufs_bsg_reply be signed int According to the comments in struct ufs_bsg_reply and its usage, the result should be signed int, not __u32. Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- include/uapi/scsi/scsi_bsg_ufs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index d55f2176dfd4..64b0cb33e549 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -95,7 +95,7 @@ struct ufs_bsg_reply { * msg and status fields. The per-msgcode reply structure * will contain valid data. */ - __u32 result; + int result; /* If there was reply_payload, how much was received? */ __u32 reply_payload_rcv_len; -- cgit v1.2.3 From f6b9d0fe5c0573ddd0cbf3071a2003897325c86c Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Thu, 1 Dec 2022 15:04:35 +0100 Subject: scsi: ufs: core: Advanced RPMB detection Check UFS Advanced RPMB LU enablement during ufshcd_lu_init(). Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 6 ++++++ include/ufs/ufs.h | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index d1bcb4c4e4e4..641fed6dae5d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4954,6 +4954,12 @@ static void ufshcd_lu_init(struct ufs_hba *hba, struct scsi_device *sdev) desc_buf[UNIT_DESC_PARAM_LU_WR_PROTECT] == UFS_LU_POWER_ON_WP) hba->dev_info.is_lu_power_on_wp = true; + /* In case of RPMB LU, check if advanced RPMB mode is enabled */ + if (desc_buf[UNIT_DESC_PARAM_UNIT_INDEX] == UFS_UPIU_RPMB_WLUN && + desc_buf[RPMB_UNIT_DESC_PARAM_REGION_EN] & BIT(4)) + hba->dev_info.b_advanced_rpmb_en = true; + + kfree(desc_buf); set_qdepth: /* diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 1bba3fead2ce..17e401df674c 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -212,6 +212,28 @@ enum unit_desc_param { UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS = 0x29, }; +/* RPMB Unit descriptor parameters offsets in bytes*/ +enum rpmb_unit_desc_param { + RPMB_UNIT_DESC_PARAM_LEN = 0x0, + RPMB_UNIT_DESC_PARAM_TYPE = 0x1, + RPMB_UNIT_DESC_PARAM_UNIT_INDEX = 0x2, + RPMB_UNIT_DESC_PARAM_LU_ENABLE = 0x3, + RPMB_UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4, + RPMB_UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5, + RPMB_UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6, + RPMB_UNIT_DESC_PARAM_PSA_SENSITIVE = 0x7, + RPMB_UNIT_DESC_PARAM_MEM_TYPE = 0x8, + RPMB_UNIT_DESC_PARAM_REGION_EN = 0x9, + RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA, + RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_COUNT = 0xB, + RPMB_UNIT_DESC_PARAM_REGION0_SIZE = 0x13, + RPMB_UNIT_DESC_PARAM_REGION1_SIZE = 0x14, + RPMB_UNIT_DESC_PARAM_REGION2_SIZE = 0x15, + RPMB_UNIT_DESC_PARAM_REGION3_SIZE = 0x16, + RPMB_UNIT_DESC_PARAM_PROVISIONING_TYPE = 0x17, + RPMB_UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18, +}; + /* Device descriptor parameters offsets in bytes*/ enum device_desc_param { DEVICE_DESC_PARAM_LEN = 0x0, @@ -601,6 +623,8 @@ struct ufs_dev_info { bool b_rpm_dev_flush_capable; u8 b_presrv_uspc_en; + + bool b_advanced_rpmb_en; }; /* -- cgit v1.2.3 From 6ff265fc5ef660499e0edc4641647e99eed3f519 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Thu, 1 Dec 2022 15:04:37 +0100 Subject: scsi: ufs: core: bsg: Add advanced RPMB support in ufs_bsg Add advanced RPMB support in ufs_bsg: 1. According to the UFS specification, only one RPMB operation can be performed at any time. We can ensure this by using reserved slot and its dev_cmd sync operation protection mechanism. 2. For Advanced RPMB, RPMB metadata is packaged in an EHS (Extra Header Segment) of a command UPIU, and the corresponding reply EHS (from the device) should also be returned to the user space. bsg_job->request and bsg_job->reply allow us to pass and return EHS from/back to userspace. Compared to normal/legacy RPMB, the advantages of advanced RPMB are: 1. The data length in the Advanced RPMB data read/write command can be larger than 4KB. For the legacy RPMB, the data length in a single RPMB data transfer is 256 bytes. 2. All of the advanced RPMB operations will be a single command. For legacy RPMB, take the read write-counter value as an example, you need two commands (first SECURITY PROTOCOL OUT, then second SECURITY PROTOCOL IN). Signed-off-by: Bean Huo Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs_bsg.c | 93 +++++++++++++++++++++++++++++++---- drivers/ufs/core/ufshcd.c | 103 +++++++++++++++++++++++++++++++++++++++ include/uapi/scsi/scsi_bsg_ufs.h | 46 ++++++++++++++++- include/ufs/ufs.h | 5 ++ include/ufs/ufshcd.h | 6 ++- include/ufs/ufshci.h | 1 + 6 files changed, 242 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c index 850a0d798f63..a8e58faa7da2 100644 --- a/drivers/ufs/core/ufs_bsg.c +++ b/drivers/ufs/core/ufs_bsg.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include "ufs_bsg.h" @@ -68,6 +69,72 @@ out: return 0; } +static int ufs_bsg_exec_advanced_rpmb_req(struct ufs_hba *hba, struct bsg_job *job) +{ + struct ufs_rpmb_request *rpmb_request = job->request; + struct ufs_rpmb_reply *rpmb_reply = job->reply; + struct bsg_buffer *payload = NULL; + enum dma_data_direction dir; + struct scatterlist *sg_list; + int rpmb_req_type; + int sg_cnt; + int ret; + int data_len; + + if (hba->ufs_version < ufshci_version(4, 0) || !hba->dev_info.b_advanced_rpmb_en || + !(hba->capabilities & MASK_EHSLUTRD_SUPPORTED)) + return -EINVAL; + + if (rpmb_request->ehs_req.length != 2 || rpmb_request->ehs_req.ehs_type != 1) + return -EINVAL; + + rpmb_req_type = be16_to_cpu(rpmb_request->ehs_req.meta.req_resp_type); + + switch (rpmb_req_type) { + case UFS_RPMB_WRITE_KEY: + case UFS_RPMB_READ_CNT: + case UFS_RPMB_PURGE_ENABLE: + dir = DMA_NONE; + break; + case UFS_RPMB_WRITE: + case UFS_RPMB_SEC_CONF_WRITE: + dir = DMA_TO_DEVICE; + break; + case UFS_RPMB_READ: + case UFS_RPMB_SEC_CONF_READ: + case UFS_RPMB_PURGE_STATUS_READ: + dir = DMA_FROM_DEVICE; + break; + default: + return -EINVAL; + } + + if (dir != DMA_NONE) { + payload = &job->request_payload; + if (!payload || !payload->payload_len || !payload->sg_cnt) + return -EINVAL; + + sg_cnt = dma_map_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir); + if (unlikely(!sg_cnt)) + return -ENOMEM; + sg_list = payload->sg_list; + data_len = payload->payload_len; + } + + ret = ufshcd_advanced_rpmb_req_handler(hba, &rpmb_request->bsg_request.upiu_req, + &rpmb_reply->bsg_reply.upiu_rsp, &rpmb_request->ehs_req, + &rpmb_reply->ehs_rsp, sg_cnt, sg_list, dir); + + if (dir != DMA_NONE) { + dma_unmap_sg(hba->host->dma_dev, payload->sg_list, payload->sg_cnt, dir); + + if (!ret) + rpmb_reply->bsg_reply.reply_payload_rcv_len = data_len; + } + + return ret; +} + static int ufs_bsg_request(struct bsg_job *job) { struct ufs_bsg_request *bsg_request = job->request; @@ -75,10 +142,11 @@ static int ufs_bsg_request(struct bsg_job *job) struct ufs_hba *hba = shost_priv(dev_to_shost(job->dev->parent)); struct uic_command uc = {}; int msgcode; - uint8_t *desc_buff = NULL; + uint8_t *buff = NULL; int desc_len = 0; enum query_opcode desc_op = UPIU_QUERY_OPCODE_NOP; int ret; + bool rpmb = false; bsg_reply->reply_payload_rcv_len = 0; @@ -88,8 +156,7 @@ static int ufs_bsg_request(struct bsg_job *job) switch (msgcode) { case UPIU_TRANSACTION_QUERY_REQ: desc_op = bsg_request->upiu_req.qr.opcode; - ret = ufs_bsg_alloc_desc_buffer(hba, job, &desc_buff, - &desc_len, desc_op); + ret = ufs_bsg_alloc_desc_buffer(hba, job, &buff, &desc_len, desc_op); if (ret) goto out; fallthrough; @@ -97,25 +164,31 @@ static int ufs_bsg_request(struct bsg_job *job) case UPIU_TRANSACTION_TASK_REQ: ret = ufshcd_exec_raw_upiu_cmd(hba, &bsg_request->upiu_req, &bsg_reply->upiu_rsp, msgcode, - desc_buff, &desc_len, desc_op); + buff, &desc_len, desc_op); if (ret) dev_err(hba->dev, "exe raw upiu: error code %d\n", ret); - else if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len) + else if (desc_op == UPIU_QUERY_OPCODE_READ_DESC && desc_len) { bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(job->request_payload.sg_list, job->request_payload.sg_cnt, - desc_buff, desc_len); + buff, desc_len); + } break; case UPIU_TRANSACTION_UIC_CMD: memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE); ret = ufshcd_send_uic_cmd(hba, &uc); if (ret) - dev_err(hba->dev, - "send uic cmd: error code %d\n", ret); + dev_err(hba->dev, "send uic cmd: error code %d\n", ret); memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE); break; + case UPIU_TRANSACTION_ARPMB_CMD: + rpmb = true; + ret = ufs_bsg_exec_advanced_rpmb_req(hba, job); + if (ret) + dev_err(hba->dev, "ARPMB OP failed: error code %d\n", ret); + break; default: ret = -ENOTSUPP; dev_err(hba->dev, "unsupported msgcode 0x%x\n", msgcode); @@ -125,9 +198,9 @@ static int ufs_bsg_request(struct bsg_job *job) out: ufshcd_rpm_put_sync(hba); - kfree(desc_buff); + kfree(buff); bsg_reply->result = ret; - job->reply_len = sizeof(struct ufs_bsg_reply); + job->reply_len = !rpmb ? sizeof(struct ufs_bsg_reply) : sizeof(struct ufs_rpmb_reply); /* complete the job here only if no error */ if (ret == 0) bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index bacc94f87ee2..1ecee6507e88 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -56,6 +56,9 @@ /* Query request timeout */ #define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */ +/* Advanced RPMB request timeout */ +#define ADVANCED_RPMB_REQ_TIMEOUT 3000 /* 3 seconds */ + /* Task management command timeout */ #define TM_CMD_TIMEOUT 100 /* msecs */ @@ -2954,6 +2957,12 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n", __func__); break; + case UPIU_TRANSACTION_RESPONSE: + if (hba->dev_cmd.type != DEV_CMD_TYPE_RPMB) { + err = -EINVAL; + dev_err(hba->dev, "%s: unexpected response %x\n", __func__, resp); + } + break; default: err = -EINVAL; dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n", @@ -7006,6 +7015,100 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, return err; } +/** + * ufshcd_advanced_rpmb_req_handler - handle advanced RPMB request + * @hba: per adapter instance + * @req_upiu: upiu request + * @rsp_upiu: upiu reply + * @req_ehs: EHS field which contains Advanced RPMB Request Message + * @rsp_ehs: EHS field which returns Advanced RPMB Response Message + * @sg_cnt: The number of sg lists actually used + * @sg_list: Pointer to SG list when DATA IN/OUT UPIU is required in ARPMB operation + * @dir: DMA direction + * + * Returns zero on success, non-zero on failure + */ +int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, + struct utp_upiu_req *rsp_upiu, struct ufs_ehs *req_ehs, + struct ufs_ehs *rsp_ehs, int sg_cnt, struct scatterlist *sg_list, + enum dma_data_direction dir) +{ + DECLARE_COMPLETION_ONSTACK(wait); + const u32 tag = hba->reserved_slot; + struct ufshcd_lrb *lrbp; + int err = 0; + int result; + u8 upiu_flags; + u8 *ehs_data; + u16 ehs_len; + + /* Protects use of hba->reserved_slot. */ + ufshcd_hold(hba, false); + mutex_lock(&hba->dev_cmd.lock); + down_read(&hba->clk_scaling_lock); + + lrbp = &hba->lrb[tag]; + WARN_ON(lrbp->cmd); + lrbp->cmd = NULL; + lrbp->task_tag = tag; + lrbp->lun = UFS_UPIU_RPMB_WLUN; + + lrbp->intr_cmd = true; + ufshcd_prepare_lrbp_crypto(NULL, lrbp); + hba->dev_cmd.type = DEV_CMD_TYPE_RPMB; + + /* Advanced RPMB starts from UFS 4.0, so its command type is UTP_CMD_TYPE_UFS_STORAGE */ + lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE; + + ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, dir, 2); + + /* update the task tag and LUN in the request upiu */ + req_upiu->header.dword_0 |= cpu_to_be32(upiu_flags << 16 | UFS_UPIU_RPMB_WLUN << 8 | tag); + + /* copy the UPIU(contains CDB) request as it is */ + memcpy(lrbp->ucd_req_ptr, req_upiu, sizeof(*lrbp->ucd_req_ptr)); + /* Copy EHS, starting with byte32, immediately after the CDB package */ + memcpy(lrbp->ucd_req_ptr + 1, req_ehs, sizeof(*req_ehs)); + + if (dir != DMA_NONE && sg_list) + ufshcd_sgl_to_prdt(hba, lrbp, sg_cnt, sg_list); + + memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); + + hba->dev_cmd.complete = &wait; + + ufshcd_send_command(hba, tag); + + err = ufshcd_wait_for_dev_cmd(hba, lrbp, ADVANCED_RPMB_REQ_TIMEOUT); + + if (!err) { + /* Just copy the upiu response as it is */ + memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu)); + /* Get the response UPIU result */ + result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr); + + ehs_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) >> 24; + /* + * Since the bLength in EHS indicates the total size of the EHS Header and EHS Data + * in 32 Byte units, the value of the bLength Request/Response for Advanced RPMB + * Message is 02h + */ + if (ehs_len == 2 && rsp_ehs) { + /* + * ucd_rsp_ptr points to a buffer with a length of 512 bytes + * (ALIGNED_UPIU_SIZE = 512), and the EHS data just starts from byte32 + */ + ehs_data = (u8 *)lrbp->ucd_rsp_ptr + EHS_OFFSET_IN_RESPONSE; + memcpy(rsp_ehs, ehs_data, ehs_len * 32); + } + } + + up_read(&hba->clk_scaling_lock); + mutex_unlock(&hba->dev_cmd.lock); + ufshcd_release(hba); + return err ? : result; +} + /** * ufshcd_eh_device_reset_handler() - Reset a single logical unit. * @cmd: SCSI command pointer diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index 64b0cb33e549..276e2772328f 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -14,10 +14,27 @@ */ #define UFS_CDB_SIZE 16 -#define UPIU_TRANSACTION_UIC_CMD 0x1F /* uic commands are 4DW long, per UFSHCI V2.1 paragraph 5.6.1 */ #define UIC_CMD_SIZE (sizeof(__u32) * 4) +enum ufs_bsg_msg_code { + UPIU_TRANSACTION_UIC_CMD = 0x1F, + UPIU_TRANSACTION_ARPMB_CMD, +}; + +/* UFS RPMB Request Message Types */ +enum ufs_rpmb_op_type { + UFS_RPMB_WRITE_KEY = 0x01, + UFS_RPMB_READ_CNT = 0x02, + UFS_RPMB_WRITE = 0x03, + UFS_RPMB_READ = 0x04, + UFS_RPMB_READ_RESP = 0x05, + UFS_RPMB_SEC_CONF_WRITE = 0x06, + UFS_RPMB_SEC_CONF_READ = 0x07, + UFS_RPMB_PURGE_ENABLE = 0x08, + UFS_RPMB_PURGE_STATUS_READ = 0x09, +}; + /** * struct utp_upiu_header - UPIU header structure * @dword_0: UPIU header DW-0 @@ -79,6 +96,23 @@ struct utp_upiu_req { }; }; +struct ufs_arpmb_meta { + __u16 req_resp_type; + __u8 nonce[16]; + __u32 write_counter; + __u16 addr_lun; + __u16 block_count; + __u16 result; +} __attribute__((__packed__)); + +struct ufs_ehs { + __u8 length; + __u8 ehs_type; + __u16 ehssub_type; + struct ufs_arpmb_meta meta; + __u8 mac_key[32]; +} __attribute__((__packed__)); + /* request (CDB) structure of the sg_io_v4 */ struct ufs_bsg_request { __u32 msgcode; @@ -102,4 +136,14 @@ struct ufs_bsg_reply { struct utp_upiu_req upiu_rsp; }; + +struct ufs_rpmb_request { + struct ufs_bsg_request bsg_request; + struct ufs_ehs ehs_req; +}; + +struct ufs_rpmb_reply { + struct ufs_bsg_reply bsg_reply; + struct ufs_ehs ehs_rsp; +}; #endif /* UFS_BSG_H */ diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 17e401df674c..0c112195b288 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -49,6 +49,11 @@ */ #define UFS_WB_EXCEED_LIFETIME 0x0B +/* + * In UFS Spec, the Extra Header Segment (EHS) starts from byte 32 in UPIU request/response packet + */ +#define EHS_OFFSET_IN_RESPONSE 32 + /* Well known logical unit id in LUN field of UPIU */ enum { UFS_UPIU_REPORT_LUNS_WLUN = 0x81, diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 5cf81dff60aa..c3dfa8084b5c 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -30,6 +30,7 @@ struct ufs_hba; enum dev_cmd_type { DEV_CMD_TYPE_NOP = 0x0, DEV_CMD_TYPE_QUERY = 0x1, + DEV_CMD_TYPE_RPMB = 0x2, }; enum ufs_event_type { @@ -1201,7 +1202,10 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, int msgcode, u8 *desc_buff, int *buff_len, enum query_opcode desc_op); - +int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, + struct utp_upiu_req *rsp_upiu, struct ufs_ehs *ehs_req, + struct ufs_ehs *ehs_rsp, int sg_cnt, + struct scatterlist *sg_list, enum dma_data_direction dir); int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable); int ufshcd_wb_toggle_buf_flush(struct ufs_hba *hba, bool enable); int ufshcd_suspend_prepare(struct device *dev); diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index f525566a0864..af216296b86e 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -63,6 +63,7 @@ enum { enum { MASK_TRANSFER_REQUESTS_SLOTS = 0x0000001F, MASK_TASK_MANAGEMENT_REQUEST_SLOTS = 0x00070000, + MASK_EHSLUTRD_SUPPORTED = 0x00400000, MASK_AUTO_HIBERN8_SUPPORT = 0x00800000, MASK_64_ADDRESSING_SUPPORT = 0x01000000, MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000, -- cgit v1.2.3 From ada1e653a5eae7361d95781ed812caa0c8e07dbb Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 8 Dec 2022 15:43:58 -0800 Subject: scsi: ufs: core: Allow UFS host drivers to override the sg entry size Modify the UFSHCD core to allow 'struct ufshcd_sg_entry' to be variable-length. The default is the standard length, but variants can override ufs_hba::sg_entry_size with a larger value if there are vendor-specific fields following the standard ones. This is needed to support inline encryption with ufs-exynos (FMP). Cc: Eric Biggers Reviewed-by: Avri Altman Signed-off-by: Eric Biggers [ bvanassche: edited commit message and introduced CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE ] Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 39 ++++++++++++++++++--------------------- drivers/ufs/host/Kconfig | 4 ++++ include/ufs/ufshcd.h | 30 ++++++++++++++++++++++++++++++ include/ufs/ufshci.h | 9 +++++++-- 4 files changed, 59 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index a7d1cf2377e1..62ee2c1ff83d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -528,7 +528,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) prdt_length = le16_to_cpu( lrbp->utr_descriptor_ptr->prd_table_length); if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) - prdt_length /= sizeof(struct ufshcd_sg_entry); + prdt_length /= ufshcd_sg_entry_size(hba); dev_err(hba->dev, "UPIU[%d] - PRDT - %d entries phys@0x%llx\n", @@ -537,7 +537,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) if (pr_prdt) ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr, - sizeof(struct ufshcd_sg_entry) * prdt_length); + ufshcd_sg_entry_size(hba) * prdt_length); } } @@ -2418,7 +2418,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) */ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { - struct ufshcd_sg_entry *prd_table; + struct ufshcd_sg_entry *prd; struct scatterlist *sg; struct scsi_cmnd *cmd; int sg_segments; @@ -2433,13 +2433,12 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) lrbp->utr_descriptor_ptr->prd_table_length = - cpu_to_le16((sg_segments * - sizeof(struct ufshcd_sg_entry))); + cpu_to_le16(sg_segments * ufshcd_sg_entry_size(hba)); else lrbp->utr_descriptor_ptr->prd_table_length = cpu_to_le16(sg_segments); - prd_table = lrbp->ucd_prdt_ptr; + prd = lrbp->ucd_prdt_ptr; scsi_for_each_sg(cmd, sg, sg_segments, i) { const unsigned int len = sg_dma_len(sg); @@ -2453,9 +2452,10 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) * indicates 4 bytes, '7' indicates 8 bytes, etc." */ WARN_ONCE(len > 256 * 1024, "len = %#x\n", len); - prd_table[i].size = cpu_to_le32(len - 1); - prd_table[i].addr = cpu_to_le64(sg->dma_address); - prd_table[i].reserved = 0; + prd->size = cpu_to_le32(len - 1); + prd->addr = cpu_to_le64(sg->dma_address); + prd->reserved = 0; + prd = (void *)prd + ufshcd_sg_entry_size(hba); } } else { lrbp->utr_descriptor_ptr->prd_table_length = 0; @@ -2745,10 +2745,11 @@ static void ufshcd_map_queues(struct Scsi_Host *shost) static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i) { - struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr; + struct utp_transfer_cmd_desc *cmd_descp = (void *)hba->ucdl_base_addr + + i * sizeof_utp_transfer_cmd_desc(hba); struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr; dma_addr_t cmd_desc_element_addr = hba->ucdl_dma_addr + - i * sizeof(struct utp_transfer_cmd_desc); + i * sizeof_utp_transfer_cmd_desc(hba); u16 response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu); u16 prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); @@ -2756,11 +2757,11 @@ static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i) lrb->utr_descriptor_ptr = utrdlp + i; lrb->utrd_dma_addr = hba->utrdl_dma_addr + i * sizeof(struct utp_transfer_req_desc); - lrb->ucd_req_ptr = (struct utp_upiu_req *)(cmd_descp + i); + lrb->ucd_req_ptr = (struct utp_upiu_req *)cmd_descp->command_upiu; lrb->ucd_req_dma_addr = cmd_desc_element_addr; - lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; + lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp->response_upiu; lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset; - lrb->ucd_prdt_ptr = cmd_descp[i].prd_table; + lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp->prd_table; lrb->ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset; } @@ -3669,7 +3670,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) size_t utmrdl_size, utrdl_size, ucdl_size; /* Allocate memory for UTP command descriptors */ - ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs); + ucdl_size = sizeof_utp_transfer_cmd_desc(hba) * hba->nutrs; hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev, ucdl_size, &hba->ucdl_dma_addr, @@ -3763,7 +3764,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); - cmd_desc_size = sizeof(struct utp_transfer_cmd_desc); + cmd_desc_size = sizeof_utp_transfer_cmd_desc(hba); cmd_desc_dma_addr = hba->ucdl_dma_addr; for (i = 0; i < hba->nutrs; i++) { @@ -9658,6 +9659,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle) hba->dev = dev; hba->dev_ref_clk_freq = REF_CLK_FREQ_INVAL; hba->nop_out_timeout = NOP_OUT_TIMEOUT; + ufshcd_set_sg_entry_size(hba, sizeof(struct ufshcd_sg_entry)); INIT_LIST_HEAD(&hba->clk_list_head); spin_lock_init(&hba->outstanding_lock); @@ -10036,11 +10038,6 @@ static int __init ufshcd_core_init(void) { int ret; - /* Verify that there are no gaps in struct utp_transfer_cmd_desc. */ - static_assert(sizeof(struct utp_transfer_cmd_desc) == - 2 * ALIGNED_UPIU_SIZE + - SG_ALL * sizeof(struct ufshcd_sg_entry)); - ufs_debugfs_init(); ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv); diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig index 4cc2dbd79ed0..7f01f453e792 100644 --- a/drivers/ufs/host/Kconfig +++ b/drivers/ufs/host/Kconfig @@ -124,3 +124,7 @@ config SCSI_UFS_EXYNOS Select this if you have UFS host controller on Samsung Exynos SoC. If unsure, say N. + +config SCSI_UFS_VARIABLE_SG_ENTRY_SIZE + bool + default y if SCSI_UFS_EXYNOS && SCSI_UFS_CRYPTO diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 5cf81dff60aa..e03f111947b6 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -754,6 +754,7 @@ struct ufs_hba_monitor { * @vops: pointer to variant specific operations * @vps: pointer to variant specific parameters * @priv: pointer to variant specific private data + * @sg_entry_size: size of struct ufshcd_sg_entry (may include variant fields) * @irq: Irq number of the controller * @is_irq_enabled: whether or not the UFS controller interrupt is enabled. * @dev_ref_clk_freq: reference clock frequency @@ -877,6 +878,9 @@ struct ufs_hba { const struct ufs_hba_variant_ops *vops; struct ufs_hba_variant_params *vps; void *priv; +#ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE + size_t sg_entry_size; +#endif unsigned int irq; bool is_irq_enabled; enum ufs_ref_clk_freq dev_ref_clk_freq; @@ -980,6 +984,32 @@ struct ufs_hba { bool complete_put; }; +#ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE +static inline size_t ufshcd_sg_entry_size(const struct ufs_hba *hba) +{ + return hba->sg_entry_size; +} + +static inline void ufshcd_set_sg_entry_size(struct ufs_hba *hba, size_t sg_entry_size) +{ + WARN_ON_ONCE(sg_entry_size < sizeof(struct ufshcd_sg_entry)); + hba->sg_entry_size = sg_entry_size; +} +#else +static inline size_t ufshcd_sg_entry_size(const struct ufs_hba *hba) +{ + return sizeof(struct ufshcd_sg_entry); +} + +#define ufshcd_set_sg_entry_size(hba, sg_entry_size) \ + ({ (void)(hba); BUILD_BUG_ON(sg_entry_size != sizeof(struct ufshcd_sg_entry)); }) +#endif + +static inline size_t sizeof_utp_transfer_cmd_desc(const struct ufs_hba *hba) +{ + return sizeof(struct utp_transfer_cmd_desc) + SG_ALL * ufshcd_sg_entry_size(hba); +} + /* Returns true if clocks can be gated. Otherwise false */ static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba) { diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index f525566a0864..e145a478afa2 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -422,18 +422,23 @@ struct ufshcd_sg_entry { __le64 addr; __le32 reserved; __le32 size; + /* + * followed by variant-specific fields if + * CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE has been defined. + */ }; /** * struct utp_transfer_cmd_desc - UTP Command Descriptor (UCD) * @command_upiu: Command UPIU Frame address * @response_upiu: Response UPIU Frame address - * @prd_table: Physical Region Descriptor + * @prd_table: Physical Region Descriptor: an array of SG_ALL struct + * ufshcd_sg_entry's. Variant-specific fields may be present after each. */ struct utp_transfer_cmd_desc { u8 command_upiu[ALIGNED_UPIU_SIZE]; u8 response_upiu[ALIGNED_UPIU_SIZE]; - struct ufshcd_sg_entry prd_table[SG_ALL]; + u8 prd_table[]; }; /** -- cgit v1.2.3 From f2a89b071b26b79abbe892ce88c4d674d1f21f63 Mon Sep 17 00:00:00 2001 From: Arthur Simchaev Date: Sun, 11 Dec 2022 15:05:09 +0200 Subject: scsi: ufs: core: Remove redundant desc_size variable from hba Always read the descriptor with QUERY_DESC_MAX_SIZE. According to the spec, the device returns the actual size. Signed-off-by: Arthur Simchaev Reviewed-by: Bean Huo Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs_bsg.c | 6 +--- drivers/ufs/core/ufshcd-priv.h | 3 -- drivers/ufs/core/ufshcd.c | 72 ++++++++---------------------------------- drivers/ufs/core/ufshpb.c | 4 +-- include/ufs/ufs.h | 1 - include/ufs/ufshcd.h | 4 --- 6 files changed, 15 insertions(+), 75 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c index b99e3f3dc4ef..7eec38c63d9f 100644 --- a/drivers/ufs/core/ufs_bsg.c +++ b/drivers/ufs/core/ufs_bsg.c @@ -21,11 +21,7 @@ static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len, if (desc_size <= 0) return -EINVAL; - ufshcd_map_desc_id_to_length(hba, desc_id, desc_len); - if (!*desc_len) - return -EINVAL; - - *desc_len = min_t(int, *desc_len, desc_size); + *desc_len = min_t(int, QUERY_DESC_MAX_SIZE, desc_size); return 0; } diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index a9e8e1f5afe7..c52e2f349aaa 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -70,9 +70,6 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); -void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, - int *desc_length); - int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd); int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 2e47c69d9b04..bb032bc3948e 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3368,37 +3368,6 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, return err; } -/** - * ufshcd_map_desc_id_to_length - map descriptor IDN to its length - * @hba: Pointer to adapter instance - * @desc_id: descriptor idn value - * @desc_len: mapped desc length (out) - */ -void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, - int *desc_len) -{ - if (desc_id >= QUERY_DESC_IDN_MAX || desc_id == QUERY_DESC_IDN_RFU_0 || - desc_id == QUERY_DESC_IDN_RFU_1) - *desc_len = 0; - else - *desc_len = hba->desc_size[desc_id]; -} -EXPORT_SYMBOL(ufshcd_map_desc_id_to_length); - -static void ufshcd_update_desc_length(struct ufs_hba *hba, - enum desc_idn desc_id, int desc_index, - unsigned char desc_len) -{ - if (hba->desc_size[desc_id] == QUERY_DESC_MAX_SIZE && - desc_id != QUERY_DESC_IDN_STRING && desc_index != UFS_RPMB_UNIT) - /* For UFS 3.1, the normal unit descriptor is 10 bytes larger - * than the RPMB unit, however, both descriptors share the same - * desc_idn, to cover both unit descriptors with one length, we - * choose the normal unit descriptor length by desc_index. - */ - hba->desc_size[desc_id] = desc_len; -} - /** * ufshcd_read_desc_param - read the specified descriptor parameter * @hba: Pointer to adapter instance @@ -3419,20 +3388,13 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, { int ret; u8 *desc_buf; - int buff_len; + int buff_len = QUERY_DESC_MAX_SIZE; bool is_kmalloc = true; /* Safety check */ if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) return -EINVAL; - /* Get the length of descriptor */ - ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); - if (!buff_len) { - dev_err(hba->dev, "%s: Failed to get desc length\n", __func__); - return -EINVAL; - } - if (param_offset >= buff_len) { dev_err(hba->dev, "%s: Invalid offset 0x%x in descriptor IDN 0x%x, length 0x%x\n", __func__, param_offset, desc_id, buff_len); @@ -3470,7 +3432,6 @@ int ufshcd_read_desc_param(struct ufs_hba *hba, /* Update descriptor length */ buff_len = desc_buf[QUERY_DESC_LENGTH_OFFSET]; - ufshcd_update_desc_length(hba, desc_id, desc_index, buff_len); if (is_kmalloc) { /* Make sure we don't copy more data than available */ @@ -4909,7 +4870,7 @@ static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev) */ static void ufshcd_lu_init(struct ufs_hba *hba, struct scsi_device *sdev) { - int len = hba->desc_size[QUERY_DESC_IDN_UNIT]; + int len = QUERY_DESC_MAX_SIZE; u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); u8 lun_qdepth = hba->nutrs; u8 *desc_buf; @@ -7480,25 +7441,24 @@ out: static void ufshcd_set_active_icc_lvl(struct ufs_hba *hba) { int ret; - int buff_len = hba->desc_size[QUERY_DESC_IDN_POWER]; u8 *desc_buf; u32 icc_level; - desc_buf = kmalloc(buff_len, GFP_KERNEL); + desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL); if (!desc_buf) return; ret = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_POWER, 0, 0, - desc_buf, buff_len); + desc_buf, QUERY_DESC_MAX_SIZE); if (ret) { dev_err(hba->dev, - "%s: Failed reading power descriptor.len = %d ret = %d", - __func__, buff_len, ret); + "%s: Failed reading power descriptor ret = %d", + __func__, ret); goto out; } icc_level = ufshcd_find_max_sup_active_icc_level(hba, desc_buf, - buff_len); + QUERY_DESC_MAX_SIZE); dev_dbg(hba->dev, "%s: setting icc_level 0x%x", __func__, icc_level); ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, @@ -7715,14 +7675,14 @@ static int ufs_get_device_desc(struct ufs_hba *hba) u8 *desc_buf; struct ufs_dev_info *dev_info = &hba->dev_info; - desc_buf = kmalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL); + desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL); if (!desc_buf) { err = -ENOMEM; goto out; } err = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_DEVICE, 0, 0, desc_buf, - hba->desc_size[QUERY_DESC_IDN_DEVICE]); + QUERY_DESC_MAX_SIZE); if (err) { dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n", __func__, err); @@ -7969,18 +7929,16 @@ static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) static int ufshcd_device_geo_params_init(struct ufs_hba *hba) { int err; - size_t buff_len; u8 *desc_buf; - buff_len = hba->desc_size[QUERY_DESC_IDN_GEOMETRY]; - desc_buf = kmalloc(buff_len, GFP_KERNEL); + desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL); if (!desc_buf) { err = -ENOMEM; goto out; } err = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_GEOMETRY, 0, 0, - desc_buf, buff_len); + desc_buf, QUERY_DESC_MAX_SIZE); if (err) { dev_err(hba->dev, "%s: Failed reading Geometry Desc. err = %d\n", __func__, err); @@ -7992,7 +7950,7 @@ static int ufshcd_device_geo_params_init(struct ufs_hba *hba) else if (desc_buf[GEOMETRY_DESC_PARAM_MAX_NUM_LUN] == 0) hba->dev_info.max_lu_supported = 8; - if (hba->desc_size[QUERY_DESC_IDN_GEOMETRY] >= + if (desc_buf[QUERY_DESC_LENGTH_OFFSET] >= GEOMETRY_DESC_PARAM_HPB_MAX_ACTIVE_REGS) ufshpb_get_geo_info(hba, desc_buf); @@ -8077,11 +8035,7 @@ out: static int ufshcd_device_params_init(struct ufs_hba *hba) { bool flag; - int ret, i; - - /* Init device descriptor sizes */ - for (i = 0; i < QUERY_DESC_IDN_MAX; i++) - hba->desc_size[i] = QUERY_DESC_MAX_SIZE; + int ret; /* Init UFS geometry descriptor related parameters */ ret = ufshcd_device_geo_params_init(hba); diff --git a/drivers/ufs/core/ufshpb.c b/drivers/ufs/core/ufshpb.c index be3fb24b93d8..19c9b5d1dcf8 100644 --- a/drivers/ufs/core/ufshpb.c +++ b/drivers/ufs/core/ufshpb.c @@ -2382,12 +2382,10 @@ static int ufshpb_get_lu_info(struct ufs_hba *hba, int lun, { u16 max_active_rgns; u8 lu_enable; - int size; + int size = QUERY_DESC_MAX_SIZE; int ret; char desc_buf[QUERY_DESC_MAX_SIZE]; - ufshcd_map_desc_id_to_length(hba, QUERY_DESC_IDN_UNIT, &size); - ufshcd_rpm_get_sync(hba); ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_UNIT, lun, 0, diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 1bba3fead2ce..2fc71075c5a1 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -38,7 +38,6 @@ #define UFS_UPIU_MAX_UNIT_NUM_ID 0x7F #define UFS_MAX_LUNS (SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID) #define UFS_UPIU_WLUN_ID (1 << 7) -#define UFS_RPMB_UNIT 0xC4 /* WriteBooster buffer is available only for the logical unit from 0 to 7 */ #define UFS_UPIU_MAX_WB_LUN_ID 8 diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 5cf81dff60aa..830ababe9932 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -952,7 +952,6 @@ struct ufs_hba { bool is_urgent_bkops_lvl_checked; struct rw_semaphore clk_scaling_lock; - unsigned char desc_size[QUERY_DESC_IDN_MAX]; atomic_t scsi_block_reqs_cnt; struct device bsg_dev; @@ -1186,9 +1185,6 @@ void ufshcd_release(struct ufs_hba *hba); void ufshcd_clkgate_delay_set(struct device *dev, unsigned long value); -void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, - int *desc_length); - u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg); -- cgit v1.2.3 From a6528a960b78715d4c3d2c9cda85714b15a0faa4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 14 Dec 2022 14:43:01 -0800 Subject: fsverity: optimize fsverity_file_open() on non-verity files Make fsverity_file_open() an inline function that does the IS_VERITY() check, then (if needed) calls __fsverity_file_open() to do the real work. This reduces the overhead on non-verity files. Signed-off-by: Eric Biggers Acked-by: Dave Chinner Link: https://lore.kernel.org/r/20221214224304.145712-2-ebiggers@kernel.org --- fs/verity/open.c | 20 ++------------------ include/linux/fsverity.h | 26 +++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/fs/verity/open.c b/fs/verity/open.c index 81ff94442f7b..673d6db9abdf 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -325,24 +325,8 @@ out_free_desc: return err; } -/** - * fsverity_file_open() - prepare to open a verity file - * @inode: the inode being opened - * @filp: the struct file being set up - * - * When opening a verity file, deny the open if it is for writing. Otherwise, - * set up the inode's ->i_verity_info if not already done. - * - * When combined with fscrypt, this must be called after fscrypt_file_open(). - * Otherwise, we won't have the key set up to decrypt the verity metadata. - * - * Return: 0 on success, -errno on failure - */ -int fsverity_file_open(struct inode *inode, struct file *filp) +int __fsverity_file_open(struct inode *inode, struct file *filp) { - if (!IS_VERITY(inode)) - return 0; - if (filp->f_mode & FMODE_WRITE) { pr_debug("Denying opening verity file (ino %lu) for write\n", inode->i_ino); @@ -351,7 +335,7 @@ int fsverity_file_open(struct inode *inode, struct file *filp) return ensure_verity_info(inode); } -EXPORT_SYMBOL_GPL(fsverity_file_open); +EXPORT_SYMBOL_GPL(__fsverity_file_open); /** * fsverity_prepare_setattr() - prepare to change a verity inode's attributes diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 40f14e5fed9d..326bf2e2b903 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -148,7 +148,7 @@ int fsverity_get_digest(struct inode *inode, /* open.c */ -int fsverity_file_open(struct inode *inode, struct file *filp); +int __fsverity_file_open(struct inode *inode, struct file *filp); int fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr); void fsverity_cleanup_inode(struct inode *inode); @@ -193,9 +193,9 @@ static inline int fsverity_get_digest(struct inode *inode, /* open.c */ -static inline int fsverity_file_open(struct inode *inode, struct file *filp) +static inline int __fsverity_file_open(struct inode *inode, struct file *filp) { - return IS_VERITY(inode) ? -EOPNOTSUPP : 0; + return -EOPNOTSUPP; } static inline int fsverity_prepare_setattr(struct dentry *dentry, @@ -254,4 +254,24 @@ static inline bool fsverity_active(const struct inode *inode) return fsverity_get_info(inode) != NULL; } +/** + * fsverity_file_open() - prepare to open a verity file + * @inode: the inode being opened + * @filp: the struct file being set up + * + * When opening a verity file, deny the open if it is for writing. Otherwise, + * set up the inode's ->i_verity_info if not already done. + * + * When combined with fscrypt, this must be called after fscrypt_file_open(). + * Otherwise, we won't have the key set up to decrypt the verity metadata. + * + * Return: 0 on success, -errno on failure + */ +static inline int fsverity_file_open(struct inode *inode, struct file *filp) +{ + if (IS_VERITY(inode)) + return __fsverity_file_open(inode, filp); + return 0; +} + #endif /* _LINUX_FSVERITY_H */ -- cgit v1.2.3 From 01d90c07a592b532c7a673dfd8baa6d6e496273d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 14 Dec 2022 14:43:02 -0800 Subject: fsverity: optimize fsverity_prepare_setattr() on non-verity files Make fsverity_prepare_setattr() an inline function that does the IS_VERITY() check, then (if needed) calls __fsverity_prepare_setattr() to do the real work. This reduces the overhead on non-verity files. Signed-off-by: Eric Biggers Acked-by: Dave Chinner Link: https://lore.kernel.org/r/20221214224304.145712-3-ebiggers@kernel.org --- fs/verity/open.c | 16 +++------------- include/linux/fsverity.h | 26 ++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/fs/verity/open.c b/fs/verity/open.c index 673d6db9abdf..e1e531d5e09a 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -337,26 +337,16 @@ int __fsverity_file_open(struct inode *inode, struct file *filp) } EXPORT_SYMBOL_GPL(__fsverity_file_open); -/** - * fsverity_prepare_setattr() - prepare to change a verity inode's attributes - * @dentry: dentry through which the inode is being changed - * @attr: attributes to change - * - * Verity files are immutable, so deny truncates. This isn't covered by the - * open-time check because sys_truncate() takes a path, not a file descriptor. - * - * Return: 0 on success, -errno on failure - */ -int fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr) +int __fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr) { - if (IS_VERITY(d_inode(dentry)) && (attr->ia_valid & ATTR_SIZE)) { + if (attr->ia_valid & ATTR_SIZE) { pr_debug("Denying truncate of verity file (ino %lu)\n", d_inode(dentry)->i_ino); return -EPERM; } return 0; } -EXPORT_SYMBOL_GPL(fsverity_prepare_setattr); +EXPORT_SYMBOL_GPL(__fsverity_prepare_setattr); /** * fsverity_cleanup_inode() - free the inode's verity info, if present diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 326bf2e2b903..84b498fff7ec 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -149,7 +149,7 @@ int fsverity_get_digest(struct inode *inode, /* open.c */ int __fsverity_file_open(struct inode *inode, struct file *filp); -int fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr); +int __fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr); void fsverity_cleanup_inode(struct inode *inode); /* read_metadata.c */ @@ -198,10 +198,10 @@ static inline int __fsverity_file_open(struct inode *inode, struct file *filp) return -EOPNOTSUPP; } -static inline int fsverity_prepare_setattr(struct dentry *dentry, - struct iattr *attr) +static inline int __fsverity_prepare_setattr(struct dentry *dentry, + struct iattr *attr) { - return IS_VERITY(d_inode(dentry)) ? -EOPNOTSUPP : 0; + return -EOPNOTSUPP; } static inline void fsverity_cleanup_inode(struct inode *inode) @@ -274,4 +274,22 @@ static inline int fsverity_file_open(struct inode *inode, struct file *filp) return 0; } +/** + * fsverity_prepare_setattr() - prepare to change a verity inode's attributes + * @dentry: dentry through which the inode is being changed + * @attr: attributes to change + * + * Verity files are immutable, so deny truncates. This isn't covered by the + * open-time check because sys_truncate() takes a path, not a file descriptor. + * + * Return: 0 on success, -errno on failure + */ +static inline int fsverity_prepare_setattr(struct dentry *dentry, + struct iattr *attr) +{ + if (IS_VERITY(d_inode(dentry))) + return __fsverity_prepare_setattr(dentry, attr); + return 0; +} + #endif /* _LINUX_FSVERITY_H */ -- cgit v1.2.3 From 9642946c6c851ba954689f184b3370e3594b6b1a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 14 Dec 2022 14:43:03 -0800 Subject: fsverity: optimize fsverity_cleanup_inode() on non-verity files Make fsverity_cleanup_inode() an inline function that checks for non-NULL ->i_verity_info, then (if needed) calls __fsverity_cleanup_inode() to do the real work. This reduces the overhead on non-verity files. Signed-off-by: Eric Biggers Acked-by: Dave Chinner Link: https://lore.kernel.org/r/20221214224304.145712-4-ebiggers@kernel.org --- fs/verity/open.c | 10 ++-------- include/linux/fsverity.h | 14 +++++++++++++- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/fs/verity/open.c b/fs/verity/open.c index e1e531d5e09a..c723a62841db 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -348,18 +348,12 @@ int __fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr) } EXPORT_SYMBOL_GPL(__fsverity_prepare_setattr); -/** - * fsverity_cleanup_inode() - free the inode's verity info, if present - * @inode: an inode being evicted - * - * Filesystems must call this on inode eviction to free ->i_verity_info. - */ -void fsverity_cleanup_inode(struct inode *inode) +void __fsverity_cleanup_inode(struct inode *inode) { fsverity_free_info(inode->i_verity_info); inode->i_verity_info = NULL; } -EXPORT_SYMBOL_GPL(fsverity_cleanup_inode); +EXPORT_SYMBOL_GPL(__fsverity_cleanup_inode); int __init fsverity_init_info_cache(void) { diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 84b498fff7ec..203f4962c54a 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -150,7 +150,19 @@ int fsverity_get_digest(struct inode *inode, int __fsverity_file_open(struct inode *inode, struct file *filp); int __fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr); -void fsverity_cleanup_inode(struct inode *inode); +void __fsverity_cleanup_inode(struct inode *inode); + +/** + * fsverity_cleanup_inode() - free the inode's verity info, if present + * @inode: an inode being evicted + * + * Filesystems must call this on inode eviction to free ->i_verity_info. + */ +static inline void fsverity_cleanup_inode(struct inode *inode) +{ + if (inode->i_verity_info) + __fsverity_cleanup_inode(inode); +} /* read_metadata.c */ -- cgit v1.2.3 From 72ea15f0ddd29b9facdab836a2f5d3e28df9b202 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 14 Dec 2022 14:43:04 -0800 Subject: fsverity: pass pos and size to ->write_merkle_tree_block fsverity_operations::write_merkle_tree_block is passed the index of the block to write and the log base 2 of the block size. However, all implementations of it use these parameters only to calculate the position and the size of the block, in bytes. Therefore, make ->write_merkle_tree_block take 'pos' and 'size' parameters instead of 'index' and 'log_blocksize'. Suggested-by: Dave Chinner Signed-off-by: Eric Biggers Acked-by: Dave Chinner Link: https://lore.kernel.org/r/20221214224304.145712-5-ebiggers@kernel.org --- fs/btrfs/verity.c | 19 +++++++------------ fs/ext4/verity.c | 6 +++--- fs/f2fs/verity.c | 6 +++--- fs/verity/enable.c | 4 ++-- include/linux/fsverity.h | 8 ++++---- 5 files changed, 19 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c index bf9eb693a6a7..c5ff16f9e9fa 100644 --- a/fs/btrfs/verity.c +++ b/fs/btrfs/verity.c @@ -783,30 +783,25 @@ again: /* * fsverity op that writes a Merkle tree block into the btree. * - * @inode: inode to write a Merkle tree block for - * @buf: Merkle tree data block to write - * @index: index of the block in the Merkle tree - * @log_blocksize: log base 2 of the Merkle tree block size - * - * Note that the block size could be different from the page size, so it is not - * safe to assume that index is a page index. + * @inode: inode to write a Merkle tree block for + * @buf: Merkle tree block to write + * @pos: the position of the block in the Merkle tree (in bytes) + * @size: the Merkle tree block size (in bytes) * * Returns 0 on success or negative error code on failure */ static int btrfs_write_merkle_tree_block(struct inode *inode, const void *buf, - u64 index, int log_blocksize) + u64 pos, unsigned int size) { - u64 off = index << log_blocksize; - u64 len = 1ULL << log_blocksize; loff_t merkle_pos = merkle_file_pos(inode); if (merkle_pos < 0) return merkle_pos; - if (merkle_pos > inode->i_sb->s_maxbytes - off - len) + if (merkle_pos > inode->i_sb->s_maxbytes - pos - size) return -EFBIG; return write_key_bytes(BTRFS_I(inode), BTRFS_VERITY_MERKLE_ITEM_KEY, - off, buf, len); + pos, buf, size); } const struct fsverity_operations btrfs_verityops = { diff --git a/fs/ext4/verity.c b/fs/ext4/verity.c index 30e3b65798b5..e4da1704438e 100644 --- a/fs/ext4/verity.c +++ b/fs/ext4/verity.c @@ -381,11 +381,11 @@ static struct page *ext4_read_merkle_tree_page(struct inode *inode, } static int ext4_write_merkle_tree_block(struct inode *inode, const void *buf, - u64 index, int log_blocksize) + u64 pos, unsigned int size) { - loff_t pos = ext4_verity_metadata_pos(inode) + (index << log_blocksize); + pos += ext4_verity_metadata_pos(inode); - return pagecache_write(inode, buf, 1 << log_blocksize, pos); + return pagecache_write(inode, buf, size, pos); } const struct fsverity_operations ext4_verityops = { diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index c352fff88a5e..f320ed8172ec 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -276,11 +276,11 @@ static struct page *f2fs_read_merkle_tree_page(struct inode *inode, } static int f2fs_write_merkle_tree_block(struct inode *inode, const void *buf, - u64 index, int log_blocksize) + u64 pos, unsigned int size) { - loff_t pos = f2fs_verity_metadata_pos(inode) + (index << log_blocksize); + pos += f2fs_verity_metadata_pos(inode); - return pagecache_write(inode, buf, 1 << log_blocksize, pos); + return pagecache_write(inode, buf, size, pos); } const struct fsverity_operations f2fs_verityops = { diff --git a/fs/verity/enable.c b/fs/verity/enable.c index df6b499bf6a1..a949ce817202 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -120,8 +120,8 @@ static int build_merkle_tree_level(struct file *filp, unsigned int level, params->block_size - pending_size); err = vops->write_merkle_tree_block(inode, pending_hashes, - dst_block_num, - params->log_blocksize); + dst_block_num << params->log_blocksize, + params->block_size); if (err) { fsverity_err(inode, "Error %d writing Merkle tree block %llu", diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 203f4962c54a..f5ed7ecfd9ab 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -109,9 +109,9 @@ struct fsverity_operations { * Write a Merkle tree block to the given inode. * * @inode: the inode for which the Merkle tree is being built - * @buf: block to write - * @index: 0-based index of the block within the Merkle tree - * @log_blocksize: log base 2 of the Merkle tree block size + * @buf: the Merkle tree block to write + * @pos: the position of the block in the Merkle tree (in bytes) + * @size: the Merkle tree block size (in bytes) * * This is only called between ->begin_enable_verity() and * ->end_enable_verity(). @@ -119,7 +119,7 @@ struct fsverity_operations { * Return: 0 on success, -errno on failure */ int (*write_merkle_tree_block)(struct inode *inode, const void *buf, - u64 index, int log_blocksize); + u64 pos, unsigned int size); }; #ifdef CONFIG_FS_VERITY -- cgit v1.2.3 From a439267609f9d57b15991c55550956d7cc5404d8 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Fri, 2 Dec 2022 12:52:13 +0100 Subject: dt-bindings: reset: meson-g12a: Add missing NNA reset Doesn't appear in the TRM I have, but it is used by the downstream galcore driver. Signed-off-by: Tomeu Vizoso Acked-by: Neil Armstrong Acked-by: Philipp Zabel Reviewed-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20221202115223.39051-2-tomeu.vizoso@collabora.com Signed-off-by: Neil Armstrong --- include/dt-bindings/reset/amlogic,meson-g12a-reset.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/dt-bindings/reset/amlogic,meson-g12a-reset.h b/include/dt-bindings/reset/amlogic,meson-g12a-reset.h index 6d487c5eba2c..45f6b8a951d0 100644 --- a/include/dt-bindings/reset/amlogic,meson-g12a-reset.h +++ b/include/dt-bindings/reset/amlogic,meson-g12a-reset.h @@ -69,7 +69,9 @@ #define RESET_PARSER_FETCH 72 #define RESET_CTL 73 #define RESET_PARSER_TOP 74 -/* 75-77 */ +/* 75 */ +#define RESET_NNA 76 +/* 77 */ #define RESET_DVALIN 78 #define RESET_HDMITX 79 /* 80-95 */ -- cgit v1.2.3 From 340ea839b4306335bd627fe0dd6789df803aef58 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Fri, 2 Dec 2022 12:52:14 +0100 Subject: dt-bindings: power: Add G12A NNA power domain Add define for the NNA power domain for the NPU in the G12A. Signed-off-by: Tomeu Vizoso Acked-by: Neil Armstrong Reviewed-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20221202115223.39051-3-tomeu.vizoso@collabora.com Signed-off-by: Neil Armstrong --- include/dt-bindings/power/meson-g12a-power.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/dt-bindings/power/meson-g12a-power.h b/include/dt-bindings/power/meson-g12a-power.h index bb5e67a842de..93b03bdd60b7 100644 --- a/include/dt-bindings/power/meson-g12a-power.h +++ b/include/dt-bindings/power/meson-g12a-power.h @@ -9,5 +9,6 @@ #define PWRC_G12A_VPU_ID 0 #define PWRC_G12A_ETH_ID 1 +#define PWRC_G12A_NNA_ID 2 #endif -- cgit v1.2.3 From ed3557c947e1d4164d370cc2d69dd7eb92706f0a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 3 Jan 2023 17:56:39 +0100 Subject: ieee802154: Add support for user scanning requests The ieee802154 layer should be able to scan a set of channels in order to look for beacons advertizing PANs. Supporting this involves adding two user commands: triggering scans and aborting scans. The user should also be notified when a new beacon is received and also upon scan termination. A scan request structure is created to list the requirements and to be accessed asynchronously when changing channels or receiving beacons. Mac layers may now implement the ->trigger_scan() and ->abort_scan() hooks. Co-developed-by: David Girault Signed-off-by: David Girault Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230103165644.432209-2-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- include/linux/ieee802154.h | 3 + include/net/cfg802154.h | 25 ++++++ include/net/nl802154.h | 58 ++++++++++++ net/ieee802154/nl802154.c | 220 +++++++++++++++++++++++++++++++++++++++++++++ net/ieee802154/nl802154.h | 3 + net/ieee802154/rdev-ops.h | 28 ++++++ net/ieee802154/trace.h | 40 +++++++++ 7 files changed, 377 insertions(+) (limited to 'include') diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h index 0303eb84d596..b22e4147d334 100644 --- a/include/linux/ieee802154.h +++ b/include/linux/ieee802154.h @@ -44,6 +44,9 @@ #define IEEE802154_SHORT_ADDR_LEN 2 #define IEEE802154_PAN_ID_LEN 2 +/* Duration in superframe order */ +#define IEEE802154_MAX_SCAN_DURATION 14 +#define IEEE802154_ACTIVE_SCAN_DURATION 15 #define IEEE802154_LIFS_PERIOD 40 #define IEEE802154_SIFS_PERIOD 12 #define IEEE802154_MAX_SIFS_FRAME_SIZE 18 diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index d09c393d229f..76d4f95e9974 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -18,6 +18,7 @@ struct wpan_phy; struct wpan_phy_cca; +struct cfg802154_scan_request; #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL struct ieee802154_llsec_device_key; @@ -67,6 +68,10 @@ struct cfg802154_ops { struct wpan_dev *wpan_dev, bool mode); int (*set_ackreq_default)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, bool ackreq); + int (*trigger_scan)(struct wpan_phy *wpan_phy, + struct cfg802154_scan_request *request); + int (*abort_scan)(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev); #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL void (*get_llsec_table)(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, @@ -278,6 +283,26 @@ struct ieee802154_coord_desc { bool gts_permit; }; +/** + * struct cfg802154_scan_request - Scan request + * + * @type: type of scan to be performed + * @page: page on which to perform the scan + * @channels: channels in te %page to be scanned + * @duration: time spent on each channel, calculated with: + * aBaseSuperframeDuration * (2 ^ duration + 1) + * @wpan_dev: the wpan device on which to perform the scan + * @wpan_phy: the wpan phy on which to perform the scan + */ +struct cfg802154_scan_request { + enum nl802154_scan_types type; + u8 page; + u32 channels; + u8 duration; + struct wpan_dev *wpan_dev; + struct wpan_phy *wpan_phy; +}; + struct ieee802154_llsec_key_id { u8 mode; u8 id; diff --git a/include/net/nl802154.h b/include/net/nl802154.h index b79a89d5207c..c267fa1c5aac 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -73,6 +73,9 @@ enum nl802154_commands { NL802154_CMD_DEL_SEC_LEVEL, NL802154_CMD_SCAN_EVENT, + NL802154_CMD_TRIGGER_SCAN, + NL802154_CMD_ABORT_SCAN, + NL802154_CMD_SCAN_DONE, /* add new commands above here */ @@ -134,6 +137,13 @@ enum nl802154_attrs { NL802154_ATTR_NETNS_FD, NL802154_ATTR_COORDINATOR, + NL802154_ATTR_SCAN_TYPE, + NL802154_ATTR_SCAN_FLAGS, + NL802154_ATTR_SCAN_CHANNELS, + NL802154_ATTR_SCAN_PREAMBLE_CODES, + NL802154_ATTR_SCAN_MEAN_PRF, + NL802154_ATTR_SCAN_DURATION, + NL802154_ATTR_SCAN_DONE_REASON, /* add attributes here, update the policy in nl802154.c */ @@ -259,6 +269,54 @@ enum nl802154_coord { NL802154_COORD_MAX, }; +/** + * enum nl802154_scan_types - Scan types + * + * @__NL802154_SCAN_INVALID: scan type number 0 is reserved + * @NL802154_SCAN_ED: An ED scan allows a device to obtain a measure of the peak + * energy in each requested channel + * @NL802154_SCAN_ACTIVE: Locate any coordinator transmitting Beacon frames using + * a Beacon Request command + * @NL802154_SCAN_PASSIVE: Locate any coordinator transmitting Beacon frames + * @NL802154_SCAN_ORPHAN: Relocate coordinator following a loss of synchronisation + * @NL802154_SCAN_ENHANCED_ACTIVE: Same as Active using Enhanced Beacon Request + * command instead of Beacon Request command + * @NL802154_SCAN_RIT_PASSIVE: Passive scan for RIT Data Request command frames + * instead of Beacon frames + * @NL802154_SCAN_ATTR_MAX: Maximum SCAN attribute number + */ +enum nl802154_scan_types { + __NL802154_SCAN_INVALID, + NL802154_SCAN_ED, + NL802154_SCAN_ACTIVE, + NL802154_SCAN_PASSIVE, + NL802154_SCAN_ORPHAN, + NL802154_SCAN_ENHANCED_ACTIVE, + NL802154_SCAN_RIT_PASSIVE, + + /* keep last */ + NL802154_SCAN_ATTR_MAX, +}; + +/** + * enum nl802154_scan_done_reasons - End of scan reasons + * + * @__NL802154_SCAN_DONE_REASON_INVALID: scan done reason number 0 is reserved. + * @NL802154_SCAN_DONE_REASON_FINISHED: The scan just finished naturally after + * going through all the requested and possible (complex) channels. + * @NL802154_SCAN_DONE_REASON_ABORTED: The scan was aborted upon user request. + * a Beacon Request command + * @NL802154_SCAN_DONE_REASON_MAX: Maximum scan done reason attribute number. + */ +enum nl802154_scan_done_reasons { + __NL802154_SCAN_DONE_REASON_INVALID, + NL802154_SCAN_DONE_REASON_FINISHED, + NL802154_SCAN_DONE_REASON_ABORTED, + + /* keep last */ + NL802154_SCAN_DONE_REASON_MAX, +}; + /** * enum nl802154_cca_modes - cca modes * diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 248ad5e46969..11aa693af449 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -221,6 +221,13 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { [NL802154_ATTR_COORDINATOR] = { .type = NLA_NESTED }, + [NL802154_ATTR_SCAN_TYPE] = { .type = NLA_U8 }, + [NL802154_ATTR_SCAN_CHANNELS] = { .type = NLA_U32 }, + [NL802154_ATTR_SCAN_PREAMBLE_CODES] = { .type = NLA_U64 }, + [NL802154_ATTR_SCAN_MEAN_PRF] = { .type = NLA_U8 }, + [NL802154_ATTR_SCAN_DURATION] = { .type = NLA_U8 }, + [NL802154_ATTR_SCAN_DONE_REASON] = { .type = NLA_U8 }, + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, [NL802154_ATTR_SEC_OUT_LEVEL] = { .type = NLA_U32, }, @@ -1384,6 +1391,203 @@ int nl802154_scan_event(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, } EXPORT_SYMBOL_GPL(nl802154_scan_event); +static int nl802154_trigger_scan(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + struct wpan_phy *wpan_phy = &rdev->wpan_phy; + struct cfg802154_scan_request *request; + u8 type; + int err; + + /* Monitors are not allowed to perform scans */ + if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) + return -EPERM; + + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (!request) + return -ENOMEM; + + request->wpan_dev = wpan_dev; + request->wpan_phy = wpan_phy; + + type = nla_get_u8(info->attrs[NL802154_ATTR_SCAN_TYPE]); + switch (type) { + case NL802154_SCAN_PASSIVE: + request->type = type; + break; + default: + pr_err("Unsupported scan type: %d\n", type); + err = -EINVAL; + goto free_request; + } + + if (info->attrs[NL802154_ATTR_PAGE]) { + request->page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]); + if (request->page > IEEE802154_MAX_PAGE) { + pr_err("Invalid page %d > %d\n", + request->page, IEEE802154_MAX_PAGE); + err = -EINVAL; + goto free_request; + } + } else { + /* Use current page by default */ + request->page = wpan_phy->current_page; + } + + if (info->attrs[NL802154_ATTR_SCAN_CHANNELS]) { + request->channels = nla_get_u32(info->attrs[NL802154_ATTR_SCAN_CHANNELS]); + if (request->channels >= BIT(IEEE802154_MAX_CHANNEL + 1)) { + pr_err("Invalid channels bitfield %x ≥ %lx\n", + request->channels, + BIT(IEEE802154_MAX_CHANNEL + 1)); + err = -EINVAL; + goto free_request; + } + } else { + /* Scan all supported channels by default */ + request->channels = wpan_phy->supported.channels[request->page]; + } + + if (info->attrs[NL802154_ATTR_SCAN_PREAMBLE_CODES] || + info->attrs[NL802154_ATTR_SCAN_MEAN_PRF]) { + pr_err("Preamble codes and mean PRF not supported yet\n"); + err = -EINVAL; + goto free_request; + } + + if (info->attrs[NL802154_ATTR_SCAN_DURATION]) { + request->duration = nla_get_u8(info->attrs[NL802154_ATTR_SCAN_DURATION]); + if (request->duration > IEEE802154_MAX_SCAN_DURATION) { + pr_err("Duration is out of range\n"); + err = -EINVAL; + goto free_request; + } + } else { + /* Use maximum duration order by default */ + request->duration = IEEE802154_MAX_SCAN_DURATION; + } + + if (wpan_dev->netdev) + dev_hold(wpan_dev->netdev); + + err = rdev_trigger_scan(rdev, request); + if (err) { + pr_err("Failure starting scanning (%d)\n", err); + goto free_device; + } + + return 0; + +free_device: + if (wpan_dev->netdev) + dev_put(wpan_dev->netdev); +free_request: + kfree(request); + + return err; +} + +static int nl802154_prep_scan_msg(struct sk_buff *msg, + struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, u32 portid, + u32 seq, int flags, u8 cmd, u8 arg) +{ + void *hdr; + + hdr = nl802154hdr_put(msg, portid, seq, flags, cmd); + if (!hdr) + return -ENOBUFS; + + if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx)) + goto nla_put_failure; + + if (wpan_dev->netdev && + nla_put_u32(msg, NL802154_ATTR_IFINDEX, wpan_dev->netdev->ifindex)) + goto nla_put_failure; + + if (nla_put_u64_64bit(msg, NL802154_ATTR_WPAN_DEV, + wpan_dev_id(wpan_dev), NL802154_ATTR_PAD)) + goto nla_put_failure; + + if (cmd == NL802154_CMD_SCAN_DONE && + nla_put_u8(msg, NL802154_ATTR_SCAN_DONE_REASON, arg)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + + return 0; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + + return -EMSGSIZE; +} + +static int nl802154_send_scan_msg(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, u8 cmd, u8 arg) +{ + struct sk_buff *msg; + int ret; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + ret = nl802154_prep_scan_msg(msg, rdev, wpan_dev, 0, 0, 0, cmd, arg); + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + + return genlmsg_multicast_netns(&nl802154_fam, + wpan_phy_net(&rdev->wpan_phy), msg, 0, + NL802154_MCGRP_SCAN, GFP_KERNEL); +} + +int nl802154_scan_started(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev) +{ + struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(wpan_phy); + int err; + + /* Ignore errors when there are no listeners */ + err = nl802154_send_scan_msg(rdev, wpan_dev, NL802154_CMD_TRIGGER_SCAN, 0); + if (err == -ESRCH) + err = 0; + + return err; +} +EXPORT_SYMBOL_GPL(nl802154_scan_started); + +int nl802154_scan_done(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + enum nl802154_scan_done_reasons reason) +{ + struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(wpan_phy); + int err; + + /* Ignore errors when there are no listeners */ + err = nl802154_send_scan_msg(rdev, wpan_dev, NL802154_CMD_SCAN_DONE, reason); + if (err == -ESRCH) + err = 0; + + if (wpan_dev->netdev) + dev_put(wpan_dev->netdev); + + return err; +} +EXPORT_SYMBOL_GPL(nl802154_scan_done); + +static int nl802154_abort_scan(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + + /* Resources are released in the notification helper above */ + return rdev_abort_scan(rdev, wpan_dev); +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, @@ -2474,6 +2678,22 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_NETDEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_TRIGGER_SCAN, + .doit = nl802154_trigger_scan, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_CHECK_NETDEV_UP | + NL802154_FLAG_NEED_RTNL, + }, + { + .cmd = NL802154_CMD_ABORT_SCAN, + .doit = nl802154_abort_scan, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_CHECK_NETDEV_UP | + NL802154_FLAG_NEED_RTNL, + }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL { .cmd = NL802154_CMD_SET_SEC_PARAMS, diff --git a/net/ieee802154/nl802154.h b/net/ieee802154/nl802154.h index 89b805500032..cfa7134be747 100644 --- a/net/ieee802154/nl802154.h +++ b/net/ieee802154/nl802154.h @@ -6,5 +6,8 @@ int nl802154_init(void); void nl802154_exit(void); int nl802154_scan_event(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, struct ieee802154_coord_desc *desc); +int nl802154_scan_started(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev); +int nl802154_scan_done(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + enum nl802154_scan_done_reasons reason); #endif /* __IEEE802154_NL802154_H */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 598f5af49775..e171d74c3251 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -209,6 +209,34 @@ rdev_set_ackreq_default(struct cfg802154_registered_device *rdev, return ret; } +static inline int rdev_trigger_scan(struct cfg802154_registered_device *rdev, + struct cfg802154_scan_request *request) +{ + int ret; + + if (!rdev->ops->trigger_scan) + return -EOPNOTSUPP; + + trace_802154_rdev_trigger_scan(&rdev->wpan_phy, request); + ret = rdev->ops->trigger_scan(&rdev->wpan_phy, request); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + +static inline int rdev_abort_scan(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev) +{ + int ret; + + if (!rdev->ops->abort_scan) + return -EOPNOTSUPP; + + trace_802154_rdev_abort_scan(&rdev->wpan_phy, wpan_dev); + ret = rdev->ops->abort_scan(&rdev->wpan_phy, wpan_dev); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL /* TODO this is already a nl802154, so move into ieee802154 */ static inline void diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h index 19c2e5d60e76..e5405f737ded 100644 --- a/net/ieee802154/trace.h +++ b/net/ieee802154/trace.h @@ -295,6 +295,46 @@ TRACE_EVENT(802154_rdev_set_ackreq_default, WPAN_DEV_PR_ARG, BOOL_TO_STR(__entry->ackreq)) ); +TRACE_EVENT(802154_rdev_trigger_scan, + TP_PROTO(struct wpan_phy *wpan_phy, + struct cfg802154_scan_request *request), + TP_ARGS(wpan_phy, request), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __field(u8, page) + __field(u32, channels) + __field(u8, duration) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __entry->page = request->page; + __entry->channels = request->channels; + __entry->duration = request->duration; + ), + TP_printk(WPAN_PHY_PR_FMT ", scan, page: %d, channels: %x, duration %d", + WPAN_PHY_PR_ARG, __entry->page, __entry->channels, __entry->duration) +); + +DECLARE_EVENT_CLASS(802154_wdev_template, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev), + TP_ARGS(wpan_phy, wpan_dev), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT, + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG) +); + +DEFINE_EVENT(802154_wdev_template, 802154_rdev_abort_scan, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev), + TP_ARGS(wpan_phy, wpan_dev) +); + TRACE_EVENT(802154_rdev_return_int, TP_PROTO(struct wpan_phy *wpan_phy, int ret), TP_ARGS(wpan_phy, ret), -- cgit v1.2.3 From 44def58f5835bbfaf81902c88460fd86a551f4b7 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 3 Jan 2023 17:56:40 +0100 Subject: ieee802154: Define a beacon frame header This definition will be used when adding support for scanning and defines the content of a beacon frame header as in the 802.15.4 specification. Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230103165644.432209-3-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- include/net/ieee802154_netdev.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'include') diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 4c33a20ea57f..2f2196049a86 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -38,6 +38,42 @@ #include +struct ieee802154_beacon_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u16 beacon_order:4, + superframe_order:4, + final_cap_slot:4, + battery_life_ext:1, + reserved0:1, + pan_coordinator:1, + assoc_permit:1; + u8 gts_count:3, + gts_reserved:4, + gts_permit:1; + u8 pend_short_addr_count:3, + reserved1:1, + pend_ext_addr_count:3, + reserved2:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + u16 assoc_permit:1, + pan_coordinator:1, + reserved0:1, + battery_life_ext:1, + final_cap_slot:4, + superframe_order:4, + beacon_order:4; + u8 gts_permit:1, + gts_reserved:4, + gts_count:3; + u8 reserved2:1, + pend_ext_addr_count:3, + reserved1:1, + pend_short_addr_count:3; +#else +#error "Please fix " +#endif +} __packed; + struct ieee802154_sechdr { #if defined(__LITTLE_ENDIAN_BITFIELD) u8 level:3, -- cgit v1.2.3 From d2aaf2a01792ccf214f933d0b1ca2d41788c7b16 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 3 Jan 2023 17:56:41 +0100 Subject: ieee802154: Introduce a helper to validate a channel This helper for now only checks if the page member and channel member are valid (in the specification range) and supported (by checking the device capabilities). Soon two new parameters will be introduced and having this helper will let us only modify its content rather than modifying the logic everywhere else in the subsystem. There is not functional change. Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230103165644.432209-4-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- include/net/cfg802154.h | 11 +++++++++++ net/ieee802154/nl802154.c | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 76d4f95e9974..1184b543fba7 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -246,6 +246,17 @@ static inline void wpan_phy_net_set(struct wpan_phy *wpan_phy, struct net *net) write_pnet(&wpan_phy->_net, net); } +static inline bool ieee802154_chan_is_valid(struct wpan_phy *phy, + u8 page, u8 channel) +{ + if (page > IEEE802154_MAX_PAGE || + channel > IEEE802154_MAX_CHANNEL || + !(phy->supported.channels[page] & BIT(channel))) + return false; + + return true; +} + /** * struct ieee802154_addr - IEEE802.15.4 device address * @mode: Address mode from frame header. Can be one of: diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 11aa693af449..0b7a9f16b3b6 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -976,8 +976,7 @@ static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]); /* check 802.15.4 constraints */ - if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL || - !(rdev->wpan_phy.supported.channels[page] & BIT(channel))) + if (!ieee802154_chan_is_valid(&rdev->wpan_phy, page, channel)) return -EINVAL; return rdev_set_channel(rdev, page, channel); -- cgit v1.2.3 From 5755cd4d9432779027771e43e51d81a2994ed795 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 3 Jan 2023 17:56:42 +0100 Subject: mac802154: Prepare forcing specific symbol duration The scan logic will bypass the whole ->set_channel() logic from the top by calling the driver hook to just switch between channels when required. We can no longer rely on the "current" page/channel settings to set the right symbol duration. Let's add these as new parameters to allow providing the page/channel couple that we want. There is no functional change. Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230103165644.432209-5-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- include/net/cfg802154.h | 3 ++- net/mac802154/cfg.c | 2 +- net/mac802154/main.c | 20 +++++++++++--------- 3 files changed, 14 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 1184b543fba7..c16ae5d2dc86 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -483,6 +483,7 @@ static inline const char *wpan_phy_name(struct wpan_phy *phy) return dev_name(&phy->dev); } -void ieee802154_configure_durations(struct wpan_phy *phy); +void ieee802154_configure_durations(struct wpan_phy *phy, + unsigned int page, unsigned int channel); #endif /* __NET_CFG802154_H */ diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index dc2d918fac68..469d6e8dd2dd 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -118,7 +118,7 @@ ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel) if (!ret) { wpan_phy->current_page = page; wpan_phy->current_channel = channel; - ieee802154_configure_durations(wpan_phy); + ieee802154_configure_durations(wpan_phy, page, channel); } return ret; diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 3ed31daf7b9c..12a13a850fdf 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -113,32 +113,33 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) } EXPORT_SYMBOL(ieee802154_alloc_hw); -void ieee802154_configure_durations(struct wpan_phy *phy) +void ieee802154_configure_durations(struct wpan_phy *phy, + unsigned int page, unsigned int channel) { u32 duration = 0; - switch (phy->current_page) { + switch (page) { case 0: - if (BIT(phy->current_channel) & 0x1) + if (BIT(channel) & 0x1) /* 868 MHz BPSK 802.15.4-2003: 20 ksym/s */ duration = 50 * NSEC_PER_USEC; - else if (BIT(phy->current_channel) & 0x7FE) + else if (BIT(channel) & 0x7FE) /* 915 MHz BPSK 802.15.4-2003: 40 ksym/s */ duration = 25 * NSEC_PER_USEC; - else if (BIT(phy->current_channel) & 0x7FFF800) + else if (BIT(channel) & 0x7FFF800) /* 2400 MHz O-QPSK 802.15.4-2006: 62.5 ksym/s */ duration = 16 * NSEC_PER_USEC; break; case 2: - if (BIT(phy->current_channel) & 0x1) + if (BIT(channel) & 0x1) /* 868 MHz O-QPSK 802.15.4-2006: 25 ksym/s */ duration = 40 * NSEC_PER_USEC; - else if (BIT(phy->current_channel) & 0x7FE) + else if (BIT(channel) & 0x7FE) /* 915 MHz O-QPSK 802.15.4-2006: 62.5 ksym/s */ duration = 16 * NSEC_PER_USEC; break; case 3: - if (BIT(phy->current_channel) & 0x3FFF) + if (BIT(channel) & 0x3FFF) /* 2.4 GHz CSS 802.15.4a-2007: 1/6 Msym/s */ duration = 6 * NSEC_PER_USEC; break; @@ -201,7 +202,8 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) ieee802154_setup_wpan_phy_pib(local->phy); - ieee802154_configure_durations(local->phy); + ieee802154_configure_durations(local->phy, local->phy->current_page, + local->phy->current_channel); if (!(hw->flags & IEEE802154_HW_CSMA_PARAMS)) { local->phy->supported.min_csma_backoffs = 4; -- cgit v1.2.3 From 57588c71177f0bfc08509c2c3a9bfe32850c0786 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 3 Jan 2023 17:56:44 +0100 Subject: mac802154: Handle passive scanning Implement the core hooks in order to provide the softMAC layer support for passive scans. Scans are requested by the user and can be aborted. Changing channels manually is prohibited during scans. The implementation uses a workqueue triggered at a certain interval depending on the symbol duration for the current channel and the duration order provided. More advanced drivers with internal scheduling capabilities might require additional care but there is none mainline yet. Received beacons during a passive scan are processed in a work queue and their result forwarded to the upper layer. Active scanning is not supported yet. Co-developed-by: David Girault Signed-off-by: David Girault Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230103165644.432209-7-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- include/linux/ieee802154.h | 4 + include/net/cfg802154.h | 16 +++ net/mac802154/Makefile | 2 +- net/mac802154/cfg.c | 31 +++++ net/mac802154/ieee802154_i.h | 37 +++++- net/mac802154/iface.c | 3 + net/mac802154/main.c | 16 ++- net/mac802154/rx.c | 36 +++++- net/mac802154/scan.c | 288 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 427 insertions(+), 6 deletions(-) create mode 100644 net/mac802154/scan.c (limited to 'include') diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h index b22e4147d334..140f61ec0f5f 100644 --- a/include/linux/ieee802154.h +++ b/include/linux/ieee802154.h @@ -47,6 +47,10 @@ /* Duration in superframe order */ #define IEEE802154_MAX_SCAN_DURATION 14 #define IEEE802154_ACTIVE_SCAN_DURATION 15 +/* Superframe duration in slots */ +#define IEEE802154_SUPERFRAME_PERIOD 16 +/* Various periods expressed in symbols */ +#define IEEE802154_SLOT_PERIOD 60 #define IEEE802154_LIFS_PERIOD 40 #define IEEE802154_SIFS_PERIOD 12 #define IEEE802154_MAX_SIFS_FRAME_SIZE 18 diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index c16ae5d2dc86..0b0f81a945b6 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -314,6 +314,22 @@ struct cfg802154_scan_request { struct wpan_phy *wpan_phy; }; +/** + * struct cfg802154_mac_pkt - MAC packet descriptor (beacon/command) + * @node: MAC packets to process list member + * @skb: the received sk_buff + * @sdata: the interface on which @skb was received + * @page: page configuration when @skb was received + * @channel: channel configuration when @skb was received + */ +struct cfg802154_mac_pkt { + struct list_head node; + struct sk_buff *skb; + struct ieee802154_sub_if_data *sdata; + u8 page; + u8 channel; +}; + struct ieee802154_llsec_key_id { u8 mode; u8 id; diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile index 4059295fdbf8..43d1347b37ee 100644 --- a/net/mac802154/Makefile +++ b/net/mac802154/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_MAC802154) += mac802154.o mac802154-objs := main.o rx.o tx.o mac_cmd.o mib.o \ - iface.o llsec.o util.o cfg.o trace.o + iface.o llsec.o util.o cfg.o scan.o trace.o CFLAGS_trace.o := -I$(src) diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 469d6e8dd2dd..187cebcaf233 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -114,6 +114,10 @@ ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel) wpan_phy->current_channel == channel) return 0; + /* Refuse to change channels during a scanning operation */ + if (mac802154_is_scanning(local)) + return -EBUSY; + ret = drv_set_channel(local, page, channel); if (!ret) { wpan_phy->current_page = page; @@ -261,6 +265,31 @@ ieee802154_set_ackreq_default(struct wpan_phy *wpan_phy, return 0; } +static int mac802154_trigger_scan(struct wpan_phy *wpan_phy, + struct cfg802154_scan_request *request) +{ + struct ieee802154_sub_if_data *sdata; + + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(request->wpan_dev); + + ASSERT_RTNL(); + + return mac802154_trigger_scan_locked(sdata, request); +} + +static int mac802154_abort_scan(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + struct ieee802154_sub_if_data *sdata; + + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev); + + ASSERT_RTNL(); + + return mac802154_abort_scan_locked(local, sdata); +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static void ieee802154_get_llsec_table(struct wpan_phy *wpan_phy, @@ -468,6 +497,8 @@ const struct cfg802154_ops mac802154_config_ops = { .set_max_frame_retries = ieee802154_set_max_frame_retries, .set_lbt_mode = ieee802154_set_lbt_mode, .set_ackreq_default = ieee802154_set_ackreq_default, + .trigger_scan = mac802154_trigger_scan, + .abort_scan = mac802154_abort_scan, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL .get_llsec_table = ieee802154_get_llsec_table, .lock_llsec_table = ieee802154_lock_llsec_table, diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index aeadee543a9c..0e4db967bd1d 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -21,6 +21,10 @@ #include "llsec.h" +enum ieee802154_ongoing { + IEEE802154_IS_SCANNING = BIT(0), +}; + /* mac802154 device private data */ struct ieee802154_local { struct ieee802154_hw hw; @@ -43,15 +47,26 @@ struct ieee802154_local { struct list_head interfaces; struct mutex iflist_mtx; - /* This one is used for scanning and other jobs not to be interfered - * with serial driver. - */ + /* Data related workqueue */ struct workqueue_struct *workqueue; + /* MAC commands related workqueue */ + struct workqueue_struct *mac_wq; struct hrtimer ifs_timer; + /* Scanning */ + u8 scan_page; + u8 scan_channel; + struct cfg802154_scan_request __rcu *scan_req; + struct delayed_work scan_work; + + /* Asynchronous tasks */ + struct list_head rx_beacon_list; + struct work_struct rx_beacon_work; + bool started; bool suspended; + unsigned long ongoing; struct tasklet_struct tasklet; struct sk_buff_head skb_queue; @@ -226,6 +241,22 @@ void mac802154_unlock_table(struct net_device *dev); int mac802154_wpan_update_llsec(struct net_device *dev); +/* PAN management handling */ +void mac802154_scan_worker(struct work_struct *work); +int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata, + struct cfg802154_scan_request *request); +int mac802154_abort_scan_locked(struct ieee802154_local *local, + struct ieee802154_sub_if_data *sdata); +int mac802154_process_beacon(struct ieee802154_local *local, + struct sk_buff *skb, + u8 page, u8 channel); +void mac802154_rx_beacon_worker(struct work_struct *work); + +static inline bool mac802154_is_scanning(struct ieee802154_local *local) +{ + return test_bit(IEEE802154_IS_SCANNING, &local->ongoing); +} + /* interface handling */ int ieee802154_iface_init(void); void ieee802154_iface_exit(void); diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 7de2f843379c..a5958d323ea3 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -302,6 +302,9 @@ static int mac802154_slave_close(struct net_device *dev) ASSERT_RTNL(); + if (mac802154_is_scanning(local)) + mac802154_abort_scan_locked(local, sdata); + netif_stop_queue(dev); local->open_count--; diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 12a13a850fdf..b1111279e06d 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -89,6 +89,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) local->ops = ops; INIT_LIST_HEAD(&local->interfaces); + INIT_LIST_HEAD(&local->rx_beacon_list); mutex_init(&local->iflist_mtx); tasklet_setup(&local->tasklet, ieee802154_tasklet_handler); @@ -96,6 +97,8 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) skb_queue_head_init(&local->skb_queue); INIT_WORK(&local->sync_tx_work, ieee802154_xmit_sync_worker); + INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_worker); + INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker); /* init supported flags with 802.15.4 default ranges */ phy->supported.max_minbe = 8; @@ -185,6 +188,7 @@ static void ieee802154_setup_wpan_phy_pib(struct wpan_phy *wpan_phy) int ieee802154_register_hw(struct ieee802154_hw *hw) { struct ieee802154_local *local = hw_to_local(hw); + char mac_wq_name[IFNAMSIZ + 10] = {}; struct net_device *dev; int rc = -ENOSYS; @@ -195,6 +199,13 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) goto out; } + snprintf(mac_wq_name, IFNAMSIZ + 10, "%s-mac-cmds", wpan_phy_name(local->phy)); + local->mac_wq = create_singlethread_workqueue(mac_wq_name); + if (!local->mac_wq) { + rc = -ENOMEM; + goto out_wq; + } + hrtimer_init(&local->ifs_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); local->ifs_timer.function = ieee802154_xmit_ifs_timer; @@ -224,7 +235,7 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) rc = wpan_phy_register(local->phy); if (rc < 0) - goto out_wq; + goto out_mac_wq; rtnl_lock(); @@ -243,6 +254,8 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) out_phy: wpan_phy_unregister(local->phy); +out_mac_wq: + destroy_workqueue(local->mac_wq); out_wq: destroy_workqueue(local->workqueue); out: @@ -263,6 +276,7 @@ void ieee802154_unregister_hw(struct ieee802154_hw *hw) rtnl_unlock(); + destroy_workqueue(local->mac_wq); destroy_workqueue(local->workqueue); wpan_phy_unregister(local->phy); } diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index c2aae2a6d6a6..2b0a80571097 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -29,12 +29,31 @@ static int ieee802154_deliver_skb(struct sk_buff *skb) return netif_receive_skb(skb); } +void mac802154_rx_beacon_worker(struct work_struct *work) +{ + struct ieee802154_local *local = + container_of(work, struct ieee802154_local, rx_beacon_work); + struct cfg802154_mac_pkt *mac_pkt; + + mac_pkt = list_first_entry_or_null(&local->rx_beacon_list, + struct cfg802154_mac_pkt, node); + if (!mac_pkt) + return; + + mac802154_process_beacon(local, mac_pkt->skb, mac_pkt->page, mac_pkt->channel); + + list_del(&mac_pkt->node); + kfree_skb(mac_pkt->skb); + kfree(mac_pkt); +} + static int ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, struct sk_buff *skb, const struct ieee802154_hdr *hdr) { - struct wpan_dev *wpan_dev = &sdata->wpan_dev; struct wpan_phy *wpan_phy = sdata->local->hw.phy; + struct wpan_dev *wpan_dev = &sdata->wpan_dev; + struct cfg802154_mac_pkt *mac_pkt; __le16 span, sshort; int rc; @@ -106,6 +125,21 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, switch (mac_cb(skb)->type) { case IEEE802154_FC_TYPE_BEACON: + dev_dbg(&sdata->dev->dev, "BEACON received\n"); + if (!mac802154_is_scanning(sdata->local)) + goto fail; + + mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC); + if (!mac_pkt) + goto fail; + + mac_pkt->skb = skb_get(skb); + mac_pkt->sdata = sdata; + mac_pkt->page = sdata->local->scan_page; + mac_pkt->channel = sdata->local->scan_channel; + list_add_tail(&mac_pkt->node, &sdata->local->rx_beacon_list); + queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work); + return NET_RX_SUCCESS; case IEEE802154_FC_TYPE_ACK: case IEEE802154_FC_TYPE_MAC_CMD: goto fail; diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c new file mode 100644 index 000000000000..56056b9c93c1 --- /dev/null +++ b/net/mac802154/scan.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * IEEE 802.15.4 scanning management + * + * Copyright (C) 2021 Qorvo US, Inc + * Authors: + * - David Girault + * - Miquel Raynal + */ + +#include +#include +#include + +#include "ieee802154_i.h" +#include "driver-ops.h" +#include "../ieee802154/nl802154.h" + +/* mac802154_scan_cleanup_locked() must be called upon scan completion or abort. + * - Completions are asynchronous, not locked by the rtnl and decided by the + * scan worker. + * - Aborts are decided by userspace, and locked by the rtnl. + * + * Concurrent modifications to the PHY, the interfaces or the hardware is in + * general prevented by the rtnl. So in most cases we don't need additional + * protection. + * + * However, the scan worker get's triggered without anybody noticing and thus we + * must ensure the presence of the devices as well as data consistency: + * - The sub-interface and device driver module get both their reference + * counters incremented whenever we start a scan, so they cannot disappear + * during operation. + * - Data consistency is achieved by the use of rcu protected pointers. + */ +static int mac802154_scan_cleanup_locked(struct ieee802154_local *local, + struct ieee802154_sub_if_data *sdata, + bool aborted) +{ + struct wpan_dev *wpan_dev = &sdata->wpan_dev; + struct wpan_phy *wpan_phy = local->phy; + struct cfg802154_scan_request *request; + u8 arg; + + /* Prevent any further use of the scan request */ + clear_bit(IEEE802154_IS_SCANNING, &local->ongoing); + cancel_delayed_work(&local->scan_work); + request = rcu_replace_pointer(local->scan_req, NULL, 1); + if (!request) + return 0; + kfree_rcu(request); + + /* Advertize first, while we know the devices cannot be removed */ + if (aborted) + arg = NL802154_SCAN_DONE_REASON_ABORTED; + else + arg = NL802154_SCAN_DONE_REASON_FINISHED; + nl802154_scan_done(wpan_phy, wpan_dev, arg); + + /* Cleanup software stack */ + ieee802154_mlme_op_post(local); + + /* Set the hardware back in its original state */ + drv_set_channel(local, wpan_phy->current_page, + wpan_phy->current_channel); + ieee802154_configure_durations(wpan_phy, wpan_phy->current_page, + wpan_phy->current_channel); + drv_stop(local); + synchronize_net(); + sdata->required_filtering = sdata->iface_default_filtering; + drv_start(local, sdata->required_filtering, &local->addr_filt); + + return 0; +} + +int mac802154_abort_scan_locked(struct ieee802154_local *local, + struct ieee802154_sub_if_data *sdata) +{ + ASSERT_RTNL(); + + if (!mac802154_is_scanning(local)) + return -ESRCH; + + return mac802154_scan_cleanup_locked(local, sdata, true); +} + +static unsigned int mac802154_scan_get_channel_time(u8 duration_order, + u8 symbol_duration) +{ + u64 base_super_frame_duration = (u64)symbol_duration * + IEEE802154_SUPERFRAME_PERIOD * IEEE802154_SLOT_PERIOD; + + return usecs_to_jiffies(base_super_frame_duration * + (BIT(duration_order) + 1)); +} + +static void mac802154_flush_queued_beacons(struct ieee802154_local *local) +{ + struct cfg802154_mac_pkt *mac_pkt, *tmp; + + list_for_each_entry_safe(mac_pkt, tmp, &local->rx_beacon_list, node) { + list_del(&mac_pkt->node); + kfree_skb(mac_pkt->skb); + kfree(mac_pkt); + } +} + +static void +mac802154_scan_get_next_channel(struct ieee802154_local *local, + struct cfg802154_scan_request *scan_req, + u8 *channel) +{ + (*channel)++; + *channel = find_next_bit((const unsigned long *)&scan_req->channels, + IEEE802154_MAX_CHANNEL + 1, + *channel); +} + +static int mac802154_scan_find_next_chan(struct ieee802154_local *local, + struct cfg802154_scan_request *scan_req, + u8 page, u8 *channel) +{ + mac802154_scan_get_next_channel(local, scan_req, channel); + if (*channel > IEEE802154_MAX_CHANNEL) + return -EINVAL; + + return 0; +} + +void mac802154_scan_worker(struct work_struct *work) +{ + struct ieee802154_local *local = + container_of(work, struct ieee802154_local, scan_work.work); + struct cfg802154_scan_request *scan_req; + struct ieee802154_sub_if_data *sdata; + unsigned int scan_duration = 0; + struct wpan_phy *wpan_phy; + u8 scan_req_duration; + u8 page, channel; + int ret; + + /* Ensure the device receiver is turned off when changing channels + * because there is no atomic way to change the channel and know on + * which one a beacon might have been received. + */ + drv_stop(local); + synchronize_net(); + mac802154_flush_queued_beacons(local); + + rcu_read_lock(); + scan_req = rcu_dereference(local->scan_req); + if (unlikely(!scan_req)) { + rcu_read_unlock(); + return; + } + + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(scan_req->wpan_dev); + + /* Wait an arbitrary amount of time in case we cannot use the device */ + if (local->suspended || !ieee802154_sdata_running(sdata)) { + rcu_read_unlock(); + queue_delayed_work(local->mac_wq, &local->scan_work, + msecs_to_jiffies(1000)); + return; + } + + wpan_phy = scan_req->wpan_phy; + scan_req_duration = scan_req->duration; + + /* Look for the next valid chan */ + page = local->scan_page; + channel = local->scan_channel; + do { + ret = mac802154_scan_find_next_chan(local, scan_req, page, &channel); + if (ret) { + rcu_read_unlock(); + goto end_scan; + } + } while (!ieee802154_chan_is_valid(scan_req->wpan_phy, page, channel)); + + rcu_read_unlock(); + + /* Bypass the stack on purpose when changing the channel */ + rtnl_lock(); + ret = drv_set_channel(local, page, channel); + rtnl_unlock(); + if (ret) { + dev_err(&sdata->dev->dev, + "Channel change failure during scan, aborting (%d)\n", ret); + goto end_scan; + } + + local->scan_page = page; + local->scan_channel = channel; + + rtnl_lock(); + ret = drv_start(local, IEEE802154_FILTERING_3_SCAN, &local->addr_filt); + rtnl_unlock(); + if (ret) { + dev_err(&sdata->dev->dev, + "Restarting failure after channel change, aborting (%d)\n", ret); + goto end_scan; + } + + ieee802154_configure_durations(wpan_phy, page, channel); + scan_duration = mac802154_scan_get_channel_time(scan_req_duration, + wpan_phy->symbol_duration); + dev_dbg(&sdata->dev->dev, + "Scan page %u channel %u for %ums\n", + page, channel, jiffies_to_msecs(scan_duration)); + queue_delayed_work(local->mac_wq, &local->scan_work, scan_duration); + return; + +end_scan: + rtnl_lock(); + mac802154_scan_cleanup_locked(local, sdata, false); + rtnl_unlock(); +} + +int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata, + struct cfg802154_scan_request *request) +{ + struct ieee802154_local *local = sdata->local; + + ASSERT_RTNL(); + + if (mac802154_is_scanning(local)) + return -EBUSY; + + /* TODO: support other scanning type */ + if (request->type != NL802154_SCAN_PASSIVE) + return -EOPNOTSUPP; + + /* Store scanning parameters */ + rcu_assign_pointer(local->scan_req, request); + + /* Software scanning requires to set promiscuous mode, so we need to + * pause the Tx queue during the entire operation. + */ + ieee802154_mlme_op_pre(local); + + sdata->required_filtering = IEEE802154_FILTERING_3_SCAN; + local->scan_page = request->page; + local->scan_channel = -1; + set_bit(IEEE802154_IS_SCANNING, &local->ongoing); + + nl802154_scan_started(request->wpan_phy, request->wpan_dev); + + queue_delayed_work(local->mac_wq, &local->scan_work, 0); + + return 0; +} + +int mac802154_process_beacon(struct ieee802154_local *local, + struct sk_buff *skb, + u8 page, u8 channel) +{ + struct ieee802154_beacon_hdr *bh = (void *)skb->data; + struct ieee802154_addr *src = &mac_cb(skb)->source; + struct cfg802154_scan_request *scan_req; + struct ieee802154_coord_desc desc; + + if (skb->len != sizeof(*bh)) + return -EINVAL; + + if (unlikely(src->mode == IEEE802154_ADDR_NONE)) + return -EINVAL; + + dev_dbg(&skb->dev->dev, + "BEACON received on page %u channel %u\n", + page, channel); + + memcpy(&desc.addr, src, sizeof(desc.addr)); + desc.page = page; + desc.channel = channel; + desc.link_quality = mac_cb(skb)->lqi; + desc.superframe_spec = get_unaligned_le16(skb->data); + desc.gts_permit = bh->gts_permit; + + trace_802154_scan_event(&desc); + + rcu_read_lock(); + scan_req = rcu_dereference(local->scan_req); + if (likely(scan_req)) + nl802154_scan_event(scan_req->wpan_phy, scan_req->wpan_dev, &desc); + rcu_read_unlock(); + + return 0; +} -- cgit v1.2.3 From c004d231cac709f09987f2a6dd733013039d27c3 Mon Sep 17 00:00:00 2001 From: Zhao Mengmeng Date: Wed, 19 Oct 2022 08:36:50 -0400 Subject: rcu: Use hlist_nulls_next_rcu() in hlist_nulls_add_tail_rcu() In commit 8dbd76e79a16 ("tcp/dccp: fix possible race __inet_lookup_established()"), function hlist_nulls_add_tail_rcu() was added back, but the local variable *last* is of type hlist_nulls_node, so use hlist_nulls_next_rcu() instead of hlist_next_rcu(). Signed-off-by: Zhao Mengmeng Signed-off-by: Paul E. McKenney --- include/linux/rculist_nulls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/rculist_nulls.h b/include/linux/rculist_nulls.h index d8afdb8784c1..ba4c00dd8005 100644 --- a/include/linux/rculist_nulls.h +++ b/include/linux/rculist_nulls.h @@ -139,7 +139,7 @@ static inline void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n, if (last) { n->next = last->next; n->pprev = &last->next; - rcu_assign_pointer(hlist_next_rcu(last), n); + rcu_assign_pointer(hlist_nulls_next_rcu(last), n); } else { hlist_nulls_add_head_rcu(n, h); } -- cgit v1.2.3 From 0cae5ded535c3a80aed94f119bbd4ee3ae284a65 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 14 Dec 2022 11:41:44 -0800 Subject: rcu: Make RCU_LOCKDEP_WARN() avoid early lockdep checks Currently, RCU_LOCKDEP_WARN() checks the condition before checking to see if lockdep is still enabled. This is necessary to avoid the false-positive splats fixed by commit 3066820034b5dd ("rcu: Reject RCU_LOCKDEP_WARN() false positives"). However, the current state can result in false-positive splats during early boot before lockdep is fully initialized. This commit therefore checks debug_lockdep_rcu_enabled() both before and after checking the condition, thus avoiding both sets of false-positive error reports. Reported-by: Steven Rostedt Reported-by: Masami Hiramatsu (Google) Reported-by: Mathieu Desnoyers Signed-off-by: Paul E. McKenney Reviewed-by: Mathieu Desnoyers Cc: Boqun Feng Cc: Matthew Wilcox Cc: Thomas Gleixner --- include/linux/rcupdate.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 03abf883a281..aa86de01aab6 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -374,11 +374,18 @@ static inline int debug_lockdep_rcu_enabled(void) * RCU_LOCKDEP_WARN - emit lockdep splat if specified condition is met * @c: condition to check * @s: informative message + * + * This checks debug_lockdep_rcu_enabled() before checking (c) to + * prevent early boot splats due to lockdep not yet being initialized, + * and rechecks it after checking (c) to prevent false-positive splats + * due to races with lockdep being disabled. See commit 3066820034b5dd + * ("rcu: Reject RCU_LOCKDEP_WARN() false positives") for more detail. */ #define RCU_LOCKDEP_WARN(c, s) \ do { \ static bool __section(".data.unlikely") __warned; \ - if ((c) && debug_lockdep_rcu_enabled() && !__warned) { \ + if (debug_lockdep_rcu_enabled() && (c) && \ + debug_lockdep_rcu_enabled() && !__warned) { \ __warned = true; \ lockdep_rcu_suspicious(__FILE__, __LINE__, s); \ } \ -- cgit v1.2.3 From 04a522b7da3dbc083f8ae0aa1a6184b959a8f81c Mon Sep 17 00:00:00 2001 From: "Uladzislau Rezki (Sony)" Date: Tue, 25 Oct 2022 16:46:12 +0200 Subject: rcu: Refactor kvfree_call_rcu() and high-level helpers Currently a kvfree_call_rcu() takes an offset within a structure as a second parameter, so a helper such as a kvfree_rcu_arg_2() has to convert rcu_head and a freed ptr to an offset in order to pass it. That leads to an extra conversion on macro entry. Instead of converting, refactor the code in way that a pointer that has to be freed is passed directly to the kvfree_call_rcu(). This patch does not make any functional change and is transparent to all kvfree_rcu() users. Signed-off-by: Uladzislau Rezki (Sony) Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 5 ++--- include/linux/rcutiny.h | 12 ++++++------ include/linux/rcutree.h | 2 +- kernel/rcu/tiny.c | 9 +++------ kernel/rcu/tree.c | 29 ++++++++++++----------------- 5 files changed, 24 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 03abf883a281..f38d4469d7f3 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -1011,8 +1011,7 @@ do { \ \ if (___p) { \ BUILD_BUG_ON(!__is_kvfree_rcu_offset(offsetof(typeof(*(ptr)), rhf))); \ - kvfree_call_rcu(&((___p)->rhf), (rcu_callback_t)(unsigned long) \ - (offsetof(typeof(*(ptr)), rhf))); \ + kvfree_call_rcu(&((___p)->rhf), (void *) (___p)); \ } \ } while (0) @@ -1021,7 +1020,7 @@ do { \ typeof(ptr) ___p = (ptr); \ \ if (___p) \ - kvfree_call_rcu(NULL, (rcu_callback_t) (___p)); \ + kvfree_call_rcu(NULL, (void *) (___p)); \ } while (0) /* diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 68f9070aa111..7f17acf29dda 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -98,25 +98,25 @@ static inline void synchronize_rcu_expedited(void) */ extern void kvfree(const void *addr); -static inline void __kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func) +static inline void __kvfree_call_rcu(struct rcu_head *head, void *ptr) { if (head) { - call_rcu(head, func); + call_rcu(head, (rcu_callback_t) ((void *) head - ptr)); return; } // kvfree_rcu(one_arg) call. might_sleep(); synchronize_rcu(); - kvfree((void *) func); + kvfree(ptr); } #ifdef CONFIG_KASAN_GENERIC -void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func); +void kvfree_call_rcu(struct rcu_head *head, void *ptr); #else -static inline void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func) +static inline void kvfree_call_rcu(struct rcu_head *head, void *ptr) { - __kvfree_call_rcu(head, func); + __kvfree_call_rcu(head, ptr); } #endif diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 4003bf6cfa1c..56bccb5a8fde 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -33,7 +33,7 @@ static inline void rcu_virt_note_context_switch(void) } void synchronize_rcu_expedited(void); -void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func); +void kvfree_call_rcu(struct rcu_head *head, void *ptr); void rcu_barrier(void); bool rcu_eqs_special_set(int cpu); diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 72913ce21258..42f7589e51e0 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -246,15 +246,12 @@ bool poll_state_synchronize_rcu(unsigned long oldstate) EXPORT_SYMBOL_GPL(poll_state_synchronize_rcu); #ifdef CONFIG_KASAN_GENERIC -void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func) +void kvfree_call_rcu(struct rcu_head *head, void *ptr) { - if (head) { - void *ptr = (void *) head - (unsigned long) func; - + if (head) kasan_record_aux_stack_noalloc(ptr); - } - __kvfree_call_rcu(head, func); + __kvfree_call_rcu(head, ptr); } EXPORT_SYMBOL_GPL(kvfree_call_rcu); #endif diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index cf34a961821a..7d222acd85bf 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3103,8 +3103,8 @@ static void kfree_rcu_work(struct work_struct *work) * This list is named "Channel 3". */ for (; head; head = next) { - unsigned long offset = (unsigned long)head->func; - void *ptr = (void *)head - offset; + void *ptr = (void *) head->func; + unsigned long offset = (void *) head - ptr; next = head->next; debug_rcu_head_unqueue((struct rcu_head *)ptr); @@ -3342,26 +3342,21 @@ add_ptr_to_bulk_krc_lock(struct kfree_rcu_cpu **krcp, * be free'd in workqueue context. This allows us to: batch requests together to * reduce the number of grace periods during heavy kfree_rcu()/kvfree_rcu() load. */ -void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func) +void kvfree_call_rcu(struct rcu_head *head, void *ptr) { unsigned long flags; struct kfree_rcu_cpu *krcp; bool success; - void *ptr; - if (head) { - ptr = (void *) head - (unsigned long) func; - } else { - /* - * Please note there is a limitation for the head-less - * variant, that is why there is a clear rule for such - * objects: it can be used from might_sleep() context - * only. For other places please embed an rcu_head to - * your data. - */ + /* + * Please note there is a limitation for the head-less + * variant, that is why there is a clear rule for such + * objects: it can be used from might_sleep() context + * only. For other places please embed an rcu_head to + * your data. + */ + if (!head) might_sleep(); - ptr = (unsigned long *) func; - } // Queue the object but don't yet schedule the batch. if (debug_rcu_head_queue(ptr)) { @@ -3382,7 +3377,7 @@ void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func) // Inline if kvfree_rcu(one_arg) call. goto unlock_return; - head->func = func; + head->func = ptr; head->next = krcp->head; krcp->head = head; success = true; -- cgit v1.2.3 From aa5210f524edcebf909e6576b515bc3e2d82af0d Mon Sep 17 00:00:00 2001 From: Pingfan Liu Date: Wed, 16 Nov 2022 09:52:43 +0800 Subject: srcu: Fix a misspelling in comment s/srcu_gq_seq/srcu_gp_seq/ Signed-off-by: Pingfan Liu Cc: Lai Jiangshan Cc: Josh Triplett Cc: Steven Rostedt Cc: Mathieu Desnoyers Cc: Reviewed-by: Mukesh Ojha Reviewed-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- include/linux/srcutree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/srcutree.h b/include/linux/srcutree.h index c689a81752c9..558057b517b7 100644 --- a/include/linux/srcutree.h +++ b/include/linux/srcutree.h @@ -49,7 +49,7 @@ struct srcu_data { struct srcu_node { spinlock_t __private lock; unsigned long srcu_have_cbs[4]; /* GP seq for children having CBs, but only */ - /* if greater than ->srcu_gq_seq. */ + /* if greater than ->srcu_gp_seq. */ unsigned long srcu_data_have_cbs[4]; /* Which srcu_data structs have CBs for given GP? */ unsigned long srcu_gp_seq_needed_exp; /* Furthest future exp GP. */ struct srcu_node *srcu_parent; /* Next up in tree. */ -- cgit v1.2.3 From 0b1182bde303dc476ea9712c2c816be2e4f0cf81 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 23 Nov 2022 15:49:55 -0800 Subject: rcu: Add srcu_down_read() and srcu_up_read() A pair of matching srcu_read_lock() and srcu_read_unlock() invocations must take place within the same context, for example, within the same task. Otherwise, lockdep complains, as is the right thing to do for most use cases. However, there are use cases involving asynchronous I/O where the SRCU reader needs to begin on one task and end on another. This commit therefore supplies the semaphore-like srcu_down_read() and srcu_up_read(), which act like srcu_read_lock() and srcu_read_unlock(), but permitting srcu_up_read() to be invoked in a different context than was the matching srcu_down_read(). Neither srcu_down_read() nor srcu_up_read() may be invoked from an NMI handler. Reported-by: Jan Kara Signed-off-by: Paul E. McKenney Tested-by: Amir Goldstein --- include/linux/srcu.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'include') diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 9b9d0bbf1d3c..74796cd7e7a9 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -214,6 +214,34 @@ srcu_read_lock_notrace(struct srcu_struct *ssp) __acquires(ssp) return retval; } +/** + * srcu_down_read - register a new reader for an SRCU-protected structure. + * @ssp: srcu_struct in which to register the new reader. + * + * Enter a semaphore-like SRCU read-side critical section. Note that + * SRCU read-side critical sections may be nested. However, it is + * illegal to call anything that waits on an SRCU grace period for the + * same srcu_struct, whether directly or indirectly. Please note that + * one way to indirectly wait on an SRCU grace period is to acquire + * a mutex that is held elsewhere while calling synchronize_srcu() or + * synchronize_srcu_expedited(). But if you want lockdep to help you + * keep this stuff straight, you should instead use srcu_read_lock(). + * + * The semaphore-like nature of srcu_down_read() means that the matching + * srcu_up_read() can be invoked from some other context, for example, + * from some other task or from an irq handler. However, neither + * srcu_down_read() nor srcu_up_read() may be invoked from an NMI handler. + * + * Calls to srcu_down_read() may be nested, similar to the manner in + * which calls to down_read() may be nested. + */ +static inline int srcu_down_read(struct srcu_struct *ssp) __acquires(ssp) +{ + WARN_ON_ONCE(in_nmi()); + srcu_check_nmi_safety(ssp, false); + return __srcu_read_lock(ssp); +} + /** * srcu_read_unlock - unregister a old reader from an SRCU-protected structure. * @ssp: srcu_struct in which to unregister the old reader. @@ -254,6 +282,23 @@ srcu_read_unlock_notrace(struct srcu_struct *ssp, int idx) __releases(ssp) __srcu_read_unlock(ssp, idx); } +/** + * srcu_up_read - unregister a old reader from an SRCU-protected structure. + * @ssp: srcu_struct in which to unregister the old reader. + * @idx: return value from corresponding srcu_read_lock(). + * + * Exit an SRCU read-side critical section, but not necessarily from + * the same context as the maching srcu_down_read(). + */ +static inline void srcu_up_read(struct srcu_struct *ssp, int idx) + __releases(ssp) +{ + WARN_ON_ONCE(idx & ~0x1); + WARN_ON_ONCE(in_nmi()); + srcu_check_nmi_safety(ssp, false); + __srcu_read_unlock(ssp, idx); +} + /** * smp_mb__after_srcu_read_unlock - ensure full ordering after srcu_read_unlock * -- cgit v1.2.3 From 47904aed898a08f028572b9b5a5cc101ddfb2d82 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sat, 19 Nov 2022 17:25:03 +0800 Subject: genirq: Fix the return type of kstat_cpu_irqs_sum() The type of member ->irqs_sum is unsigned long, but kstat_cpu_irqs_sum() returns int, which can result in truncation. Therefore, change the kstat_cpu_irqs_sum() function's return value to unsigned long to avoid truncation. Fixes: f2c66cd8eedd ("/proc/stat: scalability of irq num per cpu") Reported-by: Elliott, Robert (Servers) Signed-off-by: Zhen Lei Cc: Tejun Heo Cc: "Peter Zijlstra (Intel)" Cc: Josh Don Cc: Andrew Morton Reviewed-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- include/linux/kernel_stat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index ddb5a358fd82..90e2fdc17d79 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -75,7 +75,7 @@ extern unsigned int kstat_irqs_usr(unsigned int irq); /* * Number of interrupts per cpu, since bootup */ -static inline unsigned int kstat_cpu_irqs_sum(unsigned int cpu) +static inline unsigned long kstat_cpu_irqs_sum(unsigned int cpu) { return kstat_cpu(cpu).irqs_sum; } -- cgit v1.2.3 From 28319d6dc5e2ffefa452c2377dd0f71621b5bff0 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 25 Nov 2022 14:55:00 +0100 Subject: rcu-tasks: Fix synchronize_rcu_tasks() VS zap_pid_ns_processes() RCU Tasks and PID-namespace unshare can interact in do_exit() in a complicated circular dependency: 1) TASK A calls unshare(CLONE_NEWPID), this creates a new PID namespace that every subsequent child of TASK A will belong to. But TASK A doesn't itself belong to that new PID namespace. 2) TASK A forks() and creates TASK B. TASK A stays attached to its PID namespace (let's say PID_NS1) and TASK B is the first task belonging to the new PID namespace created by unshare() (let's call it PID_NS2). 3) Since TASK B is the first task attached to PID_NS2, it becomes the PID_NS2 child reaper. 4) TASK A forks() again and creates TASK C which get attached to PID_NS2. Note how TASK C has TASK A as a parent (belonging to PID_NS1) but has TASK B (belonging to PID_NS2) as a pid_namespace child_reaper. 5) TASK B exits and since it is the child reaper for PID_NS2, it has to kill all other tasks attached to PID_NS2, and wait for all of them to die before getting reaped itself (zap_pid_ns_process()). 6) TASK A calls synchronize_rcu_tasks() which leads to synchronize_srcu(&tasks_rcu_exit_srcu). 7) TASK B is waiting for TASK C to get reaped. But TASK B is under a tasks_rcu_exit_srcu SRCU critical section (exit_notify() is between exit_tasks_rcu_start() and exit_tasks_rcu_finish()), blocking TASK A. 8) TASK C exits and since TASK A is its parent, it waits for it to reap TASK C, but it can't because TASK A waits for TASK B that waits for TASK C. Pid_namespace semantics can hardly be changed at this point. But the coverage of tasks_rcu_exit_srcu can be reduced instead. The current task is assumed not to be concurrently reapable at this stage of exit_notify() and therefore tasks_rcu_exit_srcu can be temporarily relaxed without breaking its constraints, providing a way out of the deadlock scenario. [ paulmck: Fix build failure by adding additional declaration. ] Fixes: 3f95aa81d265 ("rcu: Make TASKS_RCU handle tasks that are almost done exiting") Reported-by: Pengfei Xu Suggested-by: Boqun Feng Suggested-by: Neeraj Upadhyay Suggested-by: Paul E. McKenney Cc: Oleg Nesterov Cc: Lai Jiangshan Cc: Eric W . Biederman Signed-off-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 2 ++ kernel/pid_namespace.c | 17 +++++++++++++++++ kernel/rcu/tasks.h | 15 +++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 03abf883a281..c0c79beac3fe 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -238,6 +238,7 @@ void synchronize_rcu_tasks_rude(void); #define rcu_note_voluntary_context_switch(t) rcu_tasks_qs(t, false) void exit_tasks_rcu_start(void); +void exit_tasks_rcu_stop(void); void exit_tasks_rcu_finish(void); #else /* #ifdef CONFIG_TASKS_RCU_GENERIC */ #define rcu_tasks_classic_qs(t, preempt) do { } while (0) @@ -246,6 +247,7 @@ void exit_tasks_rcu_finish(void); #define call_rcu_tasks call_rcu #define synchronize_rcu_tasks synchronize_rcu static inline void exit_tasks_rcu_start(void) { } +static inline void exit_tasks_rcu_stop(void) { } static inline void exit_tasks_rcu_finish(void) { } #endif /* #else #ifdef CONFIG_TASKS_RCU_GENERIC */ diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index f4f8cb0435b4..fc21c5d5fd5d 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -244,7 +244,24 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns) set_current_state(TASK_INTERRUPTIBLE); if (pid_ns->pid_allocated == init_pids) break; + /* + * Release tasks_rcu_exit_srcu to avoid following deadlock: + * + * 1) TASK A unshare(CLONE_NEWPID) + * 2) TASK A fork() twice -> TASK B (child reaper for new ns) + * and TASK C + * 3) TASK B exits, kills TASK C, waits for TASK A to reap it + * 4) TASK A calls synchronize_rcu_tasks() + * -> synchronize_srcu(tasks_rcu_exit_srcu) + * 5) *DEADLOCK* + * + * It is considered safe to release tasks_rcu_exit_srcu here + * because we assume the current task can not be concurrently + * reaped at this point. + */ + exit_tasks_rcu_stop(); schedule(); + exit_tasks_rcu_start(); } __set_current_state(TASK_RUNNING); diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h index fbaed2637a7f..5de61f12a164 100644 --- a/kernel/rcu/tasks.h +++ b/kernel/rcu/tasks.h @@ -1016,16 +1016,27 @@ void exit_tasks_rcu_start(void) __acquires(&tasks_rcu_exit_srcu) * task is exiting and may be removed from the tasklist. See * corresponding synchronize_srcu() for further details. */ -void exit_tasks_rcu_finish(void) __releases(&tasks_rcu_exit_srcu) +void exit_tasks_rcu_stop(void) __releases(&tasks_rcu_exit_srcu) { struct task_struct *t = current; __srcu_read_unlock(&tasks_rcu_exit_srcu, t->rcu_tasks_idx); - exit_tasks_rcu_finish_trace(t); +} + +/* + * Contribute to protect against tasklist scan blind spot while the + * task is exiting and may be removed from the tasklist. See + * corresponding synchronize_srcu() for further details. + */ +void exit_tasks_rcu_finish(void) +{ + exit_tasks_rcu_stop(); + exit_tasks_rcu_finish_trace(current); } #else /* #ifdef CONFIG_TASKS_RCU */ void exit_tasks_rcu_start(void) { } +void exit_tasks_rcu_stop(void) { } void exit_tasks_rcu_finish(void) { exit_tasks_rcu_finish_trace(current); } #endif /* #else #ifdef CONFIG_TASKS_RCU */ -- cgit v1.2.3 From 876293121f24fc1a7df85450d0997f54540c8979 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 29 Dec 2022 17:59:57 +0100 Subject: ata: scsi: rename flag ATA_QCFLAG_FAILED to ATA_QCFLAG_EH The name ATA_QCFLAG_FAILED is misleading since it does not mean that a QC completed in error, or that it didn't complete at all. It means that libata decided to schedule EH for the QC, so the QC is now owned by the libata error handler (EH). The normal execution path is responsible for not accessing a QC owned by EH. libata core enforces the rule by returning NULL from ata_qc_from_tag() for QCs owned by EH. It is quite easy to mistake that a QC marked with ATA_QCFLAG_FAILED was an error. However, a QC that was actually an error is instead indicated by having qc->err_mask set. E.g. when we have a NCQ error, we abort all QCs, which currently will mark all QCs as ATA_QCFLAG_FAILED. However, it will only be a single QC that is an error (i.e. has qc->err_mask set). Rename ATA_QCFLAG_FAILED to ATA_QCFLAG_EH to more clearly highlight that this flag simply means that a QC is now owned by EH. This new name will not mislead to think that the QC was an error (which is instead indicated by having qc->err_mask set). This also makes it more obvious that the EH code skips all QCs that do not have ATA_QCFLAG_EH set (rather than ATA_QCFLAG_FAILED), since the EH code should simply only care about QCs that are owned by EH itself. Signed-off-by: Niklas Cassel Reviewed-by: John Garry Signed-off-by: Damien Le Moal --- drivers/ata/acard-ahci.c | 2 +- drivers/ata/libahci.c | 4 ++-- drivers/ata/libata-core.c | 12 ++++++------ drivers/ata/libata-eh.c | 22 +++++++++++----------- drivers/ata/libata-sata.c | 4 ++-- drivers/ata/libata-sff.c | 4 ++-- drivers/ata/libata-trace.c | 2 +- drivers/ata/sata_fsl.c | 2 +- drivers/ata/sata_inic162x.c | 2 +- drivers/ata/sata_promise.c | 2 +- drivers/ata/sata_sil24.c | 2 +- drivers/ata/sata_sx4.c | 2 +- drivers/scsi/ipr.c | 4 ++-- drivers/scsi/libsas/sas_ata.c | 8 ++++---- include/linux/libata.h | 4 ++-- 15 files changed, 38 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 7654a40c12b4..da74a86b70ba 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -263,7 +263,7 @@ static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) * Setup FIS. */ if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE && - !(qc->flags & ATA_QCFLAG_FAILED)) { + !(qc->flags & ATA_QCFLAG_EH)) { ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15]; } else diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 29acc35bf4a6..03aa9eb415d3 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -2068,7 +2068,7 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) * Setup FIS. */ if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE && - !(qc->flags & ATA_QCFLAG_FAILED)) { + !(qc->flags & ATA_QCFLAG_EH)) { ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15]; @@ -2138,7 +2138,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) ahci_kick_engine(ap); } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 884ae73b11ea..6b03bebcde50 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1590,7 +1590,7 @@ static unsigned ata_exec_internal_sg(struct ata_device *dev, ap->ops->post_internal_cmd(qc); /* perform minimal error analysis */ - if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->flags & ATA_QCFLAG_EH) { if (qc->result_tf.status & (ATA_ERR | ATA_DF)) qc->err_mask |= AC_ERR_DEV; @@ -4683,10 +4683,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc) /* XXX: New EH and old EH use different mechanisms to * synchronize EH with regular execution path. * - * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED. + * In new EH, a qc owned by EH is marked with ATA_QCFLAG_EH. * Normal execution path is responsible for not accessing a - * failed qc. libata core enforces the rule by returning NULL - * from ata_qc_from_tag() for failed qcs. + * qc owned by EH. libata core enforces the rule by returning NULL + * from ata_qc_from_tag() for qcs owned by EH. * * Old EH depends on ata_qc_complete() nullifying completion * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does @@ -4698,7 +4698,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) struct ata_eh_info *ehi = &dev->link->eh_info; if (unlikely(qc->err_mask)) - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; /* * Finish internal commands without any further processing @@ -4715,7 +4715,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) * Non-internal qc has failed. Fill the result TF and * summon EH. */ - if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { + if (unlikely(qc->flags & ATA_QCFLAG_EH)) { fill_result_tf(qc); trace_ata_qc_complete_failed(qc); ata_qc_schedule_eh(qc); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2a70e1f12db5..a6c901811802 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -581,7 +581,7 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, * normal completion, error completion, and SCSI timeout. * Both completions can race against SCSI timeout. When normal * completion wins, the qc never reaches EH. When error - * completion wins, the qc has ATA_QCFLAG_FAILED set. + * completion wins, the qc has ATA_QCFLAG_EH set. * * When SCSI timeout wins, things are a bit more complex. * Normal or error completion can occur after the timeout but @@ -615,10 +615,10 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, if (i < ATA_MAX_QUEUE) { /* the scmd has an associated qc */ - if (!(qc->flags & ATA_QCFLAG_FAILED)) { + if (!(qc->flags & ATA_QCFLAG_EH)) { /* which hasn't failed yet, timeout */ qc->err_mask |= AC_ERR_TIMEOUT; - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; nr_timedout++; } } else { @@ -636,7 +636,7 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, * this point but the state of the controller is * unknown. Freeze the port to make sure the IRQ * handler doesn't diddle with those qcs. This must - * be done atomically w.r.t. setting QCFLAG_FAILED. + * be done atomically w.r.t. setting ATA_QCFLAG_EH. */ if (nr_timedout) __ata_port_freeze(ap); @@ -914,12 +914,12 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) WARN_ON(!ap->ops->error_handler); - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; ata_eh_set_pending(ap, 1); /* The following will fail if timeout has already expired. * ata_scsi_error() takes care of such scmds on EH entry. - * Note that ATA_QCFLAG_FAILED is unconditionally set after + * Note that ATA_QCFLAG_EH is unconditionally set after * this function completes. */ blk_abort_request(scsi_cmd_to_rq(qc->scsicmd)); @@ -997,7 +997,7 @@ static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link) /* include internal tag in iteration */ ata_qc_for_each_with_internal(ap, qc, tag) { if (qc && (!link || qc->dev->link == link)) { - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; ata_qc_complete(qc); nr_aborted++; } @@ -1957,7 +1957,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) all_err_mask |= ehc->i.err_mask; ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!(qc->flags & ATA_QCFLAG_EH) || qc->flags & ATA_QCFLAG_RETRY || ata_dev_phys_link(qc->dev) != link) continue; @@ -2235,7 +2235,7 @@ static void ata_eh_link_report(struct ata_link *link) desc = ehc->i.desc; ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!(qc->flags & ATA_QCFLAG_EH) || ata_dev_phys_link(qc->dev) != link || ((qc->flags & ATA_QCFLAG_QUIET) && qc->err_mask == AC_ERR_DEV)) @@ -2301,7 +2301,7 @@ static void ata_eh_link_report(struct ata_link *link) char data_buf[20] = ""; char cdb_buf[70] = ""; - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!(qc->flags & ATA_QCFLAG_EH) || ata_dev_phys_link(qc->dev) != link || !qc->err_mask) continue; @@ -3805,7 +3805,7 @@ void ata_eh_finish(struct ata_port *ap) /* retry or finish qcs */ ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_EH)) continue; if (qc->err_mask) { diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 18ef14e749a0..908f35acee1e 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1429,7 +1429,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) /* has LLDD analyzed already? */ ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!(qc->flags & ATA_QCFLAG_EH)) continue; if (qc->err_mask) @@ -1477,7 +1477,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) } ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!(qc->flags & ATA_QCFLAG_EH) || ata_dev_phys_link(qc->dev) != link) continue; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 153f49e00713..34beda28e712 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2073,7 +2073,7 @@ void ata_sff_error_handler(struct ata_port *ap) unsigned long flags; qc = __ata_qc_from_tag(ap, ap->link.active_tag); - if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) + if (qc && !(qc->flags & ATA_QCFLAG_EH)) qc = NULL; spin_lock_irqsave(ap->lock, flags); @@ -2796,7 +2796,7 @@ void ata_bmdma_error_handler(struct ata_port *ap) bool thaw = false; qc = __ata_qc_from_tag(ap, ap->link.active_tag); - if (qc && !(qc->flags & ATA_QCFLAG_FAILED)) + if (qc && !(qc->flags & ATA_QCFLAG_EH)) qc = NULL; /* reset PIO HSM and stop DMA engine */ diff --git a/drivers/ata/libata-trace.c b/drivers/ata/libata-trace.c index e0e4d0d5a100..9b5363fd0ab0 100644 --- a/drivers/ata/libata-trace.c +++ b/drivers/ata/libata-trace.c @@ -142,7 +142,7 @@ libata_trace_parse_qc_flags(struct trace_seq *p, unsigned int qc_flags) trace_seq_printf(p, "QUIET "); if (qc_flags & ATA_QCFLAG_RETRY) trace_seq_printf(p, "RETRY "); - if (qc_flags & ATA_QCFLAG_FAILED) + if (qc_flags & ATA_QCFLAG_EH) trace_seq_printf(p, "FAILED "); if (qc_flags & ATA_QCFLAG_SENSE_VALID) trace_seq_printf(p, "SENSE_VALID "); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index b9a4f68b371d..7eab9c4e1473 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1042,7 +1042,7 @@ static void sata_fsl_error_handler(struct ata_port *ap) static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc) { - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) qc->err_mask |= AC_ERR_OTHER; if (qc->err_mask) { diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 11e518f0111c..f480ff456190 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -672,7 +672,7 @@ static void inic_error_handler(struct ata_port *ap) static void inic_post_internal_cmd(struct ata_queued_cmd *qc) { /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) inic_reset_port(inic_port_base(qc->ap)); } diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 9cd7d8b71361..4e60e6c4c35a 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -828,7 +828,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) pdc_reset_port(ap); } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 2fef6ce93f07..0a01518a8d97 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -1185,7 +1185,7 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap)) + if ((qc->flags & ATA_QCFLAG_EH) && sil24_init_port(ap)) ata_eh_freeze_port(ap); } diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index ab70cbc78f96..a92c60455b1d 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -866,7 +866,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; /* make DMA engine forget about the failed command */ - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) pdc_reset_port(ap); } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 2022ffb45041..c68ca2218a05 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5370,9 +5370,9 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd) continue; ipr_cmd->done = ipr_sata_eh_done; - if (!(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { + if (!(ipr_cmd->qc->flags & ATA_QCFLAG_EH)) { ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; - ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; + ipr_cmd->qc->flags |= ATA_QCFLAG_EH; } } } diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 1ccce706167a..14da33a3b6a6 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -125,7 +125,7 @@ static void sas_ata_task_done(struct sas_task *task) } else { link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]); if (unlikely(link->eh_info.err_mask)) - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; } } else { ac = sas_to_ata_err(stat); @@ -136,7 +136,7 @@ static void sas_ata_task_done(struct sas_task *task) qc->err_mask = ac; } else { link->eh_info.err_mask |= AC_ERR_DEV; - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; } dev->sata_dev.fis[2] = ATA_ERR | ATA_DRDY; /* tf status */ @@ -476,7 +476,7 @@ static void sas_ata_internal_abort(struct sas_task *task) static void sas_ata_post_internal(struct ata_queued_cmd *qc) { - if (qc->flags & ATA_QCFLAG_FAILED) + if (qc->flags & ATA_QCFLAG_EH) qc->err_mask |= AC_ERR_OTHER; if (qc->err_mask) { @@ -631,7 +631,7 @@ void sas_ata_task_abort(struct sas_task *task) /* Internal command, fake a timeout and complete. */ qc->flags &= ~ATA_QCFLAG_ACTIVE; - qc->flags |= ATA_QCFLAG_FAILED; + qc->flags |= ATA_QCFLAG_EH; qc->err_mask |= AC_ERR_TIMEOUT; waiting = qc->private_data; complete(waiting); diff --git a/include/linux/libata.h b/include/linux/libata.h index c9149ebe7423..7985e6e2ae0e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -206,7 +206,7 @@ enum { ATA_QCFLAG_QUIET = (1 << 6), /* don't report device error */ ATA_QCFLAG_RETRY = (1 << 7), /* retry after failure */ - ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */ + ATA_QCFLAG_EH = (1 << 16), /* cmd aborted and owned by EH */ ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */ ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */ @@ -1756,7 +1756,7 @@ static inline struct ata_queued_cmd *ata_qc_from_tag(struct ata_port *ap, return qc; if ((qc->flags & (ATA_QCFLAG_ACTIVE | - ATA_QCFLAG_FAILED)) == ATA_QCFLAG_ACTIVE) + ATA_QCFLAG_EH)) == ATA_QCFLAG_ACTIVE) return qc; return NULL; -- cgit v1.2.3 From 931139af5718fb41565fff2420daf995c016ec80 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 29 Dec 2022 17:59:58 +0100 Subject: ata: libata: simplify qc_fill_rtf port operation interface The boolean return value of the qc_fill_rtf operation is used nowhere. Simplify this operation interface by making it a void function. All drivers defining this operation are also updated. Signed-off-by: Damien Le Moal Signed-off-by: Niklas Cassel Reviewed-by: John Garry --- drivers/ata/acard-ahci.c | 6 ++---- drivers/ata/libahci.c | 6 ++---- drivers/ata/libata-sff.c | 6 +----- drivers/ata/sata_fsl.c | 3 +-- drivers/ata/sata_inic162x.c | 12 +++++------- drivers/ata/sata_sil24.c | 5 ++--- drivers/scsi/ipr.c | 7 +------ drivers/scsi/libsas/sas_ata.c | 3 +-- include/linux/libata.h | 4 ++-- 9 files changed, 17 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index da74a86b70ba..993eadd173da 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -57,7 +57,7 @@ struct acard_sg { }; static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc); -static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc); +static void acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc); static int acard_ahci_port_start(struct ata_port *ap); static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); @@ -248,7 +248,7 @@ static enum ata_completion_errors acard_ahci_qc_prep(struct ata_queued_cmd *qc) return AC_ERR_OK; } -static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) +static void acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ahci_port_priv *pp = qc->ap->private_data; u8 *rx_fis = pp->rx_fis; @@ -268,8 +268,6 @@ static bool acard_ahci_qc_fill_rtf(struct ata_queued_cmd *qc) qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15]; } else ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); - - return true; } static int acard_ahci_port_start(struct ata_port *ap) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 03aa9eb415d3..0167aac25c34 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -55,7 +55,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); -static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); +static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); static enum ata_completion_errors ahci_qc_prep(struct ata_queued_cmd *qc); @@ -2053,7 +2053,7 @@ unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) } EXPORT_SYMBOL_GPL(ahci_qc_issue); -static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) +static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ahci_port_priv *pp = qc->ap->private_data; u8 *rx_fis = pp->rx_fis; @@ -2087,8 +2087,6 @@ static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc) qc->result_tf.error = fis[3]; } else ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); - - return true; } static void ahci_freeze(struct ata_port *ap) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 34beda28e712..cd82d3b5ed14 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1377,14 +1377,10 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_issue); * * LOCKING: * spin_lock_irqsave(host lock) - * - * RETURNS: - * true indicating that result TF is successfully filled. */ -bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc) +void ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc) { qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf); - return true; } EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 7eab9c4e1473..b052c5a65c17 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -566,7 +566,7 @@ static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc) return 0; } -static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc) +static void sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc) { struct sata_fsl_port_priv *pp = qc->ap->private_data; struct sata_fsl_host_priv *host_priv = qc->ap->host->private_data; @@ -577,7 +577,6 @@ static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc) cd = pp->cmdentry + tag; ata_tf_from_fis(cd->sfis, &qc->result_tf); - return true; } static int sata_fsl_scr_write(struct ata_link *link, diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index f480ff456190..2833c722118d 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -566,7 +566,7 @@ static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf) tf->status = readb(port_base + PORT_TF_COMMAND); } -static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc) +static void inic_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ata_taskfile *rtf = &qc->result_tf; struct ata_taskfile tf; @@ -580,12 +580,10 @@ static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc) */ inic_tf_read(qc->ap, &tf); - if (!(tf.status & ATA_ERR)) - return false; - - rtf->status = tf.status; - rtf->error = tf.error; - return true; + if (tf.status & ATA_ERR) { + rtf->status = tf.status; + rtf->error = tf.error; + } } static void inic_freeze(struct ata_port *ap) diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 0a01518a8d97..22cc9e9789dd 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -328,7 +328,7 @@ static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val); static int sil24_qc_defer(struct ata_queued_cmd *qc); static enum ata_completion_errors sil24_qc_prep(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); -static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc); +static void sil24_qc_fill_rtf(struct ata_queued_cmd *qc); static void sil24_pmp_attach(struct ata_port *ap); static void sil24_pmp_detach(struct ata_port *ap); static void sil24_freeze(struct ata_port *ap); @@ -901,10 +901,9 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc) return 0; } -static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc) +static void sil24_qc_fill_rtf(struct ata_queued_cmd *qc) { sil24_read_tf(qc->ap, qc->hw_tag, &qc->result_tf); - return true; } static void sil24_pmp_attach(struct ata_port *ap) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index c68ca2218a05..1c8040d250ea 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7142,11 +7142,8 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) /** * ipr_qc_fill_rtf - Read result TF * @qc: ATA queued command - * - * Return value: - * true **/ -static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc) +static void ipr_qc_fill_rtf(struct ata_queued_cmd *qc) { struct ipr_sata_port *sata_port = qc->ap->private_data; struct ipr_ioasa_gata *g = &sata_port->ioasa; @@ -7163,8 +7160,6 @@ static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc) tf->hob_lbal = g->hob_lbal; tf->hob_lbam = g->hob_lbam; tf->hob_lbah = g->hob_lbah; - - return true; } static struct ata_port_operations ipr_sata_ops = { diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 14da33a3b6a6..ac8576e7f0b7 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -226,12 +226,11 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) return ret; } -static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) +static void sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) { struct domain_device *dev = qc->ap->private_data; ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf); - return true; } static struct sas_internal *dev_to_sas_internal(struct domain_device *dev) diff --git a/include/linux/libata.h b/include/linux/libata.h index 7985e6e2ae0e..8483d8300ea3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -876,7 +876,7 @@ struct ata_port_operations { int (*check_atapi_dma)(struct ata_queued_cmd *qc); enum ata_completion_errors (*qc_prep)(struct ata_queued_cmd *qc); unsigned int (*qc_issue)(struct ata_queued_cmd *qc); - bool (*qc_fill_rtf)(struct ata_queued_cmd *qc); + void (*qc_fill_rtf)(struct ata_queued_cmd *qc); /* * Configuration and exception handling @@ -1936,7 +1936,7 @@ extern void ata_sff_queue_delayed_work(struct delayed_work *dwork, unsigned long delay); extern void ata_sff_queue_pio_task(struct ata_link *link, unsigned long delay); extern unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc); -extern bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc); +extern void ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc); extern unsigned int ata_sff_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc); extern irqreturn_t ata_sff_interrupt(int irq, void *dev_instance); -- cgit v1.2.3 From 93c4aa449b88196c7d56a556cb6a2aad21ad8a7a Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 29 Dec 2022 17:59:59 +0100 Subject: ata: libata: read the shared status for successful NCQ commands once Currently, the status is being read for each QC, inside ata_qc_complete(), which means that QCs being completed by ata_qc_complete_multiple() (i.e. multiple QCs completed during a single interrupt), can have different status and error bits set. This is because the FIS Receive Area will get updated as soon as the HBA receives a new FIS from the device in the NCQ case. Here is an example of the problem: ata14.00: ata_qc_complete_multiple: done_mask: 0x180000 qc tag: 19 cmd: 0x61 flags: 0x11b err_mask: 0x0 tf->status: 0x40 qc tag: 20 cmd: 0x61 flags: 0x11b err_mask: 0x0 tf->status: 0x43 A print in ata_qc_complete_multiple(), shows that done_mask is: 0x180000 which means that tag 19 and 20 were completed. Another print in ata_qc_complete(), after the call to fill_result_tf(), shows that tag 19 and 20 have different status values, even though they were completed in the same ata_qc_complete_multiple() call. If PMP is not enabled, simply read the status and error once, before calling ata_qc_complete() for each QC. Without PMP, we know that all QCs must share the same status and error values. If PMP is enabled, we also read the status before calling ata_qc_complete(), however, we still read the status for each QC, since the QCs can belong to different PMP links (which means that the QCs does not necessarily share the same status and error values). Do all this by introducing the new port operation .qc_ncq_fill_rtf. If set, this operation is called in ata_qc_complete_multiple() to set the result tf for all completed QCs signaled by the last SDB FIS received. QCs that have their result tf filled are marked with the new flag ATA_QCFLAG_RTF_FILLED so that any later execution of the qc_fill_rtf port operation does nothing (e.g. when called from ata_qc_complete()). Co-developed-by: Damien Le Moal Signed-off-by: Damien Le Moal Signed-off-by: Niklas Cassel --- drivers/ata/libahci.c | 90 +++++++++++++++++++++++++++++++++++++++++++++-- drivers/ata/libata-sata.c | 3 ++ include/linux/libata.h | 2 ++ 3 files changed, 92 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 0167aac25c34..e5d67eb46f3c 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -56,6 +56,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state, static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc); +static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); static enum ata_completion_errors ahci_qc_prep(struct ata_queued_cmd *qc); @@ -157,6 +158,7 @@ struct ata_port_operations ahci_ops = { .qc_prep = ahci_qc_prep, .qc_issue = ahci_qc_issue, .qc_fill_rtf = ahci_qc_fill_rtf, + .qc_ncq_fill_rtf = ahci_qc_ncq_fill_rtf, .freeze = ahci_freeze, .thaw = ahci_thaw, @@ -2058,6 +2060,13 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc) struct ahci_port_priv *pp = qc->ap->private_data; u8 *rx_fis = pp->rx_fis; + /* + * rtf may already be filled (e.g. for successful NCQ commands). + * If that is the case, we have nothing to do. + */ + if (qc->flags & ATA_QCFLAG_RTF_FILLED) + return; + if (pp->fbs_enabled) rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; @@ -2071,6 +2080,9 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc) !(qc->flags & ATA_QCFLAG_EH)) { ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf); qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15]; + qc->flags |= ATA_QCFLAG_RTF_FILLED; + return; + } /* * For NCQ commands, we never get a D2H FIS, so reading the D2H Register @@ -2080,13 +2092,85 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc) * instead. However, the SDB FIS does not contain the LBA, so we can't * use the ata_tf_from_fis() helper. */ - } else if (ata_is_ncq(qc->tf.protocol)) { + if (ata_is_ncq(qc->tf.protocol)) { const u8 *fis = rx_fis + RX_FIS_SDB; + /* + * Successful NCQ commands have been filled already. + * A failed NCQ command will read the status here. + * (Note that a failed NCQ command will get a more specific + * error when reading the NCQ Command Error log.) + */ qc->result_tf.status = fis[2]; qc->result_tf.error = fis[3]; - } else - ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); + qc->flags |= ATA_QCFLAG_RTF_FILLED; + return; + } + + ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf); + qc->flags |= ATA_QCFLAG_RTF_FILLED; +} + +static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask) +{ + struct ahci_port_priv *pp = ap->private_data; + const u8 *fis; + + /* No outstanding commands. */ + if (!ap->qc_active) + return; + + /* + * FBS not enabled, so read status and error once, since they are shared + * for all QCs. + */ + if (!pp->fbs_enabled) { + u8 status, error; + + /* No outstanding NCQ commands. */ + if (!pp->active_link->sactive) + return; + + fis = pp->rx_fis + RX_FIS_SDB; + status = fis[2]; + error = fis[3]; + + while (done_mask) { + struct ata_queued_cmd *qc; + unsigned int tag = __ffs64(done_mask); + + qc = ata_qc_from_tag(ap, tag); + if (qc && ata_is_ncq(qc->tf.protocol)) { + qc->result_tf.status = status; + qc->result_tf.error = error; + qc->flags |= ATA_QCFLAG_RTF_FILLED; + } + done_mask &= ~(1ULL << tag); + } + + return; + } + + /* + * FBS enabled, so read the status and error for each QC, since the QCs + * can belong to different PMP links. (Each PMP link has its own FIS + * Receive Area.) + */ + while (done_mask) { + struct ata_queued_cmd *qc; + unsigned int tag = __ffs64(done_mask); + + qc = ata_qc_from_tag(ap, tag); + if (qc && ata_is_ncq(qc->tf.protocol)) { + fis = pp->rx_fis; + fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ; + fis += RX_FIS_SDB; + qc->result_tf.status = fis[2]; + qc->result_tf.error = fis[3]; + qc->flags |= ATA_QCFLAG_RTF_FILLED; + } + done_mask &= ~(1ULL << tag); + } } static void ahci_freeze(struct ata_port *ap) diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 908f35acee1e..f3e7396e3191 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -655,6 +655,9 @@ int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active) return -EINVAL; } + if (ap->ops->qc_ncq_fill_rtf) + ap->ops->qc_ncq_fill_rtf(ap, done_mask); + while (done_mask) { struct ata_queued_cmd *qc; unsigned int tag = __ffs64(done_mask); diff --git a/include/linux/libata.h b/include/linux/libata.h index 8483d8300ea3..f54e02dadc6f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -200,6 +200,7 @@ enum { /* struct ata_queued_cmd flags */ ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_DMAMAP = (1 << 1), /* SG table is DMA mapped */ + ATA_QCFLAG_RTF_FILLED = (1 << 2), /* result TF has been filled */ ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ @@ -877,6 +878,7 @@ struct ata_port_operations { enum ata_completion_errors (*qc_prep)(struct ata_queued_cmd *qc); unsigned int (*qc_issue)(struct ata_queued_cmd *qc); void (*qc_fill_rtf)(struct ata_queued_cmd *qc); + void (*qc_ncq_fill_rtf)(struct ata_port *ap, u64 done_mask); /* * Configuration and exception handling -- cgit v1.2.3 From 87aab3c4cd59aef42fe280fece2be8b8156b99e0 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 29 Dec 2022 18:00:01 +0100 Subject: ata: libata: move NCQ related ATA_DFLAGs ata_dev_configure() starts off by clearing all flags in ATA_DFLAG_CFG_MASK: dev->flags &= ~ATA_DFLAG_CFG_MASK; ata_dev_configure() then calls ata_dev_config_lba() which calls ata_dev_config_ncq(). ata_dev_config_ncq() will set the correct ATA_DFLAGs depending on what is actually supported. Since these flags are set by ata_dev_configure(), they should be in ATA_DFLAG_CFG_MASK and not in ATA_DFLAG_INIT_MASK. ATA_DFLAG_NCQ_PRIO_ENABLED is set via sysfs, is should therefore not be in ATA_DFLAG_CFG_MASK. It also cannot be in ATA_DFLAG_INIT_MASK, because ata_eh_schedule_probe() calls ata_dev_init(), which will clear all flags in ATA_DFLAG_INIT_MASK. This means that ATA_DFLAG_NCQ_PRIO_ENABLED (the value the user sets via sysfs) would get silently cleared if ata_eh_schedule_probe() is called. While that should only happen in certain circumstances, it still doesn't seem right that it can get silently cleared. (ata_dev_config_ncq_prio() will still clear the ATA_DFLAG_NCQ_PRIO_ENABLED flag if ATA_DFLAG_NCQ_PRIO is suddenly no longer supported after a revalidation.) Because of this, move ATA_DFLAG_NCQ_PRIO_ENABLED to be outside of both ATA_DFLAG_CFG_MASK and ATA_DFLAG_INIT_MASK. Signed-off-by: Niklas Cassel Signed-off-by: Damien Le Moal --- include/linux/libata.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index f54e02dadc6f..3b7f5d9e2f87 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -91,22 +91,21 @@ enum { ATA_DFLAG_AN = (1 << 7), /* AN configured */ ATA_DFLAG_TRUSTED = (1 << 8), /* device supports trusted send/recv */ ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ - ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + ATA_DFLAG_NCQ_SEND_RECV = (1 << 11), /* device supports NCQ SEND and RECV */ + ATA_DFLAG_NCQ_PRIO = (1 << 12), /* device supports NCQ priority */ + ATA_DFLAG_CFG_MASK = (1 << 13) - 1, - ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ - ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ + ATA_DFLAG_PIO = (1 << 13), /* device limited to PIO mode */ + ATA_DFLAG_NCQ_OFF = (1 << 14), /* device limited to non-NCQ mode */ ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ ATA_DFLAG_NO_UNLOAD = (1 << 17), /* device doesn't support unload */ ATA_DFLAG_UNLOCK_HPA = (1 << 18), /* unlock HPA */ - ATA_DFLAG_NCQ_SEND_RECV = (1 << 19), /* device supports NCQ SEND and RECV */ - ATA_DFLAG_NCQ_PRIO = (1 << 20), /* device supports NCQ priority */ - ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 21), /* Priority cmds sent to dev */ - ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + ATA_DFLAG_INIT_MASK = (1 << 19) - 1, + ATA_DFLAG_NCQ_PRIO_ENABLED = (1 << 19), /* Priority cmds sent to dev */ ATA_DFLAG_DETACH = (1 << 24), ATA_DFLAG_DETACHED = (1 << 25), - ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */ ATA_DFLAG_DEVSLP = (1 << 27), /* device supports Device Sleep */ ATA_DFLAG_ACPI_DISABLED = (1 << 28), /* ACPI for the device is disabled */ -- cgit v1.2.3 From 33e3f0a3358b8f9bb54b2661b9c1d37a75664c79 Mon Sep 17 00:00:00 2001 From: Richard Clark Date: Tue, 13 Dec 2022 12:39:36 +0800 Subject: workqueue: Add a new flag to spot the potential UAF error Currently if the user queues a new work item unintentionally into a wq after the destroy_workqueue(wq), the work still can be queued and scheduled without any noticeable kernel message before the end of a RCU grace period. As a debug-aid facility, this commit adds a new flag __WQ_DESTROYING to spot that issue by triggering a kernel WARN message. Signed-off-by: Richard Clark Reviewed-by: Lai Jiangshan Signed-off-by: Tejun Heo --- include/linux/workqueue.h | 1 + kernel/workqueue.c | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index a0143dd24430..ac551b8ee7d9 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -335,6 +335,7 @@ enum { */ WQ_POWER_EFFICIENT = 1 << 7, + __WQ_DESTROYING = 1 << 15, /* internal: workqueue is destroying */ __WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */ __WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */ __WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */ diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 07895deca271..5b06262a419c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1433,9 +1433,13 @@ static void __queue_work(int cpu, struct workqueue_struct *wq, lockdep_assert_irqs_disabled(); - /* if draining, only works from the same workqueue are allowed */ - if (unlikely(wq->flags & __WQ_DRAINING) && - WARN_ON_ONCE(!is_chained_work(wq))) + /* + * For a draining wq, only works from the same workqueue are + * allowed. The __WQ_DESTROYING helps to spot the issue that + * queues a new work item to a wq after destroy_workqueue(wq). + */ + if (unlikely(wq->flags & (__WQ_DESTROYING | __WQ_DRAINING) && + WARN_ON_ONCE(!is_chained_work(wq)))) return; rcu_read_lock(); retry: @@ -4414,6 +4418,11 @@ void destroy_workqueue(struct workqueue_struct *wq) */ workqueue_sysfs_unregister(wq); + /* mark the workqueue destruction is in progress */ + mutex_lock(&wq->mutex); + wq->flags |= __WQ_DESTROYING; + mutex_unlock(&wq->mutex); + /* drain it before proceeding with destruction */ drain_workqueue(wq); -- cgit v1.2.3 From 4a20bc3e207488064e08fc5d7220d6acf95c80dd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 8 Dec 2022 09:02:00 -0800 Subject: cxl/pci: Move tracepoint definitions to drivers/cxl/core/ CXL is using tracepoints for reporting RAS capability register payloads for AER events, and has plans to use tracepoints for the output payload of Get Poison List and Get Event Records commands. For organization purposes it would be nice to keep those all under a single + local CXL trace system. This also organization also potentially helps in the future when CXL drivers expand beyond generic memory expanders, however that would also entail a move away from the expander-specific cxl_dev_state context, save that for later. Note that the powerpc-specific drivers/misc/cxl/ also defines a 'cxl' trace system, however, it is unlikely that a single platform will ever load both drivers simultaneously. Cc: Steven Rostedt Tested-by: Alison Schofield Reviewed-by: Dave Jiang Link: https://lore.kernel.org/r/167051869176.436579.9728373544811641087.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams --- drivers/cxl/core/Makefile | 3 ++ drivers/cxl/core/pci.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ drivers/cxl/core/trace.c | 5 ++ drivers/cxl/core/trace.h | 109 +++++++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 2 + drivers/cxl/cxlpci.h | 3 ++ drivers/cxl/pci.c | 111 -------------------------------------------- include/trace/events/cxl.h | 112 --------------------------------------------- tools/testing/cxl/Kbuild | 2 + 9 files changed, 236 insertions(+), 223 deletions(-) create mode 100644 drivers/cxl/core/trace.c create mode 100644 drivers/cxl/core/trace.h delete mode 100644 include/trace/events/cxl.h (limited to 'include') diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index 79c7257f4107..ca4ae31d8f57 100644 --- a/drivers/cxl/core/Makefile +++ b/drivers/cxl/core/Makefile @@ -3,6 +3,8 @@ obj-$(CONFIG_CXL_BUS) += cxl_core.o obj-$(CONFIG_CXL_SUSPEND) += suspend.o ccflags-y += -I$(srctree)/drivers/cxl +CFLAGS_trace.o = -DTRACE_INCLUDE_PATH=. -I$(src) + cxl_core-y := port.o cxl_core-y += pmem.o cxl_core-y += regs.o @@ -10,4 +12,5 @@ cxl_core-y += memdev.o cxl_core-y += mbox.o cxl_core-y += pci.o cxl_core-y += hdm.o +cxl_core-$(CONFIG_TRACING) += trace.o cxl_core-$(CONFIG_CXL_REGION) += region.o diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 57764e9cd19d..1d1492440287 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -9,6 +9,7 @@ #include #include #include "core.h" +#include "trace.h" /** * DOC: cxl core pci @@ -622,3 +623,114 @@ void read_cdat_data(struct cxl_port *port) } } EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL); + +void cxl_cor_error_detected(struct pci_dev *pdev) +{ + struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); + struct cxl_memdev *cxlmd = cxlds->cxlmd; + struct device *dev = &cxlmd->dev; + void __iomem *addr; + u32 status; + + if (!cxlds->regs.ras) + return; + + addr = cxlds->regs.ras + CXL_RAS_CORRECTABLE_STATUS_OFFSET; + status = readl(addr); + if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) { + writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr); + trace_cxl_aer_correctable_error(dev, status); + } +} +EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, CXL); + +/* CXL spec rev3.0 8.2.4.16.1 */ +static void header_log_copy(struct cxl_dev_state *cxlds, u32 *log) +{ + void __iomem *addr; + u32 *log_addr; + int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32); + + addr = cxlds->regs.ras + CXL_RAS_HEADER_LOG_OFFSET; + log_addr = log; + + for (i = 0; i < log_u32_size; i++) { + *log_addr = readl(addr); + log_addr++; + addr += sizeof(u32); + } +} + +/* + * Log the state of the RAS status registers and prepare them to log the + * next error status. Return 1 if reset needed. + */ +static bool cxl_report_and_clear(struct cxl_dev_state *cxlds) +{ + struct cxl_memdev *cxlmd = cxlds->cxlmd; + struct device *dev = &cxlmd->dev; + u32 hl[CXL_HEADERLOG_SIZE_U32]; + void __iomem *addr; + u32 status; + u32 fe; + + if (!cxlds->regs.ras) + return false; + + addr = cxlds->regs.ras + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET; + status = readl(addr); + if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK)) + return false; + + /* If multiple errors, log header points to first error from ctrl reg */ + if (hweight32(status) > 1) { + addr = cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET; + fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, readl(addr))); + } else { + fe = status; + } + + header_log_copy(cxlds, hl); + trace_cxl_aer_uncorrectable_error(dev, status, fe, hl); + writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr); + + return true; +} + +pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); + struct cxl_memdev *cxlmd = cxlds->cxlmd; + struct device *dev = &cxlmd->dev; + bool ue; + + /* + * A frozen channel indicates an impending reset which is fatal to + * CXL.mem operation, and will likely crash the system. On the off + * chance the situation is recoverable dump the status of the RAS + * capability registers and bounce the active state of the memdev. + */ + ue = cxl_report_and_clear(cxlds); + + switch (state) { + case pci_channel_io_normal: + if (ue) { + device_release_driver(dev); + return PCI_ERS_RESULT_NEED_RESET; + } + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + dev_warn(&pdev->dev, + "%s: frozen state error detected, disable CXL.mem\n", + dev_name(dev)); + device_release_driver(dev); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + dev_warn(&pdev->dev, + "failure state error detected, request disconnect\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + return PCI_ERS_RESULT_NEED_RESET; +} +EXPORT_SYMBOL_NS_GPL(cxl_error_detected, CXL); diff --git a/drivers/cxl/core/trace.c b/drivers/cxl/core/trace.c new file mode 100644 index 000000000000..29ae7ce81dc5 --- /dev/null +++ b/drivers/cxl/core/trace.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2022 Intel Corporation. All rights reserved. */ + +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h new file mode 100644 index 000000000000..20ca2fe2ca8e --- /dev/null +++ b/drivers/cxl/core/trace.h @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2022 Intel Corporation. All rights reserved. */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cxl + +#if !defined(_CXL_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _CXL_EVENTS_H + +#include +#include + +#define CXL_RAS_UC_CACHE_DATA_PARITY BIT(0) +#define CXL_RAS_UC_CACHE_ADDR_PARITY BIT(1) +#define CXL_RAS_UC_CACHE_BE_PARITY BIT(2) +#define CXL_RAS_UC_CACHE_DATA_ECC BIT(3) +#define CXL_RAS_UC_MEM_DATA_PARITY BIT(4) +#define CXL_RAS_UC_MEM_ADDR_PARITY BIT(5) +#define CXL_RAS_UC_MEM_BE_PARITY BIT(6) +#define CXL_RAS_UC_MEM_DATA_ECC BIT(7) +#define CXL_RAS_UC_REINIT_THRESH BIT(8) +#define CXL_RAS_UC_RSVD_ENCODE BIT(9) +#define CXL_RAS_UC_POISON BIT(10) +#define CXL_RAS_UC_RECV_OVERFLOW BIT(11) +#define CXL_RAS_UC_INTERNAL_ERR BIT(14) +#define CXL_RAS_UC_IDE_TX_ERR BIT(15) +#define CXL_RAS_UC_IDE_RX_ERR BIT(16) + +#define show_uc_errs(status) __print_flags(status, " | ", \ + { CXL_RAS_UC_CACHE_DATA_PARITY, "Cache Data Parity Error" }, \ + { CXL_RAS_UC_CACHE_ADDR_PARITY, "Cache Address Parity Error" }, \ + { CXL_RAS_UC_CACHE_BE_PARITY, "Cache Byte Enable Parity Error" }, \ + { CXL_RAS_UC_CACHE_DATA_ECC, "Cache Data ECC Error" }, \ + { CXL_RAS_UC_MEM_DATA_PARITY, "Memory Data Parity Error" }, \ + { CXL_RAS_UC_MEM_ADDR_PARITY, "Memory Address Parity Error" }, \ + { CXL_RAS_UC_MEM_BE_PARITY, "Memory Byte Enable Parity Error" }, \ + { CXL_RAS_UC_MEM_DATA_ECC, "Memory Data ECC Error" }, \ + { CXL_RAS_UC_REINIT_THRESH, "REINIT Threshold Hit" }, \ + { CXL_RAS_UC_RSVD_ENCODE, "Received Unrecognized Encoding" }, \ + { CXL_RAS_UC_POISON, "Received Poison From Peer" }, \ + { CXL_RAS_UC_RECV_OVERFLOW, "Receiver Overflow" }, \ + { CXL_RAS_UC_INTERNAL_ERR, "Component Specific Error" }, \ + { CXL_RAS_UC_IDE_TX_ERR, "IDE Tx Error" }, \ + { CXL_RAS_UC_IDE_RX_ERR, "IDE Rx Error" } \ +) + +TRACE_EVENT(cxl_aer_uncorrectable_error, + TP_PROTO(const struct device *dev, u32 status, u32 fe, u32 *hl), + TP_ARGS(dev, status, fe, hl), + TP_STRUCT__entry( + __string(dev_name, dev_name(dev)) + __field(u32, status) + __field(u32, first_error) + __array(u32, header_log, CXL_HEADERLOG_SIZE_U32) + ), + TP_fast_assign( + __assign_str(dev_name, dev_name(dev)); + __entry->status = status; + __entry->first_error = fe; + /* + * Embed the 512B headerlog data for user app retrieval and + * parsing, but no need to print this in the trace buffer. + */ + memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE); + ), + TP_printk("%s: status: '%s' first_error: '%s'", + __get_str(dev_name), + show_uc_errs(__entry->status), + show_uc_errs(__entry->first_error) + ) +); + +#define CXL_RAS_CE_CACHE_DATA_ECC BIT(0) +#define CXL_RAS_CE_MEM_DATA_ECC BIT(1) +#define CXL_RAS_CE_CRC_THRESH BIT(2) +#define CLX_RAS_CE_RETRY_THRESH BIT(3) +#define CXL_RAS_CE_CACHE_POISON BIT(4) +#define CXL_RAS_CE_MEM_POISON BIT(5) +#define CXL_RAS_CE_PHYS_LAYER_ERR BIT(6) + +#define show_ce_errs(status) __print_flags(status, " | ", \ + { CXL_RAS_CE_CACHE_DATA_ECC, "Cache Data ECC Error" }, \ + { CXL_RAS_CE_MEM_DATA_ECC, "Memory Data ECC Error" }, \ + { CXL_RAS_CE_CRC_THRESH, "CRC Threshold Hit" }, \ + { CLX_RAS_CE_RETRY_THRESH, "Retry Threshold" }, \ + { CXL_RAS_CE_CACHE_POISON, "Received Cache Poison From Peer" }, \ + { CXL_RAS_CE_MEM_POISON, "Received Memory Poison From Peer" }, \ + { CXL_RAS_CE_PHYS_LAYER_ERR, "Received Error From Physical Layer" } \ +) + +TRACE_EVENT(cxl_aer_correctable_error, + TP_PROTO(const struct device *dev, u32 status), + TP_ARGS(dev, status), + TP_STRUCT__entry( + __string(dev_name, dev_name(dev)) + __field(u32, status) + ), + TP_fast_assign( + __assign_str(dev_name, dev_name(dev)); + __entry->status = status; + ), + TP_printk("%s: status: '%s'", + __get_str(dev_name), show_ce_errs(__entry->status) + ) +); + +#endif /* _CXL_EVENTS_H */ + +#define TRACE_INCLUDE_FILE trace +#include diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 1b1cf459ac77..aa3af3bb73b2 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -140,6 +140,8 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw) #define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0) #define CXL_RAS_HEADER_LOG_OFFSET 0x18 #define CXL_RAS_CAPABILITY_LENGTH 0x58 +#define CXL_HEADERLOG_SIZE SZ_512 +#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32) /* CXL 2.0 8.2.8.1 Device Capabilities Array Register */ #define CXLDEV_CAP_ARRAY_OFFSET 0x0 diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h index 920909791bb9..77dbdb980b12 100644 --- a/drivers/cxl/cxlpci.h +++ b/drivers/cxl/cxlpci.h @@ -66,4 +66,7 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port); struct cxl_dev_state; int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm); void read_cdat_data(struct cxl_port *port); +void cxl_cor_error_detected(struct pci_dev *pdev); +pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, + pci_channel_state_t state); #endif /* __CXL_PCI_H__ */ diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 33083a522fd1..3a66aadb4df0 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -14,8 +14,6 @@ #include "cxlmem.h" #include "cxlpci.h" #include "cxl.h" -#define CREATE_TRACE_POINTS -#include /** * DOC: cxl pci @@ -514,96 +512,6 @@ static const struct pci_device_id cxl_mem_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, cxl_mem_pci_tbl); -/* CXL spec rev3.0 8.2.4.16.1 */ -static void header_log_copy(struct cxl_dev_state *cxlds, u32 *log) -{ - void __iomem *addr; - u32 *log_addr; - int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32); - - addr = cxlds->regs.ras + CXL_RAS_HEADER_LOG_OFFSET; - log_addr = log; - - for (i = 0; i < log_u32_size; i++) { - *log_addr = readl(addr); - log_addr++; - addr += sizeof(u32); - } -} - -/* - * Log the state of the RAS status registers and prepare them to log the - * next error status. Return 1 if reset needed. - */ -static bool cxl_report_and_clear(struct cxl_dev_state *cxlds) -{ - struct cxl_memdev *cxlmd = cxlds->cxlmd; - struct device *dev = &cxlmd->dev; - u32 hl[CXL_HEADERLOG_SIZE_U32]; - void __iomem *addr; - u32 status; - u32 fe; - - if (!cxlds->regs.ras) - return false; - - addr = cxlds->regs.ras + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET; - status = readl(addr); - if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK)) - return false; - - /* If multiple errors, log header points to first error from ctrl reg */ - if (hweight32(status) > 1) { - addr = cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET; - fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, readl(addr))); - } else { - fe = status; - } - - header_log_copy(cxlds, hl); - trace_cxl_aer_uncorrectable_error(dev, status, fe, hl); - writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr); - - return true; -} - -static pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); - struct cxl_memdev *cxlmd = cxlds->cxlmd; - struct device *dev = &cxlmd->dev; - bool ue; - - /* - * A frozen channel indicates an impending reset which is fatal to - * CXL.mem operation, and will likely crash the system. On the off - * chance the situation is recoverable dump the status of the RAS - * capability registers and bounce the active state of the memdev. - */ - ue = cxl_report_and_clear(cxlds); - - switch (state) { - case pci_channel_io_normal: - if (ue) { - device_release_driver(dev); - return PCI_ERS_RESULT_NEED_RESET; - } - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - dev_warn(&pdev->dev, - "%s: frozen state error detected, disable CXL.mem\n", - dev_name(dev)); - device_release_driver(dev); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - dev_warn(&pdev->dev, - "failure state error detected, request disconnect\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - return PCI_ERS_RESULT_NEED_RESET; -} - static pci_ers_result_t cxl_slot_reset(struct pci_dev *pdev) { struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); @@ -628,25 +536,6 @@ static void cxl_error_resume(struct pci_dev *pdev) dev->driver ? "successful" : "failed"); } -static void cxl_cor_error_detected(struct pci_dev *pdev) -{ - struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); - struct cxl_memdev *cxlmd = cxlds->cxlmd; - struct device *dev = &cxlmd->dev; - void __iomem *addr; - u32 status; - - if (!cxlds->regs.ras) - return; - - addr = cxlds->regs.ras + CXL_RAS_CORRECTABLE_STATUS_OFFSET; - status = readl(addr); - if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) { - writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr); - trace_cxl_aer_correctable_error(dev, status); - } -} - static const struct pci_error_handlers cxl_error_handlers = { .error_detected = cxl_error_detected, .slot_reset = cxl_slot_reset, diff --git a/include/trace/events/cxl.h b/include/trace/events/cxl.h deleted file mode 100644 index ad085a2534ef..000000000000 --- a/include/trace/events/cxl.h +++ /dev/null @@ -1,112 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM cxl - -#if !defined(_CXL_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ) -#define _CXL_EVENTS_H - -#include - -#define CXL_HEADERLOG_SIZE SZ_512 -#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32) - -#define CXL_RAS_UC_CACHE_DATA_PARITY BIT(0) -#define CXL_RAS_UC_CACHE_ADDR_PARITY BIT(1) -#define CXL_RAS_UC_CACHE_BE_PARITY BIT(2) -#define CXL_RAS_UC_CACHE_DATA_ECC BIT(3) -#define CXL_RAS_UC_MEM_DATA_PARITY BIT(4) -#define CXL_RAS_UC_MEM_ADDR_PARITY BIT(5) -#define CXL_RAS_UC_MEM_BE_PARITY BIT(6) -#define CXL_RAS_UC_MEM_DATA_ECC BIT(7) -#define CXL_RAS_UC_REINIT_THRESH BIT(8) -#define CXL_RAS_UC_RSVD_ENCODE BIT(9) -#define CXL_RAS_UC_POISON BIT(10) -#define CXL_RAS_UC_RECV_OVERFLOW BIT(11) -#define CXL_RAS_UC_INTERNAL_ERR BIT(14) -#define CXL_RAS_UC_IDE_TX_ERR BIT(15) -#define CXL_RAS_UC_IDE_RX_ERR BIT(16) - -#define show_uc_errs(status) __print_flags(status, " | ", \ - { CXL_RAS_UC_CACHE_DATA_PARITY, "Cache Data Parity Error" }, \ - { CXL_RAS_UC_CACHE_ADDR_PARITY, "Cache Address Parity Error" }, \ - { CXL_RAS_UC_CACHE_BE_PARITY, "Cache Byte Enable Parity Error" }, \ - { CXL_RAS_UC_CACHE_DATA_ECC, "Cache Data ECC Error" }, \ - { CXL_RAS_UC_MEM_DATA_PARITY, "Memory Data Parity Error" }, \ - { CXL_RAS_UC_MEM_ADDR_PARITY, "Memory Address Parity Error" }, \ - { CXL_RAS_UC_MEM_BE_PARITY, "Memory Byte Enable Parity Error" }, \ - { CXL_RAS_UC_MEM_DATA_ECC, "Memory Data ECC Error" }, \ - { CXL_RAS_UC_REINIT_THRESH, "REINIT Threshold Hit" }, \ - { CXL_RAS_UC_RSVD_ENCODE, "Received Unrecognized Encoding" }, \ - { CXL_RAS_UC_POISON, "Received Poison From Peer" }, \ - { CXL_RAS_UC_RECV_OVERFLOW, "Receiver Overflow" }, \ - { CXL_RAS_UC_INTERNAL_ERR, "Component Specific Error" }, \ - { CXL_RAS_UC_IDE_TX_ERR, "IDE Tx Error" }, \ - { CXL_RAS_UC_IDE_RX_ERR, "IDE Rx Error" } \ -) - -TRACE_EVENT(cxl_aer_uncorrectable_error, - TP_PROTO(const struct device *dev, u32 status, u32 fe, u32 *hl), - TP_ARGS(dev, status, fe, hl), - TP_STRUCT__entry( - __string(dev_name, dev_name(dev)) - __field(u32, status) - __field(u32, first_error) - __array(u32, header_log, CXL_HEADERLOG_SIZE_U32) - ), - TP_fast_assign( - __assign_str(dev_name, dev_name(dev)); - __entry->status = status; - __entry->first_error = fe; - /* - * Embed the 512B headerlog data for user app retrieval and - * parsing, but no need to print this in the trace buffer. - */ - memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE); - ), - TP_printk("%s: status: '%s' first_error: '%s'", - __get_str(dev_name), - show_uc_errs(__entry->status), - show_uc_errs(__entry->first_error) - ) -); - -#define CXL_RAS_CE_CACHE_DATA_ECC BIT(0) -#define CXL_RAS_CE_MEM_DATA_ECC BIT(1) -#define CXL_RAS_CE_CRC_THRESH BIT(2) -#define CLX_RAS_CE_RETRY_THRESH BIT(3) -#define CXL_RAS_CE_CACHE_POISON BIT(4) -#define CXL_RAS_CE_MEM_POISON BIT(5) -#define CXL_RAS_CE_PHYS_LAYER_ERR BIT(6) - -#define show_ce_errs(status) __print_flags(status, " | ", \ - { CXL_RAS_CE_CACHE_DATA_ECC, "Cache Data ECC Error" }, \ - { CXL_RAS_CE_MEM_DATA_ECC, "Memory Data ECC Error" }, \ - { CXL_RAS_CE_CRC_THRESH, "CRC Threshold Hit" }, \ - { CLX_RAS_CE_RETRY_THRESH, "Retry Threshold" }, \ - { CXL_RAS_CE_CACHE_POISON, "Received Cache Poison From Peer" }, \ - { CXL_RAS_CE_MEM_POISON, "Received Memory Poison From Peer" }, \ - { CXL_RAS_CE_PHYS_LAYER_ERR, "Received Error From Physical Layer" } \ -) - -TRACE_EVENT(cxl_aer_correctable_error, - TP_PROTO(const struct device *dev, u32 status), - TP_ARGS(dev, status), - TP_STRUCT__entry( - __string(dev_name, dev_name(dev)) - __field(u32, status) - ), - TP_fast_assign( - __assign_str(dev_name, dev_name(dev)); - __entry->status = status; - ), - TP_printk("%s: status: '%s'", - __get_str(dev_name), show_ce_errs(__entry->status) - ) -); - -#endif /* _CXL_EVENTS_H */ - -/* This part must be outside protection */ -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE cxl -#include diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index 0805f08af8b3..12af1c9270ff 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -17,6 +17,7 @@ CXL_SRC := $(DRIVERS)/cxl CXL_CORE_SRC := $(DRIVERS)/cxl/core ccflags-y := -I$(srctree)/drivers/cxl/ ccflags-y += -D__mock=__weak +ccflags-y += -DTRACE_INCLUDE_PATH=$(CXL_CORE_SRC) -I$(srctree)/drivers/cxl/core/ obj-m += cxl_acpi.o @@ -49,6 +50,7 @@ cxl_core-y += $(CXL_CORE_SRC)/memdev.o cxl_core-y += $(CXL_CORE_SRC)/mbox.o cxl_core-y += $(CXL_CORE_SRC)/pci.o cxl_core-y += $(CXL_CORE_SRC)/hdm.o +cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o cxl_core-y += config_check.o -- cgit v1.2.3 From a4b2e6063cfeaab1160501acfb27e8618a7c693f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 15 Dec 2022 16:20:23 +0100 Subject: firmware: xilinx: Clear IOCTL_SET_SD_TAPDELAY using PM_MMIO_WRITE In case the tap delay required by Arasan SDHCI is set to 0, the current embeddedsw firmware unconditionally writes IOU_SLCR SD_ITAPDLY to 0x100 (SD0_ITAPDLYENA=1, SD0_ITAPDLYSEL=0). Previous behavior was to keep the IOU_SLCR SD_ITAPDLY set to 0x0. There is some sort of difference in the behavior between SD0_ITAPDLYENA=1/0 with the same SD0_ITAPDLYSEL=0, even though the behavior should be identical -- zero delay added to rxclk_in line. The former breaks HS200 training in low temperature conditions. Write IOU_SLCR SD_ITAPDLY register to 0 using PM_MMIO_WRITE which seem to allow unrestricted WRITE access (and PM_MMIO_READ which allows read access) to the entire address space. This way, it is possible to work around the defect in IOCTL_SET_SD_TAPDELAY design which does not permit clearing SDx_ITAPDLYENA bit. Note that the embeddedsw firmware does not permit clearing the SD_ITAPDLY SD0_ITAPDLYENA bit, this bit can only ever be set by the firmware and it is often impossible to update the possibly broken firmware. Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20221215152023.8387-1-marex@denx.de Signed-off-by: Michal Simek --- drivers/firmware/xilinx/zynqmp.c | 27 +++++++++++++++++++++++++-- include/linux/firmware/xlnx-zynqmp.h | 4 ++++ 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 129f68d7a6f5..acd83d29c866 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -738,8 +738,31 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data); */ int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SET_SD_TAPDELAY, - type, value, NULL); + u32 reg = (type == PM_TAPDELAY_INPUT) ? SD_ITAPDLY : SD_OTAPDLYSEL; + u32 mask = (node_id == NODE_SD_0) ? GENMASK(15, 0) : GENMASK(31, 16); + + if (value) { + return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, + IOCTL_SET_SD_TAPDELAY, + type, value, NULL); + } + + /* + * Work around completely misdesigned firmware API on Xilinx ZynqMP. + * The IOCTL_SET_SD_TAPDELAY firmware call allows the caller to only + * ever set IOU_SLCR SD_ITAPDLY Register SD0_ITAPDLYENA/SD1_ITAPDLYENA + * bits, but there is no matching call to clear those bits. If those + * bits are not cleared, SDMMC tuning may fail. + * + * Luckily, there are PM_MMIO_READ/PM_MMIO_WRITE calls which seem to + * allow complete unrestricted access to all address space, including + * IOU_SLCR SD_ITAPDLY Register and all the other registers, access + * to which was supposed to be protected by the current firmware API. + * + * Use PM_MMIO_READ/PM_MMIO_WRITE to re-implement the missing counter + * part of IOCTL_SET_SD_TAPDELAY which clears SDx_ITAPDLYENA bits. + */ + return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, reg, mask, 0, 0, NULL); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay); diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index b986e267d149..eb88b4ba62f9 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -79,6 +79,10 @@ #define EVENT_ERROR_PSM_ERR1 (0x28108000U) #define EVENT_ERROR_PSM_ERR2 (0x2810C000U) +/* ZynqMP SD tap delay tuning */ +#define SD_ITAPDLY 0xFF180314 +#define SD_OTAPDLYSEL 0xFF180318 + enum pm_api_cb_id { PM_INIT_SUSPEND_CB = 30, PM_ACKNOWLEDGE_CB = 31, -- cgit v1.2.3 From 991f1372d028ddc135c732f97bf909d72ca8b0b0 Mon Sep 17 00:00:00 2001 From: Melody Olvera Date: Fri, 16 Dec 2022 15:09:13 -0800 Subject: dt-bindings: interconnect: Add QDU1000/QRU1000 devices Add separate schema for QDU1000 and QRU1000 interconnect devices to document the different NoCs on these platforms. Signed-off-by: Melody Olvera Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20221216230914.21771-2-quic_molvera@quicinc.com Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,qdu1000-rpmh.yaml | 70 ++++++++++++++++ .../dt-bindings/interconnect/qcom,qdu1000-rpmh.h | 98 ++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 Documentation/devicetree/bindings/interconnect/qcom,qdu1000-rpmh.yaml create mode 100644 include/dt-bindings/interconnect/qcom,qdu1000-rpmh.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qdu1000-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,qdu1000-rpmh.yaml new file mode 100644 index 000000000000..0070b0396e31 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,qdu1000-rpmh.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,qdu1000-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on QDU1000 + +maintainers: + - Georgi Djakov + - Odelu Kukatla + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + +properties: + compatible: + enum: + - qcom,qdu1000-clk-virt + - qcom,qdu1000-gem-noc + - qcom,qdu1000-mc-virt + - qcom,qdu1000-system-noc + + '#interconnect-cells': true + + reg: + maxItems: 1 + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,qdu1000-clk-virt + - qcom,qdu1000-mc-virt + then: + properties: + reg: false + else: + required: + - reg + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + + system_noc: interconnect@1640000 { + compatible = "qcom,qdu1000-system-noc"; + reg = <0x1640000 0x45080>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + clk_virt: interconnect-0 { + compatible = "qcom,qdu1000-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/include/dt-bindings/interconnect/qcom,qdu1000-rpmh.h b/include/dt-bindings/interconnect/qcom,qdu1000-rpmh.h new file mode 100644 index 000000000000..7f0ad1571128 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,qdu1000-rpmh.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_QDU1000_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_QDU1000_H + +#define MASTER_QUP_CORE_0 0 +#define MASTER_QUP_CORE_1 1 +#define SLAVE_QUP_CORE_0 2 +#define SLAVE_QUP_CORE_1 3 + +#define MASTER_SYS_TCU 0 +#define MASTER_APPSS_PROC 1 +#define MASTER_GEMNOC_ECPRI_DMA 2 +#define MASTER_FEC_2_GEMNOC 3 +#define MASTER_ANOC_PCIE_GEM_NOC 4 +#define MASTER_SNOC_GC_MEM_NOC 5 +#define MASTER_SNOC_SF_MEM_NOC 6 +#define MASTER_MSS_PROC 7 +#define SLAVE_GEM_NOC_CNOC 8 +#define SLAVE_LLCC 9 +#define SLAVE_GEMNOC_MODEM_CNOC 10 +#define SLAVE_MEM_NOC_PCIE_SNOC 11 + +#define MASTER_LLCC 0 +#define SLAVE_EBI1 1 + +#define MASTER_GIC_AHB 0 +#define MASTER_QDSS_BAM 1 +#define MASTER_QPIC 2 +#define MASTER_QSPI_0 3 +#define MASTER_QUP_0 4 +#define MASTER_QUP_1 5 +#define MASTER_SNOC_CFG 6 +#define MASTER_ANOC_SNOC 7 +#define MASTER_ANOC_GSI 8 +#define MASTER_GEM_NOC_CNOC 9 +#define MASTER_GEMNOC_MODEM_CNOC 10 +#define MASTER_GEM_NOC_PCIE_SNOC 11 +#define MASTER_CRYPTO 12 +#define MASTER_ECPRI_GSI 13 +#define MASTER_PIMEM 14 +#define MASTER_SNOC_ECPRI_DMA 15 +#define MASTER_GIC 16 +#define MASTER_PCIE 17 +#define MASTER_QDSS_ETR 18 +#define MASTER_QDSS_ETR_1 19 +#define MASTER_SDCC_1 20 +#define MASTER_USB3 21 +#define SLAVE_AHB2PHY_SOUTH 22 +#define SLAVE_AHB2PHY_NORTH 23 +#define SLAVE_AHB2PHY_EAST 24 +#define SLAVE_AOSS 25 +#define SLAVE_CLK_CTL 26 +#define SLAVE_RBCPR_CX_CFG 27 +#define SLAVE_RBCPR_MX_CFG 28 +#define SLAVE_CRYPTO_0_CFG 29 +#define SLAVE_ECPRI_CFG 30 +#define SLAVE_IMEM_CFG 31 +#define SLAVE_IPC_ROUTER_CFG 32 +#define SLAVE_CNOC_MSS 33 +#define SLAVE_PCIE_CFG 34 +#define SLAVE_PDM 35 +#define SLAVE_PIMEM_CFG 36 +#define SLAVE_PRNG 37 +#define SLAVE_QDSS_CFG 38 +#define SLAVE_QPIC 40 +#define SLAVE_QSPI_0 41 +#define SLAVE_QUP_0 42 +#define SLAVE_QUP_1 43 +#define SLAVE_SDCC_2 44 +#define SLAVE_SMBUS_CFG 45 +#define SLAVE_SNOC_CFG 46 +#define SLAVE_TCSR 47 +#define SLAVE_TLMM 48 +#define SLAVE_TME_CFG 49 +#define SLAVE_TSC_CFG 50 +#define SLAVE_USB3_0 51 +#define SLAVE_VSENSE_CTRL_CFG 52 +#define SLAVE_A1NOC_SNOC 53 +#define SLAVE_ANOC_SNOC_GSI 54 +#define SLAVE_DDRSS_CFG 55 +#define SLAVE_ECPRI_GEMNOC 56 +#define SLAVE_SNOC_GEM_NOC_GC 57 +#define SLAVE_SNOC_GEM_NOC_SF 58 +#define SLAVE_MODEM_OFFLINE 59 +#define SLAVE_ANOC_PCIE_GEM_NOC 60 +#define SLAVE_IMEM 61 +#define SLAVE_PIMEM 62 +#define SLAVE_SERVICE_SNOC 63 +#define SLAVE_ETHERNET_SS 64 +#define SLAVE_PCIE_0 65 +#define SLAVE_QDSS_STM 66 +#define SLAVE_TCU 67 + +#endif -- cgit v1.2.3 From 439a1bcac648fe9b59210cde8991fb2acf37bdab Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 19 Sep 2022 15:53:13 -0700 Subject: fortify: Use __builtin_dynamic_object_size() when available Since the commits starting with c37495d6254c ("slab: add __alloc_size attributes for better bounds checking"), the compilers have runtime allocation size hints available in some places. This was immediately available to CONFIG_UBSAN_BOUNDS, but CONFIG_FORTIFY_SOURCE needed updating to explicitly make use of the hints via the associated __builtin_dynamic_object_size() helper. Detect and use the builtin when it is available, increasing the accuracy of the mitigation. When runtime sizes are not available, __builtin_dynamic_object_size() falls back to __builtin_object_size(), leaving the existing bounds checking unchanged. Additionally update the VMALLOC_LINEAR_OVERFLOW LKDTM test to make the hint invisible, otherwise the architectural defense is not exercised (the buffer overflow is detected in the memset() rather than when it crosses the edge of the allocation). Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: Nick Desaulniers Cc: Nathan Chancellor Cc: Tom Rix Cc: linux-hardening@vger.kernel.org Cc: llvm@lists.linux.dev Reviewed-by: Miguel Ojeda # include/linux/compiler_attributes.h Signed-off-by: Kees Cook --- drivers/misc/lkdtm/heap.c | 1 + include/linux/compiler_attributes.h | 5 +++++ include/linux/fortify-string.h | 7 +++++++ 3 files changed, 13 insertions(+) (limited to 'include') diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index 62516078a619..0ce4cbf6abda 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c @@ -31,6 +31,7 @@ static void lkdtm_VMALLOC_LINEAR_OVERFLOW(void) char *one, *two; one = vzalloc(PAGE_SIZE); + OPTIMIZER_HIDE_VAR(one); two = vzalloc(PAGE_SIZE); pr_info("Attempting vmalloc linear overflow ...\n"); diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h index 898b3458b24a..56467f86a27c 100644 --- a/include/linux/compiler_attributes.h +++ b/include/linux/compiler_attributes.h @@ -297,6 +297,11 @@ * * clang: https://clang.llvm.org/docs/AttributeReference.html#pass-object-size-pass-dynamic-object-size */ +#if __has_attribute(__pass_dynamic_object_size__) +# define __pass_dynamic_object_size(type) __attribute__((__pass_dynamic_object_size__(type))) +#else +# define __pass_dynamic_object_size(type) +#endif #if __has_attribute(__pass_object_size__) # define __pass_object_size(type) __attribute__((__pass_object_size__(type))) #else diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index 7cad8bb031e9..c9de1f59ee80 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -90,10 +90,17 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) * size, rather than struct size), but there remain some stragglers using * type 0 that will be converted in the future. */ +#if __has_builtin(__builtin_dynamic_object_size) +#define POS __pass_dynamic_object_size(1) +#define POS0 __pass_dynamic_object_size(0) +#define __struct_size(p) __builtin_dynamic_object_size(p, 0) +#define __member_size(p) __builtin_dynamic_object_size(p, 1) +#else #define POS __pass_object_size(1) #define POS0 __pass_object_size(0) #define __struct_size(p) __builtin_object_size(p, 0) #define __member_size(p) __builtin_object_size(p, 1) +#endif #define __compiletime_lessthan(bounds, length) ( \ __builtin_constant_p((bounds) < (length)) && \ -- cgit v1.2.3 From 3ca0a6ea8f6de0f21a9331ff3596a9c073fbdab0 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sat, 19 Nov 2022 17:25:04 +0800 Subject: sched: Add helper kstat_cpu_softirqs_sum() Add a kstat_cpu_softirqs_sum() function that is similar to kstat_cpu_irqs_sum(), but which counts software interrupts since boot on the specified CPU. Signed-off-by: Zhen Lei Cc: Josh Don Cc: Tejun Heo Cc: Peter Zijlstra Reviewed-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- include/linux/kernel_stat.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 90e2fdc17d79..898076e173a9 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -67,6 +67,17 @@ static inline unsigned int kstat_softirqs_cpu(unsigned int irq, int cpu) return kstat_cpu(cpu).softirqs[irq]; } +static inline unsigned int kstat_cpu_softirqs_sum(int cpu) +{ + int i; + unsigned int sum = 0; + + for (i = 0; i < NR_SOFTIRQS; i++) + sum += kstat_softirqs_cpu(i, cpu); + + return sum; +} + /* * Number of interrupts per specific IRQ source, since bootup */ -- cgit v1.2.3 From 7c182722a0a9447e31f9645de4f311e5bc59b480 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sat, 19 Nov 2022 17:25:05 +0800 Subject: sched: Add helper nr_context_switches_cpu() Add a function nr_context_switches_cpu() that returns number of context switches since boot on the specified CPU. This information will be used to diagnose RCU CPU stalls. Signed-off-by: Zhen Lei Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Juri Lelli Cc: Vincent Guittot Cc: Dietmar Eggemann Cc: Steven Rostedt Cc: Ben Segall Cc: Mel Gorman Cc: Daniel Bristot de Oliveira Cc: Valentin Schneider Reviewed-by: Frederic Weisbecker Signed-off-by: Paul E. McKenney --- include/linux/kernel_stat.h | 1 + kernel/sched/core.c | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'include') diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 898076e173a9..9935f7ecbfb9 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -52,6 +52,7 @@ DECLARE_PER_CPU(struct kernel_cpustat, kernel_cpustat); #define kstat_cpu(cpu) per_cpu(kstat, cpu) #define kcpustat_cpu(cpu) per_cpu(kernel_cpustat, cpu) +extern unsigned long long nr_context_switches_cpu(int cpu); extern unsigned long long nr_context_switches(void); extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 25b582b6ee5f..2e40a6c116e1 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5282,6 +5282,11 @@ bool single_task_running(void) } EXPORT_SYMBOL(single_task_running); +unsigned long long nr_context_switches_cpu(int cpu) +{ + return cpu_rq(cpu)->nr_switches; +} + unsigned long long nr_context_switches(void) { int i; -- cgit v1.2.3 From 589c3357370a596ef7c99c00baca8ac799fce531 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Sun, 11 Dec 2022 23:06:19 -0800 Subject: PCI/CXL: Export native CXL error reporting control CXL _OSC Error Reporting Control is used by the OS to determine if Firmware has control of various CXL error reporting capabilities including the event logs. Expose the result of negotiating CXL Error Reporting Control in struct pci_host_bridge for consumption by the CXL drivers. Cc: Bjorn Helgaas Cc: Lukas Wunner Cc: linux-pci@vger.kernel.org Cc: linux-acpi@vger.kernel.org Signed-off-by: Ira Weiny Acked-by: Bjorn Helgaas Reviewed-by: Jonathan Cameron Reviewed-by: Dan Williams Link: https://lore.kernel.org/r/20221212070627.1372402-2-ira.weiny@intel.com Signed-off-by: Dan Williams --- drivers/acpi/pci_root.c | 3 +++ drivers/pci/probe.c | 1 + include/linux/pci.h | 1 + 3 files changed, 5 insertions(+) (limited to 'include') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index b3c202d2a433..84030804a763 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -1047,6 +1047,9 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, if (!(root->osc_control_set & OSC_PCI_EXPRESS_DPC_CONTROL)) host_bridge->native_dpc = 0; + if (!(root->osc_ext_control_set & OSC_CXL_ERROR_REPORTING_CONTROL)) + host_bridge->native_cxl_error = 0; + /* * Evaluate the "PCI Boot Configuration" _DSM Function. If it * exists and returns 0, we must preserve any PCI resource diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 1779582fb500..f796dfb9b14b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -596,6 +596,7 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge) bridge->native_ltr = 1; bridge->native_dpc = 1; bridge->domain_nr = PCI_DOMAIN_NR_NOT_SET; + bridge->native_cxl_error = 1; device_initialize(&bridge->dev); } diff --git a/include/linux/pci.h b/include/linux/pci.h index adffd65e84b4..22319ea71ab0 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -578,6 +578,7 @@ struct pci_host_bridge { unsigned int native_pme:1; /* OS may use PCIe PME */ unsigned int native_ltr:1; /* OS may use PCIe LTR */ unsigned int native_dpc:1; /* OS may use PCIe DPC */ + unsigned int native_cxl_error:1; /* OS may use CXL RAS/Events */ unsigned int preserve_config:1; /* Preserve FW resource setup */ unsigned int size_windows:1; /* Enable root bus sizing */ unsigned int msi_domain:1; /* Bridge wants MSI domain */ -- cgit v1.2.3 From 37e2b57078d412547f1c14bb83eff86ab9d92d3d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sat, 3 Sep 2022 00:08:51 +0100 Subject: exportfs: Replace zero-length array with DECLARE_FLEX_ARRAY() helper Zero-length arrays are deprecated and we are moving towards adopting C99 flexible-array members instead. So, replace zero-length array declaration in struct fid with the new DECLARE_FLEX_ARRAY() helper macro. This helper allows for a flexible-array member in a union. Link: https://github.com/KSPP/linux/issues/21 Link: https://github.com/KSPP/linux/issues/193 Link: https://github.com/KSPP/linux/issues/197 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Reviewed-by: Kees Cook Signed-off-by: Gustavo A. R. Silva --- include/linux/exportfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index fe848901fcc3..1640d97e4c0d 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h @@ -131,7 +131,7 @@ struct fid { u32 parent_block; u32 parent_generation; } udf; - __u32 raw[0]; + DECLARE_FLEX_ARRAY(__u32, raw); }; }; -- cgit v1.2.3 From 06919d226d01132c03d851966d4df3870fa1b55a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sat, 3 Sep 2022 00:17:18 +0100 Subject: mm/memremap: Replace zero-length array with DECLARE_FLEX_ARRAY() helper Zero-length arrays are deprecated and we are moving towards adopting C99 flexible-array members, instead. So, replace zero-length array declaration in struct dev_pagemap with the new DECLARE_FLEX_ARRAY() helper macro. This helper allows for a flexible-array member in a union. Also, this addresses multiple warnings reported when building with Clang-15 and -Wzero-length-array. Link: https://github.com/KSPP/linux/issues/193 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Reviewed-by: Kees Cook Signed-off-by: Gustavo A. R. Silva --- include/linux/memremap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/memremap.h b/include/linux/memremap.h index 7fcaf3180a5b..1314d9c5f05b 100644 --- a/include/linux/memremap.h +++ b/include/linux/memremap.h @@ -135,7 +135,7 @@ struct dev_pagemap { int nr_range; union { struct range range; - struct range ranges[0]; + DECLARE_FLEX_ARRAY(struct range, ranges); }; }; -- cgit v1.2.3 From d90fa2c64d59f5f151beeef5dbc599784b3391ca Mon Sep 17 00:00:00 2001 From: Rob Barnes Date: Wed, 4 Jan 2023 01:15:23 +0000 Subject: platform/chrome: cros_ec: Poll EC log on EC panic Add handler for CrOS EC panic events. When a panic is reported, immediately poll for EC log. This should result in the log leading to the EC panic being preserved. ACPI_NOTIFY_CROS_EC_PANIC is defined in coreboot at https://review.coreboot.org/plugins/gitiles/coreboot/+/refs/heads/master/src/ec/google/chromeec/acpi/ec.asl Signed-off-by: Rob Barnes Reviewed-by: Prashant Malani Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20230104011524.369764-2-robbarnes@google.com --- drivers/platform/chrome/cros_ec_debugfs.c | 23 +++++++++++++++++++++++ drivers/platform/chrome/cros_ec_lpc.c | 7 +++++++ include/linux/platform_data/cros_ec_proto.h | 9 +++++++++ 3 files changed, 39 insertions(+) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index 21d973fc6be2..34f7b46f8761 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -49,6 +49,7 @@ struct cros_ec_debugfs { struct delayed_work log_poll_work; /* EC panicinfo */ struct debugfs_blob_wrapper panicinfo_blob; + struct notifier_block notifier_panic; }; /* @@ -437,6 +438,22 @@ free: return ret; } +static int cros_ec_debugfs_panic_event(struct notifier_block *nb, + unsigned long queued_during_suspend, void *_notify) +{ + struct cros_ec_debugfs *debug_info = + container_of(nb, struct cros_ec_debugfs, notifier_panic); + + if (debug_info->log_buffer.buf) { + /* Force log poll work to run immediately */ + mod_delayed_work(debug_info->log_poll_work.wq, &debug_info->log_poll_work, 0); + /* Block until log poll work finishes */ + flush_delayed_work(&debug_info->log_poll_work); + } + + return NOTIFY_DONE; +} + static int cros_ec_debugfs_probe(struct platform_device *pd) { struct cros_ec_dev *ec = dev_get_drvdata(pd->dev.parent); @@ -473,6 +490,12 @@ static int cros_ec_debugfs_probe(struct platform_device *pd) debugfs_create_u16("suspend_timeout_ms", 0664, debug_info->dir, &ec->ec_dev->suspend_timeout_ms); + debug_info->notifier_panic.notifier_call = cros_ec_debugfs_panic_event; + ret = blocking_notifier_chain_register(&ec->ec_dev->panic_notifier, + &debug_info->notifier_panic); + if (ret) + goto remove_debugfs; + ec->debug_info = debug_info; dev_set_drvdata(&pd->dev, ec); diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 7fc8f82280ac..5738f1d25091 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -320,6 +320,13 @@ static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data) ec_dev->last_event_time = cros_ec_get_time_ns(); + if (value == ACPI_NOTIFY_CROS_EC_PANIC) { + dev_emerg(ec_dev->dev, "CrOS EC Panic Reported. Shutdown is imminent!"); + blocking_notifier_call_chain(&ec_dev->panic_notifier, 0, ec_dev); + /* Do not query for other events after a panic is reported */ + return; + } + if (ec_dev->mkbp_event_supported) do { ret = cros_ec_get_next_event(ec_dev, NULL, diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index e43107e0bee1..7fb2196f99b0 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -41,6 +41,13 @@ #define EC_MAX_REQUEST_OVERHEAD 1 #define EC_MAX_RESPONSE_OVERHEAD 32 +/* + * EC panic is not covered by the standard (0-F) ACPI notify values. + * Arbitrarily choosing B0 to notify ec panic, which is in the 84-BF + * device specific ACPI notify range. + */ +#define ACPI_NOTIFY_CROS_EC_PANIC 0xB0 + /* * Command interface between EC and AP, for LPC, I2C and SPI interfaces. */ @@ -176,6 +183,8 @@ struct cros_ec_device { /* The platform devices used by the mfd driver */ struct platform_device *ec; struct platform_device *pd; + + struct blocking_notifier_head panic_notifier; }; /** -- cgit v1.2.3 From 2c7bc10d0f7b0f66d9042ed88bb3ecd588352a00 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 4 Jan 2023 20:05:21 -0800 Subject: netlink: add macro for checking dump ctx size We encourage casting struct netlink_callback::ctx to a local struct (in a comment above the field). Provide a convenience macro for checking if the local struct fits into the ctx. Reviewed-by: Jacob Keller Reviewed-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- include/linux/netlink.h | 4 ++++ net/netfilter/nf_conntrack_netlink.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/netlink.h b/include/linux/netlink.h index d81bde5a5844..38f6334f408c 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -263,6 +263,10 @@ struct netlink_callback { }; }; +#define NL_ASSET_DUMP_CTX_FITS(type_name) \ + BUILD_BUG_ON(sizeof(type_name) > \ + sizeof_field(struct netlink_callback, ctx)) + struct netlink_notify { struct net *net; u32 portid; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 1286ae7d4609..90672e293e57 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -3866,7 +3866,7 @@ static int __init ctnetlink_init(void) { int ret; - BUILD_BUG_ON(sizeof(struct ctnetlink_list_dump_ctx) > sizeof_field(struct netlink_callback, ctx)); + NL_ASSET_DUMP_CTX_FITS(struct ctnetlink_list_dump_ctx); ret = nfnetlink_subsys_register(&ctnl_subsys); if (ret < 0) { -- cgit v1.2.3 From 1c4428b295884316eaff16be9c1d85f7c2361696 Mon Sep 17 00:00:00 2001 From: Nicolai Stange Date: Thu, 29 Dec 2022 22:17:05 +0100 Subject: crypto: xts - restrict key lengths to approved values in FIPS mode According to FIPS 140-3 IG C.I., only (total) key lengths of either 256 bits or 512 bits are allowed with xts(aes). Make xts_verify_key() to reject anything else in FIPS mode. As xts(aes) is the only approved xts() template instantiation in FIPS mode, the new restriction implemented in xts_verify_key() effectively only applies to this particular construction. Signed-off-by: Nicolai Stange Signed-off-by: Vladis Dronov Signed-off-by: Herbert Xu --- include/crypto/xts.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/crypto/xts.h b/include/crypto/xts.h index 0f8dba69feb4..a233c1054df2 100644 --- a/include/crypto/xts.h +++ b/include/crypto/xts.h @@ -35,6 +35,13 @@ static inline int xts_verify_key(struct crypto_skcipher *tfm, if (keylen % 2) return -EINVAL; + /* + * In FIPS mode only a combined key length of either 256 or + * 512 bits is allowed, c.f. FIPS 140-3 IG C.I. + */ + if (fips_enabled && keylen != 32 && keylen != 64) + return -EINVAL; + /* ensure that the AES and tweak key are not identical */ if ((fips_enabled || (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) && -- cgit v1.2.3 From 0ee433676e4f499cb65f3d375a60a0ac54af4c47 Mon Sep 17 00:00:00 2001 From: Vladis Dronov Date: Thu, 29 Dec 2022 22:17:06 +0100 Subject: crypto: xts - drop xts_check_key() xts_check_key() is obsoleted by xts_verify_key(). Over time XTS crypto drivers adopted the newer xts_verify_key() variant, but xts_check_key() is still used by a number of drivers. Switch drivers to use the newer xts_verify_key() and make a couple of cleanups. This allows us to drop xts_check_key() completely and avoid redundancy. Signed-off-by: Vladis Dronov Reviewed-by: Eric Biggers Reviewed-by: Nicolai Stange Signed-off-by: Herbert Xu --- arch/s390/crypto/paes_s390.c | 2 +- drivers/crypto/atmel-aes.c | 2 +- drivers/crypto/axis/artpec6_crypto.c | 2 +- drivers/crypto/cavium/cpt/cptvf_algs.c | 8 +++----- drivers/crypto/cavium/nitrox/nitrox_skcipher.c | 8 +++----- drivers/crypto/ccree/cc_cipher.c | 2 +- drivers/crypto/marvell/octeontx/otx_cptvf_algs.c | 2 +- drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c | 2 +- include/crypto/xts.h | 22 ++++------------------ 9 files changed, 16 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c index a279b7d23a5e..29dc827e0fe8 100644 --- a/arch/s390/crypto/paes_s390.c +++ b/arch/s390/crypto/paes_s390.c @@ -474,7 +474,7 @@ static int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, return rc; /* - * xts_check_key verifies the key length is not odd and makes + * xts_verify_key verifies the key length is not odd and makes * sure that the two keys are not the same. This can be done * on the two protected keys as well */ diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 063394cfa874..e90e4a6cc37a 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -1879,7 +1879,7 @@ static int atmel_aes_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, struct atmel_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); int err; - err = xts_check_key(crypto_skcipher_tfm(tfm), key, keylen); + err = xts_verify_key(tfm, key, keylen); if (err) return err; diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index 51c66afbe677..f6f41e316dfe 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -1621,7 +1621,7 @@ artpec6_crypto_xts_set_key(struct crypto_skcipher *cipher, const u8 *key, crypto_skcipher_ctx(cipher); int ret; - ret = xts_check_key(&cipher->base, key, keylen); + ret = xts_verify_key(cipher, key, keylen); if (ret) return ret; diff --git a/drivers/crypto/cavium/cpt/cptvf_algs.c b/drivers/crypto/cavium/cpt/cptvf_algs.c index 9eca0c302186..0b38c2600b86 100644 --- a/drivers/crypto/cavium/cpt/cptvf_algs.c +++ b/drivers/crypto/cavium/cpt/cptvf_algs.c @@ -232,13 +232,12 @@ static int cvm_decrypt(struct skcipher_request *req) static int cvm_xts_setkey(struct crypto_skcipher *cipher, const u8 *key, u32 keylen) { - struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); - struct cvm_enc_ctx *ctx = crypto_tfm_ctx(tfm); + struct cvm_enc_ctx *ctx = crypto_skcipher_ctx(cipher); int err; const u8 *key1 = key; const u8 *key2 = key + (keylen / 2); - err = xts_check_key(tfm, key, keylen); + err = xts_verify_key(cipher, key, keylen); if (err) return err; ctx->key_len = keylen; @@ -289,8 +288,7 @@ static int cvm_validate_keylen(struct cvm_enc_ctx *ctx, u32 keylen) static int cvm_setkey(struct crypto_skcipher *cipher, const u8 *key, u32 keylen, u8 cipher_type) { - struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); - struct cvm_enc_ctx *ctx = crypto_tfm_ctx(tfm); + struct cvm_enc_ctx *ctx = crypto_skcipher_ctx(cipher); ctx->cipher_type = cipher_type; if (!cvm_validate_keylen(ctx, keylen)) { diff --git a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c index 248b4fff1c72..138261dcd032 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c +++ b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c @@ -337,12 +337,11 @@ static int nitrox_3des_decrypt(struct skcipher_request *skreq) static int nitrox_aes_xts_setkey(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { - struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); - struct nitrox_crypto_ctx *nctx = crypto_tfm_ctx(tfm); + struct nitrox_crypto_ctx *nctx = crypto_skcipher_ctx(cipher); struct flexi_crypto_context *fctx; int aes_keylen, ret; - ret = xts_check_key(tfm, key, keylen); + ret = xts_verify_key(cipher, key, keylen); if (ret) return ret; @@ -362,8 +361,7 @@ static int nitrox_aes_xts_setkey(struct crypto_skcipher *cipher, static int nitrox_aes_ctr_rfc3686_setkey(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { - struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); - struct nitrox_crypto_ctx *nctx = crypto_tfm_ctx(tfm); + struct nitrox_crypto_ctx *nctx = crypto_skcipher_ctx(cipher); struct flexi_crypto_context *fctx; int aes_keylen; diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index 309da6334a0a..2cd44d7457a4 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -460,7 +460,7 @@ static int cc_cipher_setkey(struct crypto_skcipher *sktfm, const u8 *key, } if (ctx_p->cipher_mode == DRV_CIPHER_XTS && - xts_check_key(tfm, key, keylen)) { + xts_verify_key(sktfm, key, keylen)) { dev_dbg(dev, "weak XTS key"); return -EINVAL; } diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c index 80ba77c793a7..83493dd0416f 100644 --- a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c +++ b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c @@ -398,7 +398,7 @@ static int otx_cpt_skcipher_xts_setkey(struct crypto_skcipher *tfm, const u8 *key1 = key; int ret; - ret = xts_check_key(crypto_skcipher_tfm(tfm), key, keylen); + ret = xts_verify_key(tfm, key, keylen); if (ret) return ret; ctx->key_len = keylen; diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c index 30b423605c9c..443202caa140 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c @@ -412,7 +412,7 @@ static int otx2_cpt_skcipher_xts_setkey(struct crypto_skcipher *tfm, const u8 *key1 = key; int ret; - ret = xts_check_key(crypto_skcipher_tfm(tfm), key, keylen); + ret = xts_verify_key(tfm, key, keylen); if (ret) return ret; ctx->key_len = keylen; diff --git a/include/crypto/xts.h b/include/crypto/xts.h index a233c1054df2..15b16c4853d8 100644 --- a/include/crypto/xts.h +++ b/include/crypto/xts.h @@ -8,23 +8,6 @@ #define XTS_BLOCK_SIZE 16 -static inline int xts_check_key(struct crypto_tfm *tfm, - const u8 *key, unsigned int keylen) -{ - /* - * key consists of keys of equal size concatenated, therefore - * the length must be even. - */ - if (keylen % 2) - return -EINVAL; - - /* ensure that the AES and tweak key are not identical */ - if (fips_enabled && !crypto_memneq(key, key + (keylen / 2), keylen / 2)) - return -EINVAL; - - return 0; -} - static inline int xts_verify_key(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) { @@ -42,7 +25,10 @@ static inline int xts_verify_key(struct crypto_skcipher *tfm, if (fips_enabled && keylen != 32 && keylen != 64) return -EINVAL; - /* ensure that the AES and tweak key are not identical */ + /* + * Ensure that the AES and tweak key are not identical when + * in FIPS mode or the FORBID_WEAK_KEYS flag is set. + */ if ((fips_enabled || (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)) && !crypto_memneq(key, key + (keylen / 2), keylen / 2)) -- cgit v1.2.3 From 9053637e0da783efdb37bbfea6a27b856c0228d7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 5 Jan 2023 22:33:58 -0800 Subject: devlink: remove the registration guarantee of references The objective of exposing the devlink instance locks to drivers was to let them use these locks to prevent user space from accessing the device before it's fully initialized. This is difficult because devlink_unregister() waits for all references to be released, meaning that devlink_unregister() can't itself be called under the instance lock. To avoid this issue devlink_register() was moved after subobject registration a while ago. Unfortunately the netdev paths get a hold of the devlink instances _before_ they are registered. Ideally netdev should wait for devlink init to finish (synchronizing on the instance lock). This can't work because we don't know if the instance will _ever_ be registered (in case of failures it may not). The other option of returning an error until devlink_register() is called is unappealing (user space would get a notification netdev exist but would have to wait arbitrary amount of time before accessing some of its attributes). Weaken the guarantees of the devlink references. Holding a reference will now only guarantee that the memory of the object is around. Another way of looking at it is that the reference now protects the object not its "registered" status. Use devlink instance lock to synchronize unregistration. This implies that releasing of the "main" reference of the devlink instance moves from devlink_unregister() to devlink_free(). Reviewed-by: Jacob Keller Signed-off-by: Jakub Kicinski Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/devlink.h | 2 ++ net/devlink/core.c | 64 ++++++++++++++++++++------------------------- net/devlink/devl_internal.h | 2 -- 3 files changed, 30 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/include/net/devlink.h b/include/net/devlink.h index 6a2e4f21779f..425ecef431b7 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1647,6 +1647,8 @@ static inline struct devlink *devlink_alloc(const struct devlink_ops *ops, return devlink_alloc_ns(ops, priv_size, &init_net, dev); } void devlink_set_features(struct devlink *devlink, u64 features); +int devl_register(struct devlink *devlink); +void devl_unregister(struct devlink *devlink); void devlink_register(struct devlink *devlink); void devlink_unregister(struct devlink *devlink); void devlink_free(struct devlink *devlink); diff --git a/net/devlink/core.c b/net/devlink/core.c index c53c996edf1d..7cf0b3efbb2f 100644 --- a/net/devlink/core.c +++ b/net/devlink/core.c @@ -83,21 +83,10 @@ struct devlink *__must_check devlink_try_get(struct devlink *devlink) return NULL; } -static void __devlink_put_rcu(struct rcu_head *head) -{ - struct devlink *devlink = container_of(head, struct devlink, rcu); - - complete(&devlink->comp); -} - void devlink_put(struct devlink *devlink) { if (refcount_dec_and_test(&devlink->refcount)) - /* Make sure unregister operation that may await the completion - * is unblocked only after all users are after the end of - * RCU grace period. - */ - call_rcu(&devlink->rcu, __devlink_put_rcu); + kfree_rcu(devlink, rcu); } struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp) @@ -110,13 +99,6 @@ retry: if (!devlink) goto unlock; - /* In case devlink_unregister() was already called and "unregistering" - * mark was set, do not allow to get a devlink reference here. - * This prevents live-lock of devlink_unregister() wait for completion. - */ - if (xa_get_mark(&devlinks, *indexp, DEVLINK_UNREGISTERING)) - goto next; - if (!devlink_try_get(devlink)) goto next; if (!net_eq(devlink_net(devlink), net)) { @@ -152,37 +134,48 @@ void devlink_set_features(struct devlink *devlink, u64 features) EXPORT_SYMBOL_GPL(devlink_set_features); /** - * devlink_register - Register devlink instance - * - * @devlink: devlink + * devl_register - Register devlink instance + * @devlink: devlink */ -void devlink_register(struct devlink *devlink) +int devl_register(struct devlink *devlink) { ASSERT_DEVLINK_NOT_REGISTERED(devlink); - /* Make sure that we are in .probe() routine */ + devl_assert_locked(devlink); xa_set_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); devlink_notify_register(devlink); + + return 0; +} +EXPORT_SYMBOL_GPL(devl_register); + +void devlink_register(struct devlink *devlink) +{ + devl_lock(devlink); + devl_register(devlink); + devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_register); /** - * devlink_unregister - Unregister devlink instance - * - * @devlink: devlink + * devl_unregister - Unregister devlink instance + * @devlink: devlink */ -void devlink_unregister(struct devlink *devlink) +void devl_unregister(struct devlink *devlink) { ASSERT_DEVLINK_REGISTERED(devlink); - /* Make sure that we are in .remove() routine */ - - xa_set_mark(&devlinks, devlink->index, DEVLINK_UNREGISTERING); - devlink_put(devlink); - wait_for_completion(&devlink->comp); + devl_assert_locked(devlink); devlink_notify_unregister(devlink); xa_clear_mark(&devlinks, devlink->index, DEVLINK_REGISTERED); - xa_clear_mark(&devlinks, devlink->index, DEVLINK_UNREGISTERING); +} +EXPORT_SYMBOL_GPL(devl_unregister); + +void devlink_unregister(struct devlink *devlink) +{ + devl_lock(devlink); + devl_unregister(devlink); + devl_unlock(devlink); } EXPORT_SYMBOL_GPL(devlink_unregister); @@ -246,7 +239,6 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops, mutex_init(&devlink->reporters_lock); mutex_init(&devlink->linecards_lock); refcount_set(&devlink->refcount, 1); - init_completion(&devlink->comp); return devlink; @@ -292,7 +284,7 @@ void devlink_free(struct devlink *devlink) xa_erase(&devlinks, devlink->index); - kfree(devlink); + devlink_put(devlink); } EXPORT_SYMBOL_GPL(devlink_free); diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h index 01a00df81d0e..5d2bbe295659 100644 --- a/net/devlink/devl_internal.h +++ b/net/devlink/devl_internal.h @@ -12,7 +12,6 @@ #include #define DEVLINK_REGISTERED XA_MARK_1 -#define DEVLINK_UNREGISTERING XA_MARK_2 #define DEVLINK_RELOAD_STATS_ARRAY_SIZE \ (__DEVLINK_RELOAD_LIMIT_MAX * __DEVLINK_RELOAD_ACTION_MAX) @@ -52,7 +51,6 @@ struct devlink { struct lock_class_key lock_key; u8 reload_failed:1; refcount_t refcount; - struct completion comp; struct rcu_head rcu; struct notifier_block netdevice_nb; char priv[] __aligned(NETDEV_ALIGN); -- cgit v1.2.3 From 7c3d5c20dc169e55064f7f38c1c56cfbc39ee5b2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Oct 2022 11:25:34 +0200 Subject: thermal/core: Add a generic thermal_zone_get_trip() function The thermal_zone_device_ops structure defines a set of ops family, get_trip_temp(), get_trip_hyst(), get_trip_type(). Each of them is returning a property of a trip point. The result is the code is calling the ops everywhere to get a trip point which is supposed to be defined in the backend driver. It is a non-sense as a thermal trip can be generic and used by the backend driver to declare its trip points. Part of the thermal framework has been changed and all the OF thermal drivers are using the same definition for the trip point and use a thermal zone registration variant to pass those trip points which are part of the thermal zone device structure. Consequently, we can use a generic function to get the trip points when they are stored in the thermal zone device structure. This approach can be generalized to all the drivers and we can get rid of the ops->get_trip_*. That will result to a much more simpler code and make possible to rework how the thermal trip are handled in the thermal core framework as discussed previously. This change adds a function thermal_zone_get_trip() where we get the thermal trip point structure which contains all the properties (type, temp, hyst) instead of doing multiple calls to ops->get_trip_*. That opens the door for trip point extension with more attributes. For instance, replacing the trip points disabled bitmask with a 'disabled' field in the structure. Here we replace all the calls to ops->get_trip_* in the thermal core code with a call to the thermal_zone_get_trip() function. The thermal zone ops defines a callback to retrieve the critical temperature. As the trip handling is being reworked, all the trip points will be the same whatever the driver and consequently finding the critical trip temperature will be just a loop to search for a critical trip point type. Provide such a generic function, so we encapsulate the ops get_crit_temp() which can be removed when all the backend drivers are using the generic trip points handling. While at it, add the thermal_zone_get_num_trips() to encapsulate the code more and reduce the grip with the thermal framework internals. Signed-off-by: Daniel Lezcano Acked-by: Rafael J. Wysocki Reviewed-by: Zhang Rui Link: https://lore.kernel.org/r/20221003092602.1323944-2-daniel.lezcano@linaro.org --- drivers/thermal/thermal_core.c | 114 ++++++++++++++++++++++++++++++-------- drivers/thermal/thermal_core.h | 2 + drivers/thermal/thermal_helpers.c | 28 +++++----- drivers/thermal/thermal_netlink.c | 19 +++---- drivers/thermal/thermal_sysfs.c | 64 +++++++++------------ include/linux/thermal.h | 7 +++ 6 files changed, 147 insertions(+), 87 deletions(-) (limited to 'include') diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index f17ab2316dbd..b043c315c005 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -344,35 +344,31 @@ static void handle_critical_trips(struct thermal_zone_device *tz, tz->ops->critical(tz); } -static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) +static void handle_thermal_trip(struct thermal_zone_device *tz, int trip_id) { - enum thermal_trip_type type; - int trip_temp, hyst = 0; + struct thermal_trip trip; /* Ignore disabled trip points */ - if (test_bit(trip, &tz->trips_disabled)) + if (test_bit(trip_id, &tz->trips_disabled)) return; - tz->ops->get_trip_temp(tz, trip, &trip_temp); - tz->ops->get_trip_type(tz, trip, &type); - if (tz->ops->get_trip_hyst) - tz->ops->get_trip_hyst(tz, trip, &hyst); + __thermal_zone_get_trip(tz, trip_id, &trip); if (tz->last_temperature != THERMAL_TEMP_INVALID) { - if (tz->last_temperature < trip_temp && - tz->temperature >= trip_temp) - thermal_notify_tz_trip_up(tz->id, trip, + if (tz->last_temperature < trip.temperature && + tz->temperature >= trip.temperature) + thermal_notify_tz_trip_up(tz->id, trip_id, tz->temperature); - if (tz->last_temperature >= trip_temp && - tz->temperature < (trip_temp - hyst)) - thermal_notify_tz_trip_down(tz->id, trip, + if (tz->last_temperature >= trip.temperature && + tz->temperature < (trip.temperature - trip.hysteresis)) + thermal_notify_tz_trip_down(tz->id, trip_id, tz->temperature); } - if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT) - handle_critical_trips(tz, trip, trip_temp, type); + if (trip.type == THERMAL_TRIP_CRITICAL || trip.type == THERMAL_TRIP_HOT) + handle_critical_trips(tz, trip_id, trip.temperature, trip.type); else - handle_non_critical_trips(tz, trip); + handle_non_critical_trips(tz, trip_id); } static void update_temperature(struct thermal_zone_device *tz) @@ -1159,6 +1155,79 @@ static void thermal_set_delay_jiffies(unsigned long *delay_jiffies, int delay_ms *delay_jiffies = round_jiffies(*delay_jiffies); } +int thermal_zone_get_num_trips(struct thermal_zone_device *tz) +{ + return tz->num_trips; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips); + +int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp) +{ + int i, ret = -EINVAL; + + if (tz->ops->get_crit_temp) + return tz->ops->get_crit_temp(tz, temp); + + if (!tz->trips) + return -EINVAL; + + mutex_lock(&tz->lock); + + for (i = 0; i < tz->num_trips; i++) { + if (tz->trips[i].type == THERMAL_TRIP_CRITICAL) { + *temp = tz->trips[i].temperature; + ret = 0; + break; + } + } + + mutex_unlock(&tz->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_crit_temp); + +int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, + struct thermal_trip *trip) +{ + int ret; + + if (!tz || trip_id < 0 || trip_id >= tz->num_trips || !trip) + return -EINVAL; + + if (tz->trips) { + *trip = tz->trips[trip_id]; + return 0; + } + + if (tz->ops->get_trip_hyst) { + ret = tz->ops->get_trip_hyst(tz, trip_id, &trip->hysteresis); + if (ret) + return ret; + } else { + trip->hysteresis = 0; + } + + ret = tz->ops->get_trip_temp(tz, trip_id, &trip->temperature); + if (ret) + return ret; + + return tz->ops->get_trip_type(tz, trip_id, &trip->type); +} + +int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, + struct thermal_trip *trip) +{ + int ret; + + mutex_lock(&tz->lock); + ret = __thermal_zone_get_trip(tz, trip_id, trip); + mutex_unlock(&tz->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_trip); + /** * thermal_zone_device_register_with_trips() - register a new thermal zone device * @type: the thermal zone device type @@ -1191,8 +1260,6 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t int polling_delay) { struct thermal_zone_device *tz; - enum thermal_trip_type trip_type; - int trip_temp; int id; int result; int count; @@ -1232,7 +1299,7 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t return ERR_PTR(-EINVAL); } - if (num_trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp)) + if (num_trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp) && !trips) return ERR_PTR(-EINVAL); tz = kzalloc(sizeof(*tz), GFP_KERNEL); @@ -1283,9 +1350,10 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t goto release_device; for (count = 0; count < num_trips; count++) { - if (tz->ops->get_trip_type(tz, count, &trip_type) || - tz->ops->get_trip_temp(tz, count, &trip_temp) || - !trip_temp) + struct thermal_trip trip; + + result = thermal_zone_get_trip(tz, count, &trip); + if (result) set_bit(count, &tz->trips_disabled); } diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index b834cb273429..5f475b0a8c2f 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -114,6 +114,8 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz, /* Helpers */ void __thermal_zone_set_trips(struct thermal_zone_device *tz); +int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, + struct thermal_trip *trip); int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); /* sysfs I/F */ diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c index 56aa2e88f34f..8977d5ddc23c 100644 --- a/drivers/thermal/thermal_helpers.c +++ b/drivers/thermal/thermal_helpers.c @@ -83,7 +83,7 @@ int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) int ret = -EINVAL; int count; int crit_temp = INT_MAX; - enum thermal_trip_type type; + struct thermal_trip trip; lockdep_assert_held(&tz->lock); @@ -91,10 +91,9 @@ int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) { for (count = 0; count < tz->num_trips; count++) { - ret = tz->ops->get_trip_type(tz, count, &type); - if (!ret && type == THERMAL_TRIP_CRITICAL) { - ret = tz->ops->get_trip_temp(tz, count, - &crit_temp); + ret = __thermal_zone_get_trip(tz, count, &trip); + if (!ret && trip.type == THERMAL_TRIP_CRITICAL) { + crit_temp = trip.temperature; break; } } @@ -164,29 +163,30 @@ EXPORT_SYMBOL_GPL(thermal_zone_get_temp); */ void __thermal_zone_set_trips(struct thermal_zone_device *tz) { - int low = -INT_MAX; - int high = INT_MAX; - int trip_temp, hysteresis; + struct thermal_trip trip; + int low = -INT_MAX, high = INT_MAX; int i, ret; lockdep_assert_held(&tz->lock); - if (!tz->ops->set_trips || !tz->ops->get_trip_hyst) + if (!tz->ops->set_trips) return; for (i = 0; i < tz->num_trips; i++) { int trip_low; - tz->ops->get_trip_temp(tz, i, &trip_temp); - tz->ops->get_trip_hyst(tz, i, &hysteresis); + ret = __thermal_zone_get_trip(tz, i , &trip); + if (ret) + return; - trip_low = trip_temp - hysteresis; + trip_low = trip.temperature - trip.hysteresis; if (trip_low < tz->temperature && trip_low > low) low = trip_low; - if (trip_temp > tz->temperature && trip_temp < high) - high = trip_temp; + if (trip.temperature > tz->temperature && + trip.temperature < high) + high = trip.temperature; } /* No need to change trip points */ diff --git a/drivers/thermal/thermal_netlink.c b/drivers/thermal/thermal_netlink.c index e2d78a996b5f..75943b06dbe7 100644 --- a/drivers/thermal/thermal_netlink.c +++ b/drivers/thermal/thermal_netlink.c @@ -452,7 +452,8 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p) struct sk_buff *msg = p->msg; struct thermal_zone_device *tz; struct nlattr *start_trip; - int i, id; + struct thermal_trip trip; + int ret, i, id; if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) return -EINVAL; @@ -471,18 +472,14 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p) for (i = 0; i < tz->num_trips; i++) { - enum thermal_trip_type type; - int temp, hyst = 0; - - tz->ops->get_trip_type(tz, i, &type); - tz->ops->get_trip_temp(tz, i, &temp); - if (tz->ops->get_trip_hyst) - tz->ops->get_trip_hyst(tz, i, &hyst); + ret = __thermal_zone_get_trip(tz, i, &trip); + if (ret) + goto out_cancel_nest; if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) || - nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, type) || - nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, temp) || - nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, hyst)) + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip.type) || + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip.temperature) || + nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip.hysteresis)) goto out_cancel_nest; } diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index d97f0bc0a26b..137bbf6adbd6 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -83,27 +83,25 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); - enum thermal_trip_type type; - int trip, result; + struct thermal_trip trip; + int trip_id, result; - if (!tz->ops->get_trip_type) - return -EPERM; - - if (sscanf(attr->attr.name, "trip_point_%d_type", &trip) != 1) + if (sscanf(attr->attr.name, "trip_point_%d_type", &trip_id) != 1) return -EINVAL; mutex_lock(&tz->lock); if (device_is_registered(dev)) - result = tz->ops->get_trip_type(tz, trip, &type); + result = __thermal_zone_get_trip(tz, trip_id, &trip); else result = -ENODEV; mutex_unlock(&tz->lock); + if (result) return result; - switch (type) { + switch (trip.type) { case THERMAL_TRIP_CRITICAL: return sprintf(buf, "critical\n"); case THERMAL_TRIP_HOT: @@ -122,17 +120,16 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct thermal_zone_device *tz = to_thermal_zone(dev); - int trip, ret; - int temperature, hyst = 0; - enum thermal_trip_type type; + struct thermal_trip trip; + int trip_id, ret; if (!tz->ops->set_trip_temp && !tz->trips) return -EPERM; - if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip) != 1) + if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1) return -EINVAL; - if (kstrtoint(buf, 10, &temperature)) + if (kstrtoint(buf, 10, &trip.temperature)) return -EINVAL; mutex_lock(&tz->lock); @@ -143,25 +140,20 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, } if (tz->ops->set_trip_temp) { - ret = tz->ops->set_trip_temp(tz, trip, temperature); + ret = tz->ops->set_trip_temp(tz, trip_id, trip.temperature); if (ret) goto unlock; } if (tz->trips) - tz->trips[trip].temperature = temperature; - - if (tz->ops->get_trip_hyst) { - ret = tz->ops->get_trip_hyst(tz, trip, &hyst); - if (ret) - goto unlock; - } + tz->trips[trip_id].temperature = trip.temperature; - ret = tz->ops->get_trip_type(tz, trip, &type); + ret = __thermal_zone_get_trip(tz, trip_id, &trip); if (ret) goto unlock; - thermal_notify_tz_trip_change(tz->id, trip, type, temperature, hyst); + thermal_notify_tz_trip_change(tz->id, trip_id, trip.type, + trip.temperature, trip.hysteresis); __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); @@ -179,19 +171,16 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); - int trip, ret; - int temperature; + struct thermal_trip trip; + int trip_id, ret; - if (!tz->ops->get_trip_temp) - return -EPERM; - - if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip) != 1) + if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1) return -EINVAL; mutex_lock(&tz->lock); if (device_is_registered(dev)) - ret = tz->ops->get_trip_temp(tz, trip, &temperature); + ret = __thermal_zone_get_trip(tz, trip_id, &trip); else ret = -ENODEV; @@ -200,7 +189,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr, if (ret) return ret; - return sprintf(buf, "%d\n", temperature); + return sprintf(buf, "%d\n", trip.temperature); } static ssize_t @@ -248,25 +237,22 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); - int trip, ret; - int temperature; + struct thermal_trip trip; + int trip_id, ret; - if (!tz->ops->get_trip_hyst) - return -EPERM; - - if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip) != 1) + if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1) return -EINVAL; mutex_lock(&tz->lock); if (device_is_registered(dev)) - ret = tz->ops->get_trip_hyst(tz, trip, &temperature); + ret = __thermal_zone_get_trip(tz, trip_id, &trip); else ret = -ENODEV; mutex_unlock(&tz->lock); - return ret ? ret : sprintf(buf, "%d\n", temperature); + return ret ? ret : sprintf(buf, "%d\n", trip.hysteresis); } static ssize_t diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 5e093602e8fc..2198b3631f61 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -334,6 +334,13 @@ static inline void devm_thermal_of_zone_unregister(struct device *dev, } #endif +int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, + struct thermal_trip *trip); + +int thermal_zone_get_num_trips(struct thermal_zone_device *tz); + +int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp); + #ifdef CONFIG_THERMAL struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, void *, struct thermal_zone_device_ops *, -- cgit v1.2.3 From 2e38a2a981b24a9e86e687d32708a3d02707c8f6 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Oct 2022 11:25:36 +0200 Subject: thermal/core: Add a generic thermal_zone_set_trip() function The thermal zone ops defines a set_trip callback where we can invoke the backend driver to set an interrupt for the next trip point temperature being crossed the way up or down, or setting the low level with the hysteresis. The ops is only called from the thermal sysfs code where the userspace has the ability to modify a trip point characteristic. With the effort of encapsulating the thermal framework core code, let's create a thermal_zone_set_trip() which is the writable side of the thermal_zone_get_trip() and put there all the ops encapsulation. Signed-off-by: Daniel Lezcano Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20221003092602.1323944-4-daniel.lezcano@linaro.org --- drivers/thermal/thermal_core.c | 39 ++++++++++++++++++++++++++++ drivers/thermal/thermal_sysfs.c | 56 +++++++++++------------------------------ include/linux/thermal.h | 3 +++ 3 files changed, 57 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index b043c315c005..c24c9efcd175 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1228,6 +1228,45 @@ int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, } EXPORT_SYMBOL_GPL(thermal_zone_get_trip); +int thermal_zone_set_trip(struct thermal_zone_device *tz, int trip_id, + const struct thermal_trip *trip) +{ + struct thermal_trip t; + int ret; + + if (!tz->ops->set_trip_temp && !tz->ops->set_trip_hyst && !tz->trips) + return -EINVAL; + + ret = __thermal_zone_get_trip(tz, trip_id, &t); + if (ret) + return ret; + + if (t.type != trip->type) + return -EINVAL; + + if (t.temperature != trip->temperature && tz->ops->set_trip_temp) { + ret = tz->ops->set_trip_temp(tz, trip_id, trip->temperature); + if (ret) + return ret; + } + + if (t.hysteresis != trip->hysteresis && tz->ops->set_trip_hyst) { + ret = tz->ops->set_trip_hyst(tz, trip_id, trip->hysteresis); + if (ret) + return ret; + } + + if (tz->trips && (t.temperature != trip->temperature || t.hysteresis != trip->hysteresis)) + tz->trips[trip_id] = *trip; + + thermal_notify_tz_trip_change(tz->id, trip_id, trip->type, + trip->temperature, trip->hysteresis); + + __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); + + return 0; +} + /** * thermal_zone_device_register_with_trips() - register a new thermal zone device * @type: the thermal zone device type diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index d2d450076090..cef860deaf91 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -123,15 +123,9 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, struct thermal_trip trip; int trip_id, ret; - if (!tz->ops->set_trip_temp && !tz->trips) - return -EPERM; - if (sscanf(attr->attr.name, "trip_point_%d_temp", &trip_id) != 1) return -EINVAL; - if (kstrtoint(buf, 10, &trip.temperature)) - return -EINVAL; - mutex_lock(&tz->lock); if (!device_is_registered(dev)) { @@ -139,31 +133,19 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, goto unlock; } - if (tz->ops->set_trip_temp) { - ret = tz->ops->set_trip_temp(tz, trip_id, trip.temperature); - if (ret) - goto unlock; - } - - if (tz->trips) - tz->trips[trip_id].temperature = trip.temperature; - ret = __thermal_zone_get_trip(tz, trip_id, &trip); if (ret) goto unlock; - thermal_notify_tz_trip_change(tz->id, trip_id, trip.type, - trip.temperature, trip.hysteresis); - - __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + ret = kstrtoint(buf, 10, &trip.temperature); + if (ret) + goto unlock; + ret = thermal_zone_set_trip(tz, trip_id, &trip); unlock: mutex_unlock(&tz->lock); - - if (ret) - return ret; - - return count; + + return ret ? ret : count; } static ssize_t @@ -197,16 +179,13 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct thermal_zone_device *tz = to_thermal_zone(dev); - int trip, ret; - int temperature; - - if (!tz->ops->set_trip_hyst) - return -EPERM; + struct thermal_trip trip; + int trip_id, ret; - if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip) != 1) + if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1) return -EINVAL; - if (kstrtoint(buf, 10, &temperature)) + if (kstrtoint(buf, 10, &trip.hysteresis)) return -EINVAL; mutex_lock(&tz->lock); @@ -216,16 +195,11 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, goto unlock; } - /* - * We are not doing any check on the 'temperature' value - * here. The driver implementing 'set_trip_hyst' has to - * take care of this. - */ - ret = tz->ops->set_trip_hyst(tz, trip, temperature); - - if (!ret) - __thermal_zone_set_trips(tz); - + ret = __thermal_zone_get_trip(tz, trip_id, &trip); + if (ret) + goto unlock; + + ret = thermal_zone_set_trip(tz, trip_id, &trip); unlock: mutex_unlock(&tz->lock); diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 2198b3631f61..e2797f314d99 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -337,6 +337,9 @@ static inline void devm_thermal_of_zone_unregister(struct device *dev, int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, struct thermal_trip *trip); +int thermal_zone_set_trip(struct thermal_zone_device *tz, int trip_id, + const struct thermal_trip *trip); + int thermal_zone_get_num_trips(struct thermal_zone_device *tz); int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp); -- cgit v1.2.3 From e6ec64f85237b48c071158617cfc954a30285fc7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 14 Dec 2022 14:16:14 +0100 Subject: thermal/drivers/qcom: Fix set_trip_temp() deadlock The set_trip_temp() callback is used when changing the trip temperature through sysfs. As it is called with the thermal-zone-device lock held it must not use thermal_zone_get_trip() directly or it will deadlock. Fixes: 78c3e2429be8 ("thermal/drivers/qcom: Use generic thermal_zone_get_trip() function") Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20221214131617.2447-2-johan+linaro@kernel.org Signed-off-by: Daniel Lezcano --- drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 2 +- drivers/thermal/thermal_core.c | 1 + include/linux/thermal.h | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c index 58055a7abaf6..bfaec74f13b2 100644 --- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c @@ -270,7 +270,7 @@ static int qpnp_tm_set_trip_temp(struct thermal_zone_device *tz, int trip_id, in struct thermal_trip trip; int ret; - ret = thermal_zone_get_trip(chip->tz_dev, trip_id, &trip); + ret = __thermal_zone_get_trip(chip->tz_dev, trip_id, &trip); if (ret) return ret; diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index c24c9efcd175..d9a3d9566d73 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1214,6 +1214,7 @@ int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, return tz->ops->get_trip_type(tz, trip_id, &trip->type); } +EXPORT_SYMBOL_GPL(__thermal_zone_get_trip); int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, struct thermal_trip *trip) diff --git a/include/linux/thermal.h b/include/linux/thermal.h index e2797f314d99..30353e4b1424 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -334,6 +334,8 @@ static inline void devm_thermal_of_zone_unregister(struct device *dev, } #endif +int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, + struct thermal_trip *trip); int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, struct thermal_trip *trip); -- cgit v1.2.3 From 4d70c74659d9746502b23d055dba03d1d28ec388 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 30 Nov 2022 15:48:35 +0200 Subject: i915: Move list_count() to list.h as list_count_nodes() for broader use Some of the existing users, and definitely will be new ones, want to count existing nodes in the list. Provide a generic API for that by moving code from i915 to list.h. Reviewed-by: Lucas De Marchi Acked-by: Jani Nikula Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20221130134838.23805-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 15 ++------------- include/linux/list.h | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index c33e0d72d670..0dcf4ac92335 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -2094,17 +2094,6 @@ static void print_request_ring(struct drm_printer *m, struct i915_request *rq) } } -static unsigned long list_count(struct list_head *list) -{ - struct list_head *pos; - unsigned long count = 0; - - list_for_each(pos, list) - count++; - - return count; -} - static unsigned long read_ul(void *p, size_t x) { return *(unsigned long *)(p + x); @@ -2279,8 +2268,8 @@ void intel_engine_dump(struct intel_engine_cs *engine, spin_lock_irqsave(&engine->sched_engine->lock, flags); engine_dump_active_requests(engine, m); - drm_printf(m, "\tOn hold?: %lu\n", - list_count(&engine->sched_engine->hold)); + drm_printf(m, "\tOn hold?: %zu\n", + list_count_nodes(&engine->sched_engine->hold)); spin_unlock_irqrestore(&engine->sched_engine->lock, flags); drm_printf(m, "\tMMIO base: 0x%08x\n", engine->mmio_base); diff --git a/include/linux/list.h b/include/linux/list.h index 61762054b4be..f10344dbad4d 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -655,6 +655,21 @@ static inline void list_splice_tail_init(struct list_head *list, !list_is_head(pos, (head)); \ pos = n, n = pos->prev) +/** + * list_count_nodes - count nodes in the list + * @head: the head for your list. + */ +static inline size_t list_count_nodes(struct list_head *head) +{ + struct list_head *pos; + size_t count = 0; + + list_for_each(pos, head) + count++; + + return count; +} + /** * list_entry_is_head - test if the entry points to the head of the list * @pos: the type * to cursor -- cgit v1.2.3 From 9b9ad70f28675c45ef93cfb6e4af9403cb7bd34c Mon Sep 17 00:00:00 2001 From: MD Danish Anwar Date: Fri, 6 Jan 2023 17:40:42 +0530 Subject: remoteproc: pru: Add enum for PRU Core Identifiers. Introducing enum pruss_pru_id for PRU Core Identifiers. PRUSS_PRU0 indicates PRU Core 0. PRUSS_PRU1 indicates PRU Core 1. PRUSS_NUM_PRUS indicates the total number of PRU Cores. Signed-off-by: MD Danish Anwar Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20230106121046.886863-3-danishanwar@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/pru_rproc.c | 7 ++++--- include/linux/remoteproc/pruss.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 include/linux/remoteproc/pruss.h (limited to 'include') diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 128bf9912f2c..f8b196a2b72a 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -438,7 +439,7 @@ static void *pru_d_da_to_va(struct pru_rproc *pru, u32 da, size_t len) dram0 = pruss->mem_regions[PRUSS_MEM_DRAM0]; dram1 = pruss->mem_regions[PRUSS_MEM_DRAM1]; /* PRU1 has its local RAM addresses reversed */ - if (pru->id == 1) + if (pru->id == PRUSS_PRU1) swap(dram0, dram1); shrd_ram = pruss->mem_regions[PRUSS_MEM_SHRD_RAM2]; @@ -747,14 +748,14 @@ static int pru_rproc_set_id(struct pru_rproc *pru) case RTU0_IRAM_ADDR_MASK: fallthrough; case PRU0_IRAM_ADDR_MASK: - pru->id = 0; + pru->id = PRUSS_PRU0; break; case TX_PRU1_IRAM_ADDR_MASK: fallthrough; case RTU1_IRAM_ADDR_MASK: fallthrough; case PRU1_IRAM_ADDR_MASK: - pru->id = 1; + pru->id = PRUSS_PRU1; break; default: ret = -EINVAL; diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h new file mode 100644 index 000000000000..fbadfcfacb34 --- /dev/null +++ b/include/linux/remoteproc/pruss.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * PRU-ICSS Subsystem user interfaces + * + * Copyright (C) 2015-2022 Texas Instruments Incorporated - http://www.ti.com + * Suman Anna + */ + +#ifndef __LINUX_PRUSS_H +#define __LINUX_PRUSS_H + +#include +#include + +#define PRU_RPROC_DRVNAME "pru-rproc" + +/** + * enum pruss_pru_id - PRU core identifiers + * @PRUSS_PRU0: PRU Core 0. + * @PRUSS_PRU1: PRU Core 1. + * @PRUSS_NUM_PRUS: Total number of PRU Cores available. + * + */ + +enum pruss_pru_id { + PRUSS_PRU0 = 0, + PRUSS_PRU1, + PRUSS_NUM_PRUS, +}; + +#endif /* __LINUX_PRUSS_H */ -- cgit v1.2.3 From 919e8942548aa878d374b1b51aa68fdf751f18b8 Mon Sep 17 00:00:00 2001 From: MD Danish Anwar Date: Fri, 6 Jan 2023 17:40:43 +0530 Subject: remoteproc: pru: Add APIs to get and put the PRU cores Add two new APIs, pru_rproc_get() and pru_rproc_put(), to the PRU driver to allow client drivers to acquire and release the remoteproc device associated with a PRU core. The PRU cores are treated as resources with only one client owning it at a time. The pru_rproc_get() function returns the rproc handle corresponding to a PRU core identified by the device tree "ti,prus" property under the client node. The pru_rproc_put() is the complementary function to pru_rproc_get(). Signed-off-by: Suman Anna Signed-off-by: Tero Kristo Signed-off-by: Grzegorz Jaszczyk Signed-off-by: MD Danish Anwar Reviewed-by: Roger Quadros Link: https://lore.kernel.org/r/20230106121046.886863-4-danishanwar@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/pru_rproc.c | 128 ++++++++++++++++++++++++++++++++++++++- include/linux/remoteproc/pruss.h | 30 +++++++++ 2 files changed, 156 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index f8b196a2b72a..1036bfd446b6 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -2,12 +2,14 @@ /* * PRU-ICSS remoteproc driver for various TI SoCs * - * Copyright (C) 2014-2020 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2014-2022 Texas Instruments Incorporated - https://www.ti.com/ * * Author(s): * Suman Anna * Andrew F. Davis * Grzegorz Jaszczyk for Texas Instruments + * Puranjay Mohan + * Md Danish Anwar */ #include @@ -112,6 +114,8 @@ struct pru_private_data { * @rproc: remoteproc pointer for this PRU core * @data: PRU core specific data * @mem_regions: data for each of the PRU memory regions + * @client_np: client device node + * @lock: mutex to protect client usage * @fw_name: name of firmware image used during loading * @mapped_irq: virtual interrupt numbers of created fw specific mapping * @pru_interrupt_map: pointer to interrupt mapping description (firmware) @@ -127,6 +131,8 @@ struct pru_rproc { struct rproc *rproc; const struct pru_private_data *data; struct pruss_mem_region mem_regions[PRU_IOMEM_MAX]; + struct device_node *client_np; + struct mutex lock; const char *fw_name; unsigned int *mapped_irq; struct pru_irq_rsc *pru_interrupt_map; @@ -147,6 +153,120 @@ void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val) writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg); } +static struct rproc *__pru_rproc_get(struct device_node *np, int index) +{ + struct rproc *rproc; + phandle rproc_phandle; + int ret; + + ret = of_property_read_u32_index(np, "ti,prus", index, &rproc_phandle); + if (ret) + return ERR_PTR(ret); + + rproc = rproc_get_by_phandle(rproc_phandle); + if (!rproc) { + ret = -EPROBE_DEFER; + return ERR_PTR(ret); + } + + /* make sure it is PRU rproc */ + if (!is_pru_rproc(rproc->dev.parent)) { + rproc_put(rproc); + return ERR_PTR(-ENODEV); + } + + return rproc; +} + +/** + * pru_rproc_get() - get the PRU rproc instance from a device node + * @np: the user/client device node + * @index: index to use for the ti,prus property + * @pru_id: optional pointer to return the PRU remoteproc processor id + * + * This function looks through a client device node's "ti,prus" property at + * index @index and returns the rproc handle for a valid PRU remote processor if + * found. The function allows only one user to own the PRU rproc resource at a + * time. Caller must call pru_rproc_put() when done with using the rproc, not + * required if the function returns a failure. + * + * When optional @pru_id pointer is passed the PRU remoteproc processor id is + * returned. + * + * Return: rproc handle on success, and an ERR_PTR on failure using one + * of the following error values + * -ENODEV if device is not found + * -EBUSY if PRU is already acquired by anyone + * -EPROBE_DEFER is PRU device is not probed yet + */ +struct rproc *pru_rproc_get(struct device_node *np, int index, + enum pruss_pru_id *pru_id) +{ + struct rproc *rproc; + struct pru_rproc *pru; + struct device *dev; + int ret; + + rproc = __pru_rproc_get(np, index); + if (IS_ERR(rproc)) + return rproc; + + pru = rproc->priv; + dev = &rproc->dev; + + mutex_lock(&pru->lock); + + if (pru->client_np) { + mutex_unlock(&pru->lock); + ret = -EBUSY; + goto err_no_rproc_handle; + } + + pru->client_np = np; + + mutex_unlock(&pru->lock); + + if (pru_id) + *pru_id = pru->id; + + return rproc; + +err_no_rproc_handle: + rproc_put(rproc); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(pru_rproc_get); + +/** + * pru_rproc_put() - release the PRU rproc resource + * @rproc: the rproc resource to release + * + * Releases the PRU rproc resource and makes it available to other + * users. + */ +void pru_rproc_put(struct rproc *rproc) +{ + struct pru_rproc *pru; + + if (IS_ERR_OR_NULL(rproc) || !is_pru_rproc(rproc->dev.parent)) + return; + + pru = rproc->priv; + + mutex_lock(&pru->lock); + + if (!pru->client_np) { + mutex_unlock(&pru->lock); + return; + } + + pru->client_np = NULL; + mutex_unlock(&pru->lock); + + rproc_put(rproc); +} +EXPORT_SYMBOL_GPL(pru_rproc_put); + static inline u32 pru_debug_read_reg(struct pru_rproc *pru, unsigned int reg) { return readl_relaxed(pru->mem_regions[PRU_IOMEM_DEBUG].va + reg); @@ -817,6 +937,8 @@ static int pru_rproc_probe(struct platform_device *pdev) pru->pruss = platform_get_drvdata(ppdev); pru->rproc = rproc; pru->fw_name = fw_name; + pru->client_np = NULL; + mutex_init(&pru->lock); for (i = 0; i < ARRAY_SIZE(mem_names); i++) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -905,7 +1027,7 @@ MODULE_DEVICE_TABLE(of, pru_rproc_match); static struct platform_driver pru_rproc_driver = { .driver = { - .name = "pru-rproc", + .name = PRU_RPROC_DRVNAME, .of_match_table = pru_rproc_match, .suppress_bind_attrs = true, }, @@ -917,5 +1039,7 @@ module_platform_driver(pru_rproc_driver); MODULE_AUTHOR("Suman Anna "); MODULE_AUTHOR("Andrew F. Davis "); MODULE_AUTHOR("Grzegorz Jaszczyk "); +MODULE_AUTHOR("Puranjay Mohan "); +MODULE_AUTHOR("Md Danish Anwar "); MODULE_DESCRIPTION("PRU-ICSS Remote Processor Driver"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h index fbadfcfacb34..579dafbbaccf 100644 --- a/include/linux/remoteproc/pruss.h +++ b/include/linux/remoteproc/pruss.h @@ -28,4 +28,34 @@ enum pruss_pru_id { PRUSS_NUM_PRUS, }; +struct device_node; + +#if IS_ENABLED(CONFIG_PRU_REMOTEPROC) + +struct rproc *pru_rproc_get(struct device_node *np, int index, + enum pruss_pru_id *pru_id); +void pru_rproc_put(struct rproc *rproc); + +#else + +static inline struct rproc * +pru_rproc_get(struct device_node *np, int index, enum pruss_pru_id *pru_id) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline void pru_rproc_put(struct rproc *rproc) { } + +#endif /* CONFIG_PRU_REMOTEPROC */ + +static inline bool is_pru_rproc(struct device *dev) +{ + const char *drv_name = dev_driver_string(dev); + + if (strncmp(drv_name, PRU_RPROC_DRVNAME, sizeof(PRU_RPROC_DRVNAME))) + return false; + + return true; +} + #endif /* __LINUX_PRUSS_H */ -- cgit v1.2.3 From 102853400321baea2527917e6e89be33508c3e18 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 6 Jan 2023 17:40:45 +0530 Subject: remoteproc: pru: Add pru_rproc_set_ctable() function Some firmwares expect the OS drivers to configure the CTABLE entries publishing dynamically allocated memory regions. For example, the PRU Ethernet firmwares use the C28 and C30 entries for retrieving the Shared RAM and System SRAM (OCMC) areas allocated by the PRU Ethernet client driver. Provide a way for users to do that through a new API, pru_rproc_set_ctable(). The API returns 0 on success and a negative value on error. NOTE: The programmable CTABLE entries are typically re-programmed by the PRU firmwares when dealing with a certain block of memory during block processing. This API provides an interface to the PRU client drivers to publish a dynamically allocated memory block with the PRU firmware using a CTABLE entry instead of a negotiated address in shared memory. Additional synchronization may be needed between the PRU client drivers and firmwares if different addresses needs to be published at run-time reusing the same CTABLE entry. CTABLE for stands for "constant table". Each CTable entry just holds the upper address bits so PRU can reference to external memory with larger address bits. For use case please see prueth_sw_emac_config() in "drivers/net/ethernet/ti/prueth_switch.c" /* Set in constant table C28 of PRUn to ICSS Shared memory */ pru_rproc_set_ctable(prueth->pru0, PRU_C28, sharedramaddr); pru_rproc_set_ctable(prueth->pru1, PRU_C28, sharedramaddr); /* Set in constant table C30 of PRUn to OCMC memory */ pru_rproc_set_ctable(prueth->pru0, PRU_C30, ocmcaddr); pru_rproc_set_ctable(prueth->pru1, PRU_C30, ocmcaddr); Signed-off-by: Andrew F. Davis Signed-off-by: Suman Anna Signed-off-by: Roger Quadros Signed-off-by: Grzegorz Jaszczyk Signed-off-by: MD Danish Anwar Link: https://lore.kernel.org/r/20230106121046.886863-6-danishanwar@ti.com Signed-off-by: Mathieu Poirier --- drivers/remoteproc/pru_rproc.c | 59 ++++++++++++++++++++++++++++++++++++++++ include/linux/remoteproc/pruss.h | 22 +++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'include') diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index c16242e2d435..f6ea445d2fa2 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -120,6 +120,7 @@ struct pru_private_data { * @mapped_irq: virtual interrupt numbers of created fw specific mapping * @pru_interrupt_map: pointer to interrupt mapping description (firmware) * @pru_interrupt_map_sz: pru_interrupt_map size + * @rmw_lock: lock for read, modify, write operations on registers * @dbg_single_step: debug state variable to set PRU into single step mode * @dbg_continuous: debug state variable to restore PRU execution mode * @evt_count: number of mapped events @@ -137,6 +138,7 @@ struct pru_rproc { unsigned int *mapped_irq; struct pru_irq_rsc *pru_interrupt_map; size_t pru_interrupt_map_sz; + spinlock_t rmw_lock; u32 dbg_single_step; u32 dbg_continuous; u8 evt_count; @@ -153,6 +155,23 @@ void pru_control_write_reg(struct pru_rproc *pru, unsigned int reg, u32 val) writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg); } +static inline +void pru_control_set_reg(struct pru_rproc *pru, unsigned int reg, + u32 mask, u32 set) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&pru->rmw_lock, flags); + + val = pru_control_read_reg(pru, reg); + val &= ~mask; + val |= (set & mask); + pru_control_write_reg(pru, reg, val); + + spin_unlock_irqrestore(&pru->rmw_lock, flags); +} + static struct rproc *__pru_rproc_get(struct device_node *np, int index) { struct rproc *rproc; @@ -269,6 +288,45 @@ void pru_rproc_put(struct rproc *rproc) } EXPORT_SYMBOL_GPL(pru_rproc_put); +/** + * pru_rproc_set_ctable() - set the constant table index for the PRU + * @rproc: the rproc instance of the PRU + * @c: constant table index to set + * @addr: physical address to set it to + * + * Return: 0 on success, or errno in error case. + */ +int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr) +{ + struct pru_rproc *pru = rproc->priv; + unsigned int reg; + u32 mask, set; + u16 idx; + u16 idx_mask; + + if (IS_ERR_OR_NULL(rproc)) + return -EINVAL; + + if (!rproc->dev.parent || !is_pru_rproc(rproc->dev.parent)) + return -ENODEV; + + /* pointer is 16 bit and index is 8-bit so mask out the rest */ + idx_mask = (c >= PRU_C28) ? 0xFFFF : 0xFF; + + /* ctable uses bit 8 and upwards only */ + idx = (addr >> 8) & idx_mask; + + /* configurable ctable (i.e. C24) starts at PRU_CTRL_CTBIR0 */ + reg = PRU_CTRL_CTBIR0 + 4 * (c >> 1); + mask = idx_mask << (16 * (c & 1)); + set = idx << (16 * (c & 1)); + + pru_control_set_reg(pru, reg, mask, set); + + return 0; +} +EXPORT_SYMBOL_GPL(pru_rproc_set_ctable); + static inline u32 pru_debug_read_reg(struct pru_rproc *pru, unsigned int reg) { return readl_relaxed(pru->mem_regions[PRU_IOMEM_DEBUG].va + reg); @@ -940,6 +998,7 @@ static int pru_rproc_probe(struct platform_device *pdev) pru->rproc = rproc; pru->fw_name = fw_name; pru->client_np = NULL; + spin_lock_init(&pru->rmw_lock); mutex_init(&pru->lock); for (i = 0; i < ARRAY_SIZE(mem_names); i++) { diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h index 579dafbbaccf..039b50d58df2 100644 --- a/include/linux/remoteproc/pruss.h +++ b/include/linux/remoteproc/pruss.h @@ -28,13 +28,29 @@ enum pruss_pru_id { PRUSS_NUM_PRUS, }; +/* + * enum pru_ctable_idx - Configurable Constant table index identifiers + */ +enum pru_ctable_idx { + PRU_C24 = 0, + PRU_C25, + PRU_C26, + PRU_C27, + PRU_C28, + PRU_C29, + PRU_C30, + PRU_C31, +}; + struct device_node; +struct rproc; #if IS_ENABLED(CONFIG_PRU_REMOTEPROC) struct rproc *pru_rproc_get(struct device_node *np, int index, enum pruss_pru_id *pru_id); void pru_rproc_put(struct rproc *rproc); +int pru_rproc_set_ctable(struct rproc *rproc, enum pru_ctable_idx c, u32 addr); #else @@ -46,6 +62,12 @@ pru_rproc_get(struct device_node *np, int index, enum pruss_pru_id *pru_id) static inline void pru_rproc_put(struct rproc *rproc) { } +static inline int pru_rproc_set_ctable(struct rproc *rproc, + enum pru_ctable_idx c, u32 addr) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_PRU_REMOTEPROC */ static inline bool is_pru_rproc(struct device *dev) -- cgit v1.2.3 From d8aa375bd70681b76c6bd5fe93bab6011e16a0fb Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 4 Jan 2023 11:34:47 +0200 Subject: dt-bindings: clock: Add SM8550 TCSR CC clocks Add bindings documentation for clock TCSR driver on SM8550. Signed-off-by: Abel Vesa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230104093450.3150578-2-abel.vesa@linaro.org --- .../bindings/clock/qcom,sm8550-tcsr.yaml | 55 ++++++++++++++++++++++ include/dt-bindings/clock/qcom,sm8550-tcsr.h | 18 +++++++ 2 files changed, 73 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml create mode 100644 include/dt-bindings/clock/qcom,sm8550-tcsr.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml new file mode 100644 index 000000000000..1bf1a41fd89c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm8550-tcsr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm TCSR Clock Controller on SM8550 + +maintainers: + - Bjorn Andersson + +description: | + Qualcomm TCSR clock control module provides the clocks, resets and + power domains on SM8550 + + See also:: include/dt-bindings/clock/qcom,sm8550-tcsr.h + +properties: + compatible: + items: + - const: qcom,sm8550-tcsr + - const: syscon + + clocks: + items: + - description: TCXO pad clock + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - clocks + +additionalProperties: false + +examples: + - | + #include + + clock-controller@1fc0000 { + compatible = "qcom,sm8550-tcsr", "syscon"; + reg = <0x1fc0000 0x30000>; + clocks = <&rpmhcc RPMH_CXO_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/qcom,sm8550-tcsr.h b/include/dt-bindings/clock/qcom,sm8550-tcsr.h new file mode 100644 index 000000000000..091cb76f953a --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8550-tcsr.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Linaro Limited + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_TCSR_CC_SM8550_H +#define _DT_BINDINGS_CLK_QCOM_TCSR_CC_SM8550_H + +/* TCSR CC clocks */ +#define TCSR_PCIE_0_CLKREF_EN 0 +#define TCSR_PCIE_1_CLKREF_EN 1 +#define TCSR_UFS_CLKREF_EN 2 +#define TCSR_UFS_PAD_CLKREF_EN 3 +#define TCSR_USB2_CLKREF_EN 4 +#define TCSR_USB3_CLKREF_EN 5 + +#endif -- cgit v1.2.3 From 33ae3d0955943ac5bacfcb6911cf7cb74822bf8c Mon Sep 17 00:00:00 2001 From: Dawei Li Date: Fri, 6 Jan 2023 23:28:03 +0800 Subject: soc: qcom: apr: make remove callback of apr driver void returned Since commit fc7a6209d571 ("bus: Make remove callback return void") forces bus_type::remove be void-returned, it doesn't make much sense for any bus based driver implementing remove callbalk to return non-void to its caller. As such, change the remove function for apr bus based drivers to return void. Signed-off-by: Dawei Li Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/TYCP286MB23232B7968D34DB8323B0F16CAFB9@TYCP286MB2323.JPNP286.PROD.OUTLOOK.COM --- include/linux/soc/qcom/apr.h | 2 +- sound/soc/qcom/qdsp6/q6core.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/soc/qcom/apr.h b/include/linux/soc/qcom/apr.h index 23c5b30f3511..be98aebcb3e1 100644 --- a/include/linux/soc/qcom/apr.h +++ b/include/linux/soc/qcom/apr.h @@ -153,7 +153,7 @@ typedef struct apr_device gpr_device_t; struct apr_driver { int (*probe)(struct apr_device *sl); - int (*remove)(struct apr_device *sl); + void (*remove)(struct apr_device *sl); int (*callback)(struct apr_device *a, struct apr_resp_pkt *d); int (*gpr_callback)(struct gpr_resp_pkt *d, void *data, int op); diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c index 5358fefd4210..49cfb32cd209 100644 --- a/sound/soc/qcom/qdsp6/q6core.c +++ b/sound/soc/qcom/qdsp6/q6core.c @@ -339,7 +339,7 @@ static int q6core_probe(struct apr_device *adev) return 0; } -static int q6core_exit(struct apr_device *adev) +static void q6core_exit(struct apr_device *adev) { struct q6core *core = dev_get_drvdata(&adev->dev); @@ -350,8 +350,6 @@ static int q6core_exit(struct apr_device *adev) g_core = NULL; kfree(core); - - return 0; } #ifdef CONFIG_OF -- cgit v1.2.3 From cd8fc5226bef3a1fda13a0e61794a039ca46744a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:20 +0100 Subject: f2fs: remove the create argument to f2fs_map_blocks The create argument is always identicaly to map->m_may_create, so use that consistently. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 63 +++++++++++++++++++-------------------------- fs/f2fs/f2fs.h | 3 +-- fs/f2fs/file.c | 12 ++++----- include/trace/events/f2fs.h | 11 +++----- 4 files changed, 38 insertions(+), 51 deletions(-) (limited to 'include') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index e6f94591717b..1cc5c6cb3146 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1477,8 +1477,7 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) * maps continuous logical blocks to physical blocks, and return such * info via f2fs_map_blocks structure. */ -int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, - int create, int flag) +int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag) { unsigned int maxblocks = map->m_len; struct dnode_of_data dn; @@ -1507,38 +1506,31 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, pgofs = (pgoff_t)map->m_lblk; end = pgofs + maxblocks; - if (!create && f2fs_lookup_read_extent_cache(inode, pgofs, &ei)) { - if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO && - map->m_may_create) - goto next_dnode; + if (map->m_may_create || + !f2fs_lookup_read_extent_cache(inode, pgofs, &ei)) + goto next_dnode; - map->m_pblk = ei.blk + pgofs - ei.fofs; - map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs); - map->m_flags = F2FS_MAP_MAPPED; - if (map->m_next_extent) - *map->m_next_extent = pgofs + map->m_len; + /* Found the map in read extent cache */ + map->m_pblk = ei.blk + pgofs - ei.fofs; + map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs); + map->m_flags = F2FS_MAP_MAPPED; + if (map->m_next_extent) + *map->m_next_extent = pgofs + map->m_len; - /* for hardware encryption, but to avoid potential issue in future */ - if (flag == F2FS_GET_BLOCK_DIO) - f2fs_wait_on_block_writeback_range(inode, + /* for hardware encryption, but to avoid potential issue in future */ + if (flag == F2FS_GET_BLOCK_DIO) + f2fs_wait_on_block_writeback_range(inode, map->m_pblk, map->m_len); - if (map->m_multidev_dio) { - block_t blk_addr = map->m_pblk; - - bidx = f2fs_target_device_index(sbi, map->m_pblk); + if (map->m_multidev_dio) { + bidx = f2fs_target_device_index(sbi, map->m_pblk); - map->m_bdev = FDEV(bidx).bdev; - map->m_pblk -= FDEV(bidx).start_blk; - map->m_len = min(map->m_len, + map->m_bdev = FDEV(bidx).bdev; + map->m_pblk -= FDEV(bidx).start_blk; + map->m_len = min(map->m_len, FDEV(bidx).end_blk + 1 - map->m_pblk); - - if (map->m_may_create) - f2fs_update_device_state(sbi, inode->i_ino, - blk_addr, map->m_len); - } - goto out; } + goto out; next_dnode: if (map->m_may_create) @@ -1602,7 +1594,7 @@ next_block: set_inode_flag(inode, FI_APPEND_WRITE); } } else { - if (create) { + if (map->m_may_create) { if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; goto sync_out; @@ -1776,7 +1768,7 @@ unlock_out: f2fs_balance_fs(sbi, dn.node_changed); } out: - trace_f2fs_map_blocks(inode, map, create, flag, err); + trace_f2fs_map_blocks(inode, map, flag, err); return err; } @@ -1798,7 +1790,7 @@ bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len) while (map.m_lblk < last_lblk) { map.m_len = last_lblk - map.m_lblk; - err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT); if (err || map.m_len == 0) return false; map.m_lblk += map.m_len; @@ -1972,7 +1964,7 @@ next: map.m_len = cluster_size - count_in_cluster; } - ret = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_FIEMAP); + ret = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_FIEMAP); if (ret) goto out; @@ -2105,7 +2097,7 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page, map->m_lblk = block_in_file; map->m_len = last_block - block_in_file; - ret = f2fs_map_blocks(inode, map, 0, F2FS_GET_BLOCK_DEFAULT); + ret = f2fs_map_blocks(inode, map, F2FS_GET_BLOCK_DEFAULT); if (ret) goto out; got_it: @@ -3807,7 +3799,7 @@ static sector_t f2fs_bmap(struct address_space *mapping, sector_t block) map.m_next_pgofs = NULL; map.m_seg_type = NO_CHECK_TYPE; - if (!f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_BMAP)) + if (!f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_BMAP)) blknr = map.m_pblk; } out: @@ -3915,7 +3907,7 @@ retry: map.m_seg_type = NO_CHECK_TYPE; map.m_may_create = false; - ret = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_FIEMAP); + ret = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_FIEMAP); if (ret) goto out; @@ -4140,8 +4132,7 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, if (flags & IOMAP_WRITE) map.m_may_create = true; - err = f2fs_map_blocks(inode, &map, flags & IOMAP_WRITE, - F2FS_GET_BLOCK_DIO); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DIO); if (err) return err; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 744cb442085f..60f421fe14ee 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3811,8 +3811,7 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index, struct page *f2fs_get_new_data_page(struct inode *inode, struct page *ipage, pgoff_t index, bool new_i_size); int f2fs_do_write_data_page(struct f2fs_io_info *fio); -int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, - int create, int flag); +int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag); int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len); int f2fs_encrypt_one_page(struct f2fs_io_info *fio); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 705a7eb4df99..939c7247c367 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1743,7 +1743,7 @@ next_alloc: f2fs_unlock_op(sbi); map.m_seg_type = CURSEG_COLD_DATA_PINNED; - err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_DIO); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_DIO); file_dont_truncate(inode); f2fs_up_write(&sbi->pin_sem); @@ -1756,7 +1756,7 @@ next_alloc: map.m_len = expanded; } else { - err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_AIO); expanded = map.m_len; } out_err: @@ -2604,7 +2604,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, */ while (map.m_lblk < pg_end) { map.m_len = pg_end - map.m_lblk; - err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT); if (err) goto out; @@ -2651,7 +2651,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, do_map: map.m_len = pg_end - map.m_lblk; - err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT); if (err) goto clear_out; @@ -3225,7 +3225,7 @@ int f2fs_precache_extents(struct inode *inode) map.m_len = end - map.m_lblk; f2fs_down_write(&fi->i_gc_rwsem[WRITE]); - err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_PRECACHE); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRECACHE); f2fs_up_write(&fi->i_gc_rwsem[WRITE]); if (err) return err; @@ -4464,7 +4464,7 @@ static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter, flag = F2FS_GET_BLOCK_PRE_AIO; } - ret = f2fs_map_blocks(inode, &map, 1, flag); + ret = f2fs_map_blocks(inode, &map, flag); /* -ENOSPC|-EDQUOT are fine to report the number of allocated blocks. */ if (ret < 0 && !((ret == -ENOSPC || ret == -EDQUOT) && map.m_len > 0)) return ret; diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 31d994e6b4ca..9183a0a11e26 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -569,10 +569,10 @@ TRACE_EVENT(f2fs_file_write_iter, ); TRACE_EVENT(f2fs_map_blocks, - TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map, - int create, int flag, int ret), + TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map, int flag, + int ret), - TP_ARGS(inode, map, create, flag, ret), + TP_ARGS(inode, map, flag, ret), TP_STRUCT__entry( __field(dev_t, dev) @@ -584,7 +584,6 @@ TRACE_EVENT(f2fs_map_blocks, __field(int, m_seg_type) __field(bool, m_may_create) __field(bool, m_multidev_dio) - __field(int, create) __field(int, flag) __field(int, ret) ), @@ -599,7 +598,6 @@ TRACE_EVENT(f2fs_map_blocks, __entry->m_seg_type = map->m_seg_type; __entry->m_may_create = map->m_may_create; __entry->m_multidev_dio = map->m_multidev_dio; - __entry->create = create; __entry->flag = flag; __entry->ret = ret; ), @@ -607,7 +605,7 @@ TRACE_EVENT(f2fs_map_blocks, TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, " "start blkaddr = 0x%llx, len = 0x%llx, flags = %u, " "seg_type = %d, may_create = %d, multidevice = %d, " - "create = %d, flag = %d, err = %d", + "flag = %d, err = %d", show_dev_ino(__entry), (unsigned long long)__entry->m_lblk, (unsigned long long)__entry->m_pblk, @@ -616,7 +614,6 @@ TRACE_EVENT(f2fs_map_blocks, __entry->m_seg_type, __entry->m_may_create, __entry->m_multidev_dio, - __entry->create, __entry->flag, __entry->ret) ); -- cgit v1.2.3 From 0b5dfa35da03277287d6c5fcd2b56a77f1c61f62 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 5 Jan 2023 14:21:16 -0800 Subject: ipv6: ioam: Replace 0-length array with flexible array Zero-length arrays are deprecated[1]. Replace struct ioam6_trace_hdr's "data" 0-length array with a flexible array. Detected with GCC 13, using -fstrict-flex-arrays=3: net/ipv6/ioam6_iptunnel.c: In function 'ioam6_build_state': net/ipv6/ioam6_iptunnel.c:194:37: warning: array subscript is outside array bounds of '__u8[0]' {aka 'unsigned char[]'} [-Warray-bounds=] 194 | tuninfo->traceh.data[trace->remlen * 4] = IPV6_TLV_PADN; | ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~ In file included from include/linux/ioam6.h:11, from net/ipv6/ioam6_iptunnel.c:13: include/uapi/linux/ioam6.h:130:17: note: while referencing 'data' 130 | __u8 data[0]; | ^~~~ [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Reviewed-by: Justin Iurman Tested-by: Justin Iurman Link: https://lore.kernel.org/r/20230105222115.never.661-kees@kernel.org Signed-off-by: Jakub Kicinski --- include/uapi/linux/ioam6.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/ioam6.h b/include/uapi/linux/ioam6.h index ac4de376f0ce..8f72b24fefb3 100644 --- a/include/uapi/linux/ioam6.h +++ b/include/uapi/linux/ioam6.h @@ -127,7 +127,7 @@ struct ioam6_trace_hdr { #endif #define IOAM6_TRACE_DATA_SIZE_MAX 244 - __u8 data[0]; + __u8 data[]; } __attribute__((packed)); #endif /* _UAPI_LINUX_IOAM6_H */ -- cgit v1.2.3 From e8d283b6cf0e83d5fcb5345e037956eb3e9b2483 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 5 Jan 2023 14:15:37 -0800 Subject: net: ipv6: rpl_iptunnel: Replace 0-length arrays with flexible arrays Zero-length arrays are deprecated[1]. Replace struct ipv6_rpl_sr_hdr's "segments" union of 0-length arrays with flexible arrays. Detected with GCC 13, using -fstrict-flex-arrays=3: In function 'rpl_validate_srh', inlined from 'rpl_build_state' at ../net/ipv6/rpl_iptunnel.c:96:7: ../net/ipv6/rpl_iptunnel.c:60:28: warning: array subscript is outside array bounds of 'struct in6_addr[0]' [-Warray-bounds=] 60 | if (ipv6_addr_type(&srh->rpl_segaddr[srh->segments_left - 1]) & | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../include/net/rpl.h:12, from ../net/ipv6/rpl_iptunnel.c:13: ../include/uapi/linux/rpl.h: In function 'rpl_build_state': ../include/uapi/linux/rpl.h:40:33: note: while referencing 'addr' 40 | struct in6_addr addr[0]; | ^~~~ [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays Cc: Hideaki YOSHIFUJI Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230105221533.never.711-kees@kernel.org Signed-off-by: Jakub Kicinski --- include/uapi/linux/rpl.h | 4 ++-- net/ipv6/rpl_iptunnel.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/rpl.h b/include/uapi/linux/rpl.h index 708adddf9f13..7c8970e5b84b 100644 --- a/include/uapi/linux/rpl.h +++ b/include/uapi/linux/rpl.h @@ -37,8 +37,8 @@ struct ipv6_rpl_sr_hdr { #endif union { - struct in6_addr addr[0]; - __u8 data[0]; + __DECLARE_FLEX_ARRAY(struct in6_addr, addr); + __DECLARE_FLEX_ARRAY(__u8, data); } segments; } __attribute__((packed)); diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c index ff691d9f4a04..b1c028df686e 100644 --- a/net/ipv6/rpl_iptunnel.c +++ b/net/ipv6/rpl_iptunnel.c @@ -13,7 +13,7 @@ #include struct rpl_iptunnel_encap { - struct ipv6_rpl_sr_hdr srh[0]; + DECLARE_FLEX_ARRAY(struct ipv6_rpl_sr_hdr, srh); }; struct rpl_lwt { -- cgit v1.2.3 From b466a25c930f2b7f1ed21c9eeaa553017ae78d1c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 5 Jan 2023 20:28:48 -0800 Subject: ethtool: Replace 0-length array with flexible array Zero-length arrays are deprecated[1]. Replace struct ethtool_rxnfc's "rule_locs" 0-length array with a flexible array. Detected with GCC 13, using -fstrict-flex-arrays=3: net/ethtool/common.c: In function 'ethtool_get_max_rxnfc_channel': net/ethtool/common.c:558:55: warning: array subscript i is outside array bounds of '__u32[0]' {aka 'unsigned int[]'} [-Warray-bounds=] 558 | .fs.location = info->rule_locs[i], | ~~~~~~~~~~~~~~~^~~ In file included from include/linux/ethtool.h:19, from include/uapi/linux/ethtool_netlink.h:12, from include/linux/ethtool_netlink.h:6, from net/ethtool/common.c:3: include/uapi/linux/ethtool.h:1186:41: note: while referencing 'rule_locs' 1186 | __u32 rule_locs[0]; | ^~~~~~~~~ [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays Cc: Andrew Lunn Cc: kernel test robot Cc: Oleksij Rempel Cc: Sean Anderson Cc: Alexandru Tachici Cc: Amit Cohen Signed-off-by: Kees Cook Reviewed-by: Vincent Mailhol Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20230106042844.give.885-kees@kernel.org Signed-off-by: Jakub Kicinski --- include/uapi/linux/ethtool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 58e587ba0450..3135fa0ba9a4 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1183,7 +1183,7 @@ struct ethtool_rxnfc { __u32 rule_cnt; __u32 rss_context; }; - __u32 rule_locs[0]; + __u32 rule_locs[]; }; -- cgit v1.2.3 From 544a4f2ecd45f9d6ed78d207583f39130ad40349 Mon Sep 17 00:00:00 2001 From: Michal Clapinski Date: Wed, 7 Dec 2022 17:43:37 +0100 Subject: sched/membarrier: Introduce MEMBARRIER_CMD_GET_REGISTRATIONS Provide a method to query previously issued registrations. Signed-off-by: Michal Clapinski Signed-off-by: Ingo Molnar Acked-by: Mathieu Desnoyers Acked-by: Paul E. McKenney Link: https://lore.kernel.org/r/20221207164338.1535591-2-mclapinski@google.com --- include/uapi/linux/membarrier.h | 4 ++++ kernel/sched/membarrier.c | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/membarrier.h b/include/uapi/linux/membarrier.h index 737605897f36..5f3ad6d5be6f 100644 --- a/include/uapi/linux/membarrier.h +++ b/include/uapi/linux/membarrier.h @@ -137,6 +137,9 @@ * @MEMBARRIER_CMD_SHARED: * Alias to MEMBARRIER_CMD_GLOBAL. Provided for * header backward compatibility. + * @MEMBARRIER_CMD_GET_REGISTRATIONS: + * Returns a bitmask of previously issued + * registration commands. * * Command to be passed to the membarrier system call. The commands need to * be a single bit each, except for MEMBARRIER_CMD_QUERY which is assigned to @@ -153,6 +156,7 @@ enum membarrier_cmd { MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 6), MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ = (1 << 7), MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ = (1 << 8), + MEMBARRIER_CMD_GET_REGISTRATIONS = (1 << 9), /* Alias for header backward compatibility. */ MEMBARRIER_CMD_SHARED = MEMBARRIER_CMD_GLOBAL, diff --git a/kernel/sched/membarrier.c b/kernel/sched/membarrier.c index 0c5be7ebb1dc..2ad881d07752 100644 --- a/kernel/sched/membarrier.c +++ b/kernel/sched/membarrier.c @@ -159,7 +159,8 @@ | MEMBARRIER_CMD_PRIVATE_EXPEDITED \ | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED \ | MEMBARRIER_PRIVATE_EXPEDITED_SYNC_CORE_BITMASK \ - | MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK) + | MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK \ + | MEMBARRIER_CMD_GET_REGISTRATIONS) static void ipi_mb(void *info) { @@ -540,6 +541,40 @@ static int membarrier_register_private_expedited(int flags) return 0; } +static int membarrier_get_registrations(void) +{ + struct task_struct *p = current; + struct mm_struct *mm = p->mm; + int registrations_mask = 0, membarrier_state, i; + static const int states[] = { + MEMBARRIER_STATE_GLOBAL_EXPEDITED | + MEMBARRIER_STATE_GLOBAL_EXPEDITED_READY, + MEMBARRIER_STATE_PRIVATE_EXPEDITED | + MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY, + MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE | + MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY, + MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ | + MEMBARRIER_STATE_PRIVATE_EXPEDITED_RSEQ_READY + }; + static const int registration_cmds[] = { + MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, + MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, + MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, + MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ + }; + BUILD_BUG_ON(ARRAY_SIZE(states) != ARRAY_SIZE(registration_cmds)); + + membarrier_state = atomic_read(&mm->membarrier_state); + for (i = 0; i < ARRAY_SIZE(states); ++i) { + if (membarrier_state & states[i]) { + registrations_mask |= registration_cmds[i]; + membarrier_state &= ~states[i]; + } + } + WARN_ON_ONCE(membarrier_state != 0); + return registrations_mask; +} + /** * sys_membarrier - issue memory barriers on a set of threads * @cmd: Takes command values defined in enum membarrier_cmd. @@ -623,6 +658,8 @@ SYSCALL_DEFINE3(membarrier, int, cmd, unsigned int, flags, int, cpu_id) return membarrier_private_expedited(MEMBARRIER_FLAG_RSEQ, cpu_id); case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ: return membarrier_register_private_expedited(MEMBARRIER_FLAG_RSEQ); + case MEMBARRIER_CMD_GET_REGISTRATIONS: + return membarrier_get_registrations(); default: return -EINVAL; } -- cgit v1.2.3 From 925b61ba2dafa9c13c9afa9b83a45d499cd73f2f Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sat, 31 Dec 2022 17:14:28 -0600 Subject: dt-bindings: clock: Add D1 CAN bus gates and resets The D1 CCU contains gates and resets for two CAN buses. While the CAN bus controllers are only documented for the T113 SoC, the CCU is the same across all SoC variants. Reviewed-by: Andre Przywara Signed-off-by: Samuel Holland Acked-by: Philipp Zabel Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20221231231429.18357-6-samuel@sholland.org Signed-off-by: Jernej Skrabec --- include/dt-bindings/clock/sun20i-d1-ccu.h | 2 ++ include/dt-bindings/reset/sun20i-d1-ccu.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/include/dt-bindings/clock/sun20i-d1-ccu.h b/include/dt-bindings/clock/sun20i-d1-ccu.h index e3ac53315e1a..e143b9929763 100644 --- a/include/dt-bindings/clock/sun20i-d1-ccu.h +++ b/include/dt-bindings/clock/sun20i-d1-ccu.h @@ -152,5 +152,7 @@ #define CLK_FANOUT0 142 #define CLK_FANOUT1 143 #define CLK_FANOUT2 144 +#define CLK_BUS_CAN0 145 +#define CLK_BUS_CAN1 146 #endif /* _DT_BINDINGS_CLK_SUN20I_D1_CCU_H_ */ diff --git a/include/dt-bindings/reset/sun20i-d1-ccu.h b/include/dt-bindings/reset/sun20i-d1-ccu.h index de9ff5203239..f8001cf50bf1 100644 --- a/include/dt-bindings/reset/sun20i-d1-ccu.h +++ b/include/dt-bindings/reset/sun20i-d1-ccu.h @@ -73,5 +73,7 @@ #define RST_BUS_DSP_CFG 63 #define RST_BUS_DSP_DBG 64 #define RST_BUS_RISCV_CFG 65 +#define RST_BUS_CAN0 66 +#define RST_BUS_CAN1 67 #endif /* _DT_BINDINGS_RST_SUN20I_D1_CCU_H_ */ -- cgit v1.2.3 From 2ad9bd8332ac1bc072cc7d785e7cb09d6ad36f4c Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 5 Jan 2023 11:07:30 -0800 Subject: iov: add import_ubuf() Like import_single_range(), but for ITER_UBUF. Signed-off-by: Jens Axboe Signed-off-by: Keith Busch Reviewed-by: Christoph Hellwig --- include/linux/uio.h | 1 + lib/iov_iter.c | 11 +++++++++++ 2 files changed, 12 insertions(+) (limited to 'include') diff --git a/include/linux/uio.h b/include/linux/uio.h index 9f158238edba..73b1d5d1e4f1 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -346,6 +346,7 @@ ssize_t __import_iovec(int type, const struct iovec __user *uvec, struct iov_iter *i, bool compat); int import_single_range(int type, void __user *buf, size_t len, struct iovec *iov, struct iov_iter *i); +int import_ubuf(int type, void __user *buf, size_t len, struct iov_iter *i); static inline void iov_iter_ubuf(struct iov_iter *i, unsigned int direction, void __user *buf, size_t count) diff --git a/lib/iov_iter.c b/lib/iov_iter.c index f9a3ff37ecd1..f036760b66e2 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1877,6 +1877,17 @@ int import_single_range(int rw, void __user *buf, size_t len, } EXPORT_SYMBOL(import_single_range); +int import_ubuf(int rw, void __user *buf, size_t len, struct iov_iter *i) +{ + if (len > MAX_RW_COUNT) + len = MAX_RW_COUNT; + if (unlikely(!access_ok(buf, len))) + return -EFAULT; + + iov_iter_ubuf(i, rw, buf, len); + return 0; +} + /** * iov_iter_restore() - Restore a &struct iov_iter to the same state as when * iov_iter_save_state() was called. -- cgit v1.2.3 From b6c00fb9949fbd073e651a77aa75faca978cf2a6 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Wed, 4 Jan 2023 12:13:41 -0800 Subject: perf: Add PMU_FORMAT_ATTR_SHOW The macro PMU_FORMAT_ATTR facilitates the definition of both the "show" function and "format_attr". But it only works for a non-hybrid platform. For a hybrid platform, the name "format_attr_hybrid_" is used. The definition of the "show" function can be shared between a non-hybrid platform and a hybrid platform. Add a new macro PMU_FORMAT_ATTR_SHOW. No functional change. The PMU_FORMAT_ATTR_SHOW will be used in the following patch. Signed-off-by: Kan Liang Signed-off-by: Ingo Molnar Acked-by: Peter Zijlstra Link: https://lore.kernel.org/r/20230104201349.1451191-1-kan.liang@linux.intel.com --- include/linux/perf_event.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index c6a3bac76966..ad92ad37600e 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1724,7 +1724,7 @@ static struct perf_pmu_events_attr _var = { \ .id = _id, } \ })[0].attr.attr) -#define PMU_FORMAT_ATTR(_name, _format) \ +#define PMU_FORMAT_ATTR_SHOW(_name, _format) \ static ssize_t \ _name##_show(struct device *dev, \ struct device_attribute *attr, \ @@ -1733,6 +1733,9 @@ _name##_show(struct device *dev, \ BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ return sprintf(page, _format "\n"); \ } \ + +#define PMU_FORMAT_ATTR(_name, _format) \ + PMU_FORMAT_ATTR_SHOW(_name, _format) \ \ static struct device_attribute format_attr_##_name = __ATTR_RO(_name) -- cgit v1.2.3 From 7bdb1767bf011c7f6065ac483ad2f00e434c3979 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 29 Dec 2022 12:40:59 -0800 Subject: perf/core: Change the layout of perf_sample_data The layout of perf_sample_data is designed to minimize cache-line access. The perf_sample_data_init() used to initialize a couple of fields unconditionally so they were placed together at the head. But it's changed now to set the fields according to the actual sample_type flags. The main user (the perf tools) sets the IP, TID, TIME, PERIOD always. Also group relevant fields like addr, phys_addr and data_page_size. Suggested-by: Peter Zijlstra Signed-off-by: Namhyung Kim Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20221229204101.1099430-1-namhyung@kernel.org --- include/linux/perf_event.h | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ad92ad37600e..03949d017ac9 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1098,47 +1098,51 @@ extern u64 perf_event_read_value(struct perf_event *event, struct perf_sample_data { /* - * Fields set by perf_sample_data_init(), group so as to - * minimize the cachelines touched. + * Fields set by perf_sample_data_init() unconditionally, + * group so as to minimize the cachelines touched. */ u64 sample_flags; u64 period; /* - * The other fields, optionally {set,used} by - * perf_{prepare,output}_sample(). + * Fields commonly set by __perf_event_header__init_id(), + * group so as to minimize the cachelines touched. */ - struct perf_branch_stack *br_stack; - union perf_sample_weight weight; - union perf_mem_data_src data_src; - u64 txn; - u64 addr; - struct perf_raw_record *raw; - u64 type; - u64 ip; struct { u32 pid; u32 tid; } tid_entry; u64 time; u64 id; - u64 stream_id; struct { u32 cpu; u32 reserved; } cpu_entry; + + /* + * The other fields, optionally {set,used} by + * perf_{prepare,output}_sample(). + */ + u64 ip; struct perf_callchain_entry *callchain; - u64 aux_size; + struct perf_raw_record *raw; + struct perf_branch_stack *br_stack; + union perf_sample_weight weight; + union perf_mem_data_src data_src; + u64 txn; struct perf_regs regs_user; struct perf_regs regs_intr; u64 stack_user_size; - u64 phys_addr; + u64 stream_id; u64 cgroup; + u64 addr; + u64 phys_addr; u64 data_page_size; u64 code_page_size; + u64 aux_size; } ____cacheline_aligned; /* default value for data source */ -- cgit v1.2.3 From 2bb185c68bf4c147f43d932e8a34fa150d148940 Mon Sep 17 00:00:00 2001 From: Luoyouming Date: Sat, 24 Dec 2022 18:22:00 +0800 Subject: RDMA/hns: Add compatibility handling for only support userspace rq inline The rq inline makes some changes as follows, Firstly, it is only used in user space. Secondly, it should notify hardware in QP RTR status. Thirdly, Add compatibility processing between different user space and kernel space. Link: https://lore.kernel.org/r/20221224102201.3114536-3-xuhaoyue1@hisilicon.com Signed-off-by: Luoyouming Signed-off-by: Haoyue Xu Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 2 +- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 30 ++++++++++++++++++++--------- drivers/infiniband/hw/hns/hns_roce_main.c | 6 ++++++ drivers/infiniband/hw/hns/hns_roce_qp.c | 2 +- include/uapi/rdma/hns-abi.h | 2 ++ 5 files changed, 31 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index b73307d0e210..e9957fc51ffc 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -871,7 +871,7 @@ struct hns_roce_hw { u32 step_idx); int (*modify_qp)(struct ib_qp *ibqp, const struct ib_qp_attr *attr, int attr_mask, enum ib_qp_state cur_state, - enum ib_qp_state new_state); + enum ib_qp_state new_state, struct ib_udata *udata); int (*qp_flow_control_init)(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp); void (*dereg_mr)(struct hns_roce_dev *hr_dev); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index c0c57b9ba452..c0b487bcd349 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -2837,7 +2837,7 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev, attr->port_num = 1; attr->qp_access_flags = IB_ACCESS_REMOTE_WRITE; ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_INIT, - IB_QPS_INIT); + IB_QPS_INIT, NULL); if (ret) { ibdev_err(ibdev, "failed to modify qp to init, ret = %d.\n", ret); @@ -2859,7 +2859,7 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev, rdma_ah_set_sl(&attr->ah_attr, (u8)sl_num); ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_INIT, - IB_QPS_RTR); + IB_QPS_RTR, NULL); hr_dev->loop_idc = loopback; if (ret) { ibdev_err(ibdev, "failed to modify qp to rtr, ret = %d.\n", @@ -2874,7 +2874,7 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev, attr->retry_cnt = HNS_ROCE_FREE_MR_USED_QP_RETRY_CNT; attr->timeout = HNS_ROCE_FREE_MR_USED_QP_TIMEOUT; ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_RTR, - IB_QPS_RTS); + IB_QPS_RTS, NULL); if (ret) ibdev_err(ibdev, "failed to modify qp to rts, ret = %d.\n", ret); @@ -4572,8 +4572,11 @@ static inline enum ib_mtu get_mtu(struct ib_qp *ibqp, static int modify_qp_init_to_rtr(struct ib_qp *ibqp, const struct ib_qp_attr *attr, int attr_mask, struct hns_roce_v2_qp_context *context, - struct hns_roce_v2_qp_context *qpc_mask) + struct hns_roce_v2_qp_context *qpc_mask, + struct ib_udata *udata) { + struct hns_roce_ucontext *uctx = rdma_udata_to_drv_context(udata, + struct hns_roce_ucontext, ibucontext); struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); struct ib_device *ibdev = &hr_dev->ib_dev; @@ -4693,6 +4696,14 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp, hr_reg_write(context, QPC_LP_SGEN_INI, 3); hr_reg_clear(qpc_mask, QPC_LP_SGEN_INI); + if (udata && ibqp->qp_type == IB_QPT_RC && + (uctx->config & HNS_ROCE_RQ_INLINE_FLAGS)) { + hr_reg_write_bool(context, QPC_RQIE, + hr_dev->caps.flags & + HNS_ROCE_CAP_FLAG_RQ_INLINE); + hr_reg_clear(qpc_mask, QPC_RQIE); + } + return 0; } @@ -5040,7 +5051,8 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp, enum ib_qp_state cur_state, enum ib_qp_state new_state, struct hns_roce_v2_qp_context *context, - struct hns_roce_v2_qp_context *qpc_mask) + struct hns_roce_v2_qp_context *qpc_mask, + struct ib_udata *udata) { struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); int ret = 0; @@ -5057,7 +5069,7 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp, modify_qp_init_to_init(ibqp, attr, context, qpc_mask); } else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) { ret = modify_qp_init_to_rtr(ibqp, attr, attr_mask, context, - qpc_mask); + qpc_mask, udata); } else if (cur_state == IB_QPS_RTR && new_state == IB_QPS_RTS) { ret = modify_qp_rtr_to_rts(ibqp, attr, attr_mask, context, qpc_mask); @@ -5262,7 +5274,7 @@ static void v2_set_flushed_fields(struct ib_qp *ibqp, static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, int attr_mask, enum ib_qp_state cur_state, - enum ib_qp_state new_state) + enum ib_qp_state new_state, struct ib_udata *udata) { struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); @@ -5285,7 +5297,7 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, memset(qpc_mask, 0xff, hr_dev->caps.qpc_sz); ret = hns_roce_v2_set_abs_fields(ibqp, attr, attr_mask, cur_state, - new_state, context, qpc_mask); + new_state, context, qpc_mask, udata); if (ret) goto out; @@ -5488,7 +5500,7 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev, if (modify_qp_is_ok(hr_qp)) { /* Modify qp to reset before destroying qp */ ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, NULL, 0, - hr_qp->state, IB_QPS_RESET); + hr_qp->state, IB_QPS_RESET, udata); if (ret) ibdev_err(ibdev, "failed to modify QP to RST, ret = %d.\n", diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 946ba1109e87..3e3ece03dec3 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -379,6 +379,12 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx, resp.max_inline_data = hr_dev->caps.max_sq_inline; } + if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) { + context->config |= ucmd.config & HNS_ROCE_RQ_INLINE_FLAGS; + if (context->config & HNS_ROCE_RQ_INLINE_FLAGS) + resp.config |= HNS_ROCE_RSP_RQ_INLINE_FLAGS; + } + ret = hns_roce_uar_alloc(hr_dev, &context->uar); if (ret) goto error_fail_uar_alloc; diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 53121422a915..d855a917f4cf 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -1346,7 +1346,7 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, goto out; ret = hr_dev->hw->modify_qp(ibqp, attr, attr_mask, cur_state, - new_state); + new_state, udata); out: mutex_unlock(&hr_qp->mutex); diff --git a/include/uapi/rdma/hns-abi.h b/include/uapi/rdma/hns-abi.h index 745790ce3c26..6c0940837d93 100644 --- a/include/uapi/rdma/hns-abi.h +++ b/include/uapi/rdma/hns-abi.h @@ -87,10 +87,12 @@ struct hns_roce_ib_create_qp_resp { enum { HNS_ROCE_EXSGE_FLAGS = 1 << 0, + HNS_ROCE_RQ_INLINE_FLAGS = 1 << 1, }; enum { HNS_ROCE_RSP_EXSGE_FLAGS = 1 << 0, + HNS_ROCE_RSP_RQ_INLINE_FLAGS = 1 << 1, }; struct hns_roce_ib_alloc_ucontext_resp { -- cgit v1.2.3 From 1d91855304c2046115ee10be2c93161d93d5d40d Mon Sep 17 00:00:00 2001 From: Luoyouming Date: Sat, 24 Dec 2022 18:22:01 +0800 Subject: RDMA/hns: Support cqe inline in user space Enable the CQEIE field and configure the CQEIS field of QPC. And add compatibility handling. Link: https://lore.kernel.org/r/20221224102201.3114536-4-xuhaoyue1@hisilicon.com Signed-off-by: Luoyouming Signed-off-by: Haoyue Xu Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/hns/hns_roce_device.h | 1 + drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 12 ++++++++++++ drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 3 ++- drivers/infiniband/hw/hns/hns_roce_main.c | 6 ++++++ include/uapi/rdma/hns-abi.h | 2 ++ 5 files changed, 23 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index e9957fc51ffc..84239b907de2 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -144,6 +144,7 @@ enum { HNS_ROCE_CAP_FLAG_DIRECT_WQE = BIT(12), HNS_ROCE_CAP_FLAG_SDI_MODE = BIT(14), HNS_ROCE_CAP_FLAG_STASH = BIT(17), + HNS_ROCE_CAP_FLAG_CQE_INLINE = BIT(19), }; #define HNS_ROCE_DB_TYPE_COUNT 2 diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index c0b487bcd349..dbf97fe5948f 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -4704,6 +4704,18 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp, hr_reg_clear(qpc_mask, QPC_RQIE); } + if (udata && + (ibqp->qp_type == IB_QPT_RC || ibqp->qp_type == IB_QPT_XRC_TGT) && + (uctx->config & HNS_ROCE_CQE_INLINE_FLAGS)) { + hr_reg_write_bool(context, QPC_CQEIE, + hr_dev->caps.flags & + HNS_ROCE_CAP_FLAG_CQE_INLINE); + hr_reg_clear(qpc_mask, QPC_CQEIE); + + hr_reg_write(context, QPC_CQEIS, 0); + hr_reg_clear(qpc_mask, QPC_CQEIS); + } + return 0; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index b1b3e1e0b84e..af9d00225cdf 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -531,7 +531,8 @@ struct hns_roce_v2_qp_context { #define QPC_RQ_RTY_TX_ERR QPC_FIELD_LOC(607, 607) #define QPC_RX_CQN QPC_FIELD_LOC(631, 608) #define QPC_XRC_QP_TYPE QPC_FIELD_LOC(632, 632) -#define QPC_RSV3 QPC_FIELD_LOC(634, 633) +#define QPC_CQEIE QPC_FIELD_LOC(633, 633) +#define QPC_CQEIS QPC_FIELD_LOC(634, 634) #define QPC_MIN_RNR_TIME QPC_FIELD_LOC(639, 635) #define QPC_RQ_PRODUCER_IDX QPC_FIELD_LOC(655, 640) #define QPC_RQ_CONSUMER_IDX QPC_FIELD_LOC(671, 656) diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 3e3ece03dec3..485e110ca433 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -385,6 +385,12 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx, resp.config |= HNS_ROCE_RSP_RQ_INLINE_FLAGS; } + if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_CQE_INLINE) { + context->config |= ucmd.config & HNS_ROCE_CQE_INLINE_FLAGS; + if (context->config & HNS_ROCE_CQE_INLINE_FLAGS) + resp.config |= HNS_ROCE_RSP_CQE_INLINE_FLAGS; + } + ret = hns_roce_uar_alloc(hr_dev, &context->uar); if (ret) goto error_fail_uar_alloc; diff --git a/include/uapi/rdma/hns-abi.h b/include/uapi/rdma/hns-abi.h index 6c0940837d93..2e68a8b0c92c 100644 --- a/include/uapi/rdma/hns-abi.h +++ b/include/uapi/rdma/hns-abi.h @@ -88,11 +88,13 @@ struct hns_roce_ib_create_qp_resp { enum { HNS_ROCE_EXSGE_FLAGS = 1 << 0, HNS_ROCE_RQ_INLINE_FLAGS = 1 << 1, + HNS_ROCE_CQE_INLINE_FLAGS = 1 << 2, }; enum { HNS_ROCE_RSP_EXSGE_FLAGS = 1 << 0, HNS_ROCE_RSP_RQ_INLINE_FLAGS = 1 << 1, + HNS_ROCE_RSP_CQE_INLINE_FLAGS = 1 << 2, }; struct hns_roce_ib_alloc_ucontext_resp { -- cgit v1.2.3 From 00a5d41ee1b05a8f0c75e1f7e26d363f4c68420e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 28 Sep 2022 14:19:08 +0200 Subject: ARM: omap2: smartreflex: remove on_init control Nothing calls omap_enable_smartreflex_on_init() any more, so it does not need to be tracked either. Acked-by: Tony Lindgren Signed-off-by: Arnd Bergmann --- arch/arm/mach-omap2/pm.h | 3 --- arch/arm/mach-omap2/sr_device.c | 13 ------------- drivers/soc/ti/smartreflex.c | 4 ---- include/linux/power/smartreflex.h | 3 --- 4 files changed, 23 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 80e84ae66aee..f523ca03161f 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -110,14 +110,11 @@ extern u16 pm44xx_errata; #ifdef CONFIG_POWER_AVS_OMAP extern int omap_devinit_smartreflex(void); -extern void omap_enable_smartreflex_on_init(void); #else static inline int omap_devinit_smartreflex(void) { return -EINVAL; } - -static inline void omap_enable_smartreflex_on_init(void) {} #endif #ifdef CONFIG_TWL4030_CORE diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c index db672cf19a51..d2133423b0c9 100644 --- a/arch/arm/mach-omap2/sr_device.c +++ b/arch/arm/mach-omap2/sr_device.c @@ -26,8 +26,6 @@ #include "control.h" #include "pm.h" -static bool sr_enable_on_init; - /* Read EFUSE values from control registers for OMAP3430 */ static void __init sr_set_nvalues(struct omap_volt_data *volt_data, struct omap_sr_data *sr_data) @@ -144,8 +142,6 @@ static int __init sr_init_by_name(const char *name, const char *voltdm) sr_set_nvalues(volt_data, sr_data); - sr_data->enable_on_init = sr_enable_on_init; - exit: i++; @@ -173,15 +169,6 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user) } #endif -/* - * API to be called from board files to enable smartreflex - * autocompensation at init. - */ -void __init omap_enable_smartreflex_on_init(void) -{ - sr_enable_on_init = true; -} - static const char * const omap4_sr_instances[] = { "mpu", "iva", diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c index 6a389a6444f3..9d9496e0a94c 100644 --- a/drivers/soc/ti/smartreflex.c +++ b/drivers/soc/ti/smartreflex.c @@ -198,7 +198,6 @@ static void sr_stop_vddautocomp(struct omap_sr *sr) */ static int sr_late_init(struct omap_sr *sr_info) { - struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data; int ret = 0; if (sr_class->notify && sr_class->notify_flags && sr_info->irq) { @@ -209,9 +208,6 @@ static int sr_late_init(struct omap_sr *sr_info) disable_irq(sr_info->irq); } - if (pdata && pdata->enable_on_init) - sr_start_vddautocomp(sr_info); - return ret; error: diff --git a/include/linux/power/smartreflex.h b/include/linux/power/smartreflex.h index 167b9b040091..3a2c79dfc1ff 100644 --- a/include/linux/power/smartreflex.h +++ b/include/linux/power/smartreflex.h @@ -273,8 +273,6 @@ struct omap_sr_nvalue_table { * @senn_avgweight SENNAVGWEIGHT value of the sr AVGWEIGHT register * @senp_avgweight SENPAVGWEIGHT value of the sr AVGWEIGHT register * @nvalue_count: Number of distinct nvalues in the nvalue table - * @enable_on_init: whether this sr module needs to enabled at - * boot up or not. * @nvalue_table: table containing the efuse offsets and nvalues * corresponding to them. * @voltdm: Pointer to the voltage domain associated with the SR @@ -290,7 +288,6 @@ struct omap_sr_data { u32 senn_avgweight; u32 senp_avgweight; int nvalue_count; - bool enable_on_init; struct omap_sr_nvalue_table *nvalue_table; struct voltagedomain *voltdm; }; -- cgit v1.2.3 From 6aeb51c1035c1c9dd666897892d5cb168933ce7b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 28 Sep 2022 17:09:42 +0200 Subject: ARM: omap2: make functions static A number of functions are only called from the file they are defined in, so remove the extern declarations and make them local to those files. Acked-by: Tony Lindgren Signed-off-by: Arnd Bergmann --- arch/arm/mach-omap2/board-n8x0.c | 2 +- arch/arm/mach-omap2/clockdomain.c | 4 ++-- arch/arm/mach-omap2/clockdomain.h | 2 -- arch/arm/mach-omap2/cm2xxx.c | 4 ++-- arch/arm/mach-omap2/cm2xxx.h | 2 -- arch/arm/mach-omap2/common.h | 2 -- arch/arm/mach-omap2/id.c | 2 +- arch/arm/mach-omap2/id.h | 2 -- arch/arm/mach-omap2/io.c | 2 +- arch/arm/mach-omap2/omap-secure.c | 2 +- arch/arm/mach-omap2/omap-secure.h | 2 -- arch/arm/mach-omap2/omap_device.c | 14 ++++++++++---- arch/arm/mach-omap2/omap_device.h | 9 --------- arch/arm/mach-omap2/omap_hwmod.c | 4 +++- arch/arm/mach-omap2/omap_hwmod.h | 1 - arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c | 6 +++--- arch/arm/mach-omap2/omap_hwmod_common_data.h | 4 ---- arch/arm/mach-omap2/pm.c | 2 +- arch/arm/mach-omap2/powerdomain.c | 8 ++++---- arch/arm/mach-omap2/powerdomain.h | 3 --- arch/arm/mach-omap2/prcm-common.h | 1 - arch/arm/mach-omap2/prm.h | 1 - arch/arm/mach-omap2/prm3xxx.c | 5 +++-- arch/arm/mach-omap2/prm3xxx.h | 2 -- arch/arm/mach-omap2/prm_common.c | 4 ++-- arch/arm/mach-omap2/sdrc.c | 2 +- arch/arm/mach-omap2/sdrc.h | 1 - arch/arm/mach-omap2/usb-tusb6010.c | 6 ++---- arch/arm/mach-omap2/voltage.c | 2 +- arch/arm/mach-omap2/voltage.h | 1 - include/linux/platform_data/voltage-omap.h | 1 - include/linux/usb/musb.h | 2 -- 33 files changed, 39 insertions(+), 68 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 8897364e550b..3353b0a923d9 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -504,7 +504,7 @@ static void __init n8x0_mmc_init(void) } #else static struct omap_mmc_platform_data mmc1_data; -void __init n8x0_mmc_init(void) +static void __init n8x0_mmc_init(void) { } #endif /* CONFIG_MMC_OMAP */ diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index f4e488e72515..d145e7ac709b 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -831,7 +831,7 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) * -EINVAL if @clkdm is NULL or if clockdomain does not support * software-initiated sleep; 0 upon success. */ -int clkdm_sleep_nolock(struct clockdomain *clkdm) +static int clkdm_sleep_nolock(struct clockdomain *clkdm) { int ret; @@ -885,7 +885,7 @@ int clkdm_sleep(struct clockdomain *clkdm) * -EINVAL if @clkdm is NULL or if the clockdomain does not support * software-controlled wakeup; 0 upon success. */ -int clkdm_wakeup_nolock(struct clockdomain *clkdm) +static int clkdm_wakeup_nolock(struct clockdomain *clkdm) { int ret; diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index a6bce3795a32..c36fb2721261 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h @@ -204,9 +204,7 @@ void clkdm_allow_idle(struct clockdomain *clkdm); void clkdm_deny_idle_nolock(struct clockdomain *clkdm); void clkdm_deny_idle(struct clockdomain *clkdm); -int clkdm_wakeup_nolock(struct clockdomain *clkdm); int clkdm_wakeup(struct clockdomain *clkdm); -int clkdm_sleep_nolock(struct clockdomain *clkdm); int clkdm_sleep(struct clockdomain *clkdm); int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index 17833e0f22f8..1c6d69f4bf49 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c @@ -145,8 +145,8 @@ static int omap2xxx_cm_split_idlest_reg(struct clk_omap_reg *idlest_reg, * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * success or -EBUSY if the module doesn't enable in time. */ -int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, - u8 idlest_shift) +static int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift) { int ena = 0, i = 0; u8 cm_idlest_reg; diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h index ee0cb40691b2..7cbeff15ffb0 100644 --- a/arch/arm/mach-omap2/cm2xxx.h +++ b/arch/arm/mach-omap2/cm2xxx.h @@ -46,8 +46,6 @@ extern void omap2xxx_cm_set_dpll_disable_autoidle(void); extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void); -int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, - u8 idlest_shift); extern int omap2xxx_cm_fclks_active(void); extern int omap2xxx_cm_mpu_retention_allowed(void); extern u32 omap2xxx_cm_get_core_clk_src(void); diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index ebf0266e1943..08034d589081 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -106,7 +106,6 @@ void omap2420_init_early(void); void omap2430_init_early(void); void omap3430_init_early(void); void omap3630_init_early(void); -void omap3_init_early(void); /* Do not use this one */ void am33xx_init_early(void); void am35xx_init_early(void); void ti814x_init_early(void); @@ -120,7 +119,6 @@ void omap4430_init_late(void); void ti81xx_init_late(void); void am33xx_init_late(void); void omap5_init_late(void); -int omap2_common_pm_late_init(void); void dra7xx_init_early(void); void dra7xx_init_late(void); diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 59755b5a1ad7..98999aa8cc0c 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -117,7 +117,7 @@ static struct omap_id omap_ids[] __initdata = { static void __iomem *tap_base; static u16 tap_prod_id; -void omap_get_die_id(struct omap_die_id *odi) +static void omap_get_die_id(struct omap_die_id *odi) { if (soc_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) { odi->id_0 = read_tap_reg(OMAP_TAP_DIE_ID_44XX_0); diff --git a/arch/arm/mach-omap2/id.h b/arch/arm/mach-omap2/id.h index d1735f4497e3..ded7392f0526 100644 --- a/arch/arm/mach-omap2/id.h +++ b/arch/arm/mach-omap2/id.h @@ -14,6 +14,4 @@ struct omap_die_id { u32 id_3; }; -void omap_get_die_id(struct omap_die_id *odi); - #endif diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 81cb175c2dbe..14ec3f78000b 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -461,7 +461,7 @@ void __init omap2430_init_early(void) * same machine_id for 34xx and 36xx beagle.. Will get fixed with DT. */ #ifdef CONFIG_ARCH_OMAP3 -void __init omap3_init_early(void) +static void __init omap3_init_early(void) { omap2_set_globals_tap(OMAP343X_CLASS, OMAP2_L4_IO_ADDRESS(0x4830A000)); omap2_set_globals_sdrc(OMAP2_L3_IO_ADDRESS(OMAP343X_SDRC_BASE), diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c index 41aec5c93a70..29c7350b06ab 100644 --- a/arch/arm/mach-omap2/omap-secure.c +++ b/arch/arm/mach-omap2/omap-secure.c @@ -152,7 +152,7 @@ u32 omap3_save_secure_ram(void *addr, int size) * NOTE: rx51_secure_dispatcher differs from omap_secure_dispatcher because * it calling omap_smc3() instead omap_smc2() and param[0] is nargs+1 */ -u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs, +static u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { static u32 param[5]; diff --git a/arch/arm/mach-omap2/omap-secure.h b/arch/arm/mach-omap2/omap-secure.h index 2ce26a86b7bd..2517c4a5a0e2 100644 --- a/arch/arm/mach-omap2/omap-secure.h +++ b/arch/arm/mach-omap2/omap-secure.h @@ -74,8 +74,6 @@ extern int omap_secure_ram_reserve_memblock(void); extern u32 save_secure_ram_context(u32 args_pa); extern u32 omap3_save_secure_ram(void *save_regs, int size); -extern u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs, - u32 arg1, u32 arg2, u32 arg3, u32 arg4); extern u32 rx51_secure_update_aux_cr(u32 set_bits, u32 clear_bits); extern u32 rx51_secure_rng_call(u32 ptr, u32 count, u32 flag); diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index 0594aaaa1a98..4afa2f08e668 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -39,6 +39,12 @@ #include "omap_device.h" #include "omap_hwmod.h" +static struct omap_device *omap_device_alloc(struct platform_device *pdev, + struct omap_hwmod **ohs, int oh_cnt); +static void omap_device_delete(struct omap_device *od); +static struct dev_pm_domain omap_device_fail_pm_domain; +static struct dev_pm_domain omap_device_pm_domain; + /* Private functions */ static void _add_clkdev(struct omap_device *od, const char *clk_alias, @@ -296,7 +302,7 @@ static int _omap_device_idle_hwmods(struct omap_device *od) * * Returns an struct omap_device pointer or ERR_PTR() on error; */ -struct omap_device *omap_device_alloc(struct platform_device *pdev, +static struct omap_device *omap_device_alloc(struct platform_device *pdev, struct omap_hwmod **ohs, int oh_cnt) { int ret = -ENOMEM; @@ -333,7 +339,7 @@ oda_exit1: return ERR_PTR(ret); } -void omap_device_delete(struct omap_device *od) +static void omap_device_delete(struct omap_device *od) { if (!od) return; @@ -425,14 +431,14 @@ static int _od_resume_noirq(struct device *dev) #define _od_resume_noirq NULL #endif -struct dev_pm_domain omap_device_fail_pm_domain = { +static struct dev_pm_domain omap_device_fail_pm_domain = { .ops = { SET_RUNTIME_PM_OPS(_od_fail_runtime_suspend, _od_fail_runtime_resume, NULL) } }; -struct dev_pm_domain omap_device_pm_domain = { +static struct dev_pm_domain omap_device_pm_domain = { .ops = { SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume, NULL) diff --git a/arch/arm/mach-omap2/omap_device.h b/arch/arm/mach-omap2/omap_device.h index 455f0a2b43ee..aa8096ecb23c 100644 --- a/arch/arm/mach-omap2/omap_device.h +++ b/arch/arm/mach-omap2/omap_device.h @@ -25,9 +25,6 @@ #include "omap_hwmod.h" -extern struct dev_pm_domain omap_device_pm_domain; -extern struct dev_pm_domain omap_device_fail_pm_domain; - /* omap_device._state values */ #define OMAP_DEVICE_STATE_UNKNOWN 0 #define OMAP_DEVICE_STATE_ENABLED 1 @@ -66,12 +63,6 @@ struct omap_device { int omap_device_enable(struct platform_device *pdev); int omap_device_idle(struct platform_device *pdev); -/* Core code interface */ - -struct omap_device *omap_device_alloc(struct platform_device *pdev, - struct omap_hwmod **ohs, int oh_cnt); -void omap_device_delete(struct omap_device *od); - /* Other */ int omap_device_assert_hardreset(struct platform_device *pdev, diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index b03be626bc99..5a2a9b8e61ed 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -3054,6 +3054,8 @@ int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois) return 0; } +static int __init omap_hwmod_setup_one(const char *oh_name); + /** * _ensure_mpu_hwmod_is_setup - ensure the MPU SS hwmod is init'ed and set up * @oh: pointer to the hwmod currently being set up (usually not the MPU) @@ -3084,7 +3086,7 @@ static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh) * registered omap_hwmod. Also calls _setup() on each hwmod. Returns * -EINVAL upon error or 0 upon success. */ -int __init omap_hwmod_setup_one(const char *oh_name) +static int __init omap_hwmod_setup_one(const char *oh_name) { struct omap_hwmod *oh; diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index b6b53170ad1e..dcab7a01c10e 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -615,7 +615,6 @@ struct omap_hwmod *omap_hwmod_lookup(const char *name); int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), void *data); -int __init omap_hwmod_setup_one(const char *name); int omap_hwmod_parse_module_range(struct omap_hwmod *oh, struct device_node *np, struct resource *res); diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c index 2581b8a5f866..67f1f38909d9 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c @@ -62,7 +62,7 @@ struct omap_hwmod_class iva_hwmod_class = { .name = "iva", }; -struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc = { +static struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc = { .rev_offs = 0x0, .sysc_offs = 0x14, .syss_offs = 0x18, diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c index 9ab1d57f8b73..4982e04ead53 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c @@ -30,7 +30,7 @@ static struct omap_hwmod_class_sysconfig omap2_dispc_sysc = { .sysc_fields = &omap_hwmod_sysc_type1, }; -struct omap_hwmod_class omap2_dispc_hwmod_class = { +static struct omap_hwmod_class omap2_dispc_hwmod_class = { .name = "dispc", .sysc = &omap2_dispc_sysc, }; @@ -47,7 +47,7 @@ static struct omap_hwmod_class_sysconfig omap2xxx_timer_sysc = { .sysc_fields = &omap_hwmod_sysc_type1, }; -struct omap_hwmod_class omap2xxx_timer_hwmod_class = { +static struct omap_hwmod_class omap2xxx_timer_hwmod_class = { .name = "timer", .sysc = &omap2xxx_timer_sysc, }; @@ -67,7 +67,7 @@ static struct omap_hwmod_class_sysconfig omap2xxx_wd_timer_sysc = { .sysc_fields = &omap_hwmod_sysc_type1, }; -struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class = { +static struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class = { .name = "wd_timer", .sysc = &omap2xxx_wd_timer_sysc, .pre_shutdown = &omap2_wd_timer_disable, diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.h b/arch/arm/mach-omap2/omap_hwmod_common_data.h index e0d65ad65614..69dddc53e1d8 100644 --- a/arch/arm/mach-omap2/omap_hwmod_common_data.h +++ b/arch/arm/mach-omap2/omap_hwmod_common_data.h @@ -84,14 +84,10 @@ extern struct omap_hwmod_class mpu_hwmod_class; extern struct omap_hwmod_class iva_hwmod_class; extern struct omap_hwmod_class omap2_uart_class; extern struct omap_hwmod_class omap2_dss_hwmod_class; -extern struct omap_hwmod_class omap2_dispc_hwmod_class; extern struct omap_hwmod_class omap2_rfbi_hwmod_class; extern struct omap_hwmod_class omap2_venc_hwmod_class; -extern struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc; extern struct omap_hwmod_class omap2_hdq1w_class; -extern struct omap_hwmod_class omap2xxx_timer_hwmod_class; -extern struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class; extern struct omap_hwmod_class omap2xxx_gpio_hwmod_class; extern struct omap_hwmod_class omap2xxx_mailbox_hwmod_class; extern struct omap_hwmod_class omap2xxx_mcspi_class; diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 53a132f11961..700869c9eae1 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -134,7 +134,7 @@ int __maybe_unused omap_pm_nop_init(void) int (*omap_pm_soc_init)(void); -int __init omap2_common_pm_late_init(void) +static int __init omap2_common_pm_late_init(void) { int error; diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 0155a1e57a87..fd974514a7b2 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -37,8 +37,8 @@ #define PWRDM_TRACE_STATES_FLAG (1<<31) -void pwrdms_save_context(void); -void pwrdms_restore_context(void); +static void pwrdms_save_context(void); +static void pwrdms_restore_context(void); enum { PWRDM_STATE_NOW = 0, @@ -1174,12 +1174,12 @@ static int pwrdm_restore_context(struct powerdomain *pwrdm, void *unused) return 0; } -void pwrdms_save_context(void) +static void pwrdms_save_context(void) { pwrdm_for_each(pwrdm_save_context, NULL); } -void pwrdms_restore_context(void) +static void pwrdms_restore_context(void) { pwrdm_for_each(pwrdm_restore_context, NULL); } diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 4c5284d0fd62..fbc89999460b 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h @@ -269,7 +269,4 @@ extern struct powerdomain gfx_omap2_pwrdm; extern void pwrdm_lock(struct powerdomain *pwrdm); extern void pwrdm_unlock(struct powerdomain *pwrdm); -extern void pwrdms_save_context(void); -extern void pwrdms_restore_context(void); - #endif diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 48e804c93caf..5e3544a63526 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h @@ -550,7 +550,6 @@ struct omap_prcm_init_data { struct device_node *np; }; -extern void omap_prcm_irq_cleanup(void); extern int omap_prcm_register_chain_handler( struct omap_prcm_irq_setup *irq_setup); extern int omap_prcm_event_to_irq(const char *event); diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index bad15ba5256c..fc45a7ed09bb 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -16,7 +16,6 @@ extern struct omap_domain_base prm_base; extern u16 prm_features; int omap_prcm_init(void); -int omap2_prm_base_init(void); int omap2_prcm_base_init(void); # endif diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index 63e73e9b82bc..1b5d08f594aa 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -32,6 +32,7 @@ static void omap3xxx_prm_read_pending_irqs(unsigned long *events); static void omap3xxx_prm_ocp_barrier(void); static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); static void omap3xxx_prm_restore_irqen(u32 *saved_mask); +static void omap3xxx_prm_iva_idle(void); static const struct omap_prcm_irq omap3_prcm_irqs[] = { OMAP_PRCM_IRQ("wkup", 0, 0), @@ -268,7 +269,7 @@ static int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask) * Toggles the reset signal to modem IP block. Required to allow * OMAP3430 without stacked modem to idle properly. */ -void __init omap3_prm_reset_modem(void) +static void __init omap3_prm_reset_modem(void) { omap2_prm_write_mod_reg( OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON_MASK | @@ -469,7 +470,7 @@ static u32 omap3xxx_prm_read_reset_sources(void) * function forces the IVA2 into idle state so it can go * into retention/off and thus allow full-chip retention/off. */ -void omap3xxx_prm_iva_idle(void) +static void omap3xxx_prm_iva_idle(void) { /* ensure IVA2 clock is disabled */ omap2_cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); diff --git a/arch/arm/mach-omap2/prm3xxx.h b/arch/arm/mach-omap2/prm3xxx.h index ed7c389aa5a7..ab899e461c62 100644 --- a/arch/arm/mach-omap2/prm3xxx.h +++ b/arch/arm/mach-omap2/prm3xxx.h @@ -138,8 +138,6 @@ extern void omap3_prm_vcvp_write(u32 val, u8 offset); extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); int __init omap3xxx_prm_init(const struct omap_prcm_init_data *data); -void omap3xxx_prm_iva_idle(void); -void omap3_prm_reset_modem(void); int omap3xxx_prm_clear_global_cold_reset(void); void omap3_prm_save_scratchpad_contents(u32 *ptr); void omap3_prm_init_pm(bool has_uart4, bool has_iva); diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index 9a27f566612f..fd896f2295a1 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -187,7 +187,7 @@ int omap_prcm_event_to_irq(const char *name) * * No return value. */ -void omap_prcm_irq_cleanup(void) +static void omap_prcm_irq_cleanup(void) { unsigned int irq; int i; @@ -689,7 +689,7 @@ static const struct of_device_id omap_prcm_dt_match_table[] __initconst = { * on the DT data. Returns 0 in success, negative error value * otherwise. */ -int __init omap2_prm_base_init(void) +static int __init omap2_prm_base_init(void) { struct device_node *np; const struct of_device_id *match; diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c index 9900fc777f39..b1bf9e24d442 100644 --- a/arch/arm/mach-omap2/sdrc.c +++ b/arch/arm/mach-omap2/sdrc.c @@ -45,7 +45,7 @@ static struct omap2_sms_regs sms_context; * * Save SMS registers that need to be restored after off mode. */ -void omap2_sms_save_context(void) +static void omap2_sms_save_context(void) { sms_context.sms_sysconfig = sms_read_reg(SMS_SYSCONFIG); } diff --git a/arch/arm/mach-omap2/sdrc.h b/arch/arm/mach-omap2/sdrc.h index 07ff33b006a7..45b35422b587 100644 --- a/arch/arm/mach-omap2/sdrc.h +++ b/arch/arm/mach-omap2/sdrc.h @@ -80,7 +80,6 @@ static inline void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0, struct omap_sdrc_params *sdrc_cs1) {}; #endif -void omap2_sms_save_context(void); void omap2_sms_restore_context(void); struct memory_timings { diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c index a0c4c42e56b9..18fa52f828dc 100644 --- a/arch/arm/mach-omap2/usb-tusb6010.c +++ b/arch/arm/mach-omap2/usb-tusb6010.c @@ -97,7 +97,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps) } /* tusb driver calls this when it changes the chip's clocking */ -int tusb6010_platform_retime(unsigned is_refclk) +static int tusb6010_platform_retime(unsigned is_refclk) { static const char error[] = KERN_ERR "tusb6010 %s retime error %d\n"; @@ -121,7 +121,6 @@ int tusb6010_platform_retime(unsigned is_refclk) done: return status; } -EXPORT_SYMBOL_GPL(tusb6010_platform_retime); static struct resource tusb_resources[] = { /* Order is significant! The start/end fields @@ -154,8 +153,7 @@ static struct platform_device tusb_device = { /* this may be called only from board-*.c setup code */ -int __init -tusb6010_setup_interface(struct musb_hdrc_platform_data *data, +int __init tusb6010_setup_interface(struct musb_hdrc_platform_data *data, unsigned ps_refclk, unsigned waitpin, unsigned async, unsigned sync, unsigned irq, unsigned dmachan) diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c index 0a0c771dbb0a..49e8bc69abdd 100644 --- a/arch/arm/mach-omap2/voltage.c +++ b/arch/arm/mach-omap2/voltage.c @@ -67,7 +67,7 @@ unsigned long voltdm_get_voltage(struct voltagedomain *voltdm) * This API should be called by the kernel to do the voltage scaling * for a particular voltage domain during DVFS. */ -int voltdm_scale(struct voltagedomain *voltdm, +static int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt) { int ret, i; diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index 5beb91ce3b38..e610f63a020d 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -163,7 +163,6 @@ extern void omap54xx_voltagedomains_init(void); struct voltagedomain *voltdm_lookup(const char *name); void voltdm_init(struct voltagedomain **voltdm_list); -int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt); void voltdm_reset(struct voltagedomain *voltdm); unsigned long voltdm_get_voltage(struct voltagedomain *voltdm); #endif diff --git a/include/linux/platform_data/voltage-omap.h b/include/linux/platform_data/voltage-omap.h index 43e8da9fb447..6d74e507dbd2 100644 --- a/include/linux/platform_data/voltage-omap.h +++ b/include/linux/platform_data/voltage-omap.h @@ -29,7 +29,6 @@ struct omap_volt_data { struct voltagedomain; struct voltagedomain *voltdm_lookup(const char *name); -int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt); unsigned long voltdm_get_voltage(struct voltagedomain *voltdm); struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm, unsigned long volt); diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h index fc6c77918481..e4a3ad3c800f 100644 --- a/include/linux/usb/musb.h +++ b/include/linux/usb/musb.h @@ -143,8 +143,6 @@ extern int __init tusb6010_setup_interface( unsigned async_cs, unsigned sync_cs, unsigned irq, unsigned dmachan); -extern int tusb6010_platform_retime(unsigned is_refclk); - #endif /* OMAP2 */ #endif /* __LINUX_USB_MUSB_H */ -- cgit v1.2.3 From be505ba8fe90068868bc084cad2079a38486b2d5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 18 Nov 2022 10:58:06 +0800 Subject: ASoC/soundwire: remove is_sdca boolean property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Device_ID registers already tell us if a device supports the SDCA specification or not, in hindsight we never needed a property when the information is reported by both hardware and ACPI. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Reviewed-by: Charles Keepax Acked-by: Mark Brown Link: https://lore.kernel.org/r/20221118025807.534863-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 4 ++-- include/linux/soundwire/sdw.h | 2 -- sound/soc/codecs/rt1316-sdw.c | 1 - sound/soc/codecs/rt1318-sdw.c | 1 - sound/soc/codecs/rt711-sdca-sdw.c | 1 - 5 files changed, 2 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 76515c33e639..c23275b443ac 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1587,7 +1587,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) goto io_err; } - if (slave->prop.is_sdca) { + if (slave->id.class_id) { ret = sdw_read_no_pm(slave, SDW_DP0_INT); if (ret < 0) { dev_err(&slave->dev, @@ -1724,7 +1724,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) goto io_err; } - if (slave->prop.is_sdca) { + if (slave->id.class_id) { ret = sdw_read_no_pm(slave, SDW_DP0_INT); if (ret < 0) { dev_err(&slave->dev, diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 9e4537f409c2..8fb458931772 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -365,7 +365,6 @@ struct sdw_dpn_prop { * @sink_dpn_prop: Sink Data Port N properties * @scp_int1_mask: SCP_INT1_MASK desired settings * @quirks: bitmask identifying deltas from the MIPI specification - * @is_sdca: the Slave supports the SDCA specification */ struct sdw_slave_prop { u32 mipi_revision; @@ -389,7 +388,6 @@ struct sdw_slave_prop { struct sdw_dpn_prop *sink_dpn_prop; u8 scp_int1_mask; u32 quirks; - bool is_sdca; }; #define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0) diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index e6294cc7a995..c270fd9f8548 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -204,7 +204,6 @@ static int rt1316_read_prop(struct sdw_slave *slave) prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; - prop->is_sdca = true; prop->paging_support = true; diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index f85f5ab2c6d0..8bc379215c34 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -353,7 +353,6 @@ static int rt1318_read_prop(struct sdw_slave *slave) prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; - prop->is_sdca = true; prop->paging_support = true; diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 88a8392a58ed..693e11ed8d08 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -186,7 +186,6 @@ static int rt711_sdca_read_prop(struct sdw_slave *slave) prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; - prop->is_sdca = true; prop->paging_support = true; -- cgit v1.2.3 From ffa1726589a7cc4bd96a7f19f43cecdb7342478f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 18 Nov 2022 10:58:07 +0800 Subject: soundwire: enable optional clock registers for SoundWire 1.2 devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bus supports the mandatory clock registers for SDCA devices, these registers can also be optionally supported by SoundWire 1.2 devices that don't follow the SDCA class specification. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Péter Ujfalusi Signed-off-by: Bard Liao Reviewed-by: Charles Keepax Link: https://lore.kernel.org/r/20221118025807.534863-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 7 ++++--- include/linux/soundwire/sdw.h | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index c23275b443ac..55d393247a0f 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1233,10 +1233,11 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave) /* * frequency base and scale registers are required for SDCA - * devices. They may also be used for 1.2+/non-SDCA devices, - * but we will need a DisCo property to cover this case + * devices. They may also be used for 1.2+/non-SDCA devices. + * Driver can set the property, we will need a DisCo property + * to discover this case from platform firmware. */ - if (!slave->id.class_id) + if (!slave->id.class_id && !slave->prop.clock_reg_supported) return 0; if (!mclk_freq) { diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 8fb458931772..9a49263c53cf 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -365,6 +365,9 @@ struct sdw_dpn_prop { * @sink_dpn_prop: Sink Data Port N properties * @scp_int1_mask: SCP_INT1_MASK desired settings * @quirks: bitmask identifying deltas from the MIPI specification + * @clock_reg_supported: the Peripheral implements the clock base and scale + * registers introduced with the SoundWire 1.2 specification. SDCA devices + * do not need to set this boolean property as the registers are required. */ struct sdw_slave_prop { u32 mipi_revision; @@ -388,6 +391,7 @@ struct sdw_slave_prop { struct sdw_dpn_prop *sink_dpn_prop; u8 scp_int1_mask; u32 quirks; + bool clock_reg_supported; }; #define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0) -- cgit v1.2.3 From 62dc9f3f2fd07a2d4f4c97d76403f387363cb637 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 25 Nov 2022 14:20:25 +0000 Subject: soundwire: bus: export sdw_nwrite_no_pm and sdw_nread_no_pm functions The commit 167790abb90f ("soundwire: export sdw_write/read_no_pm functions") exposed the single byte no_pm versions of the IO functions that can be used without touching PM, export the multi byte no_pm versions for the same reason. Reviewed-by: Pierre-Louis Bossart Signed-off-by: Simon Trimmer Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20221125142028.1118618-2-ckeepax@opensource.cirrus.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 8 ++++---- include/linux/soundwire/sdw.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 55d393247a0f..8a5dc0ea2d3a 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -414,8 +414,7 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave, * all clients need to use the pm versions */ -static int -sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) +int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) { struct sdw_msg msg; int ret; @@ -430,9 +429,9 @@ sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) ret = 0; return ret; } +EXPORT_SYMBOL(sdw_nread_no_pm); -static int -sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) +int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) { struct sdw_msg msg; int ret; @@ -447,6 +446,7 @@ sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) ret = 0; return ret; } +EXPORT_SYMBOL(sdw_nwrite_no_pm); int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) { diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 9a49263c53cf..13019e3904b6 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -1049,7 +1049,9 @@ int sdw_write(struct sdw_slave *slave, u32 addr, u8 value); int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value); int sdw_read_no_pm(struct sdw_slave *slave, u32 addr); int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); +int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val); +int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val); int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val); int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val); -- cgit v1.2.3 From 6726b47a2a60e3f2ef15ee7c4c6d9caa27770576 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 25 Nov 2022 14:20:26 +0000 Subject: soundwire: Provide build stubs for common functions Provide stub functions when CONFIG_SOUNDWIRE is not set for functions that are quite likely to be used from common code on devices supporting multiple control buses. Reviewed-by: Pierre-Louis Bossart Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20221125142028.1118618-3-ckeepax@opensource.cirrus.com Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 105 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 13019e3904b6..3cd2a761911f 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -4,6 +4,7 @@ #ifndef __SOUNDWIRE_H #define __SOUNDWIRE_H +#include #include #include @@ -1023,15 +1024,8 @@ int sdw_stream_add_master(struct sdw_bus *bus, struct sdw_port_config *port_config, unsigned int num_ports, struct sdw_stream_runtime *stream); -int sdw_stream_add_slave(struct sdw_slave *slave, - struct sdw_stream_config *stream_config, - struct sdw_port_config *port_config, - unsigned int num_ports, - struct sdw_stream_runtime *stream); int sdw_stream_remove_master(struct sdw_bus *bus, struct sdw_stream_runtime *stream); -int sdw_stream_remove_slave(struct sdw_slave *slave, - struct sdw_stream_runtime *stream); int sdw_startup_stream(void *sdw_substream); int sdw_prepare_stream(struct sdw_stream_runtime *stream); int sdw_enable_stream(struct sdw_stream_runtime *stream); @@ -1042,8 +1036,20 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus); int sdw_bus_clk_stop(struct sdw_bus *bus); int sdw_bus_exit_clk_stop(struct sdw_bus *bus); -/* messaging and data APIs */ +int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id); +void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id); +#if IS_ENABLED(CONFIG_SOUNDWIRE) + +int sdw_stream_add_slave(struct sdw_slave *slave, + struct sdw_stream_config *stream_config, + struct sdw_port_config *port_config, + unsigned int num_ports, + struct sdw_stream_runtime *stream); +int sdw_stream_remove_slave(struct sdw_slave *slave, + struct sdw_stream_runtime *stream); + +/* messaging and data APIs */ int sdw_read(struct sdw_slave *slave, u32 addr); int sdw_write(struct sdw_slave *slave, u32 addr, u8 value); int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value); @@ -1055,7 +1061,86 @@ int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 * int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val); int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val); -int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id); -void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id); +#else + +static inline int sdw_stream_add_slave(struct sdw_slave *slave, + struct sdw_stream_config *stream_config, + struct sdw_port_config *port_config, + unsigned int num_ports, + struct sdw_stream_runtime *stream) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_stream_remove_slave(struct sdw_slave *slave, + struct sdw_stream_runtime *stream) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +/* messaging and data APIs */ +static inline int sdw_read(struct sdw_slave *slave, u32 addr) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_write(struct sdw_slave *slave, u32 addr, u8 value) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_read_no_pm(struct sdw_slave *slave, u32 addr) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +static inline int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val) +{ + WARN_ONCE(1, "SoundWire API is disabled"); + return -EINVAL; +} + +#endif /* CONFIG_SOUNDWIRE */ #endif /* __SOUNDWIRE_H */ -- cgit v1.2.3 From 0ac7200e3317bdde7b96112f24b9253208c0258b Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 28 Dec 2022 00:45:04 +0000 Subject: Revert "mfd: cros_ec: Add SCP Core-1 as a new CrOS EC MCU" This reverts commit 66ee379d743c69c726b61d078119a34d5be96a35. The feature flag introduced by Commit 66ee379d743c ("mfd: cros_ec: Add SCP Core-1 as a new CrOS EC MCU") was not first added in the source EC code base[1]. This can lead to the possible misinterpration of an EC's supported feature set, as well as causes issues with all future feature flag updates. [1] https://source.chromium.org/chromium/chromiumos/platform/ec/+/main:include/ec_commands.h Signed-off-by: Prashant Malani Acked-by: Lee Jones Reviewed-by: Benson Leung Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20221228004648.793339-2-pmalani@chromium.org --- drivers/mfd/cros_ec_dev.c | 5 ----- include/linux/platform_data/cros_ec_commands.h | 2 -- include/linux/platform_data/cros_ec_proto.h | 1 - 3 files changed, 8 deletions(-) (limited to 'include') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 344ad03bdc42..02d4271dfe06 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -64,11 +64,6 @@ static const struct cros_feature_to_name cros_mcu_devices[] = { .name = CROS_EC_DEV_SCP_NAME, .desc = "System Control Processor", }, - { - .id = EC_FEATURE_SCP_C1, - .name = CROS_EC_DEV_SCP_C1_NAME, - .desc = "System Control Processor 2nd Core", - }, { .id = EC_FEATURE_TOUCHPAD, .name = CROS_EC_DEV_TP_NAME, diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 5744a2d746aa..7c94bf5c8f05 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -1300,8 +1300,6 @@ enum ec_feature_code { * mux. */ EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK = 43, - /* The MCU is a System Companion Processor (SCP) 2nd Core. */ - EC_FEATURE_SCP_C1 = 45, }; #define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32) diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 7fb2196f99b0..017d502ed66e 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -19,7 +19,6 @@ #define CROS_EC_DEV_ISH_NAME "cros_ish" #define CROS_EC_DEV_PD_NAME "cros_pd" #define CROS_EC_DEV_SCP_NAME "cros_scp" -#define CROS_EC_DEV_SCP_C1_NAME "cros_scp_c1" #define CROS_EC_DEV_TP_NAME "cros_tp" #define CROS_EC_DEV_EC_INDEX 0 -- cgit v1.2.3 From 0e0dba884c4318c433756118794a7dff8947e6ce Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 28 Dec 2022 00:45:05 +0000 Subject: platform_chrome: cros_ec: Add Type-C VDM defines Add the EC header changes need to support USB Type-C VDM (Vendor Defined Messages) communication between the system and USB PD-enabled peripherals. The headers are already present in the EC code base, from which they've been ported [1]. [1] https://source.chromium.org/chromium/chromiumos/platform/ec/+/main:include/ec_commands.h Signed-off-by: Prashant Malani Reviewed-by: Benson Leung Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20221228004648.793339-3-pmalani@chromium.org --- include/linux/platform_data/cros_ec_commands.h | 51 ++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'include') diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 7c94bf5c8f05..6665e7da6ee2 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -1300,6 +1300,18 @@ enum ec_feature_code { * mux. */ EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK = 43, + /* + * The EC supports entering and residing in S4. + */ + EC_FEATURE_S4_RESIDENCY = 44, + /* + * The EC supports the AP directing mux sets for the board. + */ + EC_FEATURE_TYPEC_AP_MUX_SET = 45, + /* + * The EC supports the AP composing VDMs for us to send. + */ + EC_FEATURE_TYPEC_AP_VDM_SEND = 46, }; #define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32) @@ -5724,6 +5736,8 @@ enum typec_control_command { TYPEC_CONTROL_COMMAND_ENTER_MODE, TYPEC_CONTROL_COMMAND_TBT_UFP_REPLY, TYPEC_CONTROL_COMMAND_USB_MUX_SET, + TYPEC_CONTROL_COMMAND_BIST_SHARE_MODE, + TYPEC_CONTROL_COMMAND_SEND_VDM_REQ, }; /* Replies the AP may specify to the TBT EnterMode command as a UFP */ @@ -5737,6 +5751,17 @@ struct typec_usb_mux_set { uint8_t mux_flags; /* USB_PD_MUX_*-encoded USB mux state to set */ } __ec_align1; +#define VDO_MAX_SIZE 7 + +struct typec_vdm_req { + /* VDM data, including VDM header */ + uint32_t vdm_data[VDO_MAX_SIZE]; + /* Number of 32-bit fields filled in */ + uint8_t vdm_data_objects; + /* Partner to address - see enum typec_partner_type */ + uint8_t partner_type; +} __ec_align1; + struct ec_params_typec_control { uint8_t port; uint8_t command; /* enum typec_control_command */ @@ -5752,6 +5777,8 @@ struct ec_params_typec_control { uint8_t mode_to_enter; /* enum typec_mode */ uint8_t tbt_ufp_reply; /* enum typec_tbt_ufp_reply */ struct typec_usb_mux_set mux_params; + /* Used for VMD_REQ */ + struct typec_vdm_req vdm_req_params; uint8_t placeholder[128]; }; } __ec_align1; @@ -5833,6 +5860,8 @@ enum tcpc_cc_polarity { #define PD_STATUS_EVENT_DISCONNECTED BIT(3) #define PD_STATUS_EVENT_MUX_0_SET_DONE BIT(4) #define PD_STATUS_EVENT_MUX_1_SET_DONE BIT(5) +#define PD_STATUS_EVENT_VDM_REQ_REPLY BIT(6) +#define PD_STATUS_EVENT_VDM_REQ_FAILED BIT(7) struct ec_params_typec_status { uint8_t port; @@ -5876,6 +5905,28 @@ struct ec_response_typec_status { uint32_t sink_cap_pdos[7]; /* Max 7 PDOs can be present */ } __ec_align1; +/* + * Gather the response to the most recent VDM REQ from the AP + */ +#define EC_CMD_TYPEC_VDM_RESPONSE 0x013C + +struct ec_params_typec_vdm_response { + uint8_t port; +} __ec_align1; + +struct ec_response_typec_vdm_response { + /* Number of 32-bit fields filled in */ + uint8_t vdm_data_objects; + /* Partner to address - see enum typec_partner_type */ + uint8_t partner_type; + /* Reserved */ + uint16_t reserved; + /* VDM data, including VDM header */ + uint32_t vdm_response[VDO_MAX_SIZE]; +} __ec_align1; + +#undef VDO_MAX_SIZE + /*****************************************************************************/ /* The command range 0x200-0x2FF is reserved for Rotor. */ -- cgit v1.2.3 From 101ca8d05913b7d1e6e8b9dd792193d4082fff86 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Mon, 2 Jan 2023 17:06:30 -0600 Subject: rtc: efi: Enable SET/GET WAKEUP services as optional The current implementation of rtc-efi is expecting all the 4 time services GET{SET}_TIME{WAKEUP} must be supported by UEFI firmware. As per the EFI_RT_PROPERTIES_TABLE, the platform specific implementations can choose to enable selective time services based on the RTC device capabilities. This patch does the following changes to provide GET/SET RTC services on platforms that do not support the WAKEUP feature. 1) Relax time services cap check when creating a platform device. 2) Clear RTC_FEATURE_ALARM bit in the absence of WAKEUP services. 3) Conditional alarm entries in '/proc/driver/rtc'. Cc: # v6.0+ Signed-off-by: Shanker Donthineni Link: https://lore.kernel.org/r/20230102230630.192911-1-sdonthineni@nvidia.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-efi.c | 48 +++++++++++++++++++++++++++--------------------- include/linux/efi.h | 3 ++- 2 files changed, 29 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index e991cccdb6e9..1e8bc6cc1e12 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -188,9 +188,10 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm) static int efi_procfs(struct device *dev, struct seq_file *seq) { - efi_time_t eft, alm; - efi_time_cap_t cap; - efi_bool_t enabled, pending; + efi_time_t eft, alm; + efi_time_cap_t cap; + efi_bool_t enabled, pending; + struct rtc_device *rtc = dev_get_drvdata(dev); memset(&eft, 0, sizeof(eft)); memset(&alm, 0, sizeof(alm)); @@ -213,23 +214,25 @@ static int efi_procfs(struct device *dev, struct seq_file *seq) /* XXX fixme: convert to string? */ seq_printf(seq, "Timezone\t: %u\n", eft.timezone); - seq_printf(seq, - "Alarm Time\t: %u:%u:%u.%09u\n" - "Alarm Date\t: %u-%u-%u\n" - "Alarm Daylight\t: %u\n" - "Enabled\t\t: %s\n" - "Pending\t\t: %s\n", - alm.hour, alm.minute, alm.second, alm.nanosecond, - alm.year, alm.month, alm.day, - alm.daylight, - enabled == 1 ? "yes" : "no", - pending == 1 ? "yes" : "no"); - - if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE) - seq_puts(seq, "Timezone\t: unspecified\n"); - else - /* XXX fixme: convert to string? */ - seq_printf(seq, "Timezone\t: %u\n", alm.timezone); + if (test_bit(RTC_FEATURE_ALARM, rtc->features)) { + seq_printf(seq, + "Alarm Time\t: %u:%u:%u.%09u\n" + "Alarm Date\t: %u-%u-%u\n" + "Alarm Daylight\t: %u\n" + "Enabled\t\t: %s\n" + "Pending\t\t: %s\n", + alm.hour, alm.minute, alm.second, alm.nanosecond, + alm.year, alm.month, alm.day, + alm.daylight, + enabled == 1 ? "yes" : "no", + pending == 1 ? "yes" : "no"); + + if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE) + seq_puts(seq, "Timezone\t: unspecified\n"); + else + /* XXX fixme: convert to string? */ + seq_printf(seq, "Timezone\t: %u\n", alm.timezone); + } /* * now prints the capabilities @@ -269,7 +272,10 @@ static int __init efi_rtc_probe(struct platform_device *dev) rtc->ops = &efi_rtc_ops; clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); - set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features); + if (efi_rt_services_supported(EFI_RT_SUPPORTED_WAKEUP_SERVICES)) + set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features); + else + clear_bit(RTC_FEATURE_ALARM, rtc->features); device_init_wakeup(&dev->dev, true); diff --git a/include/linux/efi.h b/include/linux/efi.h index 4b27519143f5..98598bd1d2fa 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -668,7 +668,8 @@ extern struct efi { #define EFI_RT_SUPPORTED_ALL 0x3fff -#define EFI_RT_SUPPORTED_TIME_SERVICES 0x000f +#define EFI_RT_SUPPORTED_TIME_SERVICES 0x0003 +#define EFI_RT_SUPPORTED_WAKEUP_SERVICES 0x000c #define EFI_RT_SUPPORTED_VARIABLE_SERVICES 0x0070 extern struct mm_struct efi_mm; -- cgit v1.2.3 From 5306892a50bf4cd4cc945bad286c7c950078d65e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 23 Dec 2022 12:36:33 -0800 Subject: fsverity: support verification with tree block size < PAGE_SIZE Add support for verifying data from verity files whose Merkle tree block size is less than the page size. The main use case for this is to allow a single Merkle tree block size to be used across all systems, so that only one set of fsverity file digests and signatures is needed. To do this, eliminate various assumptions that the Merkle tree block size and the page size are the same: - Make fsverity_verify_page() a wrapper around a new function fsverity_verify_blocks() which verifies one or more blocks in a page. - When a Merkle tree block is needed, get the corresponding page and only verify and use the needed portion. (The Merkle tree continues to be read and cached in page-sized chunks; that doesn't need to change.) - When the Merkle tree block size and page size differ, use a bitmap fsverity_info::hash_block_verified to keep track of which Merkle tree blocks have been verified, as PageChecked cannot be used directly. Signed-off-by: Eric Biggers Reviewed-by: Andrey Albershteyn Tested-by: Ojaswin Mujoo Link: https://lore.kernel.org/r/20221223203638.41293-7-ebiggers@kernel.org --- Documentation/filesystems/fsverity.rst | 49 +++--- fs/verity/fsverity_private.h | 5 +- fs/verity/open.c | 80 +++++++-- fs/verity/verify.c | 309 ++++++++++++++++++++++++--------- include/linux/fsverity.h | 11 +- 5 files changed, 328 insertions(+), 126 deletions(-) (limited to 'include') diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst index 66cdca30ff58..0b26134ebff7 100644 --- a/Documentation/filesystems/fsverity.rst +++ b/Documentation/filesystems/fsverity.rst @@ -572,47 +572,44 @@ For filesystems using Linux's pagecache, the ``->read_folio()`` and are marked Uptodate. Merely hooking ``->read_iter()`` would be insufficient, since ``->read_iter()`` is not used for memory maps. -Therefore, fs/verity/ provides a function fsverity_verify_page() which -verifies a page that has been read into the pagecache of a verity -inode, but is still locked and not Uptodate, so it's not yet readable -by userspace. As needed to do the verification, -fsverity_verify_page() will call back into the filesystem to read -Merkle tree pages via fsverity_operations::read_merkle_tree_page(). - -fsverity_verify_page() returns false if verification failed; in this +Therefore, fs/verity/ provides the function fsverity_verify_blocks() +which verifies data that has been read into the pagecache of a verity +inode. The containing page must still be locked and not Uptodate, so +it's not yet readable by userspace. As needed to do the verification, +fsverity_verify_blocks() will call back into the filesystem to read +hash blocks via fsverity_operations::read_merkle_tree_page(). + +fsverity_verify_blocks() returns false if verification failed; in this case, the filesystem must not set the page Uptodate. Following this, as per the usual Linux pagecache behavior, attempts by userspace to read() from the part of the file containing the page will fail with EIO, and accesses to the page within a memory map will raise SIGBUS. -fsverity_verify_page() currently only supports the case where the -Merkle tree block size is equal to PAGE_SIZE (often 4096 bytes). - -In principle, fsverity_verify_page() verifies the entire path in the -Merkle tree from the data page to the root hash. However, for -efficiency the filesystem may cache the hash pages. Therefore, -fsverity_verify_page() only ascends the tree reading hash pages until -an already-verified hash page is seen, as indicated by the PageChecked -bit being set. It then verifies the path to that page. +In principle, verifying a data block requires verifying the entire +path in the Merkle tree from the data block to the root hash. +However, for efficiency the filesystem may cache the hash blocks. +Therefore, fsverity_verify_blocks() only ascends the tree reading hash +blocks until an already-verified hash block is seen. It then verifies +the path to that block. This optimization, which is also used by dm-verity, results in excellent sequential read performance. This is because usually (e.g. -127 in 128 times for 4K blocks and SHA-256) the hash page from the +127 in 128 times for 4K blocks and SHA-256) the hash block from the bottom level of the tree will already be cached and checked from -reading a previous data page. However, random reads perform worse. +reading a previous data block. However, random reads perform worse. Block device based filesystems ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Block device based filesystems (e.g. ext4 and f2fs) in Linux also use the pagecache, so the above subsection applies too. However, they -also usually read many pages from a file at once, grouped into a +also usually read many data blocks from a file at once, grouped into a structure called a "bio". To make it easier for these types of filesystems to support fs-verity, fs/verity/ also provides a function -fsverity_verify_bio() which verifies all pages in a bio. +fsverity_verify_bio() which verifies all data blocks in a bio. ext4 and f2fs also support encryption. If a verity file is also -encrypted, the pages must be decrypted before being verified. To +encrypted, the data must be decrypted before being verified. To support this, these filesystems allocate a "post-read context" for each bio and store it in ``->bi_private``:: @@ -631,10 +628,10 @@ verification. Finally, pages where no decryption or verity error occurred are marked Uptodate, and the pages are unlocked. On many filesystems, files can contain holes. Normally, -``->readahead()`` simply zeroes holes and sets the corresponding pages -Uptodate; no bios are issued. To prevent this case from bypassing -fs-verity, these filesystems use fsverity_verify_page() to verify hole -pages. +``->readahead()`` simply zeroes hole blocks and considers the +corresponding data to be up-to-date; no bios are issued. To prevent +this case from bypassing fs-verity, filesystems use +fsverity_verify_blocks() to verify hole blocks. Filesystems also disable direct I/O on verity files, since otherwise direct I/O would bypass fs-verity. diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index 23ded939d649..d34dcc033d72 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -42,9 +42,11 @@ struct merkle_tree_params { unsigned int digest_size; /* same as hash_alg->digest_size */ unsigned int block_size; /* size of data and tree blocks */ unsigned int hashes_per_block; /* number of hashes per tree block */ + unsigned int blocks_per_page; /* PAGE_SIZE / block_size */ u8 log_digestsize; /* log2(digest_size) */ u8 log_blocksize; /* log2(block_size) */ u8 log_arity; /* log2(hashes_per_block) */ + u8 log_blocks_per_page; /* log2(blocks_per_page) */ unsigned int num_levels; /* number of levels in Merkle tree */ u64 tree_size; /* Merkle tree size in bytes */ unsigned long tree_pages; /* Merkle tree size in pages */ @@ -70,9 +72,10 @@ struct fsverity_info { u8 root_hash[FS_VERITY_MAX_DIGEST_SIZE]; u8 file_digest[FS_VERITY_MAX_DIGEST_SIZE]; const struct inode *inode; + unsigned long *hash_block_verified; + spinlock_t hash_page_init_lock; }; - #define FS_VERITY_MAX_SIGNATURE_SIZE (FS_VERITY_MAX_DESCRIPTOR_SIZE - \ sizeof(struct fsverity_descriptor)) diff --git a/fs/verity/open.c b/fs/verity/open.c index 09512daa22db..9366b441d01c 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -56,7 +56,23 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, goto out_err; } - if (log_blocksize != PAGE_SHIFT) { + /* + * fs/verity/ directly assumes that the Merkle tree block size is a + * power of 2 less than or equal to PAGE_SIZE. Another restriction + * arises from the interaction between fs/verity/ and the filesystems + * themselves: filesystems expect to be able to verify a single + * filesystem block of data at a time. Therefore, the Merkle tree block + * size must also be less than or equal to the filesystem block size. + * + * The above are the only hard limitations, so in theory the Merkle tree + * block size could be as small as twice the digest size. However, + * that's not useful, and it would result in some unusually deep and + * large Merkle trees. So we currently require that the Merkle tree + * block size be at least 1024 bytes. That's small enough to test the + * sub-page block case on systems with 4K pages, but not too small. + */ + if (log_blocksize < 10 || log_blocksize > PAGE_SHIFT || + log_blocksize > inode->i_blkbits) { fsverity_warn(inode, "Unsupported log_blocksize: %u", log_blocksize); err = -EINVAL; @@ -64,6 +80,8 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, } params->log_blocksize = log_blocksize; params->block_size = 1 << log_blocksize; + params->log_blocks_per_page = PAGE_SHIFT - log_blocksize; + params->blocks_per_page = 1 << params->log_blocks_per_page; if (WARN_ON(!is_power_of_2(params->digest_size))) { err = -EINVAL; @@ -108,11 +126,19 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, } /* - * Since the data, and thus also the Merkle tree, cannot have more than - * ULONG_MAX pages, hash block indices can always fit in an - * 'unsigned long'. To be safe, explicitly check for it too. + * With block_size != PAGE_SIZE, an in-memory bitmap will need to be + * allocated to track the "verified" status of hash blocks. Don't allow + * this bitmap to get too large. For now, limit it to 1 MiB, which + * limits the file size to about 4.4 TB with SHA-256 and 4K blocks. + * + * Together with the fact that the data, and thus also the Merkle tree, + * cannot have more than ULONG_MAX pages, this implies that hash block + * indices can always fit in an 'unsigned long'. But to be safe, we + * explicitly check for that too. Note, this is only for hash block + * indices; data block indices might not fit in an 'unsigned long'. */ - if (offset > ULONG_MAX) { + if ((params->block_size != PAGE_SIZE && offset > 1 << 23) || + offset > ULONG_MAX) { fsverity_err(inode, "Too many blocks in Merkle tree"); err = -EFBIG; goto out_err; @@ -170,7 +196,7 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode, fsverity_err(inode, "Error %d initializing Merkle tree parameters", err); - goto out; + goto fail; } memcpy(vi->root_hash, desc->root_hash, vi->tree_params.digest_size); @@ -179,17 +205,48 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode, vi->file_digest); if (err) { fsverity_err(inode, "Error %d computing file digest", err); - goto out; + goto fail; } err = fsverity_verify_signature(vi, desc->signature, le32_to_cpu(desc->sig_size)); -out: - if (err) { - fsverity_free_info(vi); - vi = ERR_PTR(err); + if (err) + goto fail; + + if (vi->tree_params.block_size != PAGE_SIZE) { + /* + * When the Merkle tree block size and page size differ, we use + * a bitmap to keep track of which hash blocks have been + * verified. This bitmap must contain one bit per hash block, + * including alignment to a page boundary at the end. + * + * Eventually, to support extremely large files in an efficient + * way, it might be necessary to make pages of this bitmap + * reclaimable. But for now, simply allocating the whole bitmap + * is a simple solution that works well on the files on which + * fsverity is realistically used. E.g., with SHA-256 and 4K + * blocks, a 100MB file only needs a 24-byte bitmap, and the + * bitmap for any file under 17GB fits in a 4K page. + */ + unsigned long num_bits = + vi->tree_params.tree_pages << + vi->tree_params.log_blocks_per_page; + + vi->hash_block_verified = kvcalloc(BITS_TO_LONGS(num_bits), + sizeof(unsigned long), + GFP_KERNEL); + if (!vi->hash_block_verified) { + err = -ENOMEM; + goto fail; + } + spin_lock_init(&vi->hash_page_init_lock); } + return vi; + +fail: + fsverity_free_info(vi); + return ERR_PTR(err); } void fsverity_set_info(struct inode *inode, struct fsverity_info *vi) @@ -216,6 +273,7 @@ void fsverity_free_info(struct fsverity_info *vi) if (!vi) return; kfree(vi->tree_params.hashstate); + kvfree(vi->hash_block_verified); kmem_cache_free(fsverity_info_cachep, vi); } diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 44df06ddcc60..e59ef9d0e21c 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -12,35 +12,9 @@ static struct workqueue_struct *fsverity_read_workqueue; -/** - * hash_at_level() - compute the location of the block's hash at the given level - * - * @params: (in) the Merkle tree parameters - * @dindex: (in) the index of the data block being verified - * @level: (in) the level of hash we want (0 is leaf level) - * @hindex: (out) the index of the hash block containing the wanted hash - * @hoffset: (out) the byte offset to the wanted hash within the hash block - */ -static void hash_at_level(const struct merkle_tree_params *params, - pgoff_t dindex, unsigned int level, pgoff_t *hindex, - unsigned int *hoffset) -{ - pgoff_t position; - - /* Offset of the hash within the level's region, in hashes */ - position = dindex >> (level * params->log_arity); - - /* Index of the hash block in the tree overall */ - *hindex = params->level_start[level] + (position >> params->log_arity); - - /* Offset of the wanted hash (in bytes) within the hash block */ - *hoffset = (position & ((1 << params->log_arity) - 1)) << - params->log_digestsize; -} - static inline int cmp_hashes(const struct fsverity_info *vi, const u8 *want_hash, const u8 *real_hash, - pgoff_t index, int level) + u64 data_pos, int level) { const unsigned int hsize = vi->tree_params.digest_size; @@ -48,148 +22,310 @@ static inline int cmp_hashes(const struct fsverity_info *vi, return 0; fsverity_err(vi->inode, - "FILE CORRUPTED! index=%lu, level=%d, want_hash=%s:%*phN, real_hash=%s:%*phN", - index, level, + "FILE CORRUPTED! pos=%llu, level=%d, want_hash=%s:%*phN, real_hash=%s:%*phN", + data_pos, level, vi->tree_params.hash_alg->name, hsize, want_hash, vi->tree_params.hash_alg->name, hsize, real_hash); return -EBADMSG; } +static bool data_is_zeroed(struct inode *inode, struct page *page, + unsigned int len, unsigned int offset) +{ + void *virt = kmap_local_page(page); + + if (memchr_inv(virt + offset, 0, len)) { + kunmap_local(virt); + fsverity_err(inode, + "FILE CORRUPTED! Data past EOF is not zeroed"); + return false; + } + kunmap_local(virt); + return true; +} + +/* + * Returns true if the hash block with index @hblock_idx in the tree, located in + * @hpage, has already been verified. + */ +static bool is_hash_block_verified(struct fsverity_info *vi, struct page *hpage, + unsigned long hblock_idx) +{ + bool verified; + unsigned int blocks_per_page; + unsigned int i; + + /* + * When the Merkle tree block size and page size are the same, then the + * ->hash_block_verified bitmap isn't allocated, and we use PG_checked + * to directly indicate whether the page's block has been verified. + * + * Using PG_checked also guarantees that we re-verify hash pages that + * get evicted and re-instantiated from the backing storage, as new + * pages always start out with PG_checked cleared. + */ + if (!vi->hash_block_verified) + return PageChecked(hpage); + + /* + * When the Merkle tree block size and page size differ, we use a bitmap + * to indicate whether each hash block has been verified. + * + * However, we still need to ensure that hash pages that get evicted and + * re-instantiated from the backing storage are re-verified. To do + * this, we use PG_checked again, but now it doesn't really mean + * "checked". Instead, now it just serves as an indicator for whether + * the hash page is newly instantiated or not. + * + * The first thread that sees PG_checked=0 must clear the corresponding + * bitmap bits, then set PG_checked=1. This requires a spinlock. To + * avoid having to take this spinlock in the common case of + * PG_checked=1, we start with an opportunistic lockless read. + */ + if (PageChecked(hpage)) { + /* + * A read memory barrier is needed here to give ACQUIRE + * semantics to the above PageChecked() test. + */ + smp_rmb(); + return test_bit(hblock_idx, vi->hash_block_verified); + } + spin_lock(&vi->hash_page_init_lock); + if (PageChecked(hpage)) { + verified = test_bit(hblock_idx, vi->hash_block_verified); + } else { + blocks_per_page = vi->tree_params.blocks_per_page; + hblock_idx = round_down(hblock_idx, blocks_per_page); + for (i = 0; i < blocks_per_page; i++) + clear_bit(hblock_idx + i, vi->hash_block_verified); + /* + * A write memory barrier is needed here to give RELEASE + * semantics to the below SetPageChecked() operation. + */ + smp_wmb(); + SetPageChecked(hpage); + verified = false; + } + spin_unlock(&vi->hash_page_init_lock); + return verified; +} + /* - * Verify a single data page against the file's Merkle tree. + * Verify a single data block against the file's Merkle tree. * * In principle, we need to verify the entire path to the root node. However, - * for efficiency the filesystem may cache the hash pages. Therefore we need - * only ascend the tree until an already-verified page is seen, as indicated by - * the PageChecked bit being set; then verify the path to that page. + * for efficiency the filesystem may cache the hash blocks. Therefore we need + * only ascend the tree until an already-verified hash block is seen, and then + * verify the path to that block. * - * This code currently only supports the case where the verity block size is - * equal to PAGE_SIZE. Doing otherwise would be possible but tricky, since we - * wouldn't be able to use the PageChecked bit. - * - * Note that multiple processes may race to verify a hash page and mark it - * Checked, but it doesn't matter; the result will be the same either way. - * - * Return: true if the page is valid, else false. + * Return: %true if the data block is valid, else %false. */ -static bool verify_page(struct inode *inode, const struct fsverity_info *vi, - struct ahash_request *req, struct page *data_page, - unsigned long max_ra_pages) +static bool +verify_data_block(struct inode *inode, struct fsverity_info *vi, + struct ahash_request *req, struct page *data_page, + u64 data_pos, unsigned int dblock_offset_in_page, + unsigned long max_ra_pages) { const struct merkle_tree_params *params = &vi->tree_params; const unsigned int hsize = params->digest_size; - const pgoff_t index = data_page->index; int level; u8 _want_hash[FS_VERITY_MAX_DIGEST_SIZE]; const u8 *want_hash; u8 real_hash[FS_VERITY_MAX_DIGEST_SIZE]; - struct page *hpages[FS_VERITY_MAX_LEVELS]; - unsigned int hoffsets[FS_VERITY_MAX_LEVELS]; + /* The hash blocks that are traversed, indexed by level */ + struct { + /* Page containing the hash block */ + struct page *page; + /* Index of the hash block in the tree overall */ + unsigned long index; + /* Byte offset of the hash block within @page */ + unsigned int offset_in_page; + /* Byte offset of the wanted hash within @page */ + unsigned int hoffset; + } hblocks[FS_VERITY_MAX_LEVELS]; + /* + * The index of the previous level's block within that level; also the + * index of that block's hash within the current level. + */ + u64 hidx = data_pos >> params->log_blocksize; int err; - if (WARN_ON_ONCE(!PageLocked(data_page) || PageUptodate(data_page))) - return false; + if (unlikely(data_pos >= inode->i_size)) { + /* + * This can happen in the data page spanning EOF when the Merkle + * tree block size is less than the page size. The Merkle tree + * doesn't cover data blocks fully past EOF. But the entire + * page spanning EOF can be visible to userspace via a mmap, and + * any part past EOF should be all zeroes. Therefore, we need + * to verify that any data blocks fully past EOF are all zeroes. + */ + return data_is_zeroed(inode, data_page, params->block_size, + dblock_offset_in_page); + } /* - * Starting at the leaf level, ascend the tree saving hash pages along - * the way until we find a verified hash page, indicated by PageChecked; - * or until we reach the root. + * Starting at the leaf level, ascend the tree saving hash blocks along + * the way until we find a hash block that has already been verified, or + * until we reach the root. */ for (level = 0; level < params->num_levels; level++) { - pgoff_t hindex; + unsigned long next_hidx; + unsigned long hblock_idx; + pgoff_t hpage_idx; + unsigned int hblock_offset_in_page; unsigned int hoffset; struct page *hpage; - hash_at_level(params, index, level, &hindex, &hoffset); + /* + * The index of the block in the current level; also the index + * of that block's hash within the next level. + */ + next_hidx = hidx >> params->log_arity; + + /* Index of the hash block in the tree overall */ + hblock_idx = params->level_start[level] + next_hidx; + + /* Index of the hash page in the tree overall */ + hpage_idx = hblock_idx >> params->log_blocks_per_page; + + /* Byte offset of the hash block within the page */ + hblock_offset_in_page = + (hblock_idx << params->log_blocksize) & ~PAGE_MASK; + + /* Byte offset of the hash within the page */ + hoffset = hblock_offset_in_page + + ((hidx << params->log_digestsize) & + (params->block_size - 1)); - hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode, hindex, - level == 0 ? min(max_ra_pages, - params->tree_pages - hindex) : 0); + hpage = inode->i_sb->s_vop->read_merkle_tree_page(inode, + hpage_idx, level == 0 ? min(max_ra_pages, + params->tree_pages - hpage_idx) : 0); if (IS_ERR(hpage)) { err = PTR_ERR(hpage); fsverity_err(inode, "Error %d reading Merkle tree page %lu", - err, hindex); + err, hpage_idx); goto out; } - - if (PageChecked(hpage)) { + if (is_hash_block_verified(vi, hpage, hblock_idx)) { memcpy_from_page(_want_hash, hpage, hoffset, hsize); want_hash = _want_hash; put_page(hpage); goto descend; } - hpages[level] = hpage; - hoffsets[level] = hoffset; + hblocks[level].page = hpage; + hblocks[level].index = hblock_idx; + hblocks[level].offset_in_page = hblock_offset_in_page; + hblocks[level].hoffset = hoffset; + hidx = next_hidx; } want_hash = vi->root_hash; descend: /* Descend the tree verifying hash blocks. */ for (; level > 0; level--) { - struct page *hpage = hpages[level - 1]; - unsigned int hoffset = hoffsets[level - 1]; - - err = fsverity_hash_block(params, inode, req, hpage, 0, - real_hash); + struct page *hpage = hblocks[level - 1].page; + unsigned long hblock_idx = hblocks[level - 1].index; + unsigned int hblock_offset_in_page = + hblocks[level - 1].offset_in_page; + unsigned int hoffset = hblocks[level - 1].hoffset; + + err = fsverity_hash_block(params, inode, req, hpage, + hblock_offset_in_page, real_hash); if (err) goto out; - err = cmp_hashes(vi, want_hash, real_hash, index, level - 1); + err = cmp_hashes(vi, want_hash, real_hash, data_pos, level - 1); if (err) goto out; - SetPageChecked(hpage); + /* + * Mark the hash block as verified. This must be atomic and + * idempotent, as the same hash block might be verified by + * multiple threads concurrently. + */ + if (vi->hash_block_verified) + set_bit(hblock_idx, vi->hash_block_verified); + else + SetPageChecked(hpage); memcpy_from_page(_want_hash, hpage, hoffset, hsize); want_hash = _want_hash; put_page(hpage); } /* Finally, verify the data block. */ - err = fsverity_hash_block(params, inode, req, data_page, 0, real_hash); + err = fsverity_hash_block(params, inode, req, data_page, + dblock_offset_in_page, real_hash); if (err) goto out; - err = cmp_hashes(vi, want_hash, real_hash, index, -1); + err = cmp_hashes(vi, want_hash, real_hash, data_pos, -1); out: for (; level > 0; level--) - put_page(hpages[level - 1]); + put_page(hblocks[level - 1].page); return err == 0; } +static bool +verify_data_blocks(struct inode *inode, struct fsverity_info *vi, + struct ahash_request *req, struct page *data_page, + unsigned int len, unsigned int offset, + unsigned long max_ra_pages) +{ + const unsigned int block_size = vi->tree_params.block_size; + u64 pos = (u64)data_page->index << PAGE_SHIFT; + + if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offset, block_size))) + return false; + if (WARN_ON_ONCE(!PageLocked(data_page) || PageUptodate(data_page))) + return false; + do { + if (!verify_data_block(inode, vi, req, data_page, + pos + offset, offset, max_ra_pages)) + return false; + offset += block_size; + len -= block_size; + } while (len); + return true; +} + /** - * fsverity_verify_page() - verify a data page - * @page: the page to verity + * fsverity_verify_blocks() - verify data in a page + * @page: the page containing the data to verify + * @len: the length of the data to verify in the page + * @offset: the offset of the data to verify in the page * - * Verify a page that has just been read from a verity file. The page must be a - * pagecache page that is still locked and not yet uptodate. + * Verify data that has just been read from a verity file. The data must be + * located in a pagecache page that is still locked and not yet uptodate. The + * length and offset of the data must be Merkle tree block size aligned. * - * Return: true if the page is valid, else false. + * Return: %true if the data is valid, else %false. */ -bool fsverity_verify_page(struct page *page) +bool fsverity_verify_blocks(struct page *page, unsigned int len, + unsigned int offset) { struct inode *inode = page->mapping->host; - const struct fsverity_info *vi = inode->i_verity_info; + struct fsverity_info *vi = inode->i_verity_info; struct ahash_request *req; bool valid; /* This allocation never fails, since it's mempool-backed. */ req = fsverity_alloc_hash_request(vi->tree_params.hash_alg, GFP_NOFS); - valid = verify_page(inode, vi, req, page, 0); + valid = verify_data_blocks(inode, vi, req, page, len, offset, 0); fsverity_free_hash_request(vi->tree_params.hash_alg, req); return valid; } -EXPORT_SYMBOL_GPL(fsverity_verify_page); +EXPORT_SYMBOL_GPL(fsverity_verify_blocks); #ifdef CONFIG_BLOCK /** * fsverity_verify_bio() - verify a 'read' bio that has just completed * @bio: the bio to verify * - * Verify a set of pages that have just been read from a verity file. The pages - * must be pagecache pages that are still locked and not yet uptodate. If a - * page fails verification, then bio->bi_status is set to an error status. + * Verify the bio's data against the file's Merkle tree. All bio data segments + * must be aligned to the file's Merkle tree block size. If any data fails + * verification, then bio->bi_status is set to an error status. * * This is a helper function for use by the ->readahead() method of filesystems * that issue bios to read data directly into the page cache. Filesystems that @@ -200,7 +336,7 @@ EXPORT_SYMBOL_GPL(fsverity_verify_page); void fsverity_verify_bio(struct bio *bio) { struct inode *inode = bio_first_page_all(bio)->mapping->host; - const struct fsverity_info *vi = inode->i_verity_info; + struct fsverity_info *vi = inode->i_verity_info; struct ahash_request *req; struct bio_vec *bv; struct bvec_iter_all iter_all; @@ -223,7 +359,8 @@ void fsverity_verify_bio(struct bio *bio) } bio_for_each_segment_all(bv, bio, iter_all) { - if (!verify_page(inode, vi, req, bv->bv_page, max_ra_pages)) { + if (!verify_data_blocks(inode, vi, req, bv->bv_page, bv->bv_len, + bv->bv_offset, max_ra_pages)) { bio->bi_status = BLK_STS_IOERR; break; } diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index f5ed7ecfd9ab..6ecc51f80221 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -170,7 +170,8 @@ int fsverity_ioctl_read_metadata(struct file *filp, const void __user *uarg); /* verify.c */ -bool fsverity_verify_page(struct page *page); +bool fsverity_verify_blocks(struct page *page, unsigned int len, + unsigned int offset); void fsverity_verify_bio(struct bio *bio); void fsverity_enqueue_verify_work(struct work_struct *work); @@ -230,7 +231,8 @@ static inline int fsverity_ioctl_read_metadata(struct file *filp, /* verify.c */ -static inline bool fsverity_verify_page(struct page *page) +static inline bool fsverity_verify_blocks(struct page *page, unsigned int len, + unsigned int offset) { WARN_ON(1); return false; @@ -248,6 +250,11 @@ static inline void fsverity_enqueue_verify_work(struct work_struct *work) #endif /* !CONFIG_FS_VERITY */ +static inline bool fsverity_verify_page(struct page *page) +{ + return fsverity_verify_blocks(page, PAGE_SIZE, 0); +} + /** * fsverity_active() - do reads from the inode need to go through fs-verity? * @inode: inode to check -- cgit v1.2.3 From 56124d6c87fd749477425110d2564166621a89c4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 23 Dec 2022 12:36:34 -0800 Subject: fsverity: support enabling with tree block size < PAGE_SIZE Make FS_IOC_ENABLE_VERITY support values of fsverity_enable_arg::block_size other than PAGE_SIZE. To make this possible, rework build_merkle_tree(), which was reading data and hash pages from the file and assuming that they were the same thing as "blocks". For reading the data blocks, just replace the direct pagecache access with __kernel_read(), to naturally read one block at a time. (A disadvantage of the above is that we lose the two optimizations of hashing the pagecache pages in-place and forcing the maximum readahead. That shouldn't be very important, though.) The hash block reads are a bit more difficult to handle, as the only way to do them is through fsverity_operations::read_merkle_tree_page(). Instead, let's switch to the single-pass tree construction algorithm that fsverity-utils uses. This eliminates the need to read back any hash blocks while the tree is being built, at the small cost of an extra block-sized memory buffer per Merkle tree level. This is probably what I should have done originally. Taken together, the above two changes result in page-size independent code that is also a bit simpler than what we had before. Signed-off-by: Eric Biggers Reviewed-by: Andrey Albershteyn Tested-by: Ojaswin Mujoo Link: https://lore.kernel.org/r/20221223203638.41293-8-ebiggers@kernel.org --- Documentation/filesystems/fsverity.rst | 20 ++- fs/verity/enable.c | 260 ++++++++++++++++----------------- include/linux/fsverity.h | 3 +- 3 files changed, 134 insertions(+), 149 deletions(-) (limited to 'include') diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst index 0b26134ebff7..948d20254524 100644 --- a/Documentation/filesystems/fsverity.rst +++ b/Documentation/filesystems/fsverity.rst @@ -118,10 +118,11 @@ as follows: - ``hash_algorithm`` must be the identifier for the hash algorithm to use for the Merkle tree, such as FS_VERITY_HASH_ALG_SHA256. See ``include/uapi/linux/fsverity.h`` for the list of possible values. -- ``block_size`` must be the Merkle tree block size. Currently, this - must be equal to the system page size, which is usually 4096 bytes. - Other sizes may be supported in the future. This value is not - necessarily the same as the filesystem block size. +- ``block_size`` is the Merkle tree block size, in bytes. In Linux + v6.3 and later, this can be any power of 2 between (inclusively) + 1024 and the minimum of the system page size and the filesystem + block size. In earlier versions, the page size was the only allowed + value. - ``salt_size`` is the size of the salt in bytes, or 0 if no salt is provided. The salt is a value that is prepended to every hashed block; it can be used to personalize the hashing for a particular @@ -519,9 +520,7 @@ support paging multi-gigabyte xattrs into memory, and to support encrypting xattrs. Note that the verity metadata *must* be encrypted when the file is, since it contains hashes of the plaintext data. -Currently, ext4 verity only supports the case where the Merkle tree -block size, filesystem block size, and page size are all the same. It -also only supports extent-based files. +ext4 only allows verity on extent-based files. f2fs ---- @@ -539,11 +538,10 @@ Like ext4, f2fs stores the verity metadata (Merkle tree and fsverity_descriptor) past the end of the file, starting at the first 64K boundary beyond i_size. See explanation for ext4 above. Moreover, f2fs supports at most 4096 bytes of xattr entries per inode -which wouldn't be enough for even a single Merkle tree block. +which usually wouldn't be enough for even a single Merkle tree block. -Currently, f2fs verity only supports a Merkle tree block size of 4096. -Also, f2fs doesn't support enabling verity on files that currently -have atomic or volatile writes pending. +f2fs doesn't support enabling verity on files that currently have +atomic or volatile writes pending. btrfs ----- diff --git a/fs/verity/enable.c b/fs/verity/enable.c index 144483319f1a..e13db6507b38 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -7,132 +7,50 @@ #include "fsverity_private.h" -#include -#include #include #include #include #include -/* - * Read a file data page for Merkle tree construction. Do aggressive readahead, - * since we're sequentially reading the entire file. - */ -static struct page *read_file_data_page(struct file *file, pgoff_t index, - struct file_ra_state *ra, - unsigned long remaining_pages) -{ - DEFINE_READAHEAD(ractl, file, ra, file->f_mapping, index); - struct folio *folio; - - folio = __filemap_get_folio(ractl.mapping, index, FGP_ACCESSED, 0); - if (!folio || !folio_test_uptodate(folio)) { - if (folio) - folio_put(folio); - else - page_cache_sync_ra(&ractl, remaining_pages); - folio = read_cache_folio(ractl.mapping, index, NULL, file); - if (IS_ERR(folio)) - return &folio->page; - } - if (folio_test_readahead(folio)) - page_cache_async_ra(&ractl, folio, remaining_pages); - return folio_file_page(folio, index); -} +struct block_buffer { + u32 filled; + u8 *data; +}; -static int build_merkle_tree_level(struct file *filp, unsigned int level, - u64 num_blocks_to_hash, - const struct merkle_tree_params *params, - u8 *pending_hashes, - struct ahash_request *req) +/* Hash a block, writing the result to the next level's pending block buffer. */ +static int hash_one_block(struct inode *inode, + const struct merkle_tree_params *params, + struct ahash_request *req, struct block_buffer *cur) { - struct inode *inode = file_inode(filp); - const struct fsverity_operations *vops = inode->i_sb->s_vop; - struct file_ra_state ra = { 0 }; - unsigned int pending_size = 0; - u64 dst_block_num; - u64 i; + struct block_buffer *next = cur + 1; int err; - if (WARN_ON(params->block_size != PAGE_SIZE)) /* checked earlier too */ - return -EINVAL; - - if (level < params->num_levels) { - dst_block_num = params->level_start[level]; - } else { - if (WARN_ON(num_blocks_to_hash != 1)) - return -EINVAL; - dst_block_num = 0; /* unused */ - } + /* Zero-pad the block if it's shorter than the block size. */ + memset(&cur->data[cur->filled], 0, params->block_size - cur->filled); - file_ra_state_init(&ra, filp->f_mapping); - - for (i = 0; i < num_blocks_to_hash; i++) { - struct page *src_page; - - if (level == 0) { - /* Leaf: hashing a data block */ - src_page = read_file_data_page(filp, i, &ra, - num_blocks_to_hash - i); - if (IS_ERR(src_page)) { - err = PTR_ERR(src_page); - fsverity_err(inode, - "Error %d reading data page %llu", - err, i); - return err; - } - } else { - unsigned long num_ra_pages = - min_t(unsigned long, num_blocks_to_hash - i, - inode->i_sb->s_bdi->io_pages); - - /* Non-leaf: hashing hash block from level below */ - src_page = vops->read_merkle_tree_page(inode, - params->level_start[level - 1] + i, - num_ra_pages); - if (IS_ERR(src_page)) { - err = PTR_ERR(src_page); - fsverity_err(inode, - "Error %d reading Merkle tree page %llu", - err, params->level_start[level - 1] + i); - return err; - } - } + err = fsverity_hash_block(params, inode, req, virt_to_page(cur->data), + offset_in_page(cur->data), + &next->data[next->filled]); + if (err) + return err; + next->filled += params->digest_size; + cur->filled = 0; + return 0; +} - err = fsverity_hash_block(params, inode, req, src_page, 0, - &pending_hashes[pending_size]); - put_page(src_page); - if (err) - return err; - pending_size += params->digest_size; - - if (level == params->num_levels) /* Root hash? */ - return 0; - - if (pending_size + params->digest_size > params->block_size || - i + 1 == num_blocks_to_hash) { - /* Flush the pending hash block */ - memset(&pending_hashes[pending_size], 0, - params->block_size - pending_size); - err = vops->write_merkle_tree_block(inode, - pending_hashes, - dst_block_num << params->log_blocksize, - params->block_size); - if (err) { - fsverity_err(inode, - "Error %d writing Merkle tree block %llu", - err, dst_block_num); - return err; - } - dst_block_num++; - pending_size = 0; - } +static int write_merkle_tree_block(struct inode *inode, const u8 *buf, + unsigned long index, + const struct merkle_tree_params *params) +{ + u64 pos = (u64)index << params->log_blocksize; + int err; - if (fatal_signal_pending(current)) - return -EINTR; - cond_resched(); - } - return 0; + err = inode->i_sb->s_vop->write_merkle_tree_block(inode, buf, pos, + params->block_size); + if (err) + fsverity_err(inode, "Error %d writing Merkle tree block %lu", + err, index); + return err; } /* @@ -148,13 +66,17 @@ static int build_merkle_tree(struct file *filp, u8 *root_hash) { struct inode *inode = file_inode(filp); - u8 *pending_hashes; + const u64 data_size = inode->i_size; + const int num_levels = params->num_levels; struct ahash_request *req; - u64 blocks; - unsigned int level; - int err = -ENOMEM; + struct block_buffer _buffers[1 + FS_VERITY_MAX_LEVELS + 1] = {}; + struct block_buffer *buffers = &_buffers[1]; + unsigned long level_offset[FS_VERITY_MAX_LEVELS]; + int level; + u64 offset; + int err; - if (inode->i_size == 0) { + if (data_size == 0) { /* Empty file is a special case; root hash is all 0's */ memset(root_hash, 0, params->digest_size); return 0; @@ -163,29 +85,95 @@ static int build_merkle_tree(struct file *filp, /* This allocation never fails, since it's mempool-backed. */ req = fsverity_alloc_hash_request(params->hash_alg, GFP_KERNEL); - pending_hashes = kmalloc(params->block_size, GFP_KERNEL); - if (!pending_hashes) - goto out; - /* - * Build each level of the Merkle tree, starting at the leaf level - * (level 0) and ascending to the root node (level 'num_levels - 1'). - * Then at the end (level 'num_levels'), calculate the root hash. + * Allocate the block buffers. Buffer "-1" is for data blocks. + * Buffers 0 <= level < num_levels are for the actual tree levels. + * Buffer 'num_levels' is for the root hash. */ - blocks = ((u64)inode->i_size + params->block_size - 1) >> - params->log_blocksize; - for (level = 0; level <= params->num_levels; level++) { - err = build_merkle_tree_level(filp, level, blocks, params, - pending_hashes, req); + for (level = -1; level < num_levels; level++) { + buffers[level].data = kzalloc(params->block_size, GFP_KERNEL); + if (!buffers[level].data) { + err = -ENOMEM; + goto out; + } + } + buffers[num_levels].data = root_hash; + + BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start)); + memcpy(level_offset, params->level_start, sizeof(level_offset)); + + /* Hash each data block, also hashing the tree blocks as they fill up */ + for (offset = 0; offset < data_size; offset += params->block_size) { + ssize_t bytes_read; + loff_t pos = offset; + + buffers[-1].filled = min_t(u64, params->block_size, + data_size - offset); + bytes_read = __kernel_read(filp, buffers[-1].data, + buffers[-1].filled, &pos); + if (bytes_read < 0) { + err = bytes_read; + fsverity_err(inode, "Error %d reading file data", err); + goto out; + } + if (bytes_read != buffers[-1].filled) { + err = -EINVAL; + fsverity_err(inode, "Short read of file data"); + goto out; + } + err = hash_one_block(inode, params, req, &buffers[-1]); if (err) goto out; - blocks = (blocks + params->hashes_per_block - 1) >> - params->log_arity; + for (level = 0; level < num_levels; level++) { + if (buffers[level].filled + params->digest_size <= + params->block_size) { + /* Next block at @level isn't full yet */ + break; + } + /* Next block at @level is full */ + + err = hash_one_block(inode, params, req, + &buffers[level]); + if (err) + goto out; + err = write_merkle_tree_block(inode, + buffers[level].data, + level_offset[level], + params); + if (err) + goto out; + level_offset[level]++; + } + if (fatal_signal_pending(current)) { + err = -EINTR; + goto out; + } + cond_resched(); + } + /* Finish all nonempty pending tree blocks. */ + for (level = 0; level < num_levels; level++) { + if (buffers[level].filled != 0) { + err = hash_one_block(inode, params, req, + &buffers[level]); + if (err) + goto out; + err = write_merkle_tree_block(inode, + buffers[level].data, + level_offset[level], + params); + if (err) + goto out; + } + } + /* The root hash was filled by the last call to hash_one_block(). */ + if (WARN_ON(buffers[num_levels].filled != params->digest_size)) { + err = -EINVAL; + goto out; } - memcpy(root_hash, pending_hashes, params->digest_size); err = 0; out: - kfree(pending_hashes); + for (level = -1; level < num_levels; level++) + kfree(buffers[level].data); fsverity_free_hash_request(params->hash_alg, req); return err; } @@ -341,7 +329,7 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg) memchr_inv(arg.__reserved2, 0, sizeof(arg.__reserved2))) return -EINVAL; - if (arg.block_size != PAGE_SIZE) + if (!is_power_of_2(arg.block_size)) return -EINVAL; if (arg.salt_size > sizeof_field(struct fsverity_descriptor, salt)) diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 6ecc51f80221..991a44458996 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -93,8 +93,7 @@ struct fsverity_operations { * isn't already cached. Implementations may ignore this * argument; it's only a performance optimization. * - * This can be called at any time on an open verity file, as well as - * between ->begin_enable_verity() and ->end_enable_verity(). It may be + * This can be called at any time on an open verity file. It may be * called by multiple processes concurrently, even with the same page. * * Note that this must retrieve a *page*, not necessarily a *block*. -- cgit v1.2.3 From ccae0447af0e471426beea789a52b2b6605663e0 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Wed, 4 Jan 2023 10:03:41 +0200 Subject: RDMA/cma: Refactor the inbound/outbound path records process flow Refactors based on comments [1] of the multiple path records support patchset: - Return failure if not able to set inbound/outbound PRs; - Simplify the flow when receiving the PRs from netlink channel: When a good PR response is received, unpack it and call the path_query callback directly. This saves two memory allocations; - Define RDMA_PRIMARY_PATH_MAX_REC_NUM in a proper place. [1] https://lore.kernel.org/linux-rdma/Yyxp9E9pJtUids2o@nvidia.com/ Signed-off-by: Mark Zhang Reviewed-by: Bart Van Assche #srp Link: https://lore.kernel.org/r/7610025d57342b8b6da0f19516c9612f9c3fdc37.1672819376.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/cma.c | 30 +++--- drivers/infiniband/core/sa_query.c | 171 ++++++++++-------------------- drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 +- drivers/infiniband/ulp/srp/ib_srp.c | 2 +- include/rdma/ib_sa.h | 2 +- include/rdma/rdma_cm.h | 1 - 6 files changed, 75 insertions(+), 133 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index b9da636fe1fb..1d2bff91d78b 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2819,8 +2819,8 @@ int rdma_set_min_rnr_timer(struct rdma_cm_id *id, u8 min_rnr_timer) } EXPORT_SYMBOL(rdma_set_min_rnr_timer); -static void route_set_path_rec_inbound(struct cma_work *work, - struct sa_path_rec *path_rec) +static int route_set_path_rec_inbound(struct cma_work *work, + struct sa_path_rec *path_rec) { struct rdma_route *route = &work->id->id.route; @@ -2828,14 +2828,15 @@ static void route_set_path_rec_inbound(struct cma_work *work, route->path_rec_inbound = kzalloc(sizeof(*route->path_rec_inbound), GFP_KERNEL); if (!route->path_rec_inbound) - return; + return -ENOMEM; } *route->path_rec_inbound = *path_rec; + return 0; } -static void route_set_path_rec_outbound(struct cma_work *work, - struct sa_path_rec *path_rec) +static int route_set_path_rec_outbound(struct cma_work *work, + struct sa_path_rec *path_rec) { struct rdma_route *route = &work->id->id.route; @@ -2843,14 +2844,15 @@ static void route_set_path_rec_outbound(struct cma_work *work, route->path_rec_outbound = kzalloc(sizeof(*route->path_rec_outbound), GFP_KERNEL); if (!route->path_rec_outbound) - return; + return -ENOMEM; } *route->path_rec_outbound = *path_rec; + return 0; } static void cma_query_handler(int status, struct sa_path_rec *path_rec, - int num_prs, void *context) + unsigned int num_prs, void *context) { struct cma_work *work = context; struct rdma_route *route; @@ -2865,13 +2867,15 @@ static void cma_query_handler(int status, struct sa_path_rec *path_rec, if (!path_rec[i].flags || (path_rec[i].flags & IB_PATH_GMP)) *route->path_rec = path_rec[i]; else if (path_rec[i].flags & IB_PATH_INBOUND) - route_set_path_rec_inbound(work, &path_rec[i]); + status = route_set_path_rec_inbound(work, &path_rec[i]); else if (path_rec[i].flags & IB_PATH_OUTBOUND) - route_set_path_rec_outbound(work, &path_rec[i]); - } - if (!route->path_rec) { - status = -EINVAL; - goto fail; + status = route_set_path_rec_outbound(work, + &path_rec[i]); + else + status = -EINVAL; + + if (status) + goto fail; } route->num_pri_alt_paths = 1; diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 0de83d9a4985..59179cfc20ef 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -106,7 +106,7 @@ struct ib_sa_device { struct ib_sa_query { void (*callback)(struct ib_sa_query *sa_query, int status, - int num_prs, struct ib_sa_mad *mad); + struct ib_sa_mad *mad); void (*release)(struct ib_sa_query *); struct ib_sa_client *client; struct ib_sa_port *port; @@ -118,12 +118,6 @@ struct ib_sa_query { u32 seq; /* Local svc request sequence number */ unsigned long timeout; /* Local svc timeout */ u8 path_use; /* How will the pathrecord be used */ - - /* A separate buffer to save pathrecords of a response, as in cases - * like IB/netlink, mulptiple pathrecords are supported, so that - * mad->data is not large enough to hold them - */ - void *resp_pr_data; }; #define IB_SA_ENABLE_LOCAL_SERVICE 0x00000001 @@ -132,7 +126,7 @@ struct ib_sa_query { struct ib_sa_path_query { void (*callback)(int status, struct sa_path_rec *rec, - int num_paths, void *context); + unsigned int num_paths, void *context); void *context; struct ib_sa_query sa_query; struct sa_path_rec *conv_pr; @@ -690,6 +684,8 @@ static const struct ib_field guidinfo_rec_table[] = { .size_bits = 512 }, }; +#define RDMA_PRIMARY_PATH_MAX_REC_NUM 3 + static inline void ib_sa_disable_local_svc(struct ib_sa_query *query) { query->flags &= ~IB_SA_ENABLE_LOCAL_SERVICE; @@ -874,30 +870,21 @@ static void send_handler(struct ib_mad_agent *agent, static void ib_nl_process_good_resolve_rsp(struct ib_sa_query *query, const struct nlmsghdr *nlh) { - struct ib_path_rec_data *srec, *drec; + struct sa_path_rec recs[RDMA_PRIMARY_PATH_MAX_REC_NUM]; struct ib_sa_path_query *path_query; + struct ib_path_rec_data *rec_data; struct ib_mad_send_wc mad_send_wc; const struct nlattr *head, *curr; struct ib_sa_mad *mad = NULL; - int len, rem, num_prs = 0; + int len, rem, status = -EIO; + unsigned int num_prs = 0; u32 mask = 0; - int status = -EIO; if (!query->callback) goto out; path_query = container_of(query, struct ib_sa_path_query, sa_query); mad = query->mad_buf->mad; - if (!path_query->conv_pr && - (be16_to_cpu(mad->mad_hdr.attr_id) == IB_SA_ATTR_PATH_REC)) { - /* Need a larger buffer for possible multiple PRs */ - query->resp_pr_data = kvcalloc(RDMA_PRIMARY_PATH_MAX_REC_NUM, - sizeof(*drec), GFP_KERNEL); - if (!query->resp_pr_data) { - query->callback(query, -ENOMEM, 0, NULL); - return; - } - } head = (const struct nlattr *) nlmsg_data(nlh); len = nlmsg_len(nlh); @@ -917,36 +904,41 @@ static void ib_nl_process_good_resolve_rsp(struct ib_sa_query *query, break; } - drec = (struct ib_path_rec_data *)query->resp_pr_data; nla_for_each_attr(curr, head, len, rem) { if (curr->nla_type != LS_NLA_TYPE_PATH_RECORD) continue; - srec = nla_data(curr); - if ((srec->flags & mask) != mask) + rec_data = nla_data(curr); + if ((rec_data->flags & mask) != mask) continue; - status = 0; - if (!drec) { - memcpy(mad->data, srec->path_rec, - sizeof(srec->path_rec)); - num_prs = 1; - break; + if ((query->flags & IB_SA_QUERY_OPA) || + path_query->conv_pr) { + mad->mad_hdr.method |= IB_MGMT_METHOD_RESP; + memcpy(mad->data, rec_data->path_rec, + sizeof(rec_data->path_rec)); + query->callback(query, 0, mad); + goto out; } - memcpy(drec, srec, sizeof(*drec)); - drec++; + status = 0; + ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), + rec_data->path_rec, &recs[num_prs]); + recs[num_prs].flags = rec_data->flags; + recs[num_prs].rec_type = SA_PATH_REC_TYPE_IB; + sa_path_set_dmac_zero(&recs[num_prs]); + num_prs++; if (num_prs >= RDMA_PRIMARY_PATH_MAX_REC_NUM) break; } - if (!status) + if (!status) { mad->mad_hdr.method |= IB_MGMT_METHOD_RESP; - - query->callback(query, status, num_prs, mad); - kvfree(query->resp_pr_data); - query->resp_pr_data = NULL; + path_query->callback(status, recs, num_prs, + path_query->context); + } else + query->callback(query, status, mad); out: mad_send_wc.send_buf = query->mad_buf; @@ -1451,11 +1443,26 @@ static int opa_pr_query_possible(struct ib_sa_client *client, return PR_IB_SUPPORTED; } -static void ib_sa_pr_callback_single(struct ib_sa_path_query *query, - int status, struct ib_sa_mad *mad) +static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, + int status, struct ib_sa_mad *mad) { + struct ib_sa_path_query *query = + container_of(sa_query, struct ib_sa_path_query, sa_query); struct sa_path_rec rec = {}; + if (!mad) { + query->callback(status, NULL, 0, query->context); + return; + } + + if (sa_query->flags & IB_SA_QUERY_OPA) { + ib_unpack(opa_path_rec_table, ARRAY_SIZE(opa_path_rec_table), + mad->data, &rec); + rec.rec_type = SA_PATH_REC_TYPE_OPA; + query->callback(status, &rec, 1, query->context); + return; + } + ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), mad->data, &rec); rec.rec_type = SA_PATH_REC_TYPE_IB; @@ -1472,71 +1479,6 @@ static void ib_sa_pr_callback_single(struct ib_sa_path_query *query, } } -/** - * ib_sa_pr_callback_multiple() - Parse path records then do callback. - * - * In a multiple-PR case the PRs are saved in "query->resp_pr_data" - * (instead of"mad->data") and with "ib_path_rec_data" structure format, - * so that rec->flags can be set to indicate the type of PR. - * This is valid only in IB fabric. - */ -static void ib_sa_pr_callback_multiple(struct ib_sa_path_query *query, - int status, int num_prs, - struct ib_path_rec_data *rec_data) -{ - struct sa_path_rec *rec; - int i; - - rec = kvcalloc(num_prs, sizeof(*rec), GFP_KERNEL); - if (!rec) { - query->callback(-ENOMEM, NULL, 0, query->context); - return; - } - - for (i = 0; i < num_prs; i++) { - ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), - rec_data[i].path_rec, rec + i); - rec[i].rec_type = SA_PATH_REC_TYPE_IB; - sa_path_set_dmac_zero(rec + i); - rec[i].flags = rec_data[i].flags; - } - - query->callback(status, rec, num_prs, query->context); - kvfree(rec); -} - -static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, - int status, int num_prs, - struct ib_sa_mad *mad) -{ - struct ib_sa_path_query *query = - container_of(sa_query, struct ib_sa_path_query, sa_query); - struct sa_path_rec rec; - - if (!mad || !num_prs) { - query->callback(status, NULL, 0, query->context); - return; - } - - if (sa_query->flags & IB_SA_QUERY_OPA) { - if (num_prs != 1) { - query->callback(-EINVAL, NULL, 0, query->context); - return; - } - - ib_unpack(opa_path_rec_table, ARRAY_SIZE(opa_path_rec_table), - mad->data, &rec); - rec.rec_type = SA_PATH_REC_TYPE_OPA; - query->callback(status, &rec, num_prs, query->context); - } else { - if (!sa_query->resp_pr_data) - ib_sa_pr_callback_single(query, status, mad); - else - ib_sa_pr_callback_multiple(query, status, num_prs, - sa_query->resp_pr_data); - } -} - static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) { struct ib_sa_path_query *query = @@ -1578,7 +1520,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct sa_path_rec *resp, - int num_paths, void *context), + unsigned int num_paths, void *context), void *context, struct ib_sa_query **sa_query) { @@ -1677,8 +1619,7 @@ err1: EXPORT_SYMBOL(ib_sa_path_rec_get); static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query, - int status, int num_prs, - struct ib_sa_mad *mad) + int status, struct ib_sa_mad *mad) { struct ib_sa_mcmember_query *query = container_of(sa_query, struct ib_sa_mcmember_query, sa_query); @@ -1769,8 +1710,7 @@ err1: /* Support GuidInfoRecord */ static void ib_sa_guidinfo_rec_callback(struct ib_sa_query *sa_query, - int status, int num_paths, - struct ib_sa_mad *mad) + int status, struct ib_sa_mad *mad) { struct ib_sa_guidinfo_query *query = container_of(sa_query, struct ib_sa_guidinfo_query, sa_query); @@ -1879,8 +1819,7 @@ static void ib_classportinfo_cb(void *context) } static void ib_sa_classport_info_rec_callback(struct ib_sa_query *sa_query, - int status, int num_prs, - struct ib_sa_mad *mad) + int status, struct ib_sa_mad *mad) { unsigned long flags; struct ib_sa_classport_info_query *query = @@ -2055,13 +1994,13 @@ static void send_handler(struct ib_mad_agent *agent, /* No callback -- already got recv */ break; case IB_WC_RESP_TIMEOUT_ERR: - query->callback(query, -ETIMEDOUT, 0, NULL); + query->callback(query, -ETIMEDOUT, NULL); break; case IB_WC_WR_FLUSH_ERR: - query->callback(query, -EINTR, 0, NULL); + query->callback(query, -EINTR, NULL); break; default: - query->callback(query, -EIO, 0, NULL); + query->callback(query, -EIO, NULL); break; } @@ -2089,10 +2028,10 @@ static void recv_handler(struct ib_mad_agent *mad_agent, if (mad_recv_wc->wc->status == IB_WC_SUCCESS) query->callback(query, mad_recv_wc->recv_buf.mad->mad_hdr.status ? - -EINVAL : 0, 1, + -EINVAL : 0, (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad); else - query->callback(query, -EIO, 0, NULL); + query->callback(query, -EIO, NULL); } ib_free_recv_mad(mad_recv_wc); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index ac25fc80fb33..4b3a7dbc21a4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -742,7 +742,7 @@ void ipoib_flush_paths(struct net_device *dev) static void path_rec_completion(int status, struct sa_path_rec *pathrec, - int num_prs, void *path_ptr) + unsigned int num_prs, void *path_ptr) { struct ipoib_path *path = path_ptr; struct net_device *dev = path->dev; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index b4d6a4a5ae81..df21b30b7735 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -699,7 +699,7 @@ static void srp_free_ch_ib(struct srp_target_port *target, static void srp_path_rec_completion(int status, struct sa_path_rec *pathrec, - int num_paths, void *ch_ptr) + unsigned int num_paths, void *ch_ptr) { struct srp_rdma_ch *ch = ch_ptr; struct srp_target_port *target = ch->target; diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index e930bec33b31..b46353fc53bf 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -414,7 +414,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, struct ib_device *device, ib_sa_comp_mask comp_mask, unsigned long timeout_ms, gfp_t gfp_mask, void (*callback)(int status, struct sa_path_rec *resp, - int num_prs, void *context), + unsigned int num_prs, void *context), void *context, struct ib_sa_query **query); struct ib_sa_multicast { diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index cdc7cafab572..8a8ab2f793ab 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -49,7 +49,6 @@ struct rdma_addr { struct rdma_dev_addr dev_addr; }; -#define RDMA_PRIMARY_PATH_MAX_REC_NUM 3 struct rdma_route { struct rdma_addr addr; struct sa_path_rec *path_rec; -- cgit v1.2.3 From 7d885863e716757553197687f304da1f538f61e1 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Mon, 9 Jan 2023 13:30:12 +0100 Subject: net: phy: allow a phy to opt-out of interrupt handling Until now, it is not possible for a PHY driver to disable interrupts during runtime. If a driver offers the .config_intr() as well as the .handle_interrupt() ops, it is eligible for interrupt handling. Introduce a new flag for the dev_flags property of struct phy_device, which can be set by PHY driver to skip interrupt setup and fall back to polling mode. At the moment, this is used for the MaxLinear PHY which has broken interrupt handling and there is a need to disable interrupts in some cases. Signed-off-by: Michael Walle Reviewed-by: Andrew Lunn Signed-off-by: Paolo Abeni --- drivers/net/phy/phy_device.c | 7 +++++++ include/linux/phy.h | 3 +++ 2 files changed, 10 insertions(+) (limited to 'include') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 716870a4499c..e4562859ac00 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1487,6 +1487,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev->interrupts = PHY_INTERRUPT_DISABLED; + /* PHYs can request to use poll mode even though they have an + * associated interrupt line. This could be the case if they + * detect a broken interrupt handling. + */ + if (phydev->dev_flags & PHY_F_NO_IRQ) + phydev->irq = PHY_POLL; + /* Port is set to PORT_TP by default and the actual PHY driver will set * it to different value depending on the PHY configuration. If we have * the generic PHY driver we can't figure it out, thus set the old diff --git a/include/linux/phy.h b/include/linux/phy.h index 6378c997ded5..742754d72fc0 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -739,6 +739,9 @@ struct phy_device { #endif }; +/* Generic phy_device::dev_flags */ +#define PHY_F_NO_IRQ 0x80000000 + static inline struct phy_device *to_phy_device(const struct device *dev) { return container_of(to_mdio_device(dev), struct phy_device, mdio); -- cgit v1.2.3 From 8afbb4273977f055db219a22daaafe64be10fb95 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Jan 2023 18:58:05 +0100 Subject: driver core: make bus_get_device_klist() static No one calls this function outside of drivers/base/bus.c so make it static so it does not need to be exported anymore. Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230109175810.2965448-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 3 +-- include/linux/device/bus.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 4ec6dbab73be..4425f962bf51 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -897,11 +897,10 @@ struct kset *bus_get_kset(struct bus_type *bus) } EXPORT_SYMBOL_GPL(bus_get_kset); -struct klist *bus_get_device_klist(struct bus_type *bus) +static struct klist *bus_get_device_klist(struct bus_type *bus) { return &bus->p->klist_devices; } -EXPORT_SYMBOL_GPL(bus_get_device_klist); /* * Yes, this forcibly breaks the klist abstraction temporarily. It diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index d8b29ccd07e5..01077c503d61 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -287,6 +287,5 @@ extern int bus_unregister_notifier(struct bus_type *bus, #define BUS_NOTIFY_DRIVER_NOT_BOUND 0x00000008 /* driver fails to be bound */ extern struct kset *bus_get_kset(struct bus_type *bus); -extern struct klist *bus_get_device_klist(struct bus_type *bus); #endif -- cgit v1.2.3 From a9efdd2519edd7df84afd075b65ca6428dcb0039 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Jan 2023 18:58:06 +0100 Subject: driver core: remove subsys_find_device_by_id() This function has not been called by any code in the kernel tree in many many years so remove it as it is unused. Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230109175810.2965448-2-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 41 ----------------------------------------- include/linux/device/bus.h | 2 -- 2 files changed, 43 deletions(-) (limited to 'include') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 4425f962bf51..f8eb882bbf37 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -339,47 +339,6 @@ struct device *bus_find_device(struct bus_type *bus, } EXPORT_SYMBOL_GPL(bus_find_device); -/** - * subsys_find_device_by_id - find a device with a specific enumeration number - * @subsys: subsystem - * @id: index 'id' in struct device - * @hint: device to check first - * - * Check the hint's next object and if it is a match return it directly, - * otherwise, fall back to a full list search. Either way a reference for - * the returned object is taken. - */ -struct device *subsys_find_device_by_id(struct bus_type *subsys, unsigned int id, - struct device *hint) -{ - struct klist_iter i; - struct device *dev; - - if (!subsys) - return NULL; - - if (hint) { - klist_iter_init_node(&subsys->p->klist_devices, &i, &hint->p->knode_bus); - dev = next_device(&i); - if (dev && dev->id == id && get_device(dev)) { - klist_iter_exit(&i); - return dev; - } - klist_iter_exit(&i); - } - - klist_iter_init_node(&subsys->p->klist_devices, &i, NULL); - while ((dev = next_device(&i))) { - if (dev->id == id && get_device(dev)) { - klist_iter_exit(&i); - return dev; - } - } - klist_iter_exit(&i); - return NULL; -} -EXPORT_SYMBOL_GPL(subsys_find_device_by_id); - static struct device_driver *next_driver(struct klist_iter *i) { struct klist_node *n = klist_next(i); diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index 01077c503d61..3b1a2066afcd 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -250,8 +250,6 @@ bus_find_device_by_acpi_dev(struct bus_type *bus, const void *adev) } #endif -struct device *subsys_find_device_by_id(struct bus_type *bus, unsigned int id, - struct device *hint); int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *)); void bus_sort_breadthfirst(struct bus_type *bus, -- cgit v1.2.3 From 2e45fc5502af9826617a96fe63aee055002cac97 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Jan 2023 18:58:07 +0100 Subject: driver core: make subsys_dev_iter_init() static No one outside of drivers/base/bus.c calls this function so make it static and remove the exported symbol. Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230109175810.2965448-3-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 5 ++--- include/linux/device/bus.h | 4 ---- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index f8eb882bbf37..f781124fdf31 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -923,8 +923,8 @@ EXPORT_SYMBOL_GPL(bus_sort_breadthfirst); * otherwise if it is NULL, the iteration starts at the beginning of * the list. */ -void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys, - struct device *start, const struct device_type *type) +static void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys, + struct device *start, const struct device_type *type) { struct klist_node *start_knode = NULL; @@ -933,7 +933,6 @@ void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys, klist_iter_init_node(&subsys->p->klist_devices, &iter->ki, start_knode); iter->type = type; } -EXPORT_SYMBOL_GPL(subsys_dev_iter_init); /** * subsys_dev_iter_next - iterate to the next device diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index 3b1a2066afcd..67cb5b29f62d 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -154,10 +154,6 @@ struct subsys_dev_iter { struct klist_iter ki; const struct device_type *type; }; -void subsys_dev_iter_init(struct subsys_dev_iter *iter, - struct bus_type *subsys, - struct device *start, - const struct device_type *type); struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter); void subsys_dev_iter_exit(struct subsys_dev_iter *iter); -- cgit v1.2.3 From 38cdadefa2feecc9e7aa5f67bc4aea5b9a8ca59f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Jan 2023 18:58:08 +0100 Subject: driver core: make subsys_dev_iter_next() static The function subsys_dev_iter_next() is only used in drivers/base/bus.c so make it static to that file and remove the global export. Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230109175810.2965448-4-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 3 +-- include/linux/device/bus.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index f781124fdf31..f0aacb3b1bc6 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -946,7 +946,7 @@ static void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type * * free to do whatever it wants to do with the device including * calling back into subsys code. */ -struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter) +static struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter) { struct klist_node *knode; struct device *dev; @@ -960,7 +960,6 @@ struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter) return dev; } } -EXPORT_SYMBOL_GPL(subsys_dev_iter_next); /** * subsys_dev_iter_exit - finish iteration diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index 67cb5b29f62d..4f994d8fce0c 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -154,7 +154,6 @@ struct subsys_dev_iter { struct klist_iter ki; const struct device_type *type; }; -struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter); void subsys_dev_iter_exit(struct subsys_dev_iter *iter); int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, -- cgit v1.2.3 From af6d0743599e594cb2cec3f1a6d2600a57d1d375 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Jan 2023 18:58:09 +0100 Subject: driver core: make subsys_dev_iter_exit() static The function subsys_dev_iter_exit() is not used outside of drivers/base/bus.c so make it static to that file and remove the global export. Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230109175810.2965448-5-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 3 +-- include/linux/device/bus.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index f0aacb3b1bc6..bde52fd1d3e3 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -968,11 +968,10 @@ static struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter) * Finish an iteration. Always call this function after iteration is * complete whether the iteration ran till the end or not. */ -void subsys_dev_iter_exit(struct subsys_dev_iter *iter) +static void subsys_dev_iter_exit(struct subsys_dev_iter *iter) { klist_iter_exit(&iter->ki); } -EXPORT_SYMBOL_GPL(subsys_dev_iter_exit); int subsys_interface_register(struct subsys_interface *sif) { diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index 4f994d8fce0c..848d49f4cc09 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -154,7 +154,6 @@ struct subsys_dev_iter { struct klist_iter ki; const struct device_type *type; }; -void subsys_dev_iter_exit(struct subsys_dev_iter *iter); int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data)); -- cgit v1.2.3 From b0a8a59a1c44c07807afe50c6bd21a33c9ec98b7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Jan 2023 18:58:10 +0100 Subject: driver core: move struct subsys_dev_iter to a local file struct subsys_dev_iter is not used by any code outside of drivers/base/bus.c so move it into that file and out of the global bus.h file. Reviewed-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230109175810.2965448-6-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 5 +++++ include/linux/device/bus.h | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index bde52fd1d3e3..428c26c6b615 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -911,6 +911,11 @@ void bus_sort_breadthfirst(struct bus_type *bus, } EXPORT_SYMBOL_GPL(bus_sort_breadthfirst); +struct subsys_dev_iter { + struct klist_iter ki; + const struct device_type *type; +}; + /** * subsys_dev_iter_init - initialize subsys device iterator * @iter: subsys iterator to initialize diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index 848d49f4cc09..d529f644e92b 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -150,11 +150,6 @@ int device_match_acpi_handle(struct device *dev, const void *handle); int device_match_any(struct device *dev, const void *unused); /* iterator helpers for buses */ -struct subsys_dev_iter { - struct klist_iter ki; - const struct device_type *type; -}; - int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data)); struct device *bus_find_device(struct bus_type *bus, struct device *start, -- cgit v1.2.3 From b4f0370d3ce276397f5c48af99d0b77548825eb1 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 9 Jan 2023 18:45:06 +0100 Subject: dt-bindings: power: qcom,rpmpd: document sa8775p Add a compatible for sa8775p platforms and relevant defines to the include file. Signed-off-by: Bartosz Golaszewski Acked-by: Krzysztof Kozlowski Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230109174511.1740856-14-brgl@bgdev.pl --- .../devicetree/bindings/power/qcom,rpmpd.yaml | 1 + include/dt-bindings/power/qcom-rpmpd.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 633d49884019..1778d9851510 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -30,6 +30,7 @@ properties: - qcom,qcs404-rpmpd - qcom,qdu1000-rpmhpd - qcom,sa8540p-rpmhpd + - qcom,sa8775p-rpmhpd - qcom,sdm660-rpmpd - qcom,sc7180-rpmhpd - qcom,sc7280-rpmhpd diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index 1e19e258a74d..3117bf7d5ebf 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -4,6 +4,25 @@ #ifndef _DT_BINDINGS_POWER_QCOM_RPMPD_H #define _DT_BINDINGS_POWER_QCOM_RPMPD_H +/* SA8775P Power Domain Indexes */ +#define SA8775P_CX 0 +#define SA8775P_CX_AO 1 +#define SA8775P_DDR 2 +#define SA8775P_EBI 3 +#define SA8775P_GFX 4 +#define SA8775P_LCX 5 +#define SA8775P_LMX 6 +#define SA8775P_MMCX 7 +#define SA8775P_MMCX_AO 8 +#define SA8775P_MSS 9 +#define SA8775P_MX 10 +#define SA8775P_MX_AO 11 +#define SA8775P_MXC 12 +#define SA8775P_MXC_AO 13 +#define SA8775P_NSP0 14 +#define SA8775P_NSP1 15 +#define SA8775P_XO 16 + /* SDM670 Power Domain Indexes */ #define SDM670_MX 0 #define SDM670_MX_AO 1 -- cgit v1.2.3 From 26b36df7516692292312063ca6fd19e73c06d4e7 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Tue, 27 Dec 2022 22:45:27 +0200 Subject: clk: Add generic sync_state callback for disabling unused clocks There are unused clocks that need to remain untouched by clk_disable_unused, and most likely could be disabled later on sync_state. So provide a generic sync_state callback for the clock providers that register such clocks. Then, use the same mechanism as clk_disable_unused from that generic callback, but pass the device to make sure only the clocks belonging to the current clock provider get disabled, if unused. Also, during the default clk_disable_unused, if the driver that registered the clock has the generic clk_sync_state_disable_unused callback set for sync_state, skip disabling its clocks. Signed-off-by: Abel Vesa Reviewed-by: Bjorn Andersson Reviewed-by: Dmitry Baryshkov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20221227204528.1899863-1-abel.vesa@linaro.org --- drivers/clk/clk.c | 57 +++++++++++++++++++++++++++++++++++--------- include/linux/clk-provider.h | 1 + 2 files changed, 47 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index e62552a75f08..ac7182903d88 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1302,14 +1302,26 @@ static void clk_core_disable_unprepare(struct clk_core *core) clk_core_unprepare_lock(core); } -static void __init clk_unprepare_unused_subtree(struct clk_core *core) +static void clk_unprepare_unused_subtree(struct clk_core *core, + struct device *dev) { + bool from_sync_state = !!dev; struct clk_core *child; lockdep_assert_held(&prepare_lock); hlist_for_each_entry(child, &core->children, child_node) - clk_unprepare_unused_subtree(child); + clk_unprepare_unused_subtree(child, dev); + + if (from_sync_state && core->dev != dev) + return; + + /* + * clock will be unprepared on sync_state, + * so leave as is for now + */ + if (!from_sync_state && dev_has_sync_state(core->dev)) + return; if (core->prepare_count) return; @@ -1332,15 +1344,27 @@ static void __init clk_unprepare_unused_subtree(struct clk_core *core) clk_pm_runtime_put(core); } -static void __init clk_disable_unused_subtree(struct clk_core *core) +static void clk_disable_unused_subtree(struct clk_core *core, + struct device *dev) { + bool from_sync_state = !!dev; struct clk_core *child; unsigned long flags; lockdep_assert_held(&prepare_lock); hlist_for_each_entry(child, &core->children, child_node) - clk_disable_unused_subtree(child); + clk_disable_unused_subtree(child, dev); + + if (from_sync_state && core->dev != dev) + return; + + /* + * clock will be disabled on sync_state, + * so leave as is for now + */ + if (!from_sync_state && dev_has_sync_state(core->dev)) + return; if (core->flags & CLK_OPS_PARENT_ENABLE) clk_core_prepare_enable(core->parent); @@ -1378,7 +1402,7 @@ unprepare_out: clk_core_disable_unprepare(core->parent); } -static bool clk_ignore_unused __initdata; +static bool clk_ignore_unused; static int __init clk_ignore_unused_setup(char *__unused) { clk_ignore_unused = true; @@ -1386,35 +1410,46 @@ static int __init clk_ignore_unused_setup(char *__unused) } __setup("clk_ignore_unused", clk_ignore_unused_setup); -static int __init clk_disable_unused(void) +static void __clk_disable_unused(struct device *dev) { struct clk_core *core; if (clk_ignore_unused) { pr_warn("clk: Not disabling unused clocks\n"); - return 0; + return; } clk_prepare_lock(); hlist_for_each_entry(core, &clk_root_list, child_node) - clk_disable_unused_subtree(core); + clk_disable_unused_subtree(core, dev); hlist_for_each_entry(core, &clk_orphan_list, child_node) - clk_disable_unused_subtree(core); + clk_disable_unused_subtree(core, dev); hlist_for_each_entry(core, &clk_root_list, child_node) - clk_unprepare_unused_subtree(core); + clk_unprepare_unused_subtree(core, dev); hlist_for_each_entry(core, &clk_orphan_list, child_node) - clk_unprepare_unused_subtree(core); + clk_unprepare_unused_subtree(core, dev); clk_prepare_unlock(); +} + +static int __init clk_disable_unused(void) +{ + __clk_disable_unused(NULL); return 0; } late_initcall_sync(clk_disable_unused); +void clk_sync_state_disable_unused(struct device *dev) +{ + __clk_disable_unused(dev); +} +EXPORT_SYMBOL_GPL(clk_sync_state_disable_unused); + static int clk_core_determine_round_nolock(struct clk_core *core, struct clk_rate_request *req) { diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 842e72a5348f..cf1adfeaf257 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -720,6 +720,7 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name, void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock); +void clk_sync_state_disable_unused(struct device *dev); /** * clk_register_divider - register a divider clock with the clock framework * @dev: device registering this clock -- cgit v1.2.3 From a9236a0aa7d7f52a974cc7eaa971fae92aa477c5 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 2 Jan 2023 16:18:27 +0530 Subject: PM: domains: Allow a genpd consumer to require a synced power off Some genpd providers doesn't ensure that it has turned off at hardware. This is fine until the consumer really requires during some special scenarios that the power domain collapse at hardware before it is turned ON again. An example is the reset sequence of Adreno GPU which requires that the 'gpucc cx gdsc' power domain should move to OFF state in hardware at least once before turning in ON again to clear the internal state. Signed-off-by: Ulf Hansson Signed-off-by: Akhil P Oommen Reviewed-by: Bjorn Andersson Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230102161757.v5.1.I3e6b1f078ad0f1ca9358c573daa7b70ec132cdbe@changeid --- drivers/base/power/domain.c | 26 ++++++++++++++++++++++++++ include/linux/pm_domain.h | 5 +++++ 2 files changed, 31 insertions(+) (limited to 'include') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 967bcf9d415e..84662d338188 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -519,6 +519,31 @@ ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer); +/* + * dev_pm_genpd_synced_poweroff - Next power off should be synchronous + * + * @dev: A device that is attached to the genpd. + * + * Allows a consumer of the genpd to notify the provider that the next power off + * should be synchronous. + * + * It is assumed that the users guarantee that the genpd wouldn't be detached + * while this routine is getting called. + */ +void dev_pm_genpd_synced_poweroff(struct device *dev) +{ + struct generic_pm_domain *genpd; + + genpd = dev_to_genpd_safe(dev); + if (!genpd) + return; + + genpd_lock(genpd); + genpd->synced_poweroff = true; + genpd_unlock(genpd); +} +EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff); + static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) { unsigned int state_idx = genpd->state_idx; @@ -562,6 +587,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) out: raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL); + genpd->synced_poweroff = false; return 0; err: raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF, diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 1cd41bdf73cf..f776fb93eaa0 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -136,6 +136,7 @@ struct generic_pm_domain { unsigned int prepared_count; /* Suspend counter of prepared devices */ unsigned int performance_state; /* Aggregated max performance state */ cpumask_var_t cpus; /* A cpumask of the attached CPUs */ + bool synced_poweroff; /* A consumer needs a synced poweroff */ int (*power_off)(struct generic_pm_domain *domain); int (*power_on)(struct generic_pm_domain *domain); struct raw_notifier_head power_notifiers; /* Power on/off notifiers */ @@ -235,6 +236,7 @@ int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb); int dev_pm_genpd_remove_notifier(struct device *dev); void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next); ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev); +void dev_pm_genpd_synced_poweroff(struct device *dev); extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; @@ -300,6 +302,9 @@ static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) { return KTIME_MAX; } +static inline void dev_pm_genpd_synced_poweroff(struct device *dev) +{ } + #define simple_qos_governor (*(struct dev_power_governor *)(NULL)) #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) #endif -- cgit v1.2.3 From 0960ec915a7531e3a760cf97d523ce2fa90b1412 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 9 Jan 2023 16:47:21 +0100 Subject: dt-bindings: clock: document SM8550 DISPCC clock controller Document device tree bindings for display clock controller for Qualcomm SM8550 SoC. Signed-off-by: Neil Armstrong Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230103-topic-sm8550-upstream-dispcc-v3-1-8a03d348c572@linaro.org --- .../bindings/clock/qcom,sm8550-dispcc.yaml | 105 +++++++++++++++++++++ include/dt-bindings/clock/qcom,sm8550-dispcc.h | 101 ++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml create mode 100644 include/dt-bindings/clock/qcom,sm8550-dispcc.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml new file mode 100644 index 000000000000..ab25f7cbaa2e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm8550-dispcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display Clock & Reset Controller for SM8550 + +maintainers: + - Bjorn Andersson + - Neil Armstrong + +description: | + Qualcomm display clock control module provides the clocks, resets and power + domains on SM8550. + + See also:: include/dt-bindings/clock/qcom,sm8550-dispcc.h + +properties: + compatible: + enum: + - qcom,sm8550-dispcc + + clocks: + items: + - description: Board XO source + - description: Board Always On XO source + - description: Display's AHB clock + - description: sleep clock + - description: Byte clock from DSI PHY0 + - description: Pixel clock from DSI PHY0 + - description: Byte clock from DSI PHY1 + - description: Pixel clock from DSI PHY1 + - description: Link clock from DP PHY0 + - description: VCO DIV clock from DP PHY0 + - description: Link clock from DP PHY1 + - description: VCO DIV clock from DP PHY1 + - description: Link clock from DP PHY2 + - description: VCO DIV clock from DP PHY2 + - description: Link clock from DP PHY3 + - description: VCO DIV clock from DP PHY3 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + '#power-domain-cells': + const: 1 + + reg: + maxItems: 1 + + power-domains: + description: + A phandle and PM domain specifier for the MMCX power domain. + maxItems: 1 + + required-opps: + description: + A phandle to an OPP node describing required MMCX performance point. + maxItems: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + - '#reset-cells' + - '#power-domain-cells' + +additionalProperties: false + +examples: + - | + #include + #include + #include + clock-controller@af00000 { + compatible = "qcom,sm8550-dispcc"; + reg = <0x0af00000 0x10000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&gcc GCC_DISP_AHB_CLK>, + <&sleep_clk>, + <&dsi0_phy 0>, + <&dsi0_phy 1>, + <&dsi1_phy 0>, + <&dsi1_phy 1>, + <&dp0_phy 0>, + <&dp0_phy 1>, + <&dp1_phy 0>, + <&dp1_phy 1>, + <&dp2_phy 0>, + <&dp2_phy 1>, + <&dp3_phy 0>, + <&dp3_phy 1>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + power-domains = <&rpmhpd SM8550_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; + }; +... diff --git a/include/dt-bindings/clock/qcom,sm8550-dispcc.h b/include/dt-bindings/clock/qcom,sm8550-dispcc.h new file mode 100644 index 000000000000..ed3094c694e0 --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8550-dispcc.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_SM8550_DISP_CC_H +#define _DT_BINDINGS_CLK_QCOM_SM8550_DISP_CC_H + +/* DISP_CC clocks */ +#define DISP_CC_MDSS_ACCU_CLK 0 +#define DISP_CC_MDSS_AHB1_CLK 1 +#define DISP_CC_MDSS_AHB_CLK 2 +#define DISP_CC_MDSS_AHB_CLK_SRC 3 +#define DISP_CC_MDSS_BYTE0_CLK 4 +#define DISP_CC_MDSS_BYTE0_CLK_SRC 5 +#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 6 +#define DISP_CC_MDSS_BYTE0_INTF_CLK 7 +#define DISP_CC_MDSS_BYTE1_CLK 8 +#define DISP_CC_MDSS_BYTE1_CLK_SRC 9 +#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 10 +#define DISP_CC_MDSS_BYTE1_INTF_CLK 11 +#define DISP_CC_MDSS_DPTX0_AUX_CLK 12 +#define DISP_CC_MDSS_DPTX0_AUX_CLK_SRC 13 +#define DISP_CC_MDSS_DPTX0_CRYPTO_CLK 14 +#define DISP_CC_MDSS_DPTX0_LINK_CLK 15 +#define DISP_CC_MDSS_DPTX0_LINK_CLK_SRC 16 +#define DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC 17 +#define DISP_CC_MDSS_DPTX0_LINK_INTF_CLK 18 +#define DISP_CC_MDSS_DPTX0_PIXEL0_CLK 19 +#define DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC 20 +#define DISP_CC_MDSS_DPTX0_PIXEL1_CLK 21 +#define DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC 22 +#define DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK 23 +#define DISP_CC_MDSS_DPTX1_AUX_CLK 24 +#define DISP_CC_MDSS_DPTX1_AUX_CLK_SRC 25 +#define DISP_CC_MDSS_DPTX1_CRYPTO_CLK 26 +#define DISP_CC_MDSS_DPTX1_LINK_CLK 27 +#define DISP_CC_MDSS_DPTX1_LINK_CLK_SRC 28 +#define DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC 29 +#define DISP_CC_MDSS_DPTX1_LINK_INTF_CLK 30 +#define DISP_CC_MDSS_DPTX1_PIXEL0_CLK 31 +#define DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC 32 +#define DISP_CC_MDSS_DPTX1_PIXEL1_CLK 33 +#define DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC 34 +#define DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK 35 +#define DISP_CC_MDSS_DPTX2_AUX_CLK 36 +#define DISP_CC_MDSS_DPTX2_AUX_CLK_SRC 37 +#define DISP_CC_MDSS_DPTX2_CRYPTO_CLK 38 +#define DISP_CC_MDSS_DPTX2_LINK_CLK 39 +#define DISP_CC_MDSS_DPTX2_LINK_CLK_SRC 40 +#define DISP_CC_MDSS_DPTX2_LINK_DIV_CLK_SRC 41 +#define DISP_CC_MDSS_DPTX2_LINK_INTF_CLK 42 +#define DISP_CC_MDSS_DPTX2_PIXEL0_CLK 43 +#define DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC 44 +#define DISP_CC_MDSS_DPTX2_PIXEL1_CLK 45 +#define DISP_CC_MDSS_DPTX2_PIXEL1_CLK_SRC 46 +#define DISP_CC_MDSS_DPTX3_AUX_CLK 47 +#define DISP_CC_MDSS_DPTX3_AUX_CLK_SRC 48 +#define DISP_CC_MDSS_DPTX3_CRYPTO_CLK 49 +#define DISP_CC_MDSS_DPTX3_LINK_CLK 50 +#define DISP_CC_MDSS_DPTX3_LINK_CLK_SRC 51 +#define DISP_CC_MDSS_DPTX3_LINK_DIV_CLK_SRC 52 +#define DISP_CC_MDSS_DPTX3_LINK_INTF_CLK 53 +#define DISP_CC_MDSS_DPTX3_PIXEL0_CLK 54 +#define DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC 55 +#define DISP_CC_MDSS_ESC0_CLK 56 +#define DISP_CC_MDSS_ESC0_CLK_SRC 57 +#define DISP_CC_MDSS_ESC1_CLK 58 +#define DISP_CC_MDSS_ESC1_CLK_SRC 59 +#define DISP_CC_MDSS_MDP1_CLK 60 +#define DISP_CC_MDSS_MDP_CLK 61 +#define DISP_CC_MDSS_MDP_CLK_SRC 62 +#define DISP_CC_MDSS_MDP_LUT1_CLK 63 +#define DISP_CC_MDSS_MDP_LUT_CLK 64 +#define DISP_CC_MDSS_NON_GDSC_AHB_CLK 65 +#define DISP_CC_MDSS_PCLK0_CLK 66 +#define DISP_CC_MDSS_PCLK0_CLK_SRC 67 +#define DISP_CC_MDSS_PCLK1_CLK 68 +#define DISP_CC_MDSS_PCLK1_CLK_SRC 69 +#define DISP_CC_MDSS_RSCC_AHB_CLK 70 +#define DISP_CC_MDSS_RSCC_VSYNC_CLK 71 +#define DISP_CC_MDSS_VSYNC1_CLK 72 +#define DISP_CC_MDSS_VSYNC_CLK 73 +#define DISP_CC_MDSS_VSYNC_CLK_SRC 74 +#define DISP_CC_PLL0 75 +#define DISP_CC_PLL1 76 +#define DISP_CC_SLEEP_CLK 77 +#define DISP_CC_SLEEP_CLK_SRC 78 +#define DISP_CC_XO_CLK 79 +#define DISP_CC_XO_CLK_SRC 80 + +/* DISP_CC resets */ +#define DISP_CC_MDSS_CORE_BCR 0 +#define DISP_CC_MDSS_CORE_INT2_BCR 1 +#define DISP_CC_MDSS_RSCC_BCR 2 + +/* DISP_CC GDSCR */ +#define MDSS_GDSC 0 +#define MDSS_INT2_GDSC 1 + +#endif -- cgit v1.2.3 From d220193c50496adc2812a7c21e05874f47cbc9f9 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Wed, 4 Jan 2023 11:34:47 +0200 Subject: dt-bindings: clock: Add SM8550 TCSR CC clocks Add bindings documentation for clock TCSR driver on SM8550. Signed-off-by: Abel Vesa Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230104093450.3150578-2-abel.vesa@linaro.org --- .../bindings/clock/qcom,sm8550-tcsr.yaml | 55 ++++++++++++++++++++++ include/dt-bindings/clock/qcom,sm8550-tcsr.h | 18 +++++++ 2 files changed, 73 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml create mode 100644 include/dt-bindings/clock/qcom,sm8550-tcsr.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml new file mode 100644 index 000000000000..1bf1a41fd89c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm8550-tcsr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm TCSR Clock Controller on SM8550 + +maintainers: + - Bjorn Andersson + +description: | + Qualcomm TCSR clock control module provides the clocks, resets and + power domains on SM8550 + + See also:: include/dt-bindings/clock/qcom,sm8550-tcsr.h + +properties: + compatible: + items: + - const: qcom,sm8550-tcsr + - const: syscon + + clocks: + items: + - description: TCXO pad clock + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - clocks + +additionalProperties: false + +examples: + - | + #include + + clock-controller@1fc0000 { + compatible = "qcom,sm8550-tcsr", "syscon"; + reg = <0x1fc0000 0x30000>; + clocks = <&rpmhcc RPMH_CXO_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/qcom,sm8550-tcsr.h b/include/dt-bindings/clock/qcom,sm8550-tcsr.h new file mode 100644 index 000000000000..091cb76f953a --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8550-tcsr.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Linaro Limited + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_TCSR_CC_SM8550_H +#define _DT_BINDINGS_CLK_QCOM_TCSR_CC_SM8550_H + +/* TCSR CC clocks */ +#define TCSR_PCIE_0_CLKREF_EN 0 +#define TCSR_PCIE_1_CLKREF_EN 1 +#define TCSR_UFS_CLKREF_EN 2 +#define TCSR_UFS_PAD_CLKREF_EN 3 +#define TCSR_USB2_CLKREF_EN 4 +#define TCSR_USB3_CLKREF_EN 5 + +#endif -- cgit v1.2.3 From 129d868ede1ea835ac97f0a9f2cf3f4ed00d8ea7 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 5 Jan 2023 11:26:47 -0800 Subject: bpf: Replace 0-length arrays with flexible arrays Zero-length arrays are deprecated [1]. Replace struct bpf_array's union of 0-length arrays with flexible arrays. Detected with GCC 13, by using -fstrict-flex-arrays=3: arch/x86/net/bpf_jit_comp.c: In function 'bpf_tail_call_direct_fixup': arch/x86/net/bpf_jit_comp.c:606:37: warning: array subscript is outside array bounds of 'void *[0]' [-Warray-bounds=] 606 | target = array->ptrs[poke->tail_call.key]; | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~ In file included from include/linux/filter.h:9, from arch/x86/net/bpf_jit_comp.c:9: include/linux/bpf.h:1527:23: note: while referencing 'ptrs' 1527 | void *ptrs[0] __aligned(8); | ^~~~ [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays Signed-off-by: Kees Cook Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230105192646.never.154-kees@kernel.org --- include/linux/bpf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1697bd87fc06..ae7771c7d750 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1523,9 +1523,9 @@ struct bpf_array { u32 index_mask; struct bpf_array_aux *aux; union { - char value[0] __aligned(8); - void *ptrs[0] __aligned(8); - void __percpu *pptrs[0] __aligned(8); + DECLARE_FLEX_ARRAY(char, value) __aligned(8); + DECLARE_FLEX_ARRAY(void *, ptrs) __aligned(8); + DECLARE_FLEX_ARRAY(void __percpu *, pptrs) __aligned(8); }; }; -- cgit v1.2.3 From 4e4aafcddbbfcdd6eed5780e190fcbfac8b4685a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 9 Jan 2023 16:30:41 +0100 Subject: net: mdio: Add dedicated C45 API to MDIO bus drivers Currently C22 and C45 transactions are mixed over a combined API calls which make use of a special bit in the reg address to indicate if a C45 transaction should be performed. This makes it impossible to know if the bus driver actually supports C45. Additionally, many C22 only drivers don't return -EOPNOTSUPP when asked to perform a C45 transaction, they mistaking perform a C22 transaction. This is the first step to cleanly separate C22 from C45. To maintain backwards compatibility until all drivers which are capable of performing C45 are converted to this new API, the helper functions will fall back to the older API if the new API is not supported. Eventually this fallback will be removed. Signed-off-by: Andrew Lunn Signed-off-by: Michael Walle Signed-off-by: Jakub Kicinski --- drivers/net/phy/mdio_bus.c | 189 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mdio.h | 39 +++++----- include/linux/phy.h | 5 ++ 3 files changed, 214 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 1cd604cd1fa1..bde195864c17 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -826,6 +826,100 @@ int __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum, } EXPORT_SYMBOL_GPL(__mdiobus_modify_changed); +/** + * __mdiobus_c45_read - Unlocked version of the mdiobus_c45_read function + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to read + * + * Read a MDIO bus register. Caller must hold the mdio bus lock. + * + * NOTE: MUST NOT be called from interrupt context. + */ +int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum) +{ + int retval; + + lockdep_assert_held_once(&bus->mdio_lock); + + if (bus->read_c45) + retval = bus->read_c45(bus, addr, devad, regnum); + else + retval = bus->read(bus, addr, mdiobus_c45_addr(devad, regnum)); + + trace_mdio_access(bus, 1, addr, regnum, retval, retval); + mdiobus_stats_acct(&bus->stats[addr], true, retval); + + return retval; +} +EXPORT_SYMBOL(__mdiobus_c45_read); + +/** + * __mdiobus_c45_write - Unlocked version of the mdiobus_write function + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to write + * @val: value to write to @regnum + * + * Write a MDIO bus register. Caller must hold the mdio bus lock. + * + * NOTE: MUST NOT be called from interrupt context. + */ +int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum, + u16 val) +{ + int err; + + lockdep_assert_held_once(&bus->mdio_lock); + + if (bus->write_c45) + err = bus->write_c45(bus, addr, devad, regnum, val); + else + err = bus->write(bus, addr, mdiobus_c45_addr(devad, regnum), + val); + + trace_mdio_access(bus, 0, addr, regnum, val, err); + mdiobus_stats_acct(&bus->stats[addr], false, err); + + return err; +} +EXPORT_SYMBOL(__mdiobus_c45_write); + +/** + * __mdiobus_c45_modify_changed - Unlocked version of the mdiobus_modify function + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to modify + * @mask: bit mask of bits to clear + * @set: bit mask of bits to set + * + * Read, modify, and if any change, write the register value back to the + * device. Any error returns a negative number. + * + * NOTE: MUST NOT be called from interrupt context. + */ +static int __mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, + int devad, u32 regnum, u16 mask, + u16 set) +{ + int new, ret; + + ret = __mdiobus_c45_read(bus, addr, devad, regnum); + if (ret < 0) + return ret; + + new = (ret & ~mask) | set; + if (new == ret) + return 0; + + ret = __mdiobus_c45_write(bus, addr, devad, regnum, new); + + return ret < 0 ? ret : 1; +} + /** * mdiobus_read_nested - Nested version of the mdiobus_read function * @bus: the mii_bus struct @@ -873,6 +967,29 @@ int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) } EXPORT_SYMBOL(mdiobus_read); +/** + * mdiobus_c45_read - Convenience function for reading a given MII mgmt register + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to read + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum) +{ + int retval; + + mutex_lock(&bus->mdio_lock); + retval = __mdiobus_c45_read(bus, addr, devad, regnum); + mutex_unlock(&bus->mdio_lock); + + return retval; +} +EXPORT_SYMBOL(mdiobus_c45_read); + /** * mdiobus_write_nested - Nested version of the mdiobus_write function * @bus: the mii_bus struct @@ -922,6 +1039,31 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) } EXPORT_SYMBOL(mdiobus_write); +/** + * mdiobus_c45_write - Convenience function for writing a given MII mgmt register + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to write + * @val: value to write to @regnum + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum, + u16 val) +{ + int err; + + mutex_lock(&bus->mdio_lock); + err = __mdiobus_c45_write(bus, addr, devad, regnum, val); + mutex_unlock(&bus->mdio_lock); + + return err; +} +EXPORT_SYMBOL(mdiobus_c45_write); + /** * mdiobus_modify - Convenience function for modifying a given mdio device * register @@ -943,6 +1085,30 @@ int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask, u16 set) } EXPORT_SYMBOL_GPL(mdiobus_modify); +/** + * mdiobus_c45_modify - Convenience function for modifying a given mdio device + * register + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to write + * @mask: bit mask of bits to clear + * @set: bit mask of bits to set + */ +int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum, + u16 mask, u16 set) +{ + int err; + + mutex_lock(&bus->mdio_lock); + err = __mdiobus_c45_modify_changed(bus, addr, devad, regnum, + mask, set); + mutex_unlock(&bus->mdio_lock); + + return err < 0 ? err : 0; +} +EXPORT_SYMBOL_GPL(mdiobus_c45_modify); + /** * mdiobus_modify_changed - Convenience function for modifying a given mdio * device register and returning if it changed @@ -965,6 +1131,29 @@ int mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum, } EXPORT_SYMBOL_GPL(mdiobus_modify_changed); +/** + * mdiobus_c45_modify_changed - Convenience function for modifying a given mdio + * device register and returning if it changed + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to write + * @mask: bit mask of bits to clear + * @set: bit mask of bits to set + */ +int mdiobus_c45_modify_changed(struct mii_bus *bus, int devad, int addr, + u32 regnum, u16 mask, u16 set) +{ + int err; + + mutex_lock(&bus->mdio_lock); + err = __mdiobus_c45_modify_changed(bus, addr, devad, regnum, mask, set); + mutex_unlock(&bus->mdio_lock); + + return err; +} +EXPORT_SYMBOL_GPL(mdiobus_c45_modify_changed); + /** * mdio_bus_match - determine if given MDIO driver supports the given * MDIO device diff --git a/include/linux/mdio.h b/include/linux/mdio.h index f7fbbf3069e7..1e78c8410b21 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -423,6 +423,17 @@ int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask, u16 set); int mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum, u16 mask, u16 set); +int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum); +int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum); +int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum, + u16 val); +int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum, + u16 val); +int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum, + u16 mask, u16 set); + +int mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, int devad, + u32 regnum, u16 mask, u16 set); static inline int mdiodev_read(struct mdio_device *mdiodev, u32 regnum) { @@ -463,29 +474,19 @@ static inline u16 mdiobus_c45_devad(u32 regnum) return FIELD_GET(MII_DEVADDR_C45_MASK, regnum); } -static inline int __mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad, - u16 regnum) +static inline int mdiodev_c45_modify(struct mdio_device *mdiodev, int devad, + u32 regnum, u16 mask, u16 set) { - return __mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum)); + return mdiobus_c45_modify(mdiodev->bus, mdiodev->addr, devad, regnum, + mask, set); } -static inline int __mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad, - u16 regnum, u16 val) +static inline int mdiodev_c45_modify_changed(struct mdio_device *mdiodev, + int devad, u32 regnum, u16 mask, + u16 set) { - return __mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), - val); -} - -static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad, - u16 regnum) -{ - return mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum)); -} - -static inline int mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad, - u16 regnum, u16 val) -{ - return mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), val); + return mdiobus_c45_modify_changed(mdiodev->bus, mdiodev->addr, devad, + regnum, mask, set); } static inline int mdiodev_c45_read(struct mdio_device *mdiodev, int devad, diff --git a/include/linux/phy.h b/include/linux/phy.h index 742754d72fc0..89b43cda5bda 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -364,6 +364,11 @@ struct mii_bus { int (*read)(struct mii_bus *bus, int addr, int regnum); /** @write: Perform a write transfer on the bus */ int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val); + /** @read_c45: Perform a C45 read transfer on the bus */ + int (*read_c45)(struct mii_bus *bus, int addr, int devnum, int regnum); + /** @write_c45: Perform a C45 write transfer on the bus */ + int (*write_c45)(struct mii_bus *bus, int addr, int devnum, + int regnum, u16 val); /** @reset: Perform a reset of the bus */ int (*reset)(struct mii_bus *bus); -- cgit v1.2.3 From ce30fa56cbf09ab6b28170ced689c3cfd329e979 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 9 Jan 2023 16:30:45 +0100 Subject: net: mdio: Move mdiobus_c45_addr() next to users Now that mdiobus_c45_addr() is only used within the MDIO code during fallback, move the function next to its only users. This function should not be used any more in drivers, the c45 helpers should be used in its place, so hiding it away will prevent any new users from being added. Signed-off-by: Andrew Lunn Signed-off-by: Michael Walle Signed-off-by: Jakub Kicinski --- drivers/net/phy/mdio_bus.c | 5 +++++ include/linux/mdio.h | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index f71ba6ab85a7..522cbe6a0b23 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -839,6 +839,11 @@ int __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum, } EXPORT_SYMBOL_GPL(__mdiobus_modify_changed); +static u32 mdiobus_c45_addr(int devad, u16 regnum) +{ + return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum; +} + /** * __mdiobus_c45_read - Unlocked version of the mdiobus_c45_read function * @bus: the mii_bus struct diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 1e78c8410b21..97b49765e8b5 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -459,11 +459,6 @@ static inline int mdiodev_modify_changed(struct mdio_device *mdiodev, mask, set); } -static inline u32 mdiobus_c45_addr(int devad, u16 regnum) -{ - return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum; -} - static inline u16 mdiobus_c45_regad(u32 regnum) { return FIELD_GET(MII_REGADDR_C45_MASK, regnum); -- cgit v1.2.3 From 002dd3de097c778a74ae9e47e598bea6ad055af0 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 9 Jan 2023 16:30:46 +0100 Subject: net: mdio: mdio-bitbang: Separate C22 and C45 transactions The bitbbanging bus driver can perform both C22 and C45 transfers. Create separate functions for each and register the C45 versions using the new driver API calls. The SH Ethernet driver places wrappers around these functions. In order to not break boards which might be using C45, add similar wrappers for C45 operations. Reviewed-by: Geert Uytterhoeven Signed-off-by: Andrew Lunn Signed-off-by: Michael Walle Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/sh_eth.c | 37 +++++++++++++--- drivers/net/ethernet/ti/davinci_mdio.c | 50 ++++++++++++++++++---- drivers/net/mdio/mdio-bitbang.c | 77 +++++++++++++++++++++++----------- include/linux/mdio-bitbang.h | 6 ++- 4 files changed, 130 insertions(+), 40 deletions(-) (limited to 'include') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 71a499113308..ed17163d7811 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3044,23 +3044,46 @@ static int sh_mdio_release(struct sh_eth_private *mdp) return 0; } -static int sh_mdiobb_read(struct mii_bus *bus, int phy, int reg) +static int sh_mdiobb_read_c22(struct mii_bus *bus, int phy, int reg) { int res; pm_runtime_get_sync(bus->parent); - res = mdiobb_read(bus, phy, reg); + res = mdiobb_read_c22(bus, phy, reg); pm_runtime_put(bus->parent); return res; } -static int sh_mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) +static int sh_mdiobb_write_c22(struct mii_bus *bus, int phy, int reg, u16 val) { int res; pm_runtime_get_sync(bus->parent); - res = mdiobb_write(bus, phy, reg, val); + res = mdiobb_write_c22(bus, phy, reg, val); + pm_runtime_put(bus->parent); + + return res; +} + +static int sh_mdiobb_read_c45(struct mii_bus *bus, int phy, int devad, int reg) +{ + int res; + + pm_runtime_get_sync(bus->parent); + res = mdiobb_read_c45(bus, phy, devad, reg); + pm_runtime_put(bus->parent); + + return res; +} + +static int sh_mdiobb_write_c45(struct mii_bus *bus, int phy, int devad, + int reg, u16 val) +{ + int res; + + pm_runtime_get_sync(bus->parent); + res = mdiobb_write_c45(bus, phy, devad, reg, val); pm_runtime_put(bus->parent); return res; @@ -3091,8 +3114,10 @@ static int sh_mdio_init(struct sh_eth_private *mdp, return -ENOMEM; /* Wrap accessors with Runtime PM-aware ops */ - mdp->mii_bus->read = sh_mdiobb_read; - mdp->mii_bus->write = sh_mdiobb_write; + mdp->mii_bus->read = sh_mdiobb_read_c22; + mdp->mii_bus->write = sh_mdiobb_write_c22; + mdp->mii_bus->read_c45 = sh_mdiobb_read_c45; + mdp->mii_bus->write_c45 = sh_mdiobb_write_c45; /* Hook up MII support for ethtool */ mdp->mii_bus->name = "sh_mii"; diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 946b9753ccfb..23169e36a3d4 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -225,7 +225,7 @@ static int davinci_get_mdio_data(struct mdiobb_ctrl *ctrl) return test_bit(MDIO_PIN, ®); } -static int davinci_mdiobb_read(struct mii_bus *bus, int phy, int reg) +static int davinci_mdiobb_read_c22(struct mii_bus *bus, int phy, int reg) { int ret; @@ -233,7 +233,7 @@ static int davinci_mdiobb_read(struct mii_bus *bus, int phy, int reg) if (ret < 0) return ret; - ret = mdiobb_read(bus, phy, reg); + ret = mdiobb_read_c22(bus, phy, reg); pm_runtime_mark_last_busy(bus->parent); pm_runtime_put_autosuspend(bus->parent); @@ -241,8 +241,8 @@ static int davinci_mdiobb_read(struct mii_bus *bus, int phy, int reg) return ret; } -static int davinci_mdiobb_write(struct mii_bus *bus, int phy, int reg, - u16 val) +static int davinci_mdiobb_write_c22(struct mii_bus *bus, int phy, int reg, + u16 val) { int ret; @@ -250,7 +250,41 @@ static int davinci_mdiobb_write(struct mii_bus *bus, int phy, int reg, if (ret < 0) return ret; - ret = mdiobb_write(bus, phy, reg, val); + ret = mdiobb_write_c22(bus, phy, reg, val); + + pm_runtime_mark_last_busy(bus->parent); + pm_runtime_put_autosuspend(bus->parent); + + return ret; +} + +static int davinci_mdiobb_read_c45(struct mii_bus *bus, int phy, int devad, + int reg) +{ + int ret; + + ret = pm_runtime_resume_and_get(bus->parent); + if (ret < 0) + return ret; + + ret = mdiobb_read_c45(bus, phy, devad, reg); + + pm_runtime_mark_last_busy(bus->parent); + pm_runtime_put_autosuspend(bus->parent); + + return ret; +} + +static int davinci_mdiobb_write_c45(struct mii_bus *bus, int phy, int devad, + int reg, u16 val) +{ + int ret; + + ret = pm_runtime_resume_and_get(bus->parent); + if (ret < 0) + return ret; + + ret = mdiobb_write_c45(bus, phy, devad, reg, val); pm_runtime_mark_last_busy(bus->parent); pm_runtime_put_autosuspend(bus->parent); @@ -573,8 +607,10 @@ static int davinci_mdio_probe(struct platform_device *pdev) data->bus->name = dev_name(dev); if (data->manual_mode) { - data->bus->read = davinci_mdiobb_read; - data->bus->write = davinci_mdiobb_write; + data->bus->read = davinci_mdiobb_read_c22; + data->bus->write = davinci_mdiobb_write_c22; + data->bus->read_c45 = davinci_mdiobb_read_c45; + data->bus->write_c45 = davinci_mdiobb_write_c45; data->bus->reset = davinci_mdiobb_reset; dev_info(dev, "Configuring MDIO in manual mode\n"); diff --git a/drivers/net/mdio/mdio-bitbang.c b/drivers/net/mdio/mdio-bitbang.c index 07609114a26b..b83932562be2 100644 --- a/drivers/net/mdio/mdio-bitbang.c +++ b/drivers/net/mdio/mdio-bitbang.c @@ -127,14 +127,12 @@ static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg) /* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the lower 16 bits of the 21 bit address. This transfer is done identically to a - MDIO_WRITE except for a different code. To enable clause 45 mode or - MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices - can exist on the same bus. Normal devices should ignore the MDIO_ADDR + MDIO_WRITE except for a different code. Theoretically clause 45 and normal + devices can exist on the same bus. Normal devices should ignore the MDIO_ADDR phase. */ -static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) +static void mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, int dev_addr, + int reg) { - unsigned int dev_addr = (addr >> 16) & 0x1F; - unsigned int reg = addr & 0xFFFF; mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr); /* send the turnaround (10) */ @@ -145,21 +143,13 @@ static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr) ctrl->ops->set_mdio_dir(ctrl, 0); mdiobb_get_bit(ctrl); - - return dev_addr; } -int mdiobb_read(struct mii_bus *bus, int phy, int reg) +static int mdiobb_read_common(struct mii_bus *bus, int phy) { struct mdiobb_ctrl *ctrl = bus->priv; int ret, i; - if (reg & MII_ADDR_C45) { - reg = mdiobb_cmd_addr(ctrl, phy, reg); - mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); - } else - mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg); - ctrl->ops->set_mdio_dir(ctrl, 0); /* check the turnaround bit: the PHY should be driving it to zero, if this @@ -180,17 +170,31 @@ int mdiobb_read(struct mii_bus *bus, int phy, int reg) mdiobb_get_bit(ctrl); return ret; } -EXPORT_SYMBOL(mdiobb_read); -int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) +int mdiobb_read_c22(struct mii_bus *bus, int phy, int reg) { struct mdiobb_ctrl *ctrl = bus->priv; - if (reg & MII_ADDR_C45) { - reg = mdiobb_cmd_addr(ctrl, phy, reg); - mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); - } else - mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg); + mdiobb_cmd(ctrl, ctrl->op_c22_read, phy, reg); + + return mdiobb_read_common(bus, phy); +} +EXPORT_SYMBOL(mdiobb_read_c22); + +int mdiobb_read_c45(struct mii_bus *bus, int phy, int devad, int reg) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + mdiobb_cmd_addr(ctrl, phy, devad, reg); + mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg); + + return mdiobb_read_common(bus, phy); +} +EXPORT_SYMBOL(mdiobb_read_c45); + +static int mdiobb_write_common(struct mii_bus *bus, u16 val) +{ + struct mdiobb_ctrl *ctrl = bus->priv; /* send the turnaround (10) */ mdiobb_send_bit(ctrl, 1); @@ -202,7 +206,27 @@ int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val) mdiobb_get_bit(ctrl); return 0; } -EXPORT_SYMBOL(mdiobb_write); + +int mdiobb_write_c22(struct mii_bus *bus, int phy, int reg, u16 val) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + mdiobb_cmd(ctrl, ctrl->op_c22_write, phy, reg); + + return mdiobb_write_common(bus, val); +} +EXPORT_SYMBOL(mdiobb_write_c22); + +int mdiobb_write_c45(struct mii_bus *bus, int phy, int devad, int reg, u16 val) +{ + struct mdiobb_ctrl *ctrl = bus->priv; + + mdiobb_cmd_addr(ctrl, phy, devad, reg); + mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg); + + return mdiobb_write_common(bus, val); +} +EXPORT_SYMBOL(mdiobb_write_c45); struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) { @@ -214,8 +238,11 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) __module_get(ctrl->ops->owner); - bus->read = mdiobb_read; - bus->write = mdiobb_write; + bus->read = mdiobb_read_c22; + bus->write = mdiobb_write_c22; + bus->read_c45 = mdiobb_read_c45; + bus->write_c45 = mdiobb_write_c45; + bus->priv = ctrl; if (!ctrl->override_op_c22) { ctrl->op_c22_read = MDIO_READ; diff --git a/include/linux/mdio-bitbang.h b/include/linux/mdio-bitbang.h index 373630fe5c28..cffabdbce075 100644 --- a/include/linux/mdio-bitbang.h +++ b/include/linux/mdio-bitbang.h @@ -38,8 +38,10 @@ struct mdiobb_ctrl { u8 op_c22_write; }; -int mdiobb_read(struct mii_bus *bus, int phy, int reg); -int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val); +int mdiobb_read_c22(struct mii_bus *bus, int phy, int reg); +int mdiobb_write_c22(struct mii_bus *bus, int phy, int reg, u16 val); +int mdiobb_read_c45(struct mii_bus *bus, int devad, int phy, int reg); +int mdiobb_write_c45(struct mii_bus *bus, int devad, int phy, int reg, u16 val); /* The returned bus is not yet registered with the phy layer. */ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl); -- cgit v1.2.3 From 1d914d51f03cbbbda3c34c675e49392ce60c1c33 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 9 Jan 2023 16:30:50 +0100 Subject: net: mdio: add mdiobus_c45_read/write_nested helpers Some DSA devices pass through PHY access to the MDIO bus the switch is on. Add C45 versions of the current C22 helpers for nested accesses to MDIO busses, so that C22 and C45 can be separated in these DSA drivers. Signed-off-by: Andrew Lunn Signed-off-by: Michael Walle Signed-off-by: Jakub Kicinski --- drivers/net/phy/mdio_bus.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mdio.h | 4 ++++ 2 files changed, 59 insertions(+) (limited to 'include') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 522cbe6a0b23..902e1c88ef58 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -1008,6 +1008,33 @@ int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum) } EXPORT_SYMBOL(mdiobus_c45_read); +/** + * mdiobus_c45_read_nested - Nested version of the mdiobus_c45_read function + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to read + * + * In case of nested MDIO bus access avoid lockdep false positives by + * using mutex_lock_nested(). + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_c45_read_nested(struct mii_bus *bus, int addr, int devad, + u32 regnum) +{ + int retval; + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + retval = __mdiobus_c45_read(bus, addr, devad, regnum); + mutex_unlock(&bus->mdio_lock); + + return retval; +} +EXPORT_SYMBOL(mdiobus_c45_read_nested); + /** * mdiobus_write_nested - Nested version of the mdiobus_write function * @bus: the mii_bus struct @@ -1082,6 +1109,34 @@ int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum, } EXPORT_SYMBOL(mdiobus_c45_write); +/** + * mdiobus_c45_write_nested - Nested version of the mdiobus_c45_write function + * @bus: the mii_bus struct + * @addr: the phy address + * @devad: device address to read + * @regnum: register number to write + * @val: value to write to @regnum + * + * In case of nested MDIO bus access avoid lockdep false positives by + * using mutex_lock_nested(). + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_c45_write_nested(struct mii_bus *bus, int addr, int devad, + u32 regnum, u16 val) +{ + int err; + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + err = __mdiobus_c45_write(bus, addr, devad, regnum, val); + mutex_unlock(&bus->mdio_lock); + + return err; +} +EXPORT_SYMBOL(mdiobus_c45_write_nested); + /** * mdiobus_modify - Convenience function for modifying a given mdio device * register diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 97b49765e8b5..220f3ca8702d 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -425,10 +425,14 @@ int mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum, u16 mask, u16 set); int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum); int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum); +int mdiobus_c45_read_nested(struct mii_bus *bus, int addr, int devad, + u32 regnum); int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum, u16 val); int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum, u16 val); +int mdiobus_c45_write_nested(struct mii_bus *bus, int addr, int devad, + u32 regnum, u16 val); int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum, u16 mask, u16 set); -- cgit v1.2.3 From ca0844a2b9cfdda560c58a0df2d861a86792d658 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 28 Dec 2022 20:52:27 +0200 Subject: dt-bindings: clock: qcom: gcc-sm8350: drop test clock The test clock apparently it's not used by anyone upstream. Remove it. Signed-off-by: Dmitry Baryshkov Reviewed-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20221228185237.3111988-7-dmitry.baryshkov@linaro.org --- include/dt-bindings/clock/qcom,gcc-sm8350.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/dt-bindings/clock/qcom,gcc-sm8350.h b/include/dt-bindings/clock/qcom,gcc-sm8350.h index f6be3da5f781..529c1b8b0417 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm8350.h +++ b/include/dt-bindings/clock/qcom,gcc-sm8350.h @@ -8,7 +8,6 @@ #define _DT_BINDINGS_CLK_QCOM_GCC_SM8350_H /* GCC HW clocks */ -#define CORE_BI_PLL_TEST_SE 0 #define PCIE_0_PIPE_CLK 1 #define PCIE_1_PIPE_CLK 2 #define UFS_CARD_RX_SYMBOL_0_CLK 3 -- cgit v1.2.3 From 477c404428ed3680f0dc1153746cb891381337c1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 28 Dec 2022 20:52:28 +0200 Subject: dt-bindings: clock: qcom: gcc-sm8450: drop test clock The test clock apparently it's not used by anyone upstream. Remove it. Signed-off-by: Dmitry Baryshkov Reviewed-by: Rob Herring Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20221228185237.3111988-8-dmitry.baryshkov@linaro.org --- include/dt-bindings/clock/qcom,gcc-sm8450.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/dt-bindings/clock/qcom,gcc-sm8450.h b/include/dt-bindings/clock/qcom,gcc-sm8450.h index cf1469312c4c..9679410843a0 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm8450.h +++ b/include/dt-bindings/clock/qcom,gcc-sm8450.h @@ -8,7 +8,6 @@ #define _DT_BINDINGS_CLK_QCOM_GCC_SM8450_H /* GCC HW clocks */ -#define CORE_BI_PLL_TEST_SE 0 #define PCIE_0_PIPE_CLK 1 #define PCIE_1_PHY_AUX_CLK 2 #define PCIE_1_PIPE_CLK 3 -- cgit v1.2.3 From e656cd0bcf3d2ba2eceac82b44714bf355428ec4 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 9 Jan 2023 14:05:22 +0100 Subject: soc: qcom: rmtfs: Optionally map RMTFS to more VMs Some SoCs require that RMTFS is also mapped to the NAV VM. Trying to power on the modem without that results in the whole platform crashing and forces a hard reboot within about 2 seconds. Add support for mapping the region to additional VMs, such as NAV to open a path towards enabling modem on such platforms. Signed-off-by: Loic Poulain [Konrad: reword, make conditional and flexible, add a define for NAV VMID] Signed-off-by: Konrad Dybcio Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230109130523.298971-2-konrad.dybcio@linaro.org --- drivers/soc/qcom/rmtfs_mem.c | 29 ++++++++++++++++++++++------- include/linux/qcom_scm.h | 1 + 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index 0feaae357821..9d59ad509a5c 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c @@ -17,6 +17,7 @@ #include #define QCOM_RMTFS_MEM_DEV_MAX (MINORMASK + 1) +#define NUM_MAX_VMIDS 2 static dev_t qcom_rmtfs_mem_major; @@ -171,12 +172,12 @@ static void qcom_rmtfs_mem_release_device(struct device *dev) static int qcom_rmtfs_mem_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; - struct qcom_scm_vmperm perms[2]; + struct qcom_scm_vmperm perms[NUM_MAX_VMIDS + 1]; struct reserved_mem *rmem; struct qcom_rmtfs_mem *rmtfs_mem; u32 client_id; - u32 vmid; - int ret; + u32 num_vmids, vmid[NUM_MAX_VMIDS]; + int ret, i; rmem = of_reserved_mem_lookup(node); if (!rmem) { @@ -226,7 +227,18 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev) goto put_device; } - ret = of_property_read_u32(node, "qcom,vmid", &vmid); + num_vmids = of_property_count_u32_elems(node, "qcom,vmid"); + if (num_vmids < 0) { + dev_err(&pdev->dev, "failed to count qcom,vmid elements: %d\n", ret); + goto remove_cdev; + } else if (num_vmids > NUM_MAX_VMIDS) { + dev_warn(&pdev->dev, + "too many VMIDs (%d) specified! Only mapping first %d entries\n", + num_vmids, NUM_MAX_VMIDS); + num_vmids = NUM_MAX_VMIDS; + } + + ret = of_property_read_u32_array(node, "qcom,vmid", vmid, num_vmids); if (ret < 0 && ret != -EINVAL) { dev_err(&pdev->dev, "failed to parse qcom,vmid\n"); goto remove_cdev; @@ -238,12 +250,15 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev) perms[0].vmid = QCOM_SCM_VMID_HLOS; perms[0].perm = QCOM_SCM_PERM_RW; - perms[1].vmid = vmid; - perms[1].perm = QCOM_SCM_PERM_RW; + + for (i = 0; i < num_vmids; i++) { + perms[i + 1].vmid = vmid[i]; + perms[i + 1].perm = QCOM_SCM_PERM_RW; + } rmtfs_mem->perms = BIT(QCOM_SCM_VMID_HLOS); ret = qcom_scm_assign_mem(rmtfs_mem->addr, rmtfs_mem->size, - &rmtfs_mem->perms, perms, 2); + &rmtfs_mem->perms, perms, num_vmids + 1); if (ret < 0) { dev_err(&pdev->dev, "assign memory failed\n"); goto remove_cdev; diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index f8335644a01a..150b72edb879 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -55,6 +55,7 @@ enum qcom_scm_ice_cipher { #define QCOM_SCM_VMID_MSS_MSA 0xF #define QCOM_SCM_VMID_WLAN 0x18 #define QCOM_SCM_VMID_WLAN_CE 0x19 +#define QCOM_SCM_VMID_NAV 0x2B #define QCOM_SCM_PERM_READ 0x4 #define QCOM_SCM_PERM_WRITE 0x2 #define QCOM_SCM_PERM_EXEC 0x1 -- cgit v1.2.3 From 45ca30eb9dfe622b00ce352cf28ee141d243254b Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Mon, 9 Jan 2023 14:05:23 +0100 Subject: dt-bindings: firmware: qcom: scm: Separate VMIDs from header to bindings The SCM VMIDs represent predefined mappings that come from the irreplaceable and non-omittable firmware that comes with every Qualcomm SoC (unless you steal engineering samples from the factory) and help clarify otherwise totally magic numbers which we are required to pass to the secure world for some parts of the SoC to work at all (with modem being the prime example). On top of that, with changes to the rmtfs binding, secure VMIDs will become useful to have in device trees for readability. Separate them out and add to include/dt-bindings. Signed-off-by: Konrad Dybcio Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230109130523.298971-3-konrad.dybcio@linaro.org --- include/dt-bindings/firmware/qcom,scm.h | 16 ++++++++++++++++ include/linux/qcom_scm.h | 7 ++----- 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 include/dt-bindings/firmware/qcom,scm.h (limited to 'include') diff --git a/include/dt-bindings/firmware/qcom,scm.h b/include/dt-bindings/firmware/qcom,scm.h new file mode 100644 index 000000000000..1a4e68fa0744 --- /dev/null +++ b/include/dt-bindings/firmware/qcom,scm.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ +/* + * Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + */ + +#ifndef _DT_BINDINGS_FIRMWARE_QCOM_SCM_H +#define _DT_BINDINGS_FIRMWARE_QCOM_SCM_H + +#define QCOM_SCM_VMID_HLOS 0x3 +#define QCOM_SCM_VMID_MSS_MSA 0xF +#define QCOM_SCM_VMID_WLAN 0x18 +#define QCOM_SCM_VMID_WLAN_CE 0x19 +#define QCOM_SCM_VMID_NAV 0x2B + +#endif diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 150b72edb879..1e449a5d7f5c 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -9,6 +9,8 @@ #include #include +#include + #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) #define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0 #define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1 @@ -51,11 +53,6 @@ enum qcom_scm_ice_cipher { QCOM_SCM_ICE_CIPHER_AES_256_CBC = 4, }; -#define QCOM_SCM_VMID_HLOS 0x3 -#define QCOM_SCM_VMID_MSS_MSA 0xF -#define QCOM_SCM_VMID_WLAN 0x18 -#define QCOM_SCM_VMID_WLAN_CE 0x19 -#define QCOM_SCM_VMID_NAV 0x2B #define QCOM_SCM_PERM_READ 0x4 #define QCOM_SCM_PERM_WRITE 0x2 #define QCOM_SCM_PERM_EXEC 0x1 -- cgit v1.2.3 From 8d231dbc3b10155727bcfa9e543d397ad357f14f Mon Sep 17 00:00:00 2001 From: Maher Sanalla Date: Mon, 28 Nov 2022 18:00:17 +0200 Subject: net/mlx5: Expose shared buffer registers bits and structs Add the shared receive buffer management and configuration registers: 1. SBPR - Shared Buffer Pools Register 2. SBCM - Shared Buffer Class Management Register Signed-off-by: Maher Sanalla Reviewed-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- include/linux/mlx5/driver.h | 2 ++ include/linux/mlx5/mlx5_ifc.h | 61 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) (limited to 'include') diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index d476255c9a3f..0c4f6acf59ca 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -100,6 +100,8 @@ enum { }; enum { + MLX5_REG_SBPR = 0xb001, + MLX5_REG_SBCM = 0xb002, MLX5_REG_QPTS = 0x4002, MLX5_REG_QETCR = 0x4005, MLX5_REG_QTCT = 0x400a, diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index a9ee7bc59c90..a84bdeeed2c6 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -11000,6 +11000,67 @@ struct mlx5_ifc_pbmc_reg_bits { u8 reserved_at_2e0[0x80]; }; +struct mlx5_ifc_sbpr_reg_bits { + u8 desc[0x1]; + u8 snap[0x1]; + u8 reserved_at_2[0x4]; + u8 dir[0x2]; + u8 reserved_at_8[0x14]; + u8 pool[0x4]; + + u8 infi_size[0x1]; + u8 reserved_at_21[0x7]; + u8 size[0x18]; + + u8 reserved_at_40[0x1c]; + u8 mode[0x4]; + + u8 reserved_at_60[0x8]; + u8 buff_occupancy[0x18]; + + u8 clr[0x1]; + u8 reserved_at_81[0x7]; + u8 max_buff_occupancy[0x18]; + + u8 reserved_at_a0[0x8]; + u8 ext_buff_occupancy[0x18]; +}; + +struct mlx5_ifc_sbcm_reg_bits { + u8 desc[0x1]; + u8 snap[0x1]; + u8 reserved_at_2[0x6]; + u8 local_port[0x8]; + u8 pnat[0x2]; + u8 pg_buff[0x6]; + u8 reserved_at_18[0x6]; + u8 dir[0x2]; + + u8 reserved_at_20[0x1f]; + u8 exc[0x1]; + + u8 reserved_at_40[0x40]; + + u8 reserved_at_80[0x8]; + u8 buff_occupancy[0x18]; + + u8 clr[0x1]; + u8 reserved_at_a1[0x7]; + u8 max_buff_occupancy[0x18]; + + u8 reserved_at_c0[0x8]; + u8 min_buff[0x18]; + + u8 infi_max[0x1]; + u8 reserved_at_e1[0x7]; + u8 max_buff[0x18]; + + u8 reserved_at_100[0x20]; + + u8 reserved_at_120[0x1c]; + u8 pool[0x4]; +}; + struct mlx5_ifc_qtct_reg_bits { u8 reserved_at_0[0x8]; u8 port_number[0x8]; -- cgit v1.2.3 From fe998a3c77b9f989a30a2a01fb00d3729a6d53a4 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Wed, 29 Jun 2022 11:38:21 +0300 Subject: net/mlx5: Enable management PF initialization Enable initialization of DPU Management PF, which is a new loopback PF designed for communication with BMC. For now Management PF doesn't support nor require most upper layer protocols so avoid them. Signed-off-by: Shay Drory Reviewed-by: Eran Ben Elisha Reviewed-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/dev.c | 6 ++++++ drivers/net/ethernet/mellanox/mlx5/core/ecpf.c | 8 ++++++++ drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 2 +- include/linux/mlx5/driver.h | 5 +++++ 4 files changed, 20 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index 0571e40c6ee5..5b6b0b126e52 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -59,6 +59,9 @@ bool mlx5_eth_supported(struct mlx5_core_dev *dev) if (!IS_ENABLED(CONFIG_MLX5_CORE_EN)) return false; + if (mlx5_core_is_management_pf(dev)) + return false; + if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) return false; @@ -198,6 +201,9 @@ bool mlx5_rdma_supported(struct mlx5_core_dev *dev) if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND)) return false; + if (mlx5_core_is_management_pf(dev)) + return false; + if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV) return false; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c index 464eb3a18450..b70e36025d92 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c @@ -75,6 +75,10 @@ int mlx5_ec_init(struct mlx5_core_dev *dev) if (!mlx5_core_is_ecpf(dev)) return 0; + /* Management PF don't have a peer PF */ + if (mlx5_core_is_management_pf(dev)) + return 0; + return mlx5_host_pf_init(dev); } @@ -85,6 +89,10 @@ void mlx5_ec_cleanup(struct mlx5_core_dev *dev) if (!mlx5_core_is_ecpf(dev)) return; + /* Management PF don't have a peer PF */ + if (mlx5_core_is_management_pf(dev)) + return; + mlx5_host_pf_cleanup(dev); err = mlx5_wait_for_pages(dev, &dev->priv.host_pf_pages); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 0dfd5742c6fe..bbb6dab3b21f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1488,7 +1488,7 @@ int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 * void *hca_caps; int err; - if (!mlx5_core_is_ecpf(dev)) { + if (!mlx5_core_is_ecpf(dev) || mlx5_core_is_management_pf(dev)) { *max_sfs = 0; return 0; } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 0c4f6acf59ca..50a5780367fa 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -1202,6 +1202,11 @@ static inline bool mlx5_core_is_vf(const struct mlx5_core_dev *dev) return dev->coredev_type == MLX5_COREDEV_VF; } +static inline bool mlx5_core_is_management_pf(const struct mlx5_core_dev *dev) +{ + return MLX5_CAP_GEN(dev, num_ports) == 1 && !MLX5_CAP_GEN(dev, native_port_num); +} + static inline bool mlx5_core_is_ecpf(const struct mlx5_core_dev *dev) { return dev->caps.embedded_cpu; -- cgit v1.2.3 From 63fbae0a74c3e1df7c20c81e04353ced050d9887 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Tue, 2 Aug 2022 14:47:30 +0300 Subject: net/mlx5: Prevent high-rate FW commands from populating all slots Certain connection-based device-offload protocols (like TLS) use per-connection HW objects to track the state, maintain the context, and perform the offload properly. Some of these objects are created, modified, and destroyed via FW commands. Under high connection rate, this type of FW commands might continuously populate all slots of the FW command interface and throttle it, while starving other critical control FW commands. Limit these throttle commands to using only up to a portion (half) of the FW command interface slots. FW commands maximal rate is not hit, and the same high rate is still reached when applying this limitation. Signed-off-by: Tariq Toukan Reviewed-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 30 ++++++++++++++++++++++++++- include/linux/mlx5/driver.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 541eecfdd598..24da9c5e63e3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -94,6 +94,21 @@ static u16 in_to_opcode(void *in) return MLX5_GET(mbox_in, in, opcode); } +/* Returns true for opcodes that might be triggered very frequently and throttle + * the command interface. Limit their command slots usage. + */ +static bool mlx5_cmd_is_throttle_opcode(u16 op) +{ + switch (op) { + case MLX5_CMD_OP_CREATE_GENERAL_OBJECT: + case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT: + case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT: + case MLX5_CMD_OP_QUERY_GENERAL_OBJECT: + return true; + } + return false; +} + static struct mlx5_cmd_work_ent * cmd_alloc_ent(struct mlx5_cmd *cmd, struct mlx5_cmd_msg *in, struct mlx5_cmd_msg *out, void *uout, int uout_size, @@ -1825,6 +1840,7 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, { struct mlx5_cmd_msg *inb, *outb; u16 opcode = in_to_opcode(in); + bool throttle_op; int pages_queue; gfp_t gfp; u8 token; @@ -1833,13 +1849,21 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, opcode)) return -ENXIO; + throttle_op = mlx5_cmd_is_throttle_opcode(opcode); + if (throttle_op) { + /* atomic context may not sleep */ + if (callback) + return -EINVAL; + down(&dev->cmd.throttle_sem); + } + pages_queue = is_manage_pages(in); gfp = callback ? GFP_ATOMIC : GFP_KERNEL; inb = alloc_msg(dev, in_size, gfp); if (IS_ERR(inb)) { err = PTR_ERR(inb); - return err; + goto out_up; } token = alloc_token(&dev->cmd); @@ -1873,6 +1897,9 @@ out_out: mlx5_free_cmd_msg(dev, outb); out_in: free_msg(dev, inb); +out_up: + if (throttle_op) + up(&dev->cmd.throttle_sem); return err; } @@ -2222,6 +2249,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) sema_init(&cmd->sem, cmd->max_reg_cmds); sema_init(&cmd->pages_sem, 1); + sema_init(&cmd->throttle_sem, DIV_ROUND_UP(cmd->max_reg_cmds, 2)); cmd_h = (u32)((u64)(cmd->dma) >> 32); cmd_l = (u32)(cmd->dma); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 50a5780367fa..7c393da396b1 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -310,6 +310,7 @@ struct mlx5_cmd { struct workqueue_struct *wq; struct semaphore sem; struct semaphore pages_sem; + struct semaphore throttle_sem; int mode; u16 allowed_opcode; struct mlx5_cmd_work_ent *ent_arr[MLX5_MAX_COMMANDS]; -- cgit v1.2.3 From 8580e16c28f3f1a1bee87de115157161577334b4 Mon Sep 17 00:00:00 2001 From: Piergiorgio Beruto Date: Mon, 9 Jan 2023 17:59:39 +0100 Subject: net/ethtool: add netlink interface for the PLCA RS Add support for configuring the PLCA Reconciliation Sublayer on multi-drop PHYs that support IEEE802.3cg-2019 Clause 148 (e.g., 10BASE-T1S). This patch adds the appropriate netlink interface to ethtool. Signed-off-by: Piergiorgio Beruto Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- Documentation/networking/ethtool-netlink.rst | 138 +++++++++++++ MAINTAINERS | 6 + include/linux/ethtool.h | 12 ++ include/linux/phy.h | 57 ++++++ include/uapi/linux/ethtool_netlink.h | 25 +++ net/ethtool/Makefile | 2 +- net/ethtool/netlink.c | 29 +++ net/ethtool/netlink.h | 6 + net/ethtool/plca.c | 277 +++++++++++++++++++++++++++ 9 files changed, 551 insertions(+), 1 deletion(-) create mode 100644 net/ethtool/plca.c (limited to 'include') diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index f10f8eb44255..c59b542eb693 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -1716,6 +1716,141 @@ being used. Current supported options are toeplitz, xor or crc32. ETHTOOL_A_RSS_INDIR attribute returns RSS indrection table where each byte indicates queue number. +PLCA_GET_CFG +============ + +Gets the IEEE 802.3cg-2019 Clause 148 Physical Layer Collision Avoidance +(PLCA) Reconciliation Sublayer (RS) attributes. + +Request contents: + + ===================================== ====== ========================== + ``ETHTOOL_A_PLCA_HEADER`` nested request header + ===================================== ====== ========================== + +Kernel response contents: + + ====================================== ====== ============================= + ``ETHTOOL_A_PLCA_HEADER`` nested reply header + ``ETHTOOL_A_PLCA_VERSION`` u16 Supported PLCA management + interface standard/version + ``ETHTOOL_A_PLCA_ENABLED`` u8 PLCA Admin State + ``ETHTOOL_A_PLCA_NODE_ID`` u32 PLCA unique local node ID + ``ETHTOOL_A_PLCA_NODE_CNT`` u32 Number of PLCA nodes on the + network, including the + coordinator + ``ETHTOOL_A_PLCA_TO_TMR`` u32 Transmit Opportunity Timer + value in bit-times (BT) + ``ETHTOOL_A_PLCA_BURST_CNT`` u32 Number of additional packets + the node is allowed to send + within a single TO + ``ETHTOOL_A_PLCA_BURST_TMR`` u32 Time to wait for the MAC to + transmit a new frame before + terminating the burst + ====================================== ====== ============================= + +When set, the optional ``ETHTOOL_A_PLCA_VERSION`` attribute indicates which +standard and version the PLCA management interface complies to. When not set, +the interface is vendor-specific and (possibly) supplied by the driver. +The OPEN Alliance SIG specifies a standard register map for 10BASE-T1S PHYs +embedding the PLCA Reconcialiation Sublayer. See "10BASE-T1S PLCA Management +Registers" at https://www.opensig.org/about/specifications/. + +When set, the optional ``ETHTOOL_A_PLCA_ENABLED`` attribute indicates the +administrative state of the PLCA RS. When not set, the node operates in "plain" +CSMA/CD mode. This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.1 +aPLCAAdminState / 30.16.1.2.1 acPLCAAdminControl. + +When set, the optional ``ETHTOOL_A_PLCA_NODE_ID`` attribute indicates the +configured local node ID of the PHY. This ID determines which transmit +opportunity (TO) is reserved for the node to transmit into. This option is +corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.4 aPLCALocalNodeID. The valid +range for this attribute is [0 .. 255] where 255 means "not configured". + +When set, the optional ``ETHTOOL_A_PLCA_NODE_CNT`` attribute indicates the +configured maximum number of PLCA nodes on the mixing-segment. This number +determines the total number of transmit opportunities generated during a +PLCA cycle. This attribute is relevant only for the PLCA coordinator, which is +the node with aPLCALocalNodeID set to 0. Follower nodes ignore this setting. +This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.3 +aPLCANodeCount. The valid range for this attribute is [1 .. 255]. + +When set, the optional ``ETHTOOL_A_PLCA_TO_TMR`` attribute indicates the +configured value of the transmit opportunity timer in bit-times. This value +must be set equal across all nodes sharing the medium for PLCA to work +correctly. This option is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.5 +aPLCATransmitOpportunityTimer. The valid range for this attribute is +[0 .. 255]. + +When set, the optional ``ETHTOOL_A_PLCA_BURST_CNT`` attribute indicates the +configured number of extra packets that the node is allowed to send during a +single transmit opportunity. By default, this attribute is 0, meaning that +the node can only send a sigle frame per TO. When greater than 0, the PLCA RS +keeps the TO after any transmission, waiting for the MAC to send a new frame +for up to aPLCABurstTimer BTs. This can only happen a number of times per PLCA +cycle up to the value of this parameter. After that, the burst is over and the +normal counting of TOs resumes. This option is corresponding to +``IEEE 802.3cg-2019`` 30.16.1.1.6 aPLCAMaxBurstCount. The valid range for this +attribute is [0 .. 255]. + +When set, the optional ``ETHTOOL_A_PLCA_BURST_TMR`` attribute indicates how +many bit-times the PLCA RS waits for the MAC to initiate a new transmission +when aPLCAMaxBurstCount is greater than 0. If the MAC fails to send a new +frame within this time, the burst ends and the counting of TOs resumes. +Otherwise, the new frame is sent as part of the current burst. This option +is corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.7 aPLCABurstTimer. The +valid range for this attribute is [0 .. 255]. Although, the value should be +set greater than the Inter-Frame-Gap (IFG) time of the MAC (plus some margin) +for PLCA burst mode to work as intended. + +PLCA_SET_CFG +============ + +Sets PLCA RS parameters. + +Request contents: + + ====================================== ====== ============================= + ``ETHTOOL_A_PLCA_HEADER`` nested request header + ``ETHTOOL_A_PLCA_ENABLED`` u8 PLCA Admin State + ``ETHTOOL_A_PLCA_NODE_ID`` u8 PLCA unique local node ID + ``ETHTOOL_A_PLCA_NODE_CNT`` u8 Number of PLCA nodes on the + netkork, including the + coordinator + ``ETHTOOL_A_PLCA_TO_TMR`` u8 Transmit Opportunity Timer + value in bit-times (BT) + ``ETHTOOL_A_PLCA_BURST_CNT`` u8 Number of additional packets + the node is allowed to send + within a single TO + ``ETHTOOL_A_PLCA_BURST_TMR`` u8 Time to wait for the MAC to + transmit a new frame before + terminating the burst + ====================================== ====== ============================= + +For a description of each attribute, see ``PLCA_GET_CFG``. + +PLCA_GET_STATUS +=============== + +Gets PLCA RS status information. + +Request contents: + + ===================================== ====== ========================== + ``ETHTOOL_A_PLCA_HEADER`` nested request header + ===================================== ====== ========================== + +Kernel response contents: + + ====================================== ====== ============================= + ``ETHTOOL_A_PLCA_HEADER`` nested reply header + ``ETHTOOL_A_PLCA_STATUS`` u8 PLCA RS operational status + ====================================== ====== ============================= + +When set, the ``ETHTOOL_A_PLCA_STATUS`` attribute indicates whether the node is +detecting the presence of the BEACON on the network. This flag is +corresponding to ``IEEE 802.3cg-2019`` 30.16.1.1.2 aPLCAStatus. + Request translation =================== @@ -1817,4 +1952,7 @@ are netlink only. n/a ``ETHTOOL_MSG_PHC_VCLOCKS_GET`` n/a ``ETHTOOL_MSG_MODULE_GET`` n/a ``ETHTOOL_MSG_MODULE_SET`` + n/a ``ETHTOOL_MSG_PLCA_GET_CFG`` + n/a ``ETHTOOL_MSG_PLCA_SET_CFG`` + n/a ``ETHTOOL_MSG_PLCA_GET_STATUS`` =================================== ===================================== diff --git a/MAINTAINERS b/MAINTAINERS index 0f61b5d64716..7b6e602b90d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16616,6 +16616,12 @@ S: Maintained F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml F: drivers/iio/chemical/pms7003.c +PLCA RECONCILIATION SUBLAYER (IEEE802.3 Clause 148) +M: Piergiorgio Beruto +L: netdev@vger.kernel.org +S: Maintained +F: net/ethtool/plca.c + PLDMFW LIBRARY M: Jacob Keller S: Maintained diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 9e0a76fc7de9..d0da303f6634 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -802,12 +802,17 @@ int ethtool_virtdev_set_link_ksettings(struct net_device *dev, struct phy_device; struct phy_tdr_config; +struct phy_plca_cfg; +struct phy_plca_status; /** * struct ethtool_phy_ops - Optional PHY device options * @get_sset_count: Get number of strings that @get_strings will write. * @get_strings: Return a set of strings that describe the requested objects * @get_stats: Return extended statistics about the PHY device. + * @get_plca_cfg: Return PLCA configuration. + * @set_plca_cfg: Set PLCA configuration. + * @get_plca_status: Get PLCA configuration. * @start_cable_test: Start a cable test * @start_cable_test_tdr: Start a Time Domain Reflectometry cable test * @@ -819,6 +824,13 @@ struct ethtool_phy_ops { int (*get_strings)(struct phy_device *dev, u8 *data); int (*get_stats)(struct phy_device *dev, struct ethtool_stats *stats, u64 *data); + int (*get_plca_cfg)(struct phy_device *dev, + struct phy_plca_cfg *plca_cfg); + int (*set_plca_cfg)(struct phy_device *dev, + const struct phy_plca_cfg *plca_cfg, + struct netlink_ext_ack *extack); + int (*get_plca_status)(struct phy_device *dev, + struct phy_plca_status *plca_st); int (*start_cable_test)(struct phy_device *phydev, struct netlink_ext_ack *extack); int (*start_cable_test_tdr)(struct phy_device *phydev, diff --git a/include/linux/phy.h b/include/linux/phy.h index 89b43cda5bda..b82fdb0d82ed 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -773,6 +773,63 @@ struct phy_tdr_config { }; #define PHY_PAIR_ALL -1 +/** + * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision + * Avoidance) Reconciliation Sublayer. + * + * @version: read-only PLCA register map version. -1 = not available. Ignored + * when setting the configuration. Format is the same as reported by the PLCA + * IDVER register (31.CA00). -1 = not available. + * @enabled: PLCA configured mode (enabled/disabled). -1 = not available / don't + * set. 0 = disabled, anything else = enabled. + * @node_id: the PLCA local node identifier. -1 = not available / don't set. + * Allowed values [0 .. 254]. 255 = node disabled. + * @node_cnt: the PLCA node count (maximum number of nodes having a TO). Only + * meaningful for the coordinator (node_id = 0). -1 = not available / don't + * set. Allowed values [1 .. 255]. + * @to_tmr: The value of the PLCA to_timer in bit-times, which determines the + * PLCA transmit opportunity window opening. See IEEE802.3 Clause 148 for + * more details. The to_timer shall be set equal over all nodes. + * -1 = not available / don't set. Allowed values [0 .. 255]. + * @burst_cnt: controls how many additional frames a node is allowed to send in + * single transmit opportunity (TO). The default value of 0 means that the + * node is allowed exactly one frame per TO. A value of 1 allows two frames + * per TO, and so on. -1 = not available / don't set. + * Allowed values [0 .. 255]. + * @burst_tmr: controls how many bit times to wait for the MAC to send a new + * frame before interrupting the burst. This value should be set to a value + * greater than the MAC inter-packet gap (which is typically 96 bits). + * -1 = not available / don't set. Allowed values [0 .. 255]. + * + * A structure containing configuration parameters for setting/getting the PLCA + * RS configuration. The driver does not need to implement all the parameters, + * but should report what is actually used. + */ +struct phy_plca_cfg { + int version; + int enabled; + int node_id; + int node_cnt; + int to_tmr; + int burst_cnt; + int burst_tmr; +}; + +/** + * struct phy_plca_status - Status of the PLCA (Physical Layer Collision + * Avoidance) Reconciliation Sublayer. + * + * @pst: The PLCA status as reported by the PST bit in the PLCA STATUS + * register(31.CA03), indicating BEACON activity. + * + * A structure containing status information of the PLCA RS configuration. + * The driver does not need to implement all the parameters, but should report + * what is actually used. + */ +struct phy_plca_status { + bool pst; +}; + /** * struct phy_driver - Driver structure for a particular PHY type * diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index 5799a9db034e..75b3d6d476ff 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -52,6 +52,9 @@ enum { ETHTOOL_MSG_PSE_GET, ETHTOOL_MSG_PSE_SET, ETHTOOL_MSG_RSS_GET, + ETHTOOL_MSG_PLCA_GET_CFG, + ETHTOOL_MSG_PLCA_SET_CFG, + ETHTOOL_MSG_PLCA_GET_STATUS, /* add new constants above here */ __ETHTOOL_MSG_USER_CNT, @@ -99,6 +102,9 @@ enum { ETHTOOL_MSG_MODULE_NTF, ETHTOOL_MSG_PSE_GET_REPLY, ETHTOOL_MSG_RSS_GET_REPLY, + ETHTOOL_MSG_PLCA_GET_CFG_REPLY, + ETHTOOL_MSG_PLCA_GET_STATUS_REPLY, + ETHTOOL_MSG_PLCA_NTF, /* add new constants above here */ __ETHTOOL_MSG_KERNEL_CNT, @@ -894,6 +900,25 @@ enum { ETHTOOL_A_RSS_MAX = (__ETHTOOL_A_RSS_CNT - 1), }; +/* PLCA */ + +enum { + ETHTOOL_A_PLCA_UNSPEC, + ETHTOOL_A_PLCA_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_PLCA_VERSION, /* u16 */ + ETHTOOL_A_PLCA_ENABLED, /* u8 */ + ETHTOOL_A_PLCA_STATUS, /* u8 */ + ETHTOOL_A_PLCA_NODE_CNT, /* u32 */ + ETHTOOL_A_PLCA_NODE_ID, /* u32 */ + ETHTOOL_A_PLCA_TO_TMR, /* u32 */ + ETHTOOL_A_PLCA_BURST_CNT, /* u32 */ + ETHTOOL_A_PLCA_BURST_TMR, /* u32 */ + + /* add new constants above here */ + __ETHTOOL_A_PLCA_CNT, + ETHTOOL_A_PLCA_MAX = (__ETHTOOL_A_PLCA_CNT - 1) +}; + /* generic netlink info */ #define ETHTOOL_GENL_NAME "ethtool" #define ETHTOOL_GENL_VERSION 1 diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile index 228f13df2e18..563864c1bf5a 100644 --- a/net/ethtool/Makefile +++ b/net/ethtool/Makefile @@ -8,4 +8,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \ linkstate.o debug.o wol.o features.o privflags.o rings.o \ channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ tunnels.o fec.o eeprom.o stats.o phc_vclocks.o module.o \ - pse-pd.o + pse-pd.o plca.o diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index aee98be6237f..9f924875bba9 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -288,6 +288,8 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { [ETHTOOL_MSG_MODULE_GET] = ðnl_module_request_ops, [ETHTOOL_MSG_PSE_GET] = ðnl_pse_request_ops, [ETHTOOL_MSG_RSS_GET] = ðnl_rss_request_ops, + [ETHTOOL_MSG_PLCA_GET_CFG] = ðnl_plca_cfg_request_ops, + [ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops, }; static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) @@ -603,6 +605,7 @@ ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = { [ETHTOOL_MSG_EEE_NTF] = ðnl_eee_request_ops, [ETHTOOL_MSG_FEC_NTF] = ðnl_fec_request_ops, [ETHTOOL_MSG_MODULE_NTF] = ðnl_module_request_ops, + [ETHTOOL_MSG_PLCA_NTF] = ðnl_plca_cfg_request_ops, }; /* default notification handler */ @@ -696,6 +699,7 @@ static const ethnl_notify_handler_t ethnl_notify_handlers[] = { [ETHTOOL_MSG_EEE_NTF] = ethnl_default_notify, [ETHTOOL_MSG_FEC_NTF] = ethnl_default_notify, [ETHTOOL_MSG_MODULE_NTF] = ethnl_default_notify, + [ETHTOOL_MSG_PLCA_NTF] = ethnl_default_notify, }; void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data) @@ -1047,6 +1051,31 @@ static const struct genl_ops ethtool_genl_ops[] = { .policy = ethnl_rss_get_policy, .maxattr = ARRAY_SIZE(ethnl_rss_get_policy) - 1, }, + { + .cmd = ETHTOOL_MSG_PLCA_GET_CFG, + .doit = ethnl_default_doit, + .start = ethnl_default_start, + .dumpit = ethnl_default_dumpit, + .done = ethnl_default_done, + .policy = ethnl_plca_get_cfg_policy, + .maxattr = ARRAY_SIZE(ethnl_plca_get_cfg_policy) - 1, + }, + { + .cmd = ETHTOOL_MSG_PLCA_SET_CFG, + .flags = GENL_UNS_ADMIN_PERM, + .doit = ethnl_set_plca_cfg, + .policy = ethnl_plca_set_cfg_policy, + .maxattr = ARRAY_SIZE(ethnl_plca_set_cfg_policy) - 1, + }, + { + .cmd = ETHTOOL_MSG_PLCA_GET_STATUS, + .doit = ethnl_default_doit, + .start = ethnl_default_start, + .dumpit = ethnl_default_dumpit, + .done = ethnl_default_done, + .policy = ethnl_plca_get_status_policy, + .maxattr = ARRAY_SIZE(ethnl_plca_get_status_policy) - 1, + }, }; static const struct genl_multicast_group ethtool_nl_mcgrps[] = { diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index 3753787ba233..f271266f6e28 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -347,6 +347,8 @@ extern const struct ethnl_request_ops ethnl_phc_vclocks_request_ops; extern const struct ethnl_request_ops ethnl_module_request_ops; extern const struct ethnl_request_ops ethnl_pse_request_ops; extern const struct ethnl_request_ops ethnl_rss_request_ops; +extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; +extern const struct ethnl_request_ops ethnl_plca_status_request_ops; extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; @@ -388,6 +390,9 @@ extern const struct nla_policy ethnl_module_set_policy[ETHTOOL_A_MODULE_POWER_MO extern const struct nla_policy ethnl_pse_get_policy[ETHTOOL_A_PSE_HEADER + 1]; extern const struct nla_policy ethnl_pse_set_policy[ETHTOOL_A_PSE_MAX + 1]; extern const struct nla_policy ethnl_rss_get_policy[ETHTOOL_A_RSS_CONTEXT + 1]; +extern const struct nla_policy ethnl_plca_get_cfg_policy[ETHTOOL_A_PLCA_HEADER + 1]; +extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1]; +extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1]; int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); @@ -408,6 +413,7 @@ int ethnl_tunnel_info_dumpit(struct sk_buff *skb, struct netlink_callback *cb); int ethnl_set_fec(struct sk_buff *skb, struct genl_info *info); int ethnl_set_module(struct sk_buff *skb, struct genl_info *info); int ethnl_set_pse(struct sk_buff *skb, struct genl_info *info); +int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info); extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN]; extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN]; diff --git a/net/ethtool/plca.c b/net/ethtool/plca.c new file mode 100644 index 000000000000..d9bb13ffc654 --- /dev/null +++ b/net/ethtool/plca.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +#include "netlink.h" +#include "common.h" + +struct plca_req_info { + struct ethnl_req_info base; +}; + +struct plca_reply_data { + struct ethnl_reply_data base; + struct phy_plca_cfg plca_cfg; + struct phy_plca_status plca_st; +}; + +// Helpers ------------------------------------------------------------------ // + +#define PLCA_REPDATA(__reply_base) \ + container_of(__reply_base, struct plca_reply_data, base) + +static void plca_update_sint(int *dst, const struct nlattr *attr, + bool *mod) +{ + if (!attr) + return; + + *dst = nla_get_u32(attr); + *mod = true; +} + +// PLCA get configuration message ------------------------------------------- // + +const struct nla_policy ethnl_plca_get_cfg_policy[] = { + [ETHTOOL_A_PLCA_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), +}; + +static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base, + struct ethnl_reply_data *reply_base, + struct genl_info *info) +{ + struct plca_reply_data *data = PLCA_REPDATA(reply_base); + struct net_device *dev = reply_base->dev; + const struct ethtool_phy_ops *ops; + int ret; + + // check that the PHY device is available and connected + if (!dev->phydev) { + ret = -EOPNOTSUPP; + goto out; + } + + // note: rtnl_lock is held already by ethnl_default_doit + ops = ethtool_phy_ops; + if (!ops || !ops->get_plca_cfg) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = ethnl_ops_begin(dev); + if (!ret) + goto out; + + memset(&data->plca_cfg, 0xff, + sizeof_field(struct plca_reply_data, plca_cfg)); + + ret = ops->get_plca_cfg(dev->phydev, &data->plca_cfg); + ethnl_ops_complete(dev); + +out: + return ret; +} + +static int plca_get_cfg_reply_size(const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + return nla_total_size(sizeof(u16)) + /* _VERSION */ + nla_total_size(sizeof(u8)) + /* _ENABLED */ + nla_total_size(sizeof(u32)) + /* _NODE_CNT */ + nla_total_size(sizeof(u32)) + /* _NODE_ID */ + nla_total_size(sizeof(u32)) + /* _TO_TIMER */ + nla_total_size(sizeof(u32)) + /* _BURST_COUNT */ + nla_total_size(sizeof(u32)); /* _BURST_TIMER */ +} + +static int plca_get_cfg_fill_reply(struct sk_buff *skb, + const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + const struct plca_reply_data *data = PLCA_REPDATA(reply_base); + const struct phy_plca_cfg *plca = &data->plca_cfg; + + if ((plca->version >= 0 && + nla_put_u16(skb, ETHTOOL_A_PLCA_VERSION, plca->version)) || + (plca->enabled >= 0 && + nla_put_u8(skb, ETHTOOL_A_PLCA_ENABLED, !!plca->enabled)) || + (plca->node_id >= 0 && + nla_put_u32(skb, ETHTOOL_A_PLCA_NODE_ID, plca->node_id)) || + (plca->node_cnt >= 0 && + nla_put_u32(skb, ETHTOOL_A_PLCA_NODE_CNT, plca->node_cnt)) || + (plca->to_tmr >= 0 && + nla_put_u32(skb, ETHTOOL_A_PLCA_TO_TMR, plca->to_tmr)) || + (plca->burst_cnt >= 0 && + nla_put_u32(skb, ETHTOOL_A_PLCA_BURST_CNT, plca->burst_cnt)) || + (plca->burst_tmr >= 0 && + nla_put_u32(skb, ETHTOOL_A_PLCA_BURST_TMR, plca->burst_tmr))) + return -EMSGSIZE; + + return 0; +}; + +const struct ethnl_request_ops ethnl_plca_cfg_request_ops = { + .request_cmd = ETHTOOL_MSG_PLCA_GET_CFG, + .reply_cmd = ETHTOOL_MSG_PLCA_GET_CFG_REPLY, + .hdr_attr = ETHTOOL_A_PLCA_HEADER, + .req_info_size = sizeof(struct plca_req_info), + .reply_data_size = sizeof(struct plca_reply_data), + + .prepare_data = plca_get_cfg_prepare_data, + .reply_size = plca_get_cfg_reply_size, + .fill_reply = plca_get_cfg_fill_reply, +}; + +// PLCA set configuration message ------------------------------------------- // + +const struct nla_policy ethnl_plca_set_cfg_policy[] = { + [ETHTOOL_A_PLCA_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), + [ETHTOOL_A_PLCA_ENABLED] = NLA_POLICY_MAX(NLA_U8, 1), + [ETHTOOL_A_PLCA_NODE_ID] = NLA_POLICY_MAX(NLA_U32, 255), + [ETHTOOL_A_PLCA_NODE_CNT] = NLA_POLICY_RANGE(NLA_U32, 1, 255), + [ETHTOOL_A_PLCA_TO_TMR] = NLA_POLICY_MAX(NLA_U32, 255), + [ETHTOOL_A_PLCA_BURST_CNT] = NLA_POLICY_MAX(NLA_U32, 255), + [ETHTOOL_A_PLCA_BURST_TMR] = NLA_POLICY_MAX(NLA_U32, 255), +}; + +int ethnl_set_plca_cfg(struct sk_buff *skb, struct genl_info *info) +{ + struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; + const struct ethtool_phy_ops *ops; + struct phy_plca_cfg plca_cfg; + struct net_device *dev; + bool mod = false; + int ret; + + ret = ethnl_parse_header_dev_get(&req_info, + tb[ETHTOOL_A_PLCA_HEADER], + genl_info_net(info), info->extack, + true); + if (!ret) + return ret; + + dev = req_info.dev; + + rtnl_lock(); + + // check that the PHY device is available and connected + if (!dev->phydev) { + ret = -EOPNOTSUPP; + goto out_rtnl; + } + + ops = ethtool_phy_ops; + if (!ops || !ops->set_plca_cfg) { + ret = -EOPNOTSUPP; + goto out_rtnl; + } + + ret = ethnl_ops_begin(dev); + if (!ret) + goto out_rtnl; + + memset(&plca_cfg, 0xff, sizeof(plca_cfg)); + plca_update_sint(&plca_cfg.enabled, tb[ETHTOOL_A_PLCA_ENABLED], &mod); + plca_update_sint(&plca_cfg.node_id, tb[ETHTOOL_A_PLCA_NODE_ID], &mod); + plca_update_sint(&plca_cfg.node_cnt, tb[ETHTOOL_A_PLCA_NODE_CNT], &mod); + plca_update_sint(&plca_cfg.to_tmr, tb[ETHTOOL_A_PLCA_TO_TMR], &mod); + plca_update_sint(&plca_cfg.burst_cnt, tb[ETHTOOL_A_PLCA_BURST_CNT], + &mod); + plca_update_sint(&plca_cfg.burst_tmr, tb[ETHTOOL_A_PLCA_BURST_TMR], + &mod); + + ret = 0; + if (!mod) + goto out_ops; + + ret = ops->set_plca_cfg(dev->phydev, &plca_cfg, info->extack); + if (!ret) + goto out_ops; + + ethtool_notify(dev, ETHTOOL_MSG_PLCA_NTF, NULL); + +out_ops: + ethnl_ops_complete(dev); +out_rtnl: + rtnl_unlock(); + ethnl_parse_header_dev_put(&req_info); + + return ret; +} + +// PLCA get status message -------------------------------------------------- // + +const struct nla_policy ethnl_plca_get_status_policy[] = { + [ETHTOOL_A_PLCA_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), +}; + +static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base, + struct ethnl_reply_data *reply_base, + struct genl_info *info) +{ + struct plca_reply_data *data = PLCA_REPDATA(reply_base); + struct net_device *dev = reply_base->dev; + const struct ethtool_phy_ops *ops; + int ret; + + // check that the PHY device is available and connected + if (!dev->phydev) { + ret = -EOPNOTSUPP; + goto out; + } + + // note: rtnl_lock is held already by ethnl_default_doit + ops = ethtool_phy_ops; + if (!ops || !ops->get_plca_status) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = ethnl_ops_begin(dev); + if (!ret) + goto out; + + memset(&data->plca_st, 0xff, + sizeof_field(struct plca_reply_data, plca_st)); + + ret = ops->get_plca_status(dev->phydev, &data->plca_st); + ethnl_ops_complete(dev); +out: + return ret; +} + +static int plca_get_status_reply_size(const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + return nla_total_size(sizeof(u8)); /* _STATUS */ +} + +static int plca_get_status_fill_reply(struct sk_buff *skb, + const struct ethnl_req_info *req_base, + const struct ethnl_reply_data *reply_base) +{ + const struct plca_reply_data *data = PLCA_REPDATA(reply_base); + const u8 status = data->plca_st.pst; + + if (nla_put_u8(skb, ETHTOOL_A_PLCA_STATUS, !!status)) + return -EMSGSIZE; + + return 0; +}; + +const struct ethnl_request_ops ethnl_plca_status_request_ops = { + .request_cmd = ETHTOOL_MSG_PLCA_GET_STATUS, + .reply_cmd = ETHTOOL_MSG_PLCA_GET_STATUS_REPLY, + .hdr_attr = ETHTOOL_A_PLCA_HEADER, + .req_info_size = sizeof(struct plca_req_info), + .reply_data_size = sizeof(struct plca_reply_data), + + .prepare_data = plca_get_status_prepare_data, + .reply_size = plca_get_status_reply_size, + .fill_reply = plca_get_status_fill_reply, +}; -- cgit v1.2.3 From 16178c8ef53dc9734302c4c07633696454579ee3 Mon Sep 17 00:00:00 2001 From: Piergiorgio Beruto Date: Mon, 9 Jan 2023 17:59:58 +0100 Subject: drivers/net/phy: add the link modes for the 10BASE-T1S Ethernet PHY This patch adds the link modes for the IEEE 802.3cg Clause 147 10BASE-T1S Ethernet PHY. According to the specifications, the 10BASE-T1S supports Point-To-Point Full-Duplex, Point-To-Point Half-Duplex and/or Point-To-Multipoint (AKA Multi-Drop) Half-Duplex operations. Signed-off-by: Piergiorgio Beruto Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy-core.c | 5 ++++- drivers/net/phy/phy_device.c | 14 ++++++++++++++ drivers/net/phy/phylink.c | 6 +++++- include/linux/phy.h | 14 ++++++++++++++ include/uapi/linux/ethtool.h | 3 +++ net/ethtool/common.c | 8 ++++++++ 6 files changed, 48 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 5d08c627a516..a64186dc53f8 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -13,7 +13,7 @@ */ const char *phy_speed_to_str(int speed) { - BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 99, + BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 102, "Enum ethtool_link_mode_bit_indices and phylib are out of sync. " "If a speed or mode has been added please update phy_speed_to_str " "and the PHY settings array.\n"); @@ -260,6 +260,9 @@ static const struct phy_setting settings[] = { PHY_SETTING( 10, FULL, 10baseT_Full ), PHY_SETTING( 10, HALF, 10baseT_Half ), PHY_SETTING( 10, FULL, 10baseT1L_Full ), + PHY_SETTING( 10, FULL, 10baseT1S_Full ), + PHY_SETTING( 10, HALF, 10baseT1S_Half ), + PHY_SETTING( 10, HALF, 10baseT1S_P2MP_Half ), }; #undef PHY_SETTING diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index e4562859ac00..1cde41d39196 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -45,6 +45,9 @@ EXPORT_SYMBOL_GPL(phy_basic_features); __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init; EXPORT_SYMBOL_GPL(phy_basic_t1_features); +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1s_p2mp_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_basic_t1s_p2mp_features); + __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init; EXPORT_SYMBOL_GPL(phy_gbit_features); @@ -98,6 +101,12 @@ const int phy_basic_t1_features_array[3] = { }; EXPORT_SYMBOL_GPL(phy_basic_t1_features_array); +const int phy_basic_t1s_p2mp_features_array[2] = { + ETHTOOL_LINK_MODE_TP_BIT, + ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT, +}; +EXPORT_SYMBOL_GPL(phy_basic_t1s_p2mp_features_array); + const int phy_gbit_features_array[2] = { ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT, @@ -138,6 +147,11 @@ static void features_init(void) ARRAY_SIZE(phy_basic_t1_features_array), phy_basic_t1_features); + /* 10 half, P2MP, TP */ + linkmode_set_bit_array(phy_basic_t1s_p2mp_features_array, + ARRAY_SIZE(phy_basic_t1s_p2mp_features_array), + phy_basic_t1s_p2mp_features); + /* 10/100 half/full + 1000 half/full */ linkmode_set_bit_array(phy_basic_ports_array, ARRAY_SIZE(phy_basic_ports_array), diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 09cc65c0da93..319790221d7f 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -241,12 +241,16 @@ void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps) if (caps & MAC_ASYM_PAUSE) __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes); - if (caps & MAC_10HD) + if (caps & MAC_10HD) { __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, linkmodes); + __set_bit(ETHTOOL_LINK_MODE_10baseT1S_Half_BIT, linkmodes); + __set_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT, linkmodes); + } if (caps & MAC_10FD) { __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, linkmodes); __set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, linkmodes); + __set_bit(ETHTOOL_LINK_MODE_10baseT1S_Full_BIT, linkmodes); } if (caps & MAC_100HD) { diff --git a/include/linux/phy.h b/include/linux/phy.h index b82fdb0d82ed..63b199f574f7 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -45,6 +45,7 @@ extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_basic_t1s_p2mp_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) __ro_after_init; @@ -54,6 +55,7 @@ extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_ini #define PHY_BASIC_FEATURES ((unsigned long *)&phy_basic_features) #define PHY_BASIC_T1_FEATURES ((unsigned long *)&phy_basic_t1_features) +#define PHY_BASIC_T1S_P2MP_FEATURES ((unsigned long *)&phy_basic_t1s_p2mp_features) #define PHY_GBIT_FEATURES ((unsigned long *)&phy_gbit_features) #define PHY_GBIT_FIBRE_FEATURES ((unsigned long *)&phy_gbit_fibre_features) #define PHY_GBIT_ALL_PORTS_FEATURES ((unsigned long *)&phy_gbit_all_ports_features) @@ -66,6 +68,7 @@ extern const int phy_fibre_port_array[1]; extern const int phy_all_ports_features_array[7]; extern const int phy_10_100_features_array[4]; extern const int phy_basic_t1_features_array[3]; +extern const int phy_basic_t1s_p2mp_features_array[2]; extern const int phy_gbit_features_array[2]; extern const int phy_10gbit_features_array[1]; @@ -1041,6 +1044,17 @@ struct phy_driver { int (*get_sqi)(struct phy_device *dev); /** @get_sqi_max: Get the maximum signal quality indication */ int (*get_sqi_max)(struct phy_device *dev); + + /* PLCA RS interface */ + /** @get_plca_cfg: Return the current PLCA configuration */ + int (*get_plca_cfg)(struct phy_device *dev, + struct phy_plca_cfg *plca_cfg); + /** @set_plca_cfg: Set the PLCA configuration */ + int (*set_plca_cfg)(struct phy_device *dev, + const struct phy_plca_cfg *plca_cfg); + /** @get_plca_status: Return the current PLCA status info */ + int (*get_plca_status)(struct phy_device *dev, + struct phy_plca_status *plca_st); }; #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \ struct phy_driver, mdiodrv) diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 3135fa0ba9a4..6389953c32cf 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1741,6 +1741,9 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT = 96, ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT = 97, ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT = 98, + ETHTOOL_LINK_MODE_10baseT1S_Full_BIT = 99, + ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100, + ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101, /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS diff --git a/net/ethtool/common.c b/net/ethtool/common.c index 6f399afc2ff2..5fb19050991e 100644 --- a/net/ethtool/common.c +++ b/net/ethtool/common.c @@ -208,6 +208,9 @@ const char link_mode_names[][ETH_GSTRING_LEN] = { __DEFINE_LINK_MODE_NAME(800000, DR8_2, Full), __DEFINE_LINK_MODE_NAME(800000, SR8, Full), __DEFINE_LINK_MODE_NAME(800000, VR8, Full), + __DEFINE_LINK_MODE_NAME(10, T1S, Full), + __DEFINE_LINK_MODE_NAME(10, T1S, Half), + __DEFINE_LINK_MODE_NAME(10, T1S_P2MP, Half), }; static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS); @@ -244,6 +247,8 @@ static_assert(ARRAY_SIZE(link_mode_names) == __ETHTOOL_LINK_MODE_MASK_NBITS); #define __LINK_MODE_LANES_X 1 #define __LINK_MODE_LANES_FX 1 #define __LINK_MODE_LANES_T1L 1 +#define __LINK_MODE_LANES_T1S 1 +#define __LINK_MODE_LANES_T1S_P2MP 1 #define __LINK_MODE_LANES_VR8 8 #define __LINK_MODE_LANES_DR8_2 8 @@ -366,6 +371,9 @@ const struct link_mode_info link_mode_params[] = { __DEFINE_LINK_MODE_PARAMS(800000, DR8_2, Full), __DEFINE_LINK_MODE_PARAMS(800000, SR8, Full), __DEFINE_LINK_MODE_PARAMS(800000, VR8, Full), + __DEFINE_LINK_MODE_PARAMS(10, T1S, Full), + __DEFINE_LINK_MODE_PARAMS(10, T1S, Half), + __DEFINE_LINK_MODE_PARAMS(10, T1S_P2MP, Half), }; static_assert(ARRAY_SIZE(link_mode_params) == __ETHTOOL_LINK_MODE_MASK_NBITS); -- cgit v1.2.3 From a23a1e57a6770a8fad1c6362dfe73bd9f27e430c Mon Sep 17 00:00:00 2001 From: Piergiorgio Beruto Date: Mon, 9 Jan 2023 18:00:10 +0100 Subject: drivers/net/phy: add connection between ethtool and phylib for PLCA This patch adds the required connection between netlink ethtool and phylib to resolve PLCA get/set config and get status messages. Signed-off-by: Piergiorgio Beruto Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 192 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy_device.c | 3 + include/linux/phy.h | 7 ++ 3 files changed, 202 insertions(+) (limited to 'include') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e5b6cb1a77f9..3378ca4f49b6 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -543,6 +543,198 @@ int phy_ethtool_get_stats(struct phy_device *phydev, } EXPORT_SYMBOL(phy_ethtool_get_stats); +/** + * phy_ethtool_get_plca_cfg - Get PLCA RS configuration + * @phydev: the phy_device struct + * @plca_cfg: where to store the retrieved configuration + * + * Retrieve the PLCA configuration from the PHY. Return 0 on success or a + * negative value if an error occurred. + */ +int phy_ethtool_get_plca_cfg(struct phy_device *phydev, + struct phy_plca_cfg *plca_cfg) +{ + int ret; + + if (!phydev->drv) { + ret = -EIO; + goto out; + } + + if (!phydev->drv->get_plca_cfg) { + ret = -EOPNOTSUPP; + goto out; + } + + mutex_lock(&phydev->lock); + ret = phydev->drv->get_plca_cfg(phydev, plca_cfg); + + mutex_unlock(&phydev->lock); +out: + return ret; +} + +/** + * plca_check_valid - Check PLCA configuration before enabling + * @phydev: the phy_device struct + * @plca_cfg: current PLCA configuration + * @extack: extack for reporting useful error messages + * + * Checks whether the PLCA and PHY configuration are consistent and it is safe + * to enable PLCA. Returns 0 on success or a negative value if the PLCA or PHY + * configuration is not consistent. + */ +static int plca_check_valid(struct phy_device *phydev, + const struct phy_plca_cfg *plca_cfg, + struct netlink_ext_ack *extack) +{ + int ret = 0; + + if (!linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT, + phydev->advertising)) { + ret = -EOPNOTSUPP; + NL_SET_ERR_MSG(extack, + "Point to Multi-Point mode is not enabled"); + } else if (plca_cfg->node_id >= 255) { + NL_SET_ERR_MSG(extack, "PLCA node ID is not set"); + ret = -EINVAL; + } + + return ret; +} + +/** + * phy_ethtool_set_plca_cfg - Set PLCA RS configuration + * @phydev: the phy_device struct + * @plca_cfg: new PLCA configuration to apply + * @extack: extack for reporting useful error messages + * + * Sets the PLCA configuration in the PHY. Return 0 on success or a + * negative value if an error occurred. + */ +int phy_ethtool_set_plca_cfg(struct phy_device *phydev, + const struct phy_plca_cfg *plca_cfg, + struct netlink_ext_ack *extack) +{ + struct phy_plca_cfg *curr_plca_cfg; + int ret; + + if (!phydev->drv) { + ret = -EIO; + goto out; + } + + if (!phydev->drv->set_plca_cfg || + !phydev->drv->get_plca_cfg) { + ret = -EOPNOTSUPP; + goto out; + } + + curr_plca_cfg = kmalloc(sizeof(*curr_plca_cfg), GFP_KERNEL); + if (!curr_plca_cfg) { + ret = -ENOMEM; + goto out; + } + + mutex_lock(&phydev->lock); + + ret = phydev->drv->get_plca_cfg(phydev, curr_plca_cfg); + if (ret) + goto out_drv; + + if (curr_plca_cfg->enabled < 0 && plca_cfg->enabled >= 0) { + NL_SET_ERR_MSG(extack, + "PHY does not support changing the PLCA 'enable' attribute"); + ret = -EINVAL; + goto out_drv; + } + + if (curr_plca_cfg->node_id < 0 && plca_cfg->node_id >= 0) { + NL_SET_ERR_MSG(extack, + "PHY does not support changing the PLCA 'local node ID' attribute"); + ret = -EINVAL; + goto out_drv; + } + + if (curr_plca_cfg->node_cnt < 0 && plca_cfg->node_cnt >= 0) { + NL_SET_ERR_MSG(extack, + "PHY does not support changing the PLCA 'node count' attribute"); + ret = -EINVAL; + goto out_drv; + } + + if (curr_plca_cfg->to_tmr < 0 && plca_cfg->to_tmr >= 0) { + NL_SET_ERR_MSG(extack, + "PHY does not support changing the PLCA 'TO timer' attribute"); + ret = -EINVAL; + goto out_drv; + } + + if (curr_plca_cfg->burst_cnt < 0 && plca_cfg->burst_cnt >= 0) { + NL_SET_ERR_MSG(extack, + "PHY does not support changing the PLCA 'burst count' attribute"); + ret = -EINVAL; + goto out_drv; + } + + if (curr_plca_cfg->burst_tmr < 0 && plca_cfg->burst_tmr >= 0) { + NL_SET_ERR_MSG(extack, + "PHY does not support changing the PLCA 'burst timer' attribute"); + ret = -EINVAL; + goto out_drv; + } + + // if enabling PLCA, perform a few sanity checks + if (plca_cfg->enabled > 0) { + // allow setting node_id concurrently with enabled + if (plca_cfg->node_id >= 0) + curr_plca_cfg->node_id = plca_cfg->node_id; + + ret = plca_check_valid(phydev, curr_plca_cfg, extack); + if (ret) + goto out_drv; + } + + ret = phydev->drv->set_plca_cfg(phydev, plca_cfg); + +out_drv: + kfree(curr_plca_cfg); + mutex_unlock(&phydev->lock); +out: + return ret; +} + +/** + * phy_ethtool_get_plca_status - Get PLCA RS status information + * @phydev: the phy_device struct + * @plca_st: where to store the retrieved status information + * + * Retrieve the PLCA status information from the PHY. Return 0 on success or a + * negative value if an error occurred. + */ +int phy_ethtool_get_plca_status(struct phy_device *phydev, + struct phy_plca_status *plca_st) +{ + int ret; + + if (!phydev->drv) { + ret = -EIO; + goto out; + } + + if (!phydev->drv->get_plca_status) { + ret = -EOPNOTSUPP; + goto out; + } + + mutex_lock(&phydev->lock); + ret = phydev->drv->get_plca_status(phydev, plca_st); + + mutex_unlock(&phydev->lock); +out: + return ret; +} + /** * phy_start_cable_test - Start a cable test * diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1cde41d39196..0d371a0a49f2 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -3283,6 +3283,9 @@ static const struct ethtool_phy_ops phy_ethtool_phy_ops = { .get_sset_count = phy_ethtool_get_sset_count, .get_strings = phy_ethtool_get_strings, .get_stats = phy_ethtool_get_stats, + .get_plca_cfg = phy_ethtool_get_plca_cfg, + .set_plca_cfg = phy_ethtool_set_plca_cfg, + .get_plca_status = phy_ethtool_get_plca_status, .start_cable_test = phy_start_cable_test, .start_cable_test_tdr = phy_start_cable_test_tdr, }; diff --git a/include/linux/phy.h b/include/linux/phy.h index 63b199f574f7..7c2ec1650975 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1851,6 +1851,13 @@ int phy_ethtool_get_strings(struct phy_device *phydev, u8 *data); int phy_ethtool_get_sset_count(struct phy_device *phydev); int phy_ethtool_get_stats(struct phy_device *phydev, struct ethtool_stats *stats, u64 *data); +int phy_ethtool_get_plca_cfg(struct phy_device *phydev, + struct phy_plca_cfg *plca_cfg); +int phy_ethtool_set_plca_cfg(struct phy_device *phydev, + const struct phy_plca_cfg *plca_cfg, + struct netlink_ext_ack *extack); +int phy_ethtool_get_plca_status(struct phy_device *phydev, + struct phy_plca_status *plca_st); static inline int phy_package_read(struct phy_device *phydev, u32 regnum) { -- cgit v1.2.3 From 493323416fed6b1ec6128a65c00e5f01d38b7e17 Mon Sep 17 00:00:00 2001 From: Piergiorgio Beruto Date: Mon, 9 Jan 2023 18:00:23 +0100 Subject: drivers/net/phy: add helpers to get/set PLCA configuration This patch adds support in phylib to read/write PLCA configuration for Ethernet PHYs that support the OPEN Alliance "10BASE-T1S PLCA Management Registers" specifications. These can be found at https://www.opensig.org/about/specifications/ Signed-off-by: Piergiorgio Beruto Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- MAINTAINERS | 1 + drivers/net/phy/mdio-open-alliance.h | 46 +++++++++ drivers/net/phy/phy-c45.c | 193 +++++++++++++++++++++++++++++++++++ include/linux/phy.h | 6 ++ 4 files changed, 246 insertions(+) create mode 100644 drivers/net/phy/mdio-open-alliance.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index 7b6e602b90d5..8880701e7110 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16620,6 +16620,7 @@ PLCA RECONCILIATION SUBLAYER (IEEE802.3 Clause 148) M: Piergiorgio Beruto L: netdev@vger.kernel.org S: Maintained +F: drivers/net/phy/mdio-open-alliance.h F: net/ethtool/plca.c PLDMFW LIBRARY diff --git a/drivers/net/phy/mdio-open-alliance.h b/drivers/net/phy/mdio-open-alliance.h new file mode 100644 index 000000000000..931e14660d75 --- /dev/null +++ b/drivers/net/phy/mdio-open-alliance.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mdio-open-alliance.h - definition of OPEN Alliance SIG standard registers + */ + +#ifndef __MDIO_OPEN_ALLIANCE__ +#define __MDIO_OPEN_ALLIANCE__ + +#include + +/* NOTE: all OATC14 registers are located in MDIO_MMD_VEND2 */ + +/* Open Alliance TC14 (10BASE-T1S) registers */ +#define MDIO_OATC14_PLCA_IDVER 0xca00 /* PLCA ID and version */ +#define MDIO_OATC14_PLCA_CTRL0 0xca01 /* PLCA Control register 0 */ +#define MDIO_OATC14_PLCA_CTRL1 0xca02 /* PLCA Control register 1 */ +#define MDIO_OATC14_PLCA_STATUS 0xca03 /* PLCA Status register */ +#define MDIO_OATC14_PLCA_TOTMR 0xca04 /* PLCA TO Timer register */ +#define MDIO_OATC14_PLCA_BURST 0xca05 /* PLCA BURST mode register */ + +/* Open Alliance TC14 PLCA IDVER register */ +#define MDIO_OATC14_PLCA_IDM 0xff00 /* PLCA MAP ID */ +#define MDIO_OATC14_PLCA_VER 0x00ff /* PLCA MAP version */ + +/* Open Alliance TC14 PLCA CTRL0 register */ +#define MDIO_OATC14_PLCA_EN BIT(15) /* PLCA enable */ +#define MDIO_OATC14_PLCA_RST BIT(14) /* PLCA reset */ + +/* Open Alliance TC14 PLCA CTRL1 register */ +#define MDIO_OATC14_PLCA_NCNT 0xff00 /* PLCA node count */ +#define MDIO_OATC14_PLCA_ID 0x00ff /* PLCA local node ID */ + +/* Open Alliance TC14 PLCA STATUS register */ +#define MDIO_OATC14_PLCA_PST BIT(15) /* PLCA status indication */ + +/* Open Alliance TC14 PLCA TOTMR register */ +#define MDIO_OATC14_PLCA_TOT 0x00ff + +/* Open Alliance TC14 PLCA BURST register */ +#define MDIO_OATC14_PLCA_MAXBC 0xff00 +#define MDIO_OATC14_PLCA_BTMR 0x00ff + +/* Version Identifiers */ +#define OATC14_IDM 0x0a00 + +#endif /* __MDIO_OPEN_ALLIANCE__ */ diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index a87a4b3ffce4..cff83220595c 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -8,6 +8,8 @@ #include #include +#include "mdio-open-alliance.h" + /** * genphy_c45_baset1_able - checks if the PMA has BASE-T1 extended abilities * @phydev: target phy_device struct @@ -931,6 +933,197 @@ int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable) } EXPORT_SYMBOL_GPL(genphy_c45_fast_retrain); +/** + * genphy_c45_plca_get_cfg - get PLCA configuration from standard registers + * @phydev: target phy_device struct + * @plca_cfg: output structure to store the PLCA configuration + * + * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA + * Management Registers specifications, this function can be used to retrieve + * the current PLCA configuration from the standard registers in MMD 31. + */ +int genphy_c45_plca_get_cfg(struct phy_device *phydev, + struct phy_plca_cfg *plca_cfg) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_IDVER); + if (ret < 0) + return ret; + + if ((ret & MDIO_OATC14_PLCA_IDM) != OATC14_IDM) + return -ENODEV; + + plca_cfg->version = ret & ~MDIO_OATC14_PLCA_IDM; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL0); + if (ret < 0) + return ret; + + plca_cfg->enabled = !!(ret & MDIO_OATC14_PLCA_EN); + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_CTRL1); + if (ret < 0) + return ret; + + plca_cfg->node_cnt = (ret & MDIO_OATC14_PLCA_NCNT) >> 8; + plca_cfg->node_id = (ret & MDIO_OATC14_PLCA_ID); + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR); + if (ret < 0) + return ret; + + plca_cfg->to_tmr = ret & MDIO_OATC14_PLCA_TOT; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_BURST); + if (ret < 0) + return ret; + + plca_cfg->burst_cnt = (ret & MDIO_OATC14_PLCA_MAXBC) >> 8; + plca_cfg->burst_tmr = (ret & MDIO_OATC14_PLCA_BTMR); + + return 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_plca_get_cfg); + +/** + * genphy_c45_plca_set_cfg - set PLCA configuration using standard registers + * @phydev: target phy_device struct + * @plca_cfg: structure containing the PLCA configuration. Fields set to -1 are + * not to be changed. + * + * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA + * Management Registers specifications, this function can be used to modify + * the PLCA configuration using the standard registers in MMD 31. + */ +int genphy_c45_plca_set_cfg(struct phy_device *phydev, + const struct phy_plca_cfg *plca_cfg) +{ + int ret; + u16 val; + + // PLCA IDVER is read-only + if (plca_cfg->version >= 0) + return -EINVAL; + + // first of all, disable PLCA if required + if (plca_cfg->enabled == 0) { + ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, + MDIO_OATC14_PLCA_CTRL0, + MDIO_OATC14_PLCA_EN); + + if (ret < 0) + return ret; + } + + // check if we need to set the PLCA node count, node ID, or both + if (plca_cfg->node_cnt >= 0 || plca_cfg->node_id >= 0) { + /* if one between node count and node ID is -not- to be + * changed, read the register to later perform merge/purge of + * the configuration as appropriate + */ + if (plca_cfg->node_cnt < 0 || plca_cfg->node_id < 0) { + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, + MDIO_OATC14_PLCA_CTRL1); + + if (ret < 0) + return ret; + + val = ret; + } + + if (plca_cfg->node_cnt >= 0) + val = (val & ~MDIO_OATC14_PLCA_NCNT) | + (plca_cfg->node_cnt << 8); + + if (plca_cfg->node_id >= 0) + val = (val & ~MDIO_OATC14_PLCA_ID) | + (plca_cfg->node_id); + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + MDIO_OATC14_PLCA_CTRL1, val); + + if (ret < 0) + return ret; + } + + if (plca_cfg->to_tmr >= 0) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + MDIO_OATC14_PLCA_TOTMR, + plca_cfg->to_tmr); + + if (ret < 0) + return ret; + } + + // check if we need to set the PLCA burst count, burst timer, or both + if (plca_cfg->burst_cnt >= 0 || plca_cfg->burst_tmr >= 0) { + /* if one between burst count and burst timer is -not- to be + * changed, read the register to later perform merge/purge of + * the configuration as appropriate + */ + if (plca_cfg->burst_cnt < 0 || plca_cfg->burst_tmr < 0) { + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, + MDIO_OATC14_PLCA_BURST); + + if (ret < 0) + return ret; + + val = ret; + } + + if (plca_cfg->burst_cnt >= 0) + val = (val & ~MDIO_OATC14_PLCA_MAXBC) | + (plca_cfg->burst_cnt << 8); + + if (plca_cfg->burst_tmr >= 0) + val = (val & ~MDIO_OATC14_PLCA_BTMR) | + (plca_cfg->burst_tmr); + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + MDIO_OATC14_PLCA_BURST, val); + + if (ret < 0) + return ret; + } + + // if we need to enable PLCA, do it at the end + if (plca_cfg->enabled > 0) { + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, + MDIO_OATC14_PLCA_CTRL0, + MDIO_OATC14_PLCA_EN); + + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_plca_set_cfg); + +/** + * genphy_c45_plca_get_status - get PLCA status from standard registers + * @phydev: target phy_device struct + * @plca_st: output structure to store the PLCA status + * + * Description: if the PHY complies to the Open Alliance TC14 10BASE-T1S PLCA + * Management Registers specifications, this function can be used to retrieve + * the current PLCA status information from the standard registers in MMD 31. + */ +int genphy_c45_plca_get_status(struct phy_device *phydev, + struct phy_plca_status *plca_st) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_STATUS); + if (ret < 0) + return ret; + + plca_st->pst = !!(ret & MDIO_OATC14_PLCA_PST); + return 0; +} +EXPORT_SYMBOL_GPL(genphy_c45_plca_get_status); + struct phy_driver genphy_c45_driver = { .phy_id = 0xffffffff, .phy_id_mask = 0xffffffff, diff --git a/include/linux/phy.h b/include/linux/phy.h index 7c2ec1650975..b3cf1e08e880 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1753,6 +1753,12 @@ int genphy_c45_loopback(struct phy_device *phydev, bool enable); int genphy_c45_pma_resume(struct phy_device *phydev); int genphy_c45_pma_suspend(struct phy_device *phydev); int genphy_c45_fast_retrain(struct phy_device *phydev, bool enable); +int genphy_c45_plca_get_cfg(struct phy_device *phydev, + struct phy_plca_cfg *plca_cfg); +int genphy_c45_plca_set_cfg(struct phy_device *phydev, + const struct phy_plca_cfg *plca_cfg); +int genphy_c45_plca_get_status(struct phy_device *phydev, + struct phy_plca_status *plca_st); /* Generic C45 PHY driver */ extern struct phy_driver genphy_c45_driver; -- cgit v1.2.3 From 5970e15dbcfeb0ed3a0bf1954f35bbe60a048754 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Sun, 20 Nov 2022 09:15:34 -0500 Subject: filelock: move file locking definitions to separate header file The file locking definitions have lived in fs.h since the dawn of time, but they are only used by a small subset of the source files that include it. Move the file locking definitions to a new header file, and add the appropriate #include directives to the source files that need them. By doing this we trim down fs.h a bit and limit the amount of rebuilding that has to be done when we make changes to the file locking APIs. Reviewed-by: Xiubo Li Reviewed-by: Christian Brauner (Microsoft) Reviewed-by: Christoph Hellwig Reviewed-by: David Howells Reviewed-by: Russell King (Oracle) Acked-by: Chuck Lever Acked-by: Joseph Qi Acked-by: Steve French Acked-by: Al Viro Acked-by: Darrick J. Wong Signed-off-by: Jeff Layton --- arch/arm/kernel/sys_oabi-compat.c | 1 + fs/9p/vfs_file.c | 1 + fs/afs/internal.h | 1 + fs/attr.c | 1 + fs/ceph/caps.c | 1 + fs/ceph/locks.c | 1 + fs/cifs/cifsfs.c | 1 + fs/cifs/cifsglob.h | 1 + fs/cifs/cifssmb.c | 1 + fs/cifs/file.c | 1 + fs/cifs/smb2file.c | 1 + fs/dlm/plock.c | 1 + fs/fcntl.c | 1 + fs/file_table.c | 1 + fs/fuse/file.c | 1 + fs/gfs2/file.c | 1 + fs/inode.c | 1 + fs/ksmbd/smb2pdu.c | 1 + fs/ksmbd/vfs.c | 1 + fs/ksmbd/vfs_cache.c | 1 + fs/lockd/clntproc.c | 1 + fs/lockd/netns.h | 1 + fs/locks.c | 1 + fs/namei.c | 1 + fs/nfs/file.c | 1 + fs/nfs/nfs4_fs.h | 1 + fs/nfs/pagelist.c | 1 + fs/nfs/write.c | 1 + fs/nfs_common/grace.c | 1 + fs/nfsd/netns.h | 1 + fs/ocfs2/locks.c | 1 + fs/ocfs2/stack_user.c | 1 + fs/open.c | 1 + fs/orangefs/file.c | 1 + fs/posix_acl.c | 1 + fs/proc/fd.c | 1 + fs/utimes.c | 1 + fs/xattr.c | 1 + fs/xfs/xfs_linux.h | 1 + include/linux/filelock.h | 441 ++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 429 ------------------------------------ include/linux/lockd/xdr.h | 1 + 42 files changed, 481 insertions(+), 429 deletions(-) create mode 100644 include/linux/filelock.h (limited to 'include') diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index 68112c172025..006163195d67 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index b740017634ef..b6ba22975781 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/afs/internal.h b/fs/afs/internal.h index fd8567b98e2b..2d6d7dae225a 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/attr.c b/fs/attr.c index b45f30e516fa..f3eb8e57b451 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index f75ad432f375..2ce6cc443b48 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "super.h" #include "mds_client.h" diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 9c8dc8a55e7e..cb51c7e9c8e2 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -7,6 +7,7 @@ #include "super.h" #include "mds_client.h" +#include #include static u64 lock_secret; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 10e00c624922..f052f190b2e8 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cfdd5bf701a1..cd8171a1c9a0 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -26,6 +26,7 @@ #include #include "../smbfs_common/smb2pdu.h" #include "smb2pdu.h" +#include #define SMB_PATH_MAX 260 #define CIFS_PORT 445 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 23f10e0d6e7e..60dd4e37030a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -15,6 +15,7 @@ /* want to reuse a stale file handle and only the caller knows the file info */ #include +#include #include #include #include diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 22dfc1f8b4f1..1d9cc59d8259 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -9,6 +9,7 @@ * */ #include +#include #include #include #include diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index ba6cc50af390..9f1dd04b555a 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -7,6 +7,7 @@ * */ #include +#include #include #include #include diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index 737f185aad8d..ed4357e62f35 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include diff --git a/fs/fcntl.c b/fs/fcntl.c index 146c9ab0cd4b..7852e946fdf4 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/file_table.c b/fs/file_table.c index dd88701e54a9..372653b92617 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 875314ee6f59..1458412f2492 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -18,6 +18,7 @@ #include #include #include +#include static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, unsigned int open_flags, int opcode, diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index eea5be4fbf0e..e8e20a716004 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/inode.c b/fs/inode.c index f453eb58fd03..d02dd8f1e967 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index 14d7f3599c63..000a6648f122 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "glob.h" #include "smbfsctl.h" diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c index ff0e7a4fcd4d..5851934dc85b 100644 --- a/fs/ksmbd/vfs.c +++ b/fs/ksmbd/vfs.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/fs/ksmbd/vfs_cache.c b/fs/ksmbd/vfs_cache.c index da9163b00350..552c3882a8f4 100644 --- a/fs/ksmbd/vfs_cache.c +++ b/fs/ksmbd/vfs_cache.c @@ -5,6 +5,7 @@ */ #include +#include #include #include diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 99fffc9cb958..e875a3571c41 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h index 5bec78c8e431..17432c445fe6 100644 --- a/fs/lockd/netns.h +++ b/fs/lockd/netns.h @@ -3,6 +3,7 @@ #define __LOCKD_NETNS_H__ #include +#include #include struct lockd_net { diff --git a/fs/locks.c b/fs/locks.c index 8f01bee17715..a5cc90c958c9 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/namei.c b/fs/namei.c index 309ae6fc8c99..60a9d3ac941f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d8ec889a4b3f..b0f3c9339e70 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -31,6 +31,7 @@ #include #include +#include #include "delegation.h" #include "internal.h" diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 5edd1704f735..4c9f8bd866ab 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -23,6 +23,7 @@ #define NFS4_MAX_LOOP_ON_RECOVER (10) #include +#include struct idmap; diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 16be6dae524f..779bfc37233c 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "internal.h" #include "pnfs.h" diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 80c240e50952..1a80d548253a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/fs/nfs_common/grace.c b/fs/nfs_common/grace.c index 0a9b72685f98..1479583fbb62 100644 --- a/fs/nfs_common/grace.c +++ b/fs/nfs_common/grace.c @@ -9,6 +9,7 @@ #include #include #include +#include static unsigned int grace_net_id; static DEFINE_SPINLOCK(grace_lock); diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 8c854ba3285b..bc139401927d 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -10,6 +10,7 @@ #include #include +#include #include #include diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c index 73a3854b2afb..f37174e79fad 100644 --- a/fs/ocfs2/locks.c +++ b/fs/ocfs2/locks.c @@ -8,6 +8,7 @@ */ #include +#include #include #include diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 64e6ddcfe329..05d4414d0c33 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/fs/open.c b/fs/open.c index 82c1a28b3308..9b1c08298a07 100644 --- a/fs/open.c +++ b/fs/open.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "internal.h" diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index 167fa43b24f9..4ecb91a9bbeb 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -14,6 +14,7 @@ #include "orangefs-kernel.h" #include "orangefs-bufmap.h" #include +#include #include static int flush_racache(struct inode *inode) diff --git a/fs/posix_acl.c b/fs/posix_acl.c index d7bc81fc0840..d2271431f344 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "internal.h" diff --git a/fs/proc/fd.c b/fs/proc/fd.c index fc46d6fe080c..53e4919ef860 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -12,6 +12,7 @@ #include #include #include +#include #include diff --git a/fs/utimes.c b/fs/utimes.c index 39f356017635..00499e4ba955 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -7,6 +7,7 @@ #include #include #include +#include static bool nsec_valid(long nsec) { diff --git a/fs/xattr.c b/fs/xattr.c index adab9a70b536..3fead374901b 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -9,6 +9,7 @@ Copyright (c) 2004 Red Hat, Inc., James Morris */ #include +#include #include #include #include diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h index f9878021e7d0..e88f18f85e4b 100644 --- a/fs/xfs/xfs_linux.h +++ b/fs/xfs/xfs_linux.h @@ -34,6 +34,7 @@ typedef __u32 xfs_nlink_t; #include #include #include +#include #include #include #include diff --git a/include/linux/filelock.h b/include/linux/filelock.h new file mode 100644 index 000000000000..dc5056a66e2c --- /dev/null +++ b/include/linux/filelock.h @@ -0,0 +1,441 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_FILELOCK_H +#define _LINUX_FILELOCK_H + +#include + +#define FL_POSIX 1 +#define FL_FLOCK 2 +#define FL_DELEG 4 /* NFSv4 delegation */ +#define FL_ACCESS 8 /* not trying to lock, just looking */ +#define FL_EXISTS 16 /* when unlocking, test for existence */ +#define FL_LEASE 32 /* lease held on this file */ +#define FL_CLOSE 64 /* unlock on close */ +#define FL_SLEEP 128 /* A blocking lock */ +#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ +#define FL_UNLOCK_PENDING 512 /* Lease is being broken */ +#define FL_OFDLCK 1024 /* lock is "owned" by struct file */ +#define FL_LAYOUT 2048 /* outstanding pNFS layout */ +#define FL_RECLAIM 4096 /* reclaiming from a reboot server */ + +#define FL_CLOSE_POSIX (FL_POSIX | FL_CLOSE) + +/* + * Special return value from posix_lock_file() and vfs_lock_file() for + * asynchronous locking. + */ +#define FILE_LOCK_DEFERRED 1 + +struct file_lock; + +struct file_lock_operations { + void (*fl_copy_lock)(struct file_lock *, struct file_lock *); + void (*fl_release_private)(struct file_lock *); +}; + +struct lock_manager_operations { + void *lm_mod_owner; + fl_owner_t (*lm_get_owner)(fl_owner_t); + void (*lm_put_owner)(fl_owner_t); + void (*lm_notify)(struct file_lock *); /* unblock callback */ + int (*lm_grant)(struct file_lock *, int); + bool (*lm_break)(struct file_lock *); + int (*lm_change)(struct file_lock *, int, struct list_head *); + void (*lm_setup)(struct file_lock *, void **); + bool (*lm_breaker_owns_lease)(struct file_lock *); + bool (*lm_lock_expirable)(struct file_lock *cfl); + void (*lm_expire_lock)(void); +}; + +struct lock_manager { + struct list_head list; + /* + * NFSv4 and up also want opens blocked during the grace period; + * NLM doesn't care: + */ + bool block_opens; +}; + +struct net; +void locks_start_grace(struct net *, struct lock_manager *); +void locks_end_grace(struct lock_manager *); +bool locks_in_grace(struct net *); +bool opens_in_grace(struct net *); + +/* + * struct file_lock has a union that some filesystems use to track + * their own private info. The NFS side of things is defined here: + */ +#include + +/* + * struct file_lock represents a generic "file lock". It's used to represent + * POSIX byte range locks, BSD (flock) locks, and leases. It's important to + * note that the same struct is used to represent both a request for a lock and + * the lock itself, but the same object is never used for both. + * + * FIXME: should we create a separate "struct lock_request" to help distinguish + * these two uses? + * + * The varous i_flctx lists are ordered by: + * + * 1) lock owner + * 2) lock range start + * 3) lock range end + * + * Obviously, the last two criteria only matter for POSIX locks. + */ +struct file_lock { + struct file_lock *fl_blocker; /* The lock, that is blocking us */ + struct list_head fl_list; /* link into file_lock_context */ + struct hlist_node fl_link; /* node in global lists */ + struct list_head fl_blocked_requests; /* list of requests with + * ->fl_blocker pointing here + */ + struct list_head fl_blocked_member; /* node in + * ->fl_blocker->fl_blocked_requests + */ + fl_owner_t fl_owner; + unsigned int fl_flags; + unsigned char fl_type; + unsigned int fl_pid; + int fl_link_cpu; /* what cpu's list is this on? */ + wait_queue_head_t fl_wait; + struct file *fl_file; + loff_t fl_start; + loff_t fl_end; + + struct fasync_struct * fl_fasync; /* for lease break notifications */ + /* for lease breaks: */ + unsigned long fl_break_time; + unsigned long fl_downgrade_time; + + const struct file_lock_operations *fl_ops; /* Callbacks for filesystems */ + const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */ + union { + struct nfs_lock_info nfs_fl; + struct nfs4_lock_info nfs4_fl; + struct { + struct list_head link; /* link in AFS vnode's pending_locks list */ + int state; /* state of grant or error if -ve */ + unsigned int debug_id; + } afs; + struct { + struct inode *inode; + } ceph; + } fl_u; +} __randomize_layout; + +struct file_lock_context { + spinlock_t flc_lock; + struct list_head flc_flock; + struct list_head flc_posix; + struct list_head flc_lease; +}; + +#define locks_inode(f) file_inode(f) + +#ifdef CONFIG_FILE_LOCKING +int fcntl_getlk(struct file *, unsigned int, struct flock *); +int fcntl_setlk(unsigned int, struct file *, unsigned int, + struct flock *); + +#if BITS_PER_LONG == 32 +int fcntl_getlk64(struct file *, unsigned int, struct flock64 *); +int fcntl_setlk64(unsigned int, struct file *, unsigned int, + struct flock64 *); +#endif + +int fcntl_setlease(unsigned int fd, struct file *filp, long arg); +int fcntl_getlease(struct file *filp); + +/* fs/locks.c */ +void locks_free_lock_context(struct inode *inode); +void locks_free_lock(struct file_lock *fl); +void locks_init_lock(struct file_lock *); +struct file_lock * locks_alloc_lock(void); +void locks_copy_lock(struct file_lock *, struct file_lock *); +void locks_copy_conflock(struct file_lock *, struct file_lock *); +void locks_remove_posix(struct file *, fl_owner_t); +void locks_remove_file(struct file *); +void locks_release_private(struct file_lock *); +void posix_test_lock(struct file *, struct file_lock *); +int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); +int locks_delete_block(struct file_lock *); +int vfs_test_lock(struct file *, struct file_lock *); +int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); +int vfs_cancel_lock(struct file *filp, struct file_lock *fl); +bool vfs_inode_has_locks(struct inode *inode); +int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl); +int __break_lease(struct inode *inode, unsigned int flags, unsigned int type); +void lease_get_mtime(struct inode *, struct timespec64 *time); +int generic_setlease(struct file *, long, struct file_lock **, void **priv); +int vfs_setlease(struct file *, long, struct file_lock **, void **); +int lease_modify(struct file_lock *, int, struct list_head *); + +struct notifier_block; +int lease_register_notifier(struct notifier_block *); +void lease_unregister_notifier(struct notifier_block *); + +struct files_struct; +void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files); +bool locks_owner_has_blockers(struct file_lock_context *flctx, + fl_owner_t owner); + +static inline struct file_lock_context * +locks_inode_context(const struct inode *inode) +{ + return smp_load_acquire(&inode->i_flctx); +} + +#else /* !CONFIG_FILE_LOCKING */ +static inline int fcntl_getlk(struct file *file, unsigned int cmd, + struct flock __user *user) +{ + return -EINVAL; +} + +static inline int fcntl_setlk(unsigned int fd, struct file *file, + unsigned int cmd, struct flock __user *user) +{ + return -EACCES; +} + +#if BITS_PER_LONG == 32 +static inline int fcntl_getlk64(struct file *file, unsigned int cmd, + struct flock64 *user) +{ + return -EINVAL; +} + +static inline int fcntl_setlk64(unsigned int fd, struct file *file, + unsigned int cmd, struct flock64 *user) +{ + return -EACCES; +} +#endif +static inline int fcntl_setlease(unsigned int fd, struct file *filp, long arg) +{ + return -EINVAL; +} + +static inline int fcntl_getlease(struct file *filp) +{ + return F_UNLCK; +} + +static inline void +locks_free_lock_context(struct inode *inode) +{ +} + +static inline void locks_init_lock(struct file_lock *fl) +{ + return; +} + +static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) +{ + return; +} + +static inline void locks_copy_lock(struct file_lock *new, struct file_lock *fl) +{ + return; +} + +static inline void locks_remove_posix(struct file *filp, fl_owner_t owner) +{ + return; +} + +static inline void locks_remove_file(struct file *filp) +{ + return; +} + +static inline void posix_test_lock(struct file *filp, struct file_lock *fl) +{ + return; +} + +static inline int posix_lock_file(struct file *filp, struct file_lock *fl, + struct file_lock *conflock) +{ + return -ENOLCK; +} + +static inline int locks_delete_block(struct file_lock *waiter) +{ + return -ENOENT; +} + +static inline int vfs_test_lock(struct file *filp, struct file_lock *fl) +{ + return 0; +} + +static inline int vfs_lock_file(struct file *filp, unsigned int cmd, + struct file_lock *fl, struct file_lock *conf) +{ + return -ENOLCK; +} + +static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl) +{ + return 0; +} + +static inline bool vfs_inode_has_locks(struct inode *inode) +{ + return false; +} + +static inline int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl) +{ + return -ENOLCK; +} + +static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) +{ + return 0; +} + +static inline void lease_get_mtime(struct inode *inode, + struct timespec64 *time) +{ + return; +} + +static inline int generic_setlease(struct file *filp, long arg, + struct file_lock **flp, void **priv) +{ + return -EINVAL; +} + +static inline int vfs_setlease(struct file *filp, long arg, + struct file_lock **lease, void **priv) +{ + return -EINVAL; +} + +static inline int lease_modify(struct file_lock *fl, int arg, + struct list_head *dispose) +{ + return -EINVAL; +} + +struct files_struct; +static inline void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files) {} +static inline bool locks_owner_has_blockers(struct file_lock_context *flctx, + fl_owner_t owner) +{ + return false; +} + +static inline struct file_lock_context * +locks_inode_context(const struct inode *inode) +{ + return NULL; +} + +#endif /* !CONFIG_FILE_LOCKING */ + +static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) +{ + return locks_lock_inode_wait(locks_inode(filp), fl); +} + +#ifdef CONFIG_FILE_LOCKING +static inline int break_lease(struct inode *inode, unsigned int mode) +{ + /* + * Since this check is lockless, we must ensure that any refcounts + * taken are done before checking i_flctx->flc_lease. Otherwise, we + * could end up racing with tasks trying to set a new lease on this + * file. + */ + smp_mb(); + if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) + return __break_lease(inode, mode, FL_LEASE); + return 0; +} + +static inline int break_deleg(struct inode *inode, unsigned int mode) +{ + /* + * Since this check is lockless, we must ensure that any refcounts + * taken are done before checking i_flctx->flc_lease. Otherwise, we + * could end up racing with tasks trying to set a new lease on this + * file. + */ + smp_mb(); + if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) + return __break_lease(inode, mode, FL_DELEG); + return 0; +} + +static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode) +{ + int ret; + + ret = break_deleg(inode, O_WRONLY|O_NONBLOCK); + if (ret == -EWOULDBLOCK && delegated_inode) { + *delegated_inode = inode; + ihold(inode); + } + return ret; +} + +static inline int break_deleg_wait(struct inode **delegated_inode) +{ + int ret; + + ret = break_deleg(*delegated_inode, O_WRONLY); + iput(*delegated_inode); + *delegated_inode = NULL; + return ret; +} + +static inline int break_layout(struct inode *inode, bool wait) +{ + smp_mb(); + if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) + return __break_lease(inode, + wait ? O_WRONLY : O_WRONLY | O_NONBLOCK, + FL_LAYOUT); + return 0; +} + +#else /* !CONFIG_FILE_LOCKING */ +static inline int break_lease(struct inode *inode, unsigned int mode) +{ + return 0; +} + +static inline int break_deleg(struct inode *inode, unsigned int mode) +{ + return 0; +} + +static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode) +{ + return 0; +} + +static inline int break_deleg_wait(struct inode **delegated_inode) +{ + BUG(); + return 0; +} + +static inline int break_layout(struct inode *inode, bool wait) +{ + return 0; +} + +#endif /* CONFIG_FILE_LOCKING */ + +#endif /* _LINUX_FILELOCK_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index c1769a2c5d70..006278d84d2f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1003,135 +1003,11 @@ static inline struct file *get_file(struct file *f) #define MAX_LFS_FILESIZE ((loff_t)LLONG_MAX) #endif -#define FL_POSIX 1 -#define FL_FLOCK 2 -#define FL_DELEG 4 /* NFSv4 delegation */ -#define FL_ACCESS 8 /* not trying to lock, just looking */ -#define FL_EXISTS 16 /* when unlocking, test for existence */ -#define FL_LEASE 32 /* lease held on this file */ -#define FL_CLOSE 64 /* unlock on close */ -#define FL_SLEEP 128 /* A blocking lock */ -#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ -#define FL_UNLOCK_PENDING 512 /* Lease is being broken */ -#define FL_OFDLCK 1024 /* lock is "owned" by struct file */ -#define FL_LAYOUT 2048 /* outstanding pNFS layout */ -#define FL_RECLAIM 4096 /* reclaiming from a reboot server */ - -#define FL_CLOSE_POSIX (FL_POSIX | FL_CLOSE) - -/* - * Special return value from posix_lock_file() and vfs_lock_file() for - * asynchronous locking. - */ -#define FILE_LOCK_DEFERRED 1 - /* legacy typedef, should eventually be removed */ typedef void *fl_owner_t; struct file_lock; -struct file_lock_operations { - void (*fl_copy_lock)(struct file_lock *, struct file_lock *); - void (*fl_release_private)(struct file_lock *); -}; - -struct lock_manager_operations { - void *lm_mod_owner; - fl_owner_t (*lm_get_owner)(fl_owner_t); - void (*lm_put_owner)(fl_owner_t); - void (*lm_notify)(struct file_lock *); /* unblock callback */ - int (*lm_grant)(struct file_lock *, int); - bool (*lm_break)(struct file_lock *); - int (*lm_change)(struct file_lock *, int, struct list_head *); - void (*lm_setup)(struct file_lock *, void **); - bool (*lm_breaker_owns_lease)(struct file_lock *); - bool (*lm_lock_expirable)(struct file_lock *cfl); - void (*lm_expire_lock)(void); -}; - -struct lock_manager { - struct list_head list; - /* - * NFSv4 and up also want opens blocked during the grace period; - * NLM doesn't care: - */ - bool block_opens; -}; - -struct net; -void locks_start_grace(struct net *, struct lock_manager *); -void locks_end_grace(struct lock_manager *); -bool locks_in_grace(struct net *); -bool opens_in_grace(struct net *); - -/* that will die - we need it for nfs_lock_info */ -#include - -/* - * struct file_lock represents a generic "file lock". It's used to represent - * POSIX byte range locks, BSD (flock) locks, and leases. It's important to - * note that the same struct is used to represent both a request for a lock and - * the lock itself, but the same object is never used for both. - * - * FIXME: should we create a separate "struct lock_request" to help distinguish - * these two uses? - * - * The varous i_flctx lists are ordered by: - * - * 1) lock owner - * 2) lock range start - * 3) lock range end - * - * Obviously, the last two criteria only matter for POSIX locks. - */ -struct file_lock { - struct file_lock *fl_blocker; /* The lock, that is blocking us */ - struct list_head fl_list; /* link into file_lock_context */ - struct hlist_node fl_link; /* node in global lists */ - struct list_head fl_blocked_requests; /* list of requests with - * ->fl_blocker pointing here - */ - struct list_head fl_blocked_member; /* node in - * ->fl_blocker->fl_blocked_requests - */ - fl_owner_t fl_owner; - unsigned int fl_flags; - unsigned char fl_type; - unsigned int fl_pid; - int fl_link_cpu; /* what cpu's list is this on? */ - wait_queue_head_t fl_wait; - struct file *fl_file; - loff_t fl_start; - loff_t fl_end; - - struct fasync_struct * fl_fasync; /* for lease break notifications */ - /* for lease breaks: */ - unsigned long fl_break_time; - unsigned long fl_downgrade_time; - - const struct file_lock_operations *fl_ops; /* Callbacks for filesystems */ - const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */ - union { - struct nfs_lock_info nfs_fl; - struct nfs4_lock_info nfs4_fl; - struct { - struct list_head link; /* link in AFS vnode's pending_locks list */ - int state; /* state of grant or error if -ve */ - unsigned int debug_id; - } afs; - struct { - struct inode *inode; - } ceph; - } fl_u; -} __randomize_layout; - -struct file_lock_context { - spinlock_t flc_lock; - struct list_head flc_flock; - struct list_head flc_posix; - struct list_head flc_lease; -}; - /* The following constant reflects the upper bound of the file/locking space */ #ifndef OFFSET_MAX #define OFFSET_MAX type_max(loff_t) @@ -1140,216 +1016,6 @@ struct file_lock_context { extern void send_sigio(struct fown_struct *fown, int fd, int band); -#define locks_inode(f) file_inode(f) - -#ifdef CONFIG_FILE_LOCKING -extern int fcntl_getlk(struct file *, unsigned int, struct flock *); -extern int fcntl_setlk(unsigned int, struct file *, unsigned int, - struct flock *); - -#if BITS_PER_LONG == 32 -extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 *); -extern int fcntl_setlk64(unsigned int, struct file *, unsigned int, - struct flock64 *); -#endif - -extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg); -extern int fcntl_getlease(struct file *filp); - -/* fs/locks.c */ -void locks_free_lock_context(struct inode *inode); -void locks_free_lock(struct file_lock *fl); -extern void locks_init_lock(struct file_lock *); -extern struct file_lock * locks_alloc_lock(void); -extern void locks_copy_lock(struct file_lock *, struct file_lock *); -extern void locks_copy_conflock(struct file_lock *, struct file_lock *); -extern void locks_remove_posix(struct file *, fl_owner_t); -extern void locks_remove_file(struct file *); -extern void locks_release_private(struct file_lock *); -extern void posix_test_lock(struct file *, struct file_lock *); -extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); -extern int locks_delete_block(struct file_lock *); -extern int vfs_test_lock(struct file *, struct file_lock *); -extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); -extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl); -bool vfs_inode_has_locks(struct inode *inode); -extern int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl); -extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type); -extern void lease_get_mtime(struct inode *, struct timespec64 *time); -extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); -extern int vfs_setlease(struct file *, long, struct file_lock **, void **); -extern int lease_modify(struct file_lock *, int, struct list_head *); - -struct notifier_block; -extern int lease_register_notifier(struct notifier_block *); -extern void lease_unregister_notifier(struct notifier_block *); - -struct files_struct; -extern void show_fd_locks(struct seq_file *f, - struct file *filp, struct files_struct *files); -extern bool locks_owner_has_blockers(struct file_lock_context *flctx, - fl_owner_t owner); - -static inline struct file_lock_context * -locks_inode_context(const struct inode *inode) -{ - return smp_load_acquire(&inode->i_flctx); -} - -#else /* !CONFIG_FILE_LOCKING */ -static inline int fcntl_getlk(struct file *file, unsigned int cmd, - struct flock __user *user) -{ - return -EINVAL; -} - -static inline int fcntl_setlk(unsigned int fd, struct file *file, - unsigned int cmd, struct flock __user *user) -{ - return -EACCES; -} - -#if BITS_PER_LONG == 32 -static inline int fcntl_getlk64(struct file *file, unsigned int cmd, - struct flock64 *user) -{ - return -EINVAL; -} - -static inline int fcntl_setlk64(unsigned int fd, struct file *file, - unsigned int cmd, struct flock64 *user) -{ - return -EACCES; -} -#endif -static inline int fcntl_setlease(unsigned int fd, struct file *filp, long arg) -{ - return -EINVAL; -} - -static inline int fcntl_getlease(struct file *filp) -{ - return F_UNLCK; -} - -static inline void -locks_free_lock_context(struct inode *inode) -{ -} - -static inline void locks_init_lock(struct file_lock *fl) -{ - return; -} - -static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) -{ - return; -} - -static inline void locks_copy_lock(struct file_lock *new, struct file_lock *fl) -{ - return; -} - -static inline void locks_remove_posix(struct file *filp, fl_owner_t owner) -{ - return; -} - -static inline void locks_remove_file(struct file *filp) -{ - return; -} - -static inline void posix_test_lock(struct file *filp, struct file_lock *fl) -{ - return; -} - -static inline int posix_lock_file(struct file *filp, struct file_lock *fl, - struct file_lock *conflock) -{ - return -ENOLCK; -} - -static inline int locks_delete_block(struct file_lock *waiter) -{ - return -ENOENT; -} - -static inline int vfs_test_lock(struct file *filp, struct file_lock *fl) -{ - return 0; -} - -static inline int vfs_lock_file(struct file *filp, unsigned int cmd, - struct file_lock *fl, struct file_lock *conf) -{ - return -ENOLCK; -} - -static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl) -{ - return 0; -} - -static inline bool vfs_inode_has_locks(struct inode *inode) -{ - return false; -} - -static inline int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl) -{ - return -ENOLCK; -} - -static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) -{ - return 0; -} - -static inline void lease_get_mtime(struct inode *inode, - struct timespec64 *time) -{ - return; -} - -static inline int generic_setlease(struct file *filp, long arg, - struct file_lock **flp, void **priv) -{ - return -EINVAL; -} - -static inline int vfs_setlease(struct file *filp, long arg, - struct file_lock **lease, void **priv) -{ - return -EINVAL; -} - -static inline int lease_modify(struct file_lock *fl, int arg, - struct list_head *dispose) -{ - return -EINVAL; -} - -struct files_struct; -static inline void show_fd_locks(struct seq_file *f, - struct file *filp, struct files_struct *files) {} -static inline bool locks_owner_has_blockers(struct file_lock_context *flctx, - fl_owner_t owner) -{ - return false; -} - -static inline struct file_lock_context * -locks_inode_context(const struct inode *inode) -{ - return NULL; -} - -#endif /* !CONFIG_FILE_LOCKING */ - static inline struct inode *file_inode(const struct file *f) { return f->f_inode; @@ -1360,11 +1026,6 @@ static inline struct dentry *file_dentry(const struct file *file) return d_real(file->f_path.dentry, file_inode(file)); } -static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) -{ - return locks_lock_inode_wait(locks_inode(filp), fl); -} - struct fasync_struct { rwlock_t fa_lock; int magic; @@ -2624,96 +2285,6 @@ extern struct kobject *fs_kobj; #define MAX_RW_COUNT (INT_MAX & PAGE_MASK) -#ifdef CONFIG_FILE_LOCKING -static inline int break_lease(struct inode *inode, unsigned int mode) -{ - /* - * Since this check is lockless, we must ensure that any refcounts - * taken are done before checking i_flctx->flc_lease. Otherwise, we - * could end up racing with tasks trying to set a new lease on this - * file. - */ - smp_mb(); - if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) - return __break_lease(inode, mode, FL_LEASE); - return 0; -} - -static inline int break_deleg(struct inode *inode, unsigned int mode) -{ - /* - * Since this check is lockless, we must ensure that any refcounts - * taken are done before checking i_flctx->flc_lease. Otherwise, we - * could end up racing with tasks trying to set a new lease on this - * file. - */ - smp_mb(); - if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) - return __break_lease(inode, mode, FL_DELEG); - return 0; -} - -static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode) -{ - int ret; - - ret = break_deleg(inode, O_WRONLY|O_NONBLOCK); - if (ret == -EWOULDBLOCK && delegated_inode) { - *delegated_inode = inode; - ihold(inode); - } - return ret; -} - -static inline int break_deleg_wait(struct inode **delegated_inode) -{ - int ret; - - ret = break_deleg(*delegated_inode, O_WRONLY); - iput(*delegated_inode); - *delegated_inode = NULL; - return ret; -} - -static inline int break_layout(struct inode *inode, bool wait) -{ - smp_mb(); - if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) - return __break_lease(inode, - wait ? O_WRONLY : O_WRONLY | O_NONBLOCK, - FL_LAYOUT); - return 0; -} - -#else /* !CONFIG_FILE_LOCKING */ -static inline int break_lease(struct inode *inode, unsigned int mode) -{ - return 0; -} - -static inline int break_deleg(struct inode *inode, unsigned int mode) -{ - return 0; -} - -static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode) -{ - return 0; -} - -static inline int break_deleg_wait(struct inode **delegated_inode) -{ - BUG(); - return 0; -} - -static inline int break_layout(struct inode *inode, bool wait) -{ - return 0; -} - -#endif /* CONFIG_FILE_LOCKING */ - /* fs/open.c */ struct audit_names; struct filename { diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h index 67e4a2c5500b..b60fbcd8cdfa 100644 --- a/include/linux/lockd/xdr.h +++ b/include/linux/lockd/xdr.h @@ -11,6 +11,7 @@ #define LOCKD_XDR_H #include +#include #include #include -- cgit v1.2.3 From c65454a947263dfdf482076388aaed60af84ca2f Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 25 Nov 2022 08:48:37 -0500 Subject: fs: remove locks_inode locks_inode was turned into a wrapper around file_inode in de2a4a501e71 (Partially revert "locks: fix file locking on overlayfs"). Finish replacing locks_inode invocations everywhere with file_inode. Acked-by: Miklos Szeredi Acked-by: Al Viro Reviewed-by: David Howells Signed-off-by: Jeff Layton --- fs/afs/flock.c | 14 +++++++------- fs/lockd/clntlock.c | 2 +- fs/lockd/clntproc.c | 2 +- fs/locks.c | 28 ++++++++++++++-------------- fs/nfsd/nfs4state.c | 4 ++-- fs/open.c | 2 +- include/linux/filelock.h | 4 +--- include/linux/lockd/lockd.h | 4 ++-- 8 files changed, 29 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/fs/afs/flock.c b/fs/afs/flock.c index bbcc5afd1576..9c6dea3139f5 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -451,7 +451,7 @@ static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key, */ static int afs_do_setlk(struct file *file, struct file_lock *fl) { - struct inode *inode = locks_inode(file); + struct inode *inode = file_inode(file); struct afs_vnode *vnode = AFS_FS_I(inode); enum afs_flock_mode mode = AFS_FS_S(inode->i_sb)->flock_mode; afs_lock_type_t type; @@ -701,7 +701,7 @@ error: */ static int afs_do_unlk(struct file *file, struct file_lock *fl) { - struct afs_vnode *vnode = AFS_FS_I(locks_inode(file)); + struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); int ret; _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type); @@ -721,7 +721,7 @@ static int afs_do_unlk(struct file *file, struct file_lock *fl) */ static int afs_do_getlk(struct file *file, struct file_lock *fl) { - struct afs_vnode *vnode = AFS_FS_I(locks_inode(file)); + struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); struct key *key = afs_file_key(file); int ret, lock_count; @@ -763,7 +763,7 @@ error: */ int afs_lock(struct file *file, int cmd, struct file_lock *fl) { - struct afs_vnode *vnode = AFS_FS_I(locks_inode(file)); + struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); enum afs_flock_operation op; int ret; @@ -798,7 +798,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl) */ int afs_flock(struct file *file, int cmd, struct file_lock *fl) { - struct afs_vnode *vnode = AFS_FS_I(locks_inode(file)); + struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); enum afs_flock_operation op; int ret; @@ -843,7 +843,7 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl) */ static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl) { - struct afs_vnode *vnode = AFS_FS_I(locks_inode(fl->fl_file)); + struct afs_vnode *vnode = AFS_FS_I(file_inode(fl->fl_file)); _enter(""); @@ -861,7 +861,7 @@ static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl) */ static void afs_fl_release_private(struct file_lock *fl) { - struct afs_vnode *vnode = AFS_FS_I(locks_inode(fl->fl_file)); + struct afs_vnode *vnode = AFS_FS_I(file_inode(fl->fl_file)); _enter(""); diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index a5bb3f721a9d..82b19a30e0f0 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -188,7 +188,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) continue; if (!rpc_cmp_addr(nlm_addr(block->b_host), addr)) continue; - if (nfs_compare_fh(NFS_FH(locks_inode(fl_blocked->fl_file)), fh) != 0) + if (nfs_compare_fh(NFS_FH(file_inode(fl_blocked->fl_file)), fh) != 0) continue; /* Alright, we found a lock. Set the return status * and wake up the caller diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index e875a3571c41..16b4de868cd2 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -131,7 +131,7 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) char *nodename = req->a_host->h_rpcclnt->cl_nodename; nlmclnt_next_cookie(&argp->cookie); - memcpy(&lock->fh, NFS_FH(locks_inode(fl->fl_file)), sizeof(struct nfs_fh)); + memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh)); lock->caller = nodename; lock->oh.data = req->a_owner; lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", diff --git a/fs/locks.c b/fs/locks.c index a5cc90c958c9..624c6ac92ede 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -234,7 +234,7 @@ locks_check_ctx_file_list(struct file *filp, struct list_head *list, char *list_type) { struct file_lock *fl; - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); list_for_each_entry(fl, list, fl_list) if (fl->fl_file == filp) @@ -888,7 +888,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) { struct file_lock *cfl; struct file_lock_context *ctx; - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); void *owner; void (*func)(void); @@ -1331,7 +1331,7 @@ retry: int posix_lock_file(struct file *filp, struct file_lock *fl, struct file_lock *conflock) { - return posix_lock_inode(locks_inode(filp), fl, conflock); + return posix_lock_inode(file_inode(filp), fl, conflock); } EXPORT_SYMBOL(posix_lock_file); @@ -1630,7 +1630,7 @@ EXPORT_SYMBOL(lease_get_mtime); int fcntl_getlease(struct file *filp) { struct file_lock *fl; - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); struct file_lock_context *ctx; int type = F_UNLCK; LIST_HEAD(dispose); @@ -1668,7 +1668,7 @@ int fcntl_getlease(struct file *filp) static int check_conflicting_open(struct file *filp, const long arg, int flags) { - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); int self_wcount = 0, self_rcount = 0; if (flags & FL_LAYOUT) @@ -1704,7 +1704,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv) { struct file_lock *fl, *my_fl = NULL, *lease; - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); struct file_lock_context *ctx; bool is_deleg = (*flp)->fl_flags & FL_DELEG; int error; @@ -1820,7 +1820,7 @@ static int generic_delete_lease(struct file *filp, void *owner) { int error = -EAGAIN; struct file_lock *fl, *victim = NULL; - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); struct file_lock_context *ctx; LIST_HEAD(dispose); @@ -1862,7 +1862,7 @@ static int generic_delete_lease(struct file *filp, void *owner) int generic_setlease(struct file *filp, long arg, struct file_lock **flp, void **priv) { - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); int error; if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE)) @@ -2351,7 +2351,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, struct flock *flock) { struct file_lock *file_lock = locks_alloc_lock(); - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); struct file *f; int error; @@ -2555,7 +2555,7 @@ out: void locks_remove_posix(struct file *filp, fl_owner_t owner) { int error; - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); struct file_lock lock; struct file_lock_context *ctx; @@ -2592,7 +2592,7 @@ static void locks_remove_flock(struct file *filp, struct file_lock_context *flctx) { struct file_lock fl; - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); if (list_empty(&flctx->flc_flock)) return; @@ -2637,7 +2637,7 @@ void locks_remove_file(struct file *filp) { struct file_lock_context *ctx; - ctx = locks_inode_context(locks_inode(filp)); + ctx = locks_inode_context(file_inode(filp)); if (!ctx) return; @@ -2721,7 +2721,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, */ if (fl->fl_file != NULL) - inode = locks_inode(fl->fl_file); + inode = file_inode(fl->fl_file); seq_printf(f, "%lld: ", id); @@ -2862,7 +2862,7 @@ static void __show_fd_locks(struct seq_file *f, void show_fd_locks(struct seq_file *f, struct file *filp, struct files_struct *files) { - struct inode *inode = locks_inode(filp); + struct inode *inode = file_inode(filp); struct file_lock_context *ctx; int id = 0; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7b2ee535ade8..b989c72e54e4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5374,7 +5374,7 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, { struct nfs4_ol_stateid *st; struct file *f = fp->fi_deleg_file->nf_file; - struct inode *ino = locks_inode(f); + struct inode *ino = file_inode(f); int writes; writes = atomic_read(&ino->i_writecount); @@ -7828,7 +7828,7 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) return status; } - inode = locks_inode(nf->nf_file); + inode = file_inode(nf->nf_file); flctx = locks_inode_context(inode); if (flctx && !list_empty_careful(&flctx->flc_posix)) { diff --git a/fs/open.c b/fs/open.c index 9b1c08298a07..117ad27922a1 100644 --- a/fs/open.c +++ b/fs/open.c @@ -871,7 +871,7 @@ static int do_dentry_open(struct file *f, if (error) goto cleanup_all; - error = break_lease(locks_inode(f), f->f_flags); + error = break_lease(file_inode(f), f->f_flags); if (error) goto cleanup_all; diff --git a/include/linux/filelock.h b/include/linux/filelock.h index dc5056a66e2c..efcdd1631d9b 100644 --- a/include/linux/filelock.h +++ b/include/linux/filelock.h @@ -133,8 +133,6 @@ struct file_lock_context { struct list_head flc_lease; }; -#define locks_inode(f) file_inode(f) - #ifdef CONFIG_FILE_LOCKING int fcntl_getlk(struct file *, unsigned int, struct flock *); int fcntl_setlk(unsigned int, struct file *, unsigned int, @@ -345,7 +343,7 @@ locks_inode_context(const struct inode *inode) static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) { - return locks_lock_inode_wait(locks_inode(filp), fl); + return locks_lock_inode_wait(file_inode(filp), fl); } #ifdef CONFIG_FILE_LOCKING diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 70ce419e2709..2b7f067af3c4 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -312,7 +312,7 @@ static inline struct file *nlmsvc_file_file(struct nlm_file *file) static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) { - return locks_inode(nlmsvc_file_file(file)); + return file_inode(nlmsvc_file_file(file)); } static inline int __nlm_privileged_request4(const struct sockaddr *sap) @@ -372,7 +372,7 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp) static inline int nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2) { - return locks_inode(fl1->fl_file) == locks_inode(fl2->fl_file) + return file_inode(fl1->fl_file) == file_inode(fl2->fl_file) && fl1->fl_pid == fl2->fl_pid && fl1->fl_owner == fl2->fl_owner && fl1->fl_start == fl2->fl_start -- cgit v1.2.3 From 2364b406824f1f42026d87c1e26d4dd1ca0f65af Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 9 Jan 2023 11:13:53 +0106 Subject: printk: move size limit macros into internal.h The size limit macros are located further down in printk.c and behind ifdef conditionals. This complicates their usage for upcoming changes. Move the macros into internal.h so that they are still invisible outside of printk, but easily accessible for printk. Also, the maximum size of formatted extended messages does not need to be known by any code outside of printk, so move it to internal.h as well. And like CONSOLE_LOG_MAX, for !CONFIG_PRINTK set CONSOLE_EXT_LOG_MAX to 0 to reduce the static memory footprint. Signed-off-by: John Ogness Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230109100800.1085541-2-john.ogness@linutronix.de --- include/linux/printk.h | 2 -- kernel/printk/internal.h | 24 ++++++++++++++++++++++++ kernel/printk/printk.c | 17 ----------------- 3 files changed, 24 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/linux/printk.h b/include/linux/printk.h index 8c81806c2e99..8ef499ab3c1e 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -44,8 +44,6 @@ static inline const char *printk_skip_headers(const char *buffer) return buffer; } -#define CONSOLE_EXT_LOG_MAX 8192 - /* printk's without a loglevel use this.. */ #define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index d947ca6c84f9..f394332410c9 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -14,6 +14,24 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, #ifdef CONFIG_PRINTK +#ifdef CONFIG_PRINTK_CALLER +#define PREFIX_MAX 48 +#else +#define PREFIX_MAX 32 +#endif + +/* the maximum size of a formatted record (i.e. with prefix added per line) */ +#define CONSOLE_LOG_MAX 1024 + +/* the maximum size of a formatted extended record */ +#define CONSOLE_EXT_LOG_MAX 8192 + +/* the maximum size for a dropped text message */ +#define DROPPED_TEXT_MAX 64 + +/* the maximum size allowed to be reserved for a record */ +#define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX) + /* Flags for a single printk record. */ enum printk_info_flags { LOG_NEWLINE = 2, /* text ended with a newline */ @@ -48,6 +66,12 @@ u16 printk_parse_prefix(const char *text, int *level, enum printk_info_flags *flags); #else +#define PREFIX_MAX 0 +#define CONSOLE_LOG_MAX 0 +#define CONSOLE_EXT_LOG_MAX 0 +#define DROPPED_TEXT_MAX 0 +#define LOG_LINE_MAX 0 + /* * In !PRINTK builds we still export console_sem * semaphore and some of console functions (console_unlock()/etc.), so diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 7decf1e9c486..55bb065de65f 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -465,21 +465,6 @@ static struct latched_seq clear_seq = { .val[1] = 0, }; -#ifdef CONFIG_PRINTK_CALLER -#define PREFIX_MAX 48 -#else -#define PREFIX_MAX 32 -#endif - -/* the maximum size of a formatted record (i.e. with prefix added per line) */ -#define CONSOLE_LOG_MAX 1024 - -/* the maximum size for a dropped text message */ -#define DROPPED_TEXT_MAX 64 - -/* the maximum size allowed to be reserved for a record */ -#define LOG_LINE_MAX (CONSOLE_LOG_MAX - PREFIX_MAX) - #define LOG_LEVEL(v) ((v) & 0x07) #define LOG_FACILITY(v) ((v) >> 3 & 0xff) @@ -2387,8 +2372,6 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre #else /* CONFIG_PRINTK */ -#define CONSOLE_LOG_MAX 0 -#define DROPPED_TEXT_MAX 0 #define printk_time false #define prb_read_valid(rb, seq, r) false -- cgit v1.2.3 From 717a5651b10940ec827fe07acfb956d906250b2b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 9 Jan 2023 11:13:54 +0106 Subject: console: Use BIT() macros for @flags values Rather than manually calculating powers of 2, use the BIT() macros. Also take this opportunatity to cleanup and restructure the value comments into proper kerneldoc comments. Signed-off-by: Thomas Gleixner Signed-off-by: John Ogness Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230109100800.1085541-3-john.ogness@linutronix.de --- include/linux/console.h | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/linux/console.h b/include/linux/console.h index 9cea254b34b8..ed804dd7c2e8 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -15,6 +15,7 @@ #define _LINUX_CONSOLE_H_ 1 #include +#include #include #include @@ -125,18 +126,43 @@ static inline int con_debug_leave(void) /* * The interface for a console, or any other device that wants to capture * console messages (printer driver?) - * - * If a console driver is marked CON_BOOT then it will be auto-unregistered - * when the first real console is registered. This is for early-printk drivers. */ -#define CON_PRINTBUFFER (1) -#define CON_CONSDEV (2) /* Preferred console, /dev/console */ -#define CON_ENABLED (4) -#define CON_BOOT (8) -#define CON_ANYTIME (16) /* Safe to call when cpu is offline */ -#define CON_BRL (32) /* Used for a braille device */ -#define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */ +/** + * cons_flags - General console flags + * @CON_PRINTBUFFER: Used by newly registered consoles to avoid duplicate + * output of messages that were already shown by boot + * consoles or read by userspace via syslog() syscall. + * @CON_CONSDEV: Indicates that the console driver is backing + * /dev/console. + * @CON_ENABLED: Indicates if a console is allowed to print records. If + * false, the console also will not advance to later + * records. + * @CON_BOOT: Marks the console driver as early console driver which + * is used during boot before the real driver becomes + * available. It will be automatically unregistered + * when the real console driver is registered unless + * "keep_bootcon" parameter is used. + * @CON_ANYTIME: A misnomed historical flag which tells the core code + * that the legacy @console::write callback can be invoked + * on a CPU which is marked OFFLINE. That is misleading as + * it suggests that there is no contextual limit for + * invoking the callback. The original motivation was + * readiness of the per-CPU areas. + * @CON_BRL: Indicates a braille device which is exempt from + * receiving the printk spam for obvious reasons. + * @CON_EXTENDED: The console supports the extended output format of + * /dev/kmesg which requires a larger output buffer. + */ +enum cons_flags { + CON_PRINTBUFFER = BIT(0), + CON_CONSDEV = BIT(1), + CON_ENABLED = BIT(2), + CON_BOOT = BIT(3), + CON_ANYTIME = BIT(4), + CON_BRL = BIT(5), + CON_EXTENDED = BIT(6), +}; struct console { char name[16]; -- cgit v1.2.3 From 02b2396d7d0cf806e80c887b4c799d482d6977ed Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 9 Jan 2023 11:13:55 +0106 Subject: console: Document struct console Add kerneldoc comments to struct console. Signed-off-by: Thomas Gleixner Signed-off-by: John Ogness Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230109100800.1085541-4-john.ogness@linutronix.de --- include/linux/console.h | 54 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/linux/console.h b/include/linux/console.h index ed804dd7c2e8..1e36958aa656 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -164,24 +164,44 @@ enum cons_flags { CON_EXTENDED = BIT(6), }; +/** + * struct console - The console descriptor structure + * @name: The name of the console driver + * @write: Write callback to output messages (Optional) + * @read: Read callback for console input (Optional) + * @device: The underlying TTY device driver (Optional) + * @unblank: Callback to unblank the console (Optional) + * @setup: Callback for initializing the console (Optional) + * @exit: Callback for teardown of the console (Optional) + * @match: Callback for matching a console (Optional) + * @flags: Console flags. See enum cons_flags + * @index: Console index, e.g. port number + * @cflag: TTY control mode flags + * @ispeed: TTY input speed + * @ospeed: TTY output speed + * @seq: Sequence number of the next ringbuffer record to print + * @dropped: Number of unreported dropped ringbuffer records + * @data: Driver private data + * @node: hlist node for the console list + */ struct console { - char name[16]; - void (*write)(struct console *, const char *, unsigned); - int (*read)(struct console *, char *, unsigned); - struct tty_driver *(*device)(struct console *, int *); - void (*unblank)(void); - int (*setup)(struct console *, char *); - int (*exit)(struct console *); - int (*match)(struct console *, char *name, int idx, char *options); - short flags; - short index; - int cflag; - uint ispeed; - uint ospeed; - u64 seq; - unsigned long dropped; - void *data; - struct hlist_node node; + char name[16]; + void (*write)(struct console *co, const char *s, unsigned int count); + int (*read)(struct console *co, char *s, unsigned int count); + struct tty_driver *(*device)(struct console *co, int *index); + void (*unblank)(void); + int (*setup)(struct console *co, char *options); + int (*exit)(struct console *co); + int (*match)(struct console *co, char *name, int idx, char *options); + short flags; + short index; + int cflag; + uint ispeed; + uint ospeed; + u64 seq; + unsigned long dropped; + void *data; + struct hlist_node node; }; #ifdef CONFIG_LOCKDEP -- cgit v1.2.3 From 504fa212d7030fb1c042290dc2eb92b21515573a Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 28 Dec 2022 00:21:52 +0100 Subject: driver core: Make driver_deferred_probe_timeout a static variable It is not used outside of its compilation unit, so there's no need to export this variable. Signed-off-by: Javier Martinez Canillas Reviewed-by: Andrew Halaney Acked-by: John Stultz Link: https://lore.kernel.org/r/20221227232152.3094584-1-javierm@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 6 ++---- include/linux/device/driver.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index e9b2f9c25efe..69daf9d414eb 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -257,13 +257,11 @@ static int deferred_devs_show(struct seq_file *s, void *data) DEFINE_SHOW_ATTRIBUTE(deferred_devs); #ifdef CONFIG_MODULES -int driver_deferred_probe_timeout = 10; +static int driver_deferred_probe_timeout = 10; #else -int driver_deferred_probe_timeout; +static int driver_deferred_probe_timeout; #endif -EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout); - static int __init deferred_probe_timeout_setup(char *str) { int timeout; diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 2114d65b862f..50d0a416a5e7 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -240,7 +240,6 @@ driver_find_device_by_acpi_dev(struct device_driver *drv, const void *adev) } #endif -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 7a2b15cfa8dbbd54beb4e2ce7b2f42eb0ad00425 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 22 Dec 2022 03:19:32 +0800 Subject: f2fs: support accounting iostat count and avg_bytes Previously, we supported to account iostat io_bytes, in this patch, it adds to account iostat count and avg_bytes: time: 1671648667 io_bytes count avg_bytes [WRITE] app buffered data: 31 2 15 Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 7 +-- fs/f2fs/iostat.c | 129 ++++++++++++++++++++++---------------------- fs/f2fs/segment.c | 2 +- include/trace/events/f2fs.h | 2 +- 4 files changed, 69 insertions(+), 71 deletions(-) (limited to 'include') diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index c9c6ae966ba8..d4729f8af247 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1191,7 +1191,7 @@ enum iostat_type { FS_META_READ_IO, /* meta read IOs */ /* other */ - FS_DISCARD, /* discard */ + FS_DISCARD_IO, /* discard */ NR_IO_TYPE, }; @@ -1854,8 +1854,9 @@ struct f2fs_sb_info { #ifdef CONFIG_F2FS_IOSTAT /* For app/fs IO statistics */ spinlock_t iostat_lock; - unsigned long long rw_iostat[NR_IO_TYPE]; - unsigned long long prev_rw_iostat[NR_IO_TYPE]; + unsigned long long iostat_count[NR_IO_TYPE]; + unsigned long long iostat_bytes[NR_IO_TYPE]; + unsigned long long prev_iostat_bytes[NR_IO_TYPE]; bool iostat_enable; unsigned long iostat_next_period; unsigned int iostat_period_ms; diff --git a/fs/f2fs/iostat.c b/fs/f2fs/iostat.c index 3166a8939ed4..acf834c77291 100644 --- a/fs/f2fs/iostat.c +++ b/fs/f2fs/iostat.c @@ -18,79 +18,68 @@ static struct kmem_cache *bio_iostat_ctx_cache; static mempool_t *bio_iostat_ctx_pool; +static inline unsigned long long iostat_get_avg_bytes(struct f2fs_sb_info *sbi, + enum iostat_type type) +{ + return sbi->iostat_count[type] ? div64_u64(sbi->iostat_bytes[type], + sbi->iostat_count[type]) : 0; +} + +#define IOSTAT_INFO_SHOW(name, type) \ + seq_printf(seq, "%-23s %-16llu %-16llu %-16llu\n", \ + name":", sbi->iostat_bytes[type], \ + sbi->iostat_count[type], \ + iostat_get_avg_bytes(sbi, type)) + int __maybe_unused iostat_info_seq_show(struct seq_file *seq, void *offset) { struct super_block *sb = seq->private; struct f2fs_sb_info *sbi = F2FS_SB(sb); - time64_t now = ktime_get_real_seconds(); if (!sbi->iostat_enable) return 0; - seq_printf(seq, "time: %-16llu\n", now); + seq_printf(seq, "time: %-16llu\n", ktime_get_real_seconds()); + seq_printf(seq, "\t\t\t%-16s %-16s %-16s\n", + "io_bytes", "count", "avg_bytes"); /* print app write IOs */ seq_puts(seq, "[WRITE]\n"); - seq_printf(seq, "app buffered data: %-16llu\n", - sbi->rw_iostat[APP_BUFFERED_IO]); - seq_printf(seq, "app direct data: %-16llu\n", - sbi->rw_iostat[APP_DIRECT_IO]); - seq_printf(seq, "app mapped data: %-16llu\n", - sbi->rw_iostat[APP_MAPPED_IO]); - seq_printf(seq, "app buffered cdata: %-16llu\n", - sbi->rw_iostat[APP_BUFFERED_CDATA_IO]); - seq_printf(seq, "app mapped cdata: %-16llu\n", - sbi->rw_iostat[APP_MAPPED_CDATA_IO]); + IOSTAT_INFO_SHOW("app buffered data", APP_BUFFERED_IO); + IOSTAT_INFO_SHOW("app direct data", APP_DIRECT_IO); + IOSTAT_INFO_SHOW("app mapped data", APP_MAPPED_IO); + IOSTAT_INFO_SHOW("app buffered cdata", APP_BUFFERED_CDATA_IO); + IOSTAT_INFO_SHOW("app mapped cdata", APP_MAPPED_CDATA_IO); /* print fs write IOs */ - seq_printf(seq, "fs data: %-16llu\n", - sbi->rw_iostat[FS_DATA_IO]); - seq_printf(seq, "fs cdata: %-16llu\n", - sbi->rw_iostat[FS_CDATA_IO]); - seq_printf(seq, "fs node: %-16llu\n", - sbi->rw_iostat[FS_NODE_IO]); - seq_printf(seq, "fs meta: %-16llu\n", - sbi->rw_iostat[FS_META_IO]); - seq_printf(seq, "fs gc data: %-16llu\n", - sbi->rw_iostat[FS_GC_DATA_IO]); - seq_printf(seq, "fs gc node: %-16llu\n", - sbi->rw_iostat[FS_GC_NODE_IO]); - seq_printf(seq, "fs cp data: %-16llu\n", - sbi->rw_iostat[FS_CP_DATA_IO]); - seq_printf(seq, "fs cp node: %-16llu\n", - sbi->rw_iostat[FS_CP_NODE_IO]); - seq_printf(seq, "fs cp meta: %-16llu\n", - sbi->rw_iostat[FS_CP_META_IO]); + IOSTAT_INFO_SHOW("fs data", FS_DATA_IO); + IOSTAT_INFO_SHOW("fs cdata", FS_CDATA_IO); + IOSTAT_INFO_SHOW("fs node", FS_NODE_IO); + IOSTAT_INFO_SHOW("fs meta", FS_META_IO); + IOSTAT_INFO_SHOW("fs gc data", FS_GC_DATA_IO); + IOSTAT_INFO_SHOW("fs gc node", FS_GC_NODE_IO); + IOSTAT_INFO_SHOW("fs cp data", FS_CP_DATA_IO); + IOSTAT_INFO_SHOW("fs cp node", FS_CP_NODE_IO); + IOSTAT_INFO_SHOW("fs cp meta", FS_CP_META_IO); /* print app read IOs */ seq_puts(seq, "[READ]\n"); - seq_printf(seq, "app buffered data: %-16llu\n", - sbi->rw_iostat[APP_BUFFERED_READ_IO]); - seq_printf(seq, "app direct data: %-16llu\n", - sbi->rw_iostat[APP_DIRECT_READ_IO]); - seq_printf(seq, "app mapped data: %-16llu\n", - sbi->rw_iostat[APP_MAPPED_READ_IO]); - seq_printf(seq, "app buffered cdata: %-16llu\n", - sbi->rw_iostat[APP_BUFFERED_CDATA_READ_IO]); - seq_printf(seq, "app mapped cdata: %-16llu\n", - sbi->rw_iostat[APP_MAPPED_CDATA_READ_IO]); + IOSTAT_INFO_SHOW("app buffered data", APP_BUFFERED_READ_IO); + IOSTAT_INFO_SHOW("app direct data", APP_DIRECT_READ_IO); + IOSTAT_INFO_SHOW("app mapped data", APP_MAPPED_READ_IO); + IOSTAT_INFO_SHOW("app buffered cdata", APP_BUFFERED_CDATA_READ_IO); + IOSTAT_INFO_SHOW("app mapped cdata", APP_MAPPED_CDATA_READ_IO); /* print fs read IOs */ - seq_printf(seq, "fs data: %-16llu\n", - sbi->rw_iostat[FS_DATA_READ_IO]); - seq_printf(seq, "fs gc data: %-16llu\n", - sbi->rw_iostat[FS_GDATA_READ_IO]); - seq_printf(seq, "fs cdata: %-16llu\n", - sbi->rw_iostat[FS_CDATA_READ_IO]); - seq_printf(seq, "fs node: %-16llu\n", - sbi->rw_iostat[FS_NODE_READ_IO]); - seq_printf(seq, "fs meta: %-16llu\n", - sbi->rw_iostat[FS_META_READ_IO]); + IOSTAT_INFO_SHOW("fs data", FS_DATA_READ_IO); + IOSTAT_INFO_SHOW("fs gc data", FS_GDATA_READ_IO); + IOSTAT_INFO_SHOW("fs cdata", FS_CDATA_READ_IO); + IOSTAT_INFO_SHOW("fs node", FS_NODE_READ_IO); + IOSTAT_INFO_SHOW("fs meta", FS_META_READ_IO); /* print other IOs */ seq_puts(seq, "[OTHER]\n"); - seq_printf(seq, "fs discard: %-16llu\n", - sbi->rw_iostat[FS_DISCARD]); + IOSTAT_INFO_SHOW("fs discard", FS_DISCARD_IO); return 0; } @@ -141,9 +130,9 @@ static inline void f2fs_record_iostat(struct f2fs_sb_info *sbi) msecs_to_jiffies(sbi->iostat_period_ms); for (i = 0; i < NR_IO_TYPE; i++) { - iostat_diff[i] = sbi->rw_iostat[i] - - sbi->prev_rw_iostat[i]; - sbi->prev_rw_iostat[i] = sbi->rw_iostat[i]; + iostat_diff[i] = sbi->iostat_bytes[i] - + sbi->prev_iostat_bytes[i]; + sbi->prev_iostat_bytes[i] = sbi->iostat_bytes[i]; } spin_unlock_irqrestore(&sbi->iostat_lock, flags); @@ -159,8 +148,9 @@ void f2fs_reset_iostat(struct f2fs_sb_info *sbi) spin_lock_irq(&sbi->iostat_lock); for (i = 0; i < NR_IO_TYPE; i++) { - sbi->rw_iostat[i] = 0; - sbi->prev_rw_iostat[i] = 0; + sbi->iostat_count[i] = 0; + sbi->iostat_bytes[i] = 0; + sbi->prev_iostat_bytes[i] = 0; } spin_unlock_irq(&sbi->iostat_lock); @@ -169,6 +159,13 @@ void f2fs_reset_iostat(struct f2fs_sb_info *sbi) spin_unlock_irq(&sbi->iostat_lat_lock); } +static inline void __f2fs_update_iostat(struct f2fs_sb_info *sbi, + enum iostat_type type, unsigned long long io_bytes) +{ + sbi->iostat_bytes[type] += io_bytes; + sbi->iostat_count[type]++; +} + void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, enum iostat_type type, unsigned long long io_bytes) { @@ -178,33 +175,33 @@ void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, return; spin_lock_irqsave(&sbi->iostat_lock, flags); - sbi->rw_iostat[type] += io_bytes; + __f2fs_update_iostat(sbi, type, io_bytes); if (type == APP_BUFFERED_IO || type == APP_DIRECT_IO) - sbi->rw_iostat[APP_WRITE_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_WRITE_IO, io_bytes); if (type == APP_BUFFERED_READ_IO || type == APP_DIRECT_READ_IO) - sbi->rw_iostat[APP_READ_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_READ_IO, io_bytes); #ifdef CONFIG_F2FS_FS_COMPRESSION if (inode && f2fs_compressed_file(inode)) { if (type == APP_BUFFERED_IO) - sbi->rw_iostat[APP_BUFFERED_CDATA_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_BUFFERED_CDATA_IO, io_bytes); if (type == APP_BUFFERED_READ_IO) - sbi->rw_iostat[APP_BUFFERED_CDATA_READ_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_BUFFERED_CDATA_READ_IO, io_bytes); if (type == APP_MAPPED_READ_IO) - sbi->rw_iostat[APP_MAPPED_CDATA_READ_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_MAPPED_CDATA_READ_IO, io_bytes); if (type == APP_MAPPED_IO) - sbi->rw_iostat[APP_MAPPED_CDATA_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_MAPPED_CDATA_IO, io_bytes); if (type == FS_DATA_READ_IO) - sbi->rw_iostat[FS_CDATA_READ_IO] += io_bytes; + __f2fs_update_iostat(sbi, FS_CDATA_READ_IO, io_bytes); if (type == FS_DATA_IO) - sbi->rw_iostat[FS_CDATA_IO] += io_bytes; + __f2fs_update_iostat(sbi, FS_CDATA_IO, io_bytes); } #endif diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 8aafa1f32ecc..311243dda4ce 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1182,7 +1182,7 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, atomic_inc(&dcc->issued_discard); - f2fs_update_iostat(sbi, NULL, FS_DISCARD, len * F2FS_BLKSIZE); + f2fs_update_iostat(sbi, NULL, FS_DISCARD_IO, len * F2FS_BLKSIZE); lstart += len; start += len; diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 9183a0a11e26..3852085198fb 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -1972,7 +1972,7 @@ TRACE_EVENT(f2fs_iostat, __entry->fs_cdrio = iostat[FS_CDATA_READ_IO]; __entry->fs_nrio = iostat[FS_NODE_READ_IO]; __entry->fs_mrio = iostat[FS_META_READ_IO]; - __entry->fs_discard = iostat[FS_DISCARD]; + __entry->fs_discard = iostat[FS_DISCARD_IO]; ), TP_printk("dev = (%d,%d), " -- cgit v1.2.3 From 17cde5e601b165174e8a433b550f84f362731164 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 28 Nov 2022 17:06:42 -0400 Subject: genirq/msi: Add msi_device_has_isolated_msi() This will replace irq_domain_check_msi_remap() in following patches. The new API makes it more clear what "msi_remap" actually means from a functional perspective instead of identifying an implementation specific HW feature. Isolated MSI means that HW modeled by an irq_domain on the path from the initiating device to the CPU will validate that the MSI message specifies an interrupt number that the device is authorized to trigger. This must block devices from triggering interrupts they are not authorized to trigger. Currently authorization means the MSI vector is one assigned to the device. This is interesting for securing VFIO use cases where a rouge MSI (eg created by abusing a normal PCI MemWr DMA) must not allow the VFIO userspace to impact outside its security domain, eg userspace triggering interrupts on kernel drivers, a VM triggering interrupts on the hypervisor, or a VM triggering interrupts on another VM. As this is actually modeled as a per-irq_domain property, not a global platform property, correct the interface to accept the device parameter and scan through only the part of the irq_domains hierarchy originating from the source device. Locate the new code in msi.c as it naturally only works with CONFIG_GENERIC_MSI_IRQ, which also requires CONFIG_IRQ_DOMAIN and IRQ_DOMAIN_HIERARCHY. Link: https://lore.kernel.org/r/1-v3-3313bb5dd3a3+10f11-secure_msi_jgg@nvidia.com Tested-by: Matthew Rosato Reviewed-by: Kevin Tian Reviewed-by: Thomas Gleixner Signed-off-by: Jason Gunthorpe --- include/linux/msi.h | 13 +++++++++++++ kernel/irq/msi.c | 27 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'include') diff --git a/include/linux/msi.h b/include/linux/msi.h index a112b913fff9..e8a3f3a8a7f4 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -649,6 +649,19 @@ int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int vir void platform_msi_device_domain_free(struct irq_domain *domain, unsigned int virq, unsigned int nvec); void *platform_msi_get_host_data(struct irq_domain *domain); + +bool msi_device_has_isolated_msi(struct device *dev); +#else /* CONFIG_GENERIC_MSI_IRQ */ +static inline bool msi_device_has_isolated_msi(struct device *dev) +{ + /* + * Arguably if the platform does not enable MSI support then it has + * "isolated MSI", as an interrupt controller that cannot receive MSIs + * is inherently isolated by our definition. As nobody seems to needs + * this be conservative and return false anyhow. + */ + return false; +} #endif /* CONFIG_GENERIC_MSI_IRQ */ /* PCI specific interfaces */ diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 955267bbc2be..dfb5d40abac9 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -1623,3 +1623,30 @@ struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain) { return (struct msi_domain_info *)domain->host_data; } + +/** + * msi_device_has_isolated_msi - True if the device has isolated MSI + * @dev: The device to check + * + * Isolated MSI means that HW modeled by an irq_domain on the path from the + * initiating device to the CPU will validate that the MSI message specifies an + * interrupt number that the device is authorized to trigger. This must block + * devices from triggering interrupts they are not authorized to trigger. + * Currently authorization means the MSI vector is one assigned to the device. + * + * This is interesting for securing VFIO use cases where a rouge MSI (eg created + * by abusing a normal PCI MemWr DMA) must not allow the VFIO userspace to + * impact outside its security domain, eg userspace triggering interrupts on + * kernel drivers, a VM triggering interrupts on the hypervisor, or a VM + * triggering interrupts on another VM. + */ +bool msi_device_has_isolated_msi(struct device *dev) +{ + struct irq_domain *domain = dev_get_msi_domain(dev); + + for (; domain; domain = domain->parent) + if (domain->flags & IRQ_DOMAIN_FLAG_MSI_REMAP) + return true; + return false; +} +EXPORT_SYMBOL_GPL(msi_device_has_isolated_msi); -- cgit v1.2.3 From efc30a8f15a7981737297f9e9c62fb814d74e268 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 9 Dec 2022 13:23:08 -0400 Subject: iommu: Add iommu_group_has_isolated_msi() Compute the isolated_msi over all the devices in the IOMMU group because iommufd and vfio both need to know that the entire group is isolated before granting access to it. Link: https://lore.kernel.org/r/2-v3-3313bb5dd3a3+10f11-secure_msi_jgg@nvidia.com Tested-by: Matthew Rosato Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe --- drivers/iommu/iommu.c | 26 ++++++++++++++++++++++++++ include/linux/iommu.h | 1 + 2 files changed, 27 insertions(+) (limited to 'include') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index de91dd88705b..4c2199a493d8 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "dma-iommu.h" @@ -1897,6 +1898,31 @@ bool device_iommu_capable(struct device *dev, enum iommu_cap cap) } EXPORT_SYMBOL_GPL(device_iommu_capable); +/** + * iommu_group_has_isolated_msi() - Compute msi_device_has_isolated_msi() + * for a group + * @group: Group to query + * + * IOMMU groups should not have differing values of + * msi_device_has_isolated_msi() for devices in a group. However nothing + * directly prevents this, so ensure mistakes don't result in isolation failures + * by checking that all the devices are the same. + */ +bool iommu_group_has_isolated_msi(struct iommu_group *group) +{ + struct group_device *group_dev; + bool ret = true; + + mutex_lock(&group->mutex); + list_for_each_entry(group_dev, &group->devices, list) { + ret &= msi_device_has_isolated_msi(group_dev->dev) || + device_iommu_capable(group_dev->dev, IOMMU_CAP_INTR_REMAP); + } + mutex_unlock(&group->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(iommu_group_has_isolated_msi); + /** * iommu_set_fault_handler() - set a fault handler for an iommu domain * @domain: iommu domain diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 46e1347bfa22..9b7a9fa5ad28 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -455,6 +455,7 @@ static inline const struct iommu_ops *dev_iommu_ops(struct device *dev) extern int bus_iommu_probe(struct bus_type *bus); extern bool iommu_present(struct bus_type *bus); extern bool device_iommu_capable(struct device *dev, enum iommu_cap cap); +extern bool iommu_group_has_isolated_msi(struct iommu_group *group); extern struct iommu_domain *iommu_domain_alloc(struct bus_type *bus); extern struct iommu_group *iommu_group_get_by_id(int id); extern void iommu_domain_free(struct iommu_domain *domain); -- cgit v1.2.3 From a5e72a6bac14181249ffd04f35f6a7c9bf47fbb9 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 8 Dec 2022 10:51:02 -0400 Subject: genirq/irqdomain: Remove unused irq_domain_check_msi_remap() code After converting the users of irq_domain_check_msi_remap() it and the helpers are no longer needed. The new version does not require all the #ifdef helpers and inlines because CONFIG_GENERIC_MSI_IRQ always requires CONFIG_IRQ_DOMAIN and IRQ_DOMAIN_HIERARCHY. Link: https://lore.kernel.org/r/5-v3-3313bb5dd3a3+10f11-secure_msi_jgg@nvidia.com Tested-by: Matthew Rosato Reviewed-by: Kevin Tian Reviewed-by: Thomas Gleixner Signed-off-by: Jason Gunthorpe --- include/linux/irqdomain.h | 23 ----------------------- kernel/irq/irqdomain.c | 39 --------------------------------------- 2 files changed, 62 deletions(-) (limited to 'include') diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index a372086750ca..b04ce03d3bb6 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -276,7 +276,6 @@ struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode, void *host_data); extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, enum irq_domain_bus_token bus_token); -extern bool irq_domain_check_msi_remap(void); extern void irq_set_default_host(struct irq_domain *host); extern struct irq_domain *irq_get_default_host(void); extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, @@ -559,13 +558,6 @@ static inline bool irq_domain_is_msi(struct irq_domain *domain) return domain->flags & IRQ_DOMAIN_FLAG_MSI; } -static inline bool irq_domain_is_msi_remap(struct irq_domain *domain) -{ - return domain->flags & IRQ_DOMAIN_FLAG_MSI_REMAP; -} - -extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain); - static inline bool irq_domain_is_msi_parent(struct irq_domain *domain) { return domain->flags & IRQ_DOMAIN_FLAG_MSI_PARENT; @@ -611,17 +603,6 @@ static inline bool irq_domain_is_msi(struct irq_domain *domain) return false; } -static inline bool irq_domain_is_msi_remap(struct irq_domain *domain) -{ - return false; -} - -static inline bool -irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain) -{ - return false; -} - static inline bool irq_domain_is_msi_parent(struct irq_domain *domain) { return false; @@ -641,10 +622,6 @@ static inline struct irq_domain *irq_find_matching_fwnode( { return NULL; } -static inline bool irq_domain_check_msi_remap(void) -{ - return false; -} #endif /* !CONFIG_IRQ_DOMAIN */ #endif /* _LINUX_IRQDOMAIN_H */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8fe1da9614ee..104954951582 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -436,31 +436,6 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, } EXPORT_SYMBOL_GPL(irq_find_matching_fwspec); -/** - * irq_domain_check_msi_remap - Check whether all MSI irq domains implement - * IRQ remapping - * - * Return: false if any MSI irq domain does not support IRQ remapping, - * true otherwise (including if there is no MSI irq domain) - */ -bool irq_domain_check_msi_remap(void) -{ - struct irq_domain *h; - bool ret = true; - - mutex_lock(&irq_domain_mutex); - list_for_each_entry(h, &irq_domain_list, link) { - if (irq_domain_is_msi(h) && - !irq_domain_hierarchical_is_msi_remap(h)) { - ret = false; - break; - } - } - mutex_unlock(&irq_domain_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(irq_domain_check_msi_remap); - /** * irq_set_default_host() - Set a "default" irq domain * @domain: default domain pointer @@ -1815,20 +1790,6 @@ static void irq_domain_check_hierarchy(struct irq_domain *domain) if (domain->ops->alloc) domain->flags |= IRQ_DOMAIN_FLAG_HIERARCHY; } - -/** - * irq_domain_hierarchical_is_msi_remap - Check if the domain or any - * parent has MSI remapping support - * @domain: domain pointer - */ -bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain) -{ - for (; domain; domain = domain->parent) { - if (irq_domain_is_msi_remap(domain)) - return true; - } - return false; -} #else /* CONFIG_IRQ_DOMAIN_HIERARCHY */ /** * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain -- cgit v1.2.3 From dcb83f6ec1bf08a44b3f19719b56e8dc18058ff5 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 28 Nov 2022 20:12:43 -0400 Subject: genirq/msi: Rename IRQ_DOMAIN_MSI_REMAP to IRQ_DOMAIN_ISOLATED_MSI What x86 calls "interrupt remapping" is one way to achieve isolated MSI, make it clear this is talking about isolated MSI, no matter how it is achieved. This matches the new driver facing API name of msi_device_has_isolated_msi() No functional change. Link: https://lore.kernel.org/r/6-v3-3313bb5dd3a3+10f11-secure_msi_jgg@nvidia.com Tested-by: Matthew Rosato Reviewed-by: Kevin Tian Reviewed-by: Thomas Gleixner Signed-off-by: Jason Gunthorpe --- drivers/irqchip/irq-gic-v3-its.c | 4 ++-- include/linux/irqdomain.h | 6 ++++-- kernel/irq/msi.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 973ede0197e3..b4069f825a9b 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -4692,7 +4692,7 @@ static bool __maybe_unused its_enable_quirk_socionext_synquacer(void *data) } /* the pre-ITS breaks isolation, so disable MSI remapping */ - its->msi_domain_flags &= ~IRQ_DOMAIN_FLAG_MSI_REMAP; + its->msi_domain_flags &= ~IRQ_DOMAIN_FLAG_ISOLATED_MSI; return true; } return false; @@ -5074,7 +5074,7 @@ static int __init its_probe_one(struct resource *res, its->cmd_write = its->cmd_base; its->fwnode_handle = handle; its->get_msi_base = its_irq_get_msi_base; - its->msi_domain_flags = IRQ_DOMAIN_FLAG_MSI_REMAP; + its->msi_domain_flags = IRQ_DOMAIN_FLAG_ISOLATED_MSI; its_enable_quirks(its); diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index b04ce03d3bb6..0a3e974b7288 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -192,8 +192,10 @@ enum { /* Irq domain implements MSIs */ IRQ_DOMAIN_FLAG_MSI = (1 << 4), - /* Irq domain implements MSI remapping */ - IRQ_DOMAIN_FLAG_MSI_REMAP = (1 << 5), + /* + * Irq domain implements isolated MSI, see msi_device_has_isolated_msi() + */ + IRQ_DOMAIN_FLAG_ISOLATED_MSI = (1 << 5), /* Irq domain doesn't translate anything */ IRQ_DOMAIN_FLAG_NO_MAP = (1 << 6), diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index dfb5d40abac9..ac5e224a11b9 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -1645,7 +1645,7 @@ bool msi_device_has_isolated_msi(struct device *dev) struct irq_domain *domain = dev_get_msi_domain(dev); for (; domain; domain = domain->parent) - if (domain->flags & IRQ_DOMAIN_FLAG_MSI_REMAP) + if (domain->flags & IRQ_DOMAIN_FLAG_ISOLATED_MSI) return true; return false; } -- cgit v1.2.3 From bf210f793937a634bae6eda6a6d699c00b2b53d9 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 28 Nov 2022 20:31:57 -0400 Subject: irq/s390: Add arch_is_isolated_msi() for s390 s390 doesn't use irq_domains, so it has no place to set IRQ_DOMAIN_FLAG_ISOLATED_MSI. Instead of continuing to abuse the iommu subsystem to convey this information add a simple define which s390 can make statically true. The define will cause msi_device_has_isolated() to return true. Remove IOMMU_CAP_INTR_REMAP from the s390 iommu driver. Link: https://lore.kernel.org/r/8-v3-3313bb5dd3a3+10f11-secure_msi_jgg@nvidia.com Reviewed-by: Matthew Rosato Tested-by: Matthew Rosato Reviewed-by: Kevin Tian Signed-off-by: Jason Gunthorpe --- arch/s390/include/asm/msi.h | 17 +++++++++++++++++ drivers/iommu/s390-iommu.c | 2 -- include/linux/msi.h | 10 +++++++--- kernel/irq/msi.c | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 arch/s390/include/asm/msi.h (limited to 'include') diff --git a/arch/s390/include/asm/msi.h b/arch/s390/include/asm/msi.h new file mode 100644 index 000000000000..399343ed9ffb --- /dev/null +++ b/arch/s390/include/asm/msi.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_MSI_H +#define _ASM_S390_MSI_H +#include + +/* + * Work around S390 not using irq_domain at all so we can't set + * IRQ_DOMAIN_FLAG_ISOLATED_MSI. See for an explanation how it works: + * + * https://lore.kernel.org/r/31af8174-35e9-ebeb-b9ef-74c90d4bfd93@linux.ibm.com/ + * + * Note this is less isolated than the ARM/x86 versions as userspace can trigger + * MSI belonging to kernel devices within the same gisa. + */ +#define arch_is_isolated_msi() true + +#endif diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index ed33c6cce083..bb00580a30d8 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -34,8 +34,6 @@ static bool s390_iommu_capable(struct device *dev, enum iommu_cap cap) switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: return true; - case IOMMU_CAP_INTR_REMAP: - return true; default: return false; } diff --git a/include/linux/msi.h b/include/linux/msi.h index e8a3f3a8a7f4..13c9b74a4575 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -48,6 +48,10 @@ typedef struct arch_msi_msg_data { } __attribute__ ((packed)) arch_msi_msg_data_t; #endif +#ifndef arch_is_isolated_msi +#define arch_is_isolated_msi() false +#endif + /** * msi_msg - Representation of a MSI message * @address_lo: Low 32 bits of msi message address @@ -657,10 +661,10 @@ static inline bool msi_device_has_isolated_msi(struct device *dev) /* * Arguably if the platform does not enable MSI support then it has * "isolated MSI", as an interrupt controller that cannot receive MSIs - * is inherently isolated by our definition. As nobody seems to needs - * this be conservative and return false anyhow. + * is inherently isolated by our definition. The default definition for + * arch_is_isolated_msi() is conservative and returns false anyhow. */ - return false; + return arch_is_isolated_msi(); } #endif /* CONFIG_GENERIC_MSI_IRQ */ diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index ac5e224a11b9..4dec57fc4ea6 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -1647,6 +1647,6 @@ bool msi_device_has_isolated_msi(struct device *dev) for (; domain; domain = domain->parent) if (domain->flags & IRQ_DOMAIN_FLAG_ISOLATED_MSI) return true; - return false; + return arch_is_isolated_msi(); } EXPORT_SYMBOL_GPL(msi_device_has_isolated_msi); -- cgit v1.2.3 From b062007c63eb4452f1122384e86d402531fb1d52 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 28 Nov 2022 20:34:32 -0400 Subject: iommu: Remove IOMMU_CAP_INTR_REMAP No iommu driver implements this any more, get rid of it. Link: https://lore.kernel.org/r/9-v3-3313bb5dd3a3+10f11-secure_msi_jgg@nvidia.com Tested-by: Matthew Rosato Reviewed-by: Kevin Tian Reviewed-by: Lu Baolu Signed-off-by: Jason Gunthorpe --- drivers/iommu/iommu.c | 6 ++---- include/linux/iommu.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 4c2199a493d8..834e6ecf3e51 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1914,10 +1914,8 @@ bool iommu_group_has_isolated_msi(struct iommu_group *group) bool ret = true; mutex_lock(&group->mutex); - list_for_each_entry(group_dev, &group->devices, list) { - ret &= msi_device_has_isolated_msi(group_dev->dev) || - device_iommu_capable(group_dev->dev, IOMMU_CAP_INTR_REMAP); - } + list_for_each_entry(group_dev, &group->devices, list) + ret &= msi_device_has_isolated_msi(group_dev->dev); mutex_unlock(&group->mutex); return ret; } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 9b7a9fa5ad28..933cc57bfc48 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -120,7 +120,6 @@ static inline bool iommu_is_dma_domain(struct iommu_domain *domain) enum iommu_cap { IOMMU_CAP_CACHE_COHERENCY, /* IOMMU_CACHE is supported */ - IOMMU_CAP_INTR_REMAP, /* IOMMU supports interrupt isolation */ IOMMU_CAP_NOEXEC, /* IOMMU_NOEXEC flag */ IOMMU_CAP_PRE_BOOT_PROTECTION, /* Firmware says it used the IOMMU for DMA protection and we should too */ -- cgit v1.2.3 From c2c38c573a2e6184f9acd10e98305d3cb5f1c62b Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 22 Dec 2022 19:39:56 +0530 Subject: scsi: ufs: core: Add reinit_notify() callback reinit_notify() callback can be used by the UFS controller drivers to perform changes required for UFSHCD reinit that can happen during max gear switch. Tested-by: Andrew Halaney # Qdrive3/sa8540p-ride Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd-priv.h | 6 ++++++ include/ufs/ufshcd.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index c52e2f349aaa..8fff72e63e36 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -223,6 +223,12 @@ static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba, hba->vops->config_scaling_param(hba, p, data); } +static inline void ufshcd_vops_reinit_notify(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->reinit_notify) + hba->vops->reinit_notify(hba); +} + extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[]; /** diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index dd5912b4db77..97f007d3b851 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -298,6 +298,7 @@ struct ufs_pwr_mode_info { * @config_scaling_param: called to configure clock scaling parameters * @program_key: program or evict an inline encryption key * @event_notify: called to notify important events + * @reinit_notify: called to notify reinit of UFSHCD during max gear switch */ struct ufs_hba_variant_ops { const char *name; @@ -336,6 +337,7 @@ struct ufs_hba_variant_ops { const union ufs_crypto_cfg_entry *cfg, int slot); void (*event_notify)(struct ufs_hba *hba, enum ufs_event_type evt, void *data); + void (*reinit_notify)(struct ufs_hba *); }; /* clock gating state */ -- cgit v1.2.3 From 96a7141da33207672d7a354c885d65af4f0f9b6c Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 22 Dec 2022 19:39:57 +0530 Subject: scsi: ufs: core: Add support for reinitializing the UFS device Some platforms like Qcom, requires the UFS device to be reinitialized after switching to maximum gear speed. So add support for that in UFS core by introducing a new quirk (UFSHCD_CAP_REINIT_AFTER_MAX_GEAR_SWITCH) and doing the reinitialization, if the quirk is enabled by the controller driver. Suggested-by: Can Guo Tested-by: Andrew Halaney # Qdrive3/sa8540p-ride Signed-off-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 63 +++++++++++++++++++++++++++++++++++------------ include/ufs/ufshcd.h | 6 +++++ 2 files changed, 53 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 99ca5b035028..0514669e03be 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8231,27 +8231,18 @@ out: return ret; } -/** - * ufshcd_probe_hba - probe hba to detect device and initialize it - * @hba: per-adapter instance - * @init_dev_params: whether or not to call ufshcd_device_params_init(). - * - * Execute link-startup and verify device initialization - */ -static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) +static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) { int ret; - unsigned long flags; - ktime_t start = ktime_get(); hba->ufshcd_state = UFSHCD_STATE_RESET; ret = ufshcd_link_startup(hba); if (ret) - goto out; + return ret; if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION) - goto out; + return ret; /* Debug counters initialization */ ufshcd_clear_dbg_ufs_stats(hba); @@ -8262,12 +8253,12 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) /* Verify device initialization by sending NOP OUT UPIU */ ret = ufshcd_verify_dev_init(hba); if (ret) - goto out; + return ret; /* Initiate UFS initialization, and waiting until completion */ ret = ufshcd_complete_dev_init(hba); if (ret) - goto out; + return ret; /* * Initialize UFS device parameters used by driver, these @@ -8276,7 +8267,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) if (init_dev_params) { ret = ufshcd_device_params_init(hba); if (ret) - goto out; + return ret; } ufshcd_tune_unipro_params(hba); @@ -8297,11 +8288,51 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) if (ret) { dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", __func__, ret); + return ret; + } + } + + return 0; +} + +/** + * ufshcd_probe_hba - probe hba to detect device and initialize it + * @hba: per-adapter instance + * @init_dev_params: whether or not to call ufshcd_device_params_init(). + * + * Execute link-startup and verify device initialization + */ +static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) +{ + ktime_t start = ktime_get(); + unsigned long flags; + int ret; + + ret = ufshcd_device_init(hba, init_dev_params); + if (ret) + goto out; + + if (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) { + /* Reset the device and controller before doing reinit */ + ufshcd_device_reset(hba); + ufshcd_hba_stop(hba); + ufshcd_vops_reinit_notify(hba); + ret = ufshcd_hba_enable(hba); + if (ret) { + dev_err(hba->dev, "Host controller enable failed\n"); + ufshcd_print_evt_hist(hba); + ufshcd_print_host_state(hba); goto out; } - ufshcd_print_pwr_info(hba); + + /* Reinit the device */ + ret = ufshcd_device_init(hba, init_dev_params); + if (ret) + goto out; } + ufshcd_print_pwr_info(hba); + /* * bActiveICCLevel is volatile for UFS device (as per latest v2.1 spec) * and for removable UFS card as well, hence always set the parameter. diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 97f007d3b851..ff138927676b 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -596,6 +596,12 @@ enum ufshcd_quirks { * auto-hibernate capability but it's FASTAUTO only. */ UFSHCD_QUIRK_HIBERN_FASTAUTO = 1 << 18, + + /* + * This quirk needs to be enabled if the host controller needs + * to reinit the device after switching to maximum gear. + */ + UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH = 1 << 19, }; enum ufshcd_caps { -- cgit v1.2.3 From f3e57da528127febae7eb03d9c87408d572b0fd8 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Sun, 8 Jan 2023 23:40:56 +0100 Subject: scsi: core: Fix invisible definition compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 'include/ufs/ufshcd.h' file, 'enum dma_data_direction' will be used, which is defined in linux/dma-direction.h, however, this header file is not included in ufshcd.h, thus causing the following compilation warning: "warning: ‘enum dma_data_direction’ declared inside parameter list will not be visible outside of this definition or declaration" Fix this warning by including 'linux/dma-direction.h'. Fixes: 6ff265fc5ef6 ("scsi: ufs: core: bsg: Add advanced RPMB support in ufs_bsg") Reported-by: Xiaosen He Reported-by: Bart Van Assche Signed-off-by: Bean Huo Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- include/ufs/ufshcd.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index ff138927676b..fc7373a1a15e 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From e2cb6e8db69e96c1514c2992e2d4fd6c8c1b8820 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Sun, 8 Jan 2023 23:40:57 +0100 Subject: scsi: ufs: core: bsg: Fix cast to restricted __be16 warning Fix the following sparse endianness warning: "sparse warnings: drivers/ufs/core/ufs_bsg.c:91:25: sparse: sparse: cast to restricted __be16." For consistency with endianness annotations of other UFS data structures, change __u16/32 to __be16/32 in UFS ARPMB data structures. Fixes: 6ff265fc5ef6 ("scsi: ufs: core: bsg: Add advanced RPMB support in ufs_bsg") Reported-by: kernel test robot Signed-off-by: Bean Huo Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- include/uapi/scsi/scsi_bsg_ufs.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index 276e2772328f..2801b65299aa 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -97,18 +97,18 @@ struct utp_upiu_req { }; struct ufs_arpmb_meta { - __u16 req_resp_type; + __be16 req_resp_type; __u8 nonce[16]; - __u32 write_counter; - __u16 addr_lun; - __u16 block_count; - __u16 result; + __be32 write_counter; + __be16 addr_lun; + __be16 block_count; + __be16 result; } __attribute__((__packed__)); struct ufs_ehs { __u8 length; __u8 ehs_type; - __u16 ehssub_type; + __be16 ehssub_type; struct ufs_arpmb_meta meta; __u8 mac_key[32]; } __attribute__((__packed__)); -- cgit v1.2.3 From 0d7bb85e941327064c1f33128af563fac6cb9be3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 29 Sep 2022 15:38:56 +0200 Subject: ARM: omap1: remove unused board files All board support that was marked as 'unused' earlier can now be removed, leaving the five machines that that still had someone using them in 2022, or that are supported in qemu. Cc: Aaro Koskinen Cc: Janusz Krzysztofik Cc: Tony Lindgren Cc: linux-omap@vger.kernel.org Signed-off-by: Arnd Bergmann --- MAINTAINERS | 2 - arch/arm/Kconfig.debug | 36 +- arch/arm/configs/omap1_defconfig | 2 - arch/arm/mach-omap1/Kconfig | 91 ----- arch/arm/mach-omap1/Makefile | 18 - arch/arm/mach-omap1/board-fsample.c | 366 -------------------- arch/arm/mach-omap1/board-generic.c | 85 ----- arch/arm/mach-omap1/board-h2-mmc.c | 74 ---- arch/arm/mach-omap1/board-h2.c | 448 ------------------------ arch/arm/mach-omap1/board-h2.h | 38 --- arch/arm/mach-omap1/board-h3-mmc.c | 64 ---- arch/arm/mach-omap1/board-h3.c | 455 ------------------------- arch/arm/mach-omap1/board-h3.h | 35 -- arch/arm/mach-omap1/board-htcherald.c | 585 -------------------------------- arch/arm/mach-omap1/board-innovator.c | 481 -------------------------- arch/arm/mach-omap1/board-nand.c | 33 -- arch/arm/mach-omap1/board-palmtt.c | 285 ---------------- arch/arm/mach-omap1/board-palmz71.c | 300 ---------------- arch/arm/mach-omap1/board-perseus2.c | 333 ------------------ arch/arm/mach-omap1/fpga.c | 186 ---------- arch/arm/mach-omap1/fpga.h | 49 --- arch/arm/mach-omap1/gpio7xx.c | 272 --------------- drivers/i2c/busses/Kconfig | 2 +- drivers/mfd/Kconfig | 2 +- drivers/mmc/host/Kconfig | 2 +- drivers/usb/gadget/udc/Kconfig | 1 - drivers/usb/host/Kconfig | 1 - include/linux/platform_data/leds-omap.h | 19 -- 28 files changed, 9 insertions(+), 4256 deletions(-) delete mode 100644 arch/arm/mach-omap1/board-fsample.c delete mode 100644 arch/arm/mach-omap1/board-generic.c delete mode 100644 arch/arm/mach-omap1/board-h2-mmc.c delete mode 100644 arch/arm/mach-omap1/board-h2.c delete mode 100644 arch/arm/mach-omap1/board-h2.h delete mode 100644 arch/arm/mach-omap1/board-h3-mmc.c delete mode 100644 arch/arm/mach-omap1/board-h3.c delete mode 100644 arch/arm/mach-omap1/board-h3.h delete mode 100644 arch/arm/mach-omap1/board-htcherald.c delete mode 100644 arch/arm/mach-omap1/board-innovator.c delete mode 100644 arch/arm/mach-omap1/board-nand.c delete mode 100644 arch/arm/mach-omap1/board-palmtt.c delete mode 100644 arch/arm/mach-omap1/board-palmz71.c delete mode 100644 arch/arm/mach-omap1/board-perseus2.c delete mode 100644 arch/arm/mach-omap1/fpga.c delete mode 100644 arch/arm/mach-omap1/fpga.h delete mode 100644 arch/arm/mach-omap1/gpio7xx.c delete mode 100644 include/linux/platform_data/leds-omap.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index 570ac3442b5d..5d323d8c626e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15263,7 +15263,6 @@ Q: http://patchwork.kernel.org/project/linux-omap/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git F: arch/arm/configs/omap1_defconfig F: arch/arm/mach-omap1/ -F: arch/arm/plat-omap/ F: drivers/i2c/busses/i2c-omap.c F: include/linux/platform_data/ams-delta-fiq.h F: include/linux/platform_data/i2c-omap.h @@ -15278,7 +15277,6 @@ Q: http://patchwork.kernel.org/project/linux-omap/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git F: arch/arm/configs/omap2plus_defconfig F: arch/arm/mach-omap2/ -F: arch/arm/plat-omap/ F: drivers/bus/ti-sysc.c F: drivers/i2c/busses/i2c-omap.c F: drivers/irqchip/irq-omap-intc.c diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 320c93fabb21..c03fd448c59e 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -760,30 +760,6 @@ choice depends on ARCH_OMAP2PLUS select DEBUG_UART_8250 - config DEBUG_OMAP7XXUART1 - bool "Kernel low-level debugging via OMAP730 UART1" - depends on ARCH_OMAP730 - select DEBUG_UART_8250 - help - Say Y here if you want kernel low-level debugging support - on OMAP730 based platforms on the UART1. - - config DEBUG_OMAP7XXUART2 - bool "Kernel low-level debugging via OMAP730 UART2" - depends on ARCH_OMAP730 - select DEBUG_UART_8250 - help - Say Y here if you want kernel low-level debugging support - on OMAP730 based platforms on the UART2. - - config DEBUG_OMAP7XXUART3 - bool "Kernel low-level debugging via OMAP730 UART3" - depends on ARCH_OMAP730 - select DEBUG_UART_8250 - help - Say Y here if you want kernel low-level debugging support - on OMAP730 based platforms on the UART3. - config DEBUG_TI81XXUART1 bool "Kernel low-level debugging messages via TI81XX UART1 (ti8148evm)" depends on ARCH_OMAP2PLUS @@ -1728,9 +1704,9 @@ config DEBUG_UART_PHYS default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0 default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2 default 0xfff36000 if DEBUG_HIGHBANK_UART - default 0xfffb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 - default 0xfffb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 - default 0xfffb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3 + default 0xfffb0000 if DEBUG_OMAP1UART1 + default 0xfffb0800 if DEBUG_OMAP1UART2 + default 0xfffb9800 if DEBUG_OMAP1UART3 default 0xfffe8600 if DEBUG_BCM63XX_UART default 0xffffee00 if DEBUG_AT91_SAM9263_DBGU default 0xfffff200 if DEBUG_AT91_RM9200_DBGU @@ -1847,9 +1823,9 @@ config DEBUG_UART_VIRT default 0xfec00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN default 0xfec00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN default 0xfef36000 if DEBUG_HIGHBANK_UART - default 0xff0b0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 - default 0xff0b0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 - default 0xff0b9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3 + default 0xff0b0000 if DEBUG_OMAP1UART1 + default 0xff0b0800 if DEBUG_OMAP1UART2 + default 0xff0b9800 if DEBUG_OMAP1UART3 default 0xffd01000 if DEBUG_HIP01_UART default DEBUG_UART_PHYS if !MMU depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index 246f1bba7df5..53dd0717cea5 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -20,8 +20,6 @@ CONFIG_ARCH_OMAP=y CONFIG_ARCH_OMAP1=y CONFIG_OMAP_32K_TIMER=y CONFIG_OMAP_DM_TIMER=y -CONFIG_ARCH_OMAP730=y -CONFIG_ARCH_OMAP850=y CONFIG_ARCH_OMAP16XX=y # CONFIG_OMAP_MUX is not set CONFIG_OMAP_RESET_CLOCKS=y diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 7ec7ada287e0..03b0ba2e8653 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -19,19 +19,6 @@ menu "TI OMAP1 specific features" comment "OMAP Core Type" -config ARCH_OMAP730 - depends on ARCH_MULTI_V5 - bool "OMAP730 Based System" - select ARCH_OMAP_OTG - select CPU_ARM926T - select OMAP_MPU_TIMER - -config ARCH_OMAP850 - depends on ARCH_MULTI_V5 - bool "OMAP850 Based System" - select ARCH_OMAP_OTG - select CPU_ARM926T - config ARCH_OMAP15XX depends on ARCH_MULTI_V4T default y @@ -126,37 +113,6 @@ config ARCH_OMAP_OTG comment "OMAP Board Type" -config MACH_OMAP_INNOVATOR - bool "TI Innovator" - depends on ARCH_OMAP15XX || ARCH_OMAP16XX - depends on UNUSED_BOARD_FILES - help - TI OMAP 1510 or 1610 Innovator board support. Say Y here if you - have such a board. - -config MACH_OMAP_H2 - bool "TI H2 Support" - depends on ARCH_OMAP16XX - depends on UNUSED_BOARD_FILES - help - TI OMAP 1610/1611B H2 board support. Say Y here if you have such - a board. - -config MACH_OMAP_H3 - bool "TI H3 Support" - depends on ARCH_OMAP16XX - depends on UNUSED_BOARD_FILES - help - TI OMAP 1710 H3 board support. Say Y here if you have such - a board. - -config MACH_HERALD - bool "HTC Herald" - depends on ARCH_OMAP850 - depends on UNUSED_BOARD_FILES - help - HTC Herald smartphone support (AKA T-Mobile Wing, ...) - config MACH_OMAP_OSK bool "TI OSK Support" depends on ARCH_OMAP16XX @@ -167,28 +123,11 @@ config MACH_OMAP_OSK config OMAP_OSK_MISTRAL bool "Mistral QVGA board Support" depends on MACH_OMAP_OSK - depends on UNUSED_BOARD_FILES help The OSK supports an optional add-on board with a Quarter-VGA touchscreen, PDA-ish buttons, a resume button, bicolor LED, and camera connector. Say Y here if you have this board. -config MACH_OMAP_PERSEUS2 - bool "TI Perseus2" - depends on ARCH_OMAP730 - depends on UNUSED_BOARD_FILES - help - Support for TI OMAP 730 Perseus2 board. Say Y here if you have such - a board. - -config MACH_OMAP_FSAMPLE - bool "TI F-Sample" - depends on ARCH_OMAP730 - depends on UNUSED_BOARD_FILES - help - Support for TI OMAP 850 F-Sample board. Say Y here if you have such - a board. - config MACH_OMAP_PALMTE bool "Palm Tungsten E" depends on ARCH_OMAP15XX @@ -198,26 +137,6 @@ config MACH_OMAP_PALMTE http://palmtelinux.sourceforge.net/ for more information. Say Y here if you have this PDA model, say N otherwise. -config MACH_OMAP_PALMZ71 - bool "Palm Zire71" - depends on ARCH_OMAP15XX - depends on UNUSED_BOARD_FILES - help - Support for the Palm Zire71 PDA. To boot the kernel, - you'll need a PalmOS compatible bootloader; check out - http://hackndev.com/palm/z71 for more information. - Say Y here if you have such a PDA, say N otherwise. - -config MACH_OMAP_PALMTT - bool "Palm Tungsten|T" - depends on ARCH_OMAP15XX - depends on UNUSED_BOARD_FILES - help - Support for the Palm Tungsten|T PDA. To boot the kernel, you'll - need a PalmOS compatible bootloader (Garux); check out - http://garux.sourceforge.net/ for more information. - Say Y here if you have this PDA model, say N otherwise. - config MACH_SX1 bool "Siemens SX1" depends on ARCH_OMAP15XX @@ -249,16 +168,6 @@ config MACH_AMS_DELTA Support for the Amstrad E3 (codename Delta) videophone. Say Y here if you have such a device. -config MACH_OMAP_GENERIC - bool "Generic OMAP board" - depends on ARCH_OMAP15XX || ARCH_OMAP16XX - depends on UNUSED_BOARD_FILES - help - Support for generic OMAP-1510, 1610 or 1710 board with - no FPGA. Can be used as template for porting Linux to - custom OMAP boards. Say Y here if you have a custom - board. - endmenu endif diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 0615cb0ba580..d9e251ea4773 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -29,31 +29,13 @@ usb-fs-$(CONFIG_USB_SUPPORT) := usb.o obj-y += $(usb-fs-m) $(usb-fs-y) # Specific board support -obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o board-h2-mmc.o \ - board-nand.o -obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o -obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o -obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o board-nand.o -obj-$(CONFIG_MACH_OMAP_FSAMPLE) += board-fsample.o board-nand.o obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o -obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o board-h3-mmc.o \ - board-nand.o obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o -obj-$(CONFIG_MACH_OMAP_PALMZ71) += board-palmz71.o -obj-$(CONFIG_MACH_OMAP_PALMTT) += board-palmtt.o obj-$(CONFIG_MACH_NOKIA770) += board-nokia770.o obj-$(CONFIG_MACH_AMS_DELTA) += board-ams-delta.o ams-delta-fiq.o \ ams-delta-fiq-handler.o obj-$(CONFIG_MACH_SX1) += board-sx1.o board-sx1-mmc.o -obj-$(CONFIG_MACH_HERALD) += board-htcherald.o - -ifeq ($(CONFIG_ARCH_OMAP15XX),y) -# Innovator-1510 FPGA -obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o -endif # GPIO -obj-$(CONFIG_ARCH_OMAP730) += gpio7xx.o -obj-$(CONFIG_ARCH_OMAP850) += gpio7xx.o obj-$(CONFIG_ARCH_OMAP15XX) += gpio15xx.o obj-$(CONFIG_ARCH_OMAP16XX) += gpio16xx.o diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c deleted file mode 100644 index f21e15c7b973..000000000000 --- a/arch/arm/mach-omap1/board-fsample.c +++ /dev/null @@ -1,366 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-fsample.c - * - * Modified from board-perseus2.c - * - * Original OMAP730 support by Jean Pihet - * Updated for 2.6 by Kevin Hilman - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include "tc.h" - -#include "mux.h" -#include "flash.h" -#include "hardware.h" -#include "iomap.h" -#include "common.h" -#include "fpga.h" - -/* fsample is pretty close to p2-sample */ - -#define fsample_cpld_read(reg) __raw_readb(reg) -#define fsample_cpld_write(val, reg) __raw_writeb(val, reg) - -#define FSAMPLE_CPLD_BASE 0xE8100000 -#define FSAMPLE_CPLD_SIZE SZ_4K -#define FSAMPLE_CPLD_START 0x05080000 - -#define FSAMPLE_CPLD_REG_A (FSAMPLE_CPLD_BASE + 0x00) -#define FSAMPLE_CPLD_SWITCH (FSAMPLE_CPLD_BASE + 0x02) -#define FSAMPLE_CPLD_UART (FSAMPLE_CPLD_BASE + 0x02) -#define FSAMPLE_CPLD_REG_B (FSAMPLE_CPLD_BASE + 0x04) -#define FSAMPLE_CPLD_VERSION (FSAMPLE_CPLD_BASE + 0x06) -#define FSAMPLE_CPLD_SET_CLR (FSAMPLE_CPLD_BASE + 0x06) - -#define FSAMPLE_CPLD_BIT_BT_RESET 0 -#define FSAMPLE_CPLD_BIT_LCD_RESET 1 -#define FSAMPLE_CPLD_BIT_CAM_PWDN 2 -#define FSAMPLE_CPLD_BIT_CHARGER_ENABLE 3 -#define FSAMPLE_CPLD_BIT_SD_MMC_EN 4 -#define FSAMPLE_CPLD_BIT_aGPS_PWREN 5 -#define FSAMPLE_CPLD_BIT_BACKLIGHT 6 -#define FSAMPLE_CPLD_BIT_aGPS_EN_RESET 7 -#define FSAMPLE_CPLD_BIT_aGPS_SLEEPx_N 8 -#define FSAMPLE_CPLD_BIT_OTG_RESET 9 - -#define fsample_cpld_set(bit) \ - fsample_cpld_write((((bit) & 15) << 4) | 0x0f, FSAMPLE_CPLD_SET_CLR) - -#define fsample_cpld_clear(bit) \ - fsample_cpld_write(0xf0 | ((bit) & 15), FSAMPLE_CPLD_SET_CLR) - -static const unsigned int fsample_keymap[] = { - KEY(0, 0, KEY_UP), - KEY(1, 0, KEY_RIGHT), - KEY(2, 0, KEY_LEFT), - KEY(3, 0, KEY_DOWN), - KEY(4, 0, KEY_ENTER), - KEY(0, 1, KEY_F10), - KEY(1, 1, KEY_SEND), - KEY(2, 1, KEY_END), - KEY(3, 1, KEY_VOLUMEDOWN), - KEY(4, 1, KEY_VOLUMEUP), - KEY(5, 1, KEY_RECORD), - KEY(0, 2, KEY_F9), - KEY(1, 2, KEY_3), - KEY(2, 2, KEY_6), - KEY(3, 2, KEY_9), - KEY(4, 2, KEY_KPDOT), - KEY(0, 3, KEY_BACK), - KEY(1, 3, KEY_2), - KEY(2, 3, KEY_5), - KEY(3, 3, KEY_8), - KEY(4, 3, KEY_0), - KEY(5, 3, KEY_KPSLASH), - KEY(0, 4, KEY_HOME), - KEY(1, 4, KEY_1), - KEY(2, 4, KEY_4), - KEY(3, 4, KEY_7), - KEY(4, 4, KEY_KPASTERISK), - KEY(5, 4, KEY_POWER), -}; - -static struct smc91x_platdata smc91x_info = { - .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, - .leda = RPC_LED_100_10, - .ledb = RPC_LED_TX_RX, -}; - -static struct resource smc91x_resources[] = { - [0] = { - .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */ - .end = H2P2_DBG_FPGA_ETHR_START + 0xf, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = INT_7XX_MPU_EXT_NIRQ, - .end = 0, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, - }, -}; - -static void __init fsample_init_smc91x(void) -{ - __raw_writeb(1, H2P2_DBG_FPGA_LAN_RESET); - mdelay(50); - __raw_writeb(__raw_readb(H2P2_DBG_FPGA_LAN_RESET) & ~1, - H2P2_DBG_FPGA_LAN_RESET); - mdelay(50); -} - -static struct mtd_partition nor_partitions[] = { - /* bootloader (U-Boot, etc) in first sector */ - { - .name = "bootloader", - .offset = 0, - .size = SZ_128K, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - /* bootloader params in the next sector */ - { - .name = "params", - .offset = MTDPART_OFS_APPEND, - .size = SZ_128K, - .mask_flags = 0, - }, - /* kernel */ - { - .name = "kernel", - .offset = MTDPART_OFS_APPEND, - .size = SZ_2M, - .mask_flags = 0 - }, - /* rest of flash is a file system */ - { - .name = "rootfs", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - .mask_flags = 0 - }, -}; - -static struct physmap_flash_data nor_data = { - .width = 2, - .set_vpp = omap1_set_vpp, - .parts = nor_partitions, - .nr_parts = ARRAY_SIZE(nor_partitions), -}; - -static struct resource nor_resource = { - .start = OMAP_CS0_PHYS, - .end = OMAP_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device nor_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &nor_data, - }, - .num_resources = 1, - .resource = &nor_resource, -}; - -#define FSAMPLE_NAND_RB_GPIO_PIN 62 - -static int nand_dev_ready(struct nand_chip *chip) -{ - return gpio_get_value(FSAMPLE_NAND_RB_GPIO_PIN); -} - -static struct platform_nand_data nand_data = { - .chip = { - .nr_chips = 1, - .chip_offset = 0, - .options = NAND_SAMSUNG_LP_OPTIONS, - }, - .ctrl = { - .cmd_ctrl = omap1_nand_cmd_ctl, - .dev_ready = nand_dev_ready, - }, -}; - -static struct resource nand_resource = { - .start = OMAP_CS3_PHYS, - .end = OMAP_CS3_PHYS + SZ_4K - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device nand_device = { - .name = "gen_nand", - .id = 0, - .dev = { - .platform_data = &nand_data, - }, - .num_resources = 1, - .resource = &nand_resource, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .dev = { - .platform_data = &smc91x_info, - }, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -static struct resource kp_resources[] = { - [0] = { - .start = INT_7XX_MPUIO_KEYPAD, - .end = INT_7XX_MPUIO_KEYPAD, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct matrix_keymap_data fsample_keymap_data = { - .keymap = fsample_keymap, - .keymap_size = ARRAY_SIZE(fsample_keymap), -}; - -static struct omap_kp_platform_data kp_data = { - .rows = 8, - .cols = 8, - .keymap_data = &fsample_keymap_data, - .delay = 4, -}; - -static struct platform_device kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &kp_data, - }, - .num_resources = ARRAY_SIZE(kp_resources), - .resource = kp_resources, -}; - -static struct platform_device *devices[] __initdata = { - &nor_device, - &nand_device, - &smc91x_device, - &kp_device, -}; - -static const struct omap_lcd_config fsample_lcd_config = { - .ctrl_name = "internal", -}; - -static void __init omap_fsample_init(void) -{ - /* Early, board-dependent init */ - - /* - * Hold GSM Reset until needed - */ - omap_writew(omap_readw(OMAP7XX_DSP_M_CTL) & ~1, OMAP7XX_DSP_M_CTL); - - /* - * UARTs -> done automagically by 8250 driver - */ - - /* - * CSx timings, GPIO Mux ... setup - */ - - /* Flash: CS0 timings setup */ - omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_0); - omap_writel(0x00000088, OMAP7XX_FLASH_ACFG_0); - - /* - * Ethernet support through the debug board - * CS1 timings setup - */ - omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_1); - omap_writel(0x00000000, OMAP7XX_FLASH_ACFG_1); - - /* - * Configure MPU_EXT_NIRQ IO in IO_CONF9 register, - * It is used as the Ethernet controller interrupt - */ - omap_writel(omap_readl(OMAP7XX_IO_CONF_9) & 0x1FFFFFFF, - OMAP7XX_IO_CONF_9); - - fsample_init_smc91x(); - - BUG_ON(gpio_request(FSAMPLE_NAND_RB_GPIO_PIN, "NAND ready") < 0); - gpio_direction_input(FSAMPLE_NAND_RB_GPIO_PIN); - - omap_cfg_reg(L3_1610_FLASH_CS2B_OE); - omap_cfg_reg(M8_1610_FLASH_CS2B_WE); - - /* Mux pins for keypad */ - omap_cfg_reg(E2_7XX_KBR0); - omap_cfg_reg(J7_7XX_KBR1); - omap_cfg_reg(E1_7XX_KBR2); - omap_cfg_reg(F3_7XX_KBR3); - omap_cfg_reg(D2_7XX_KBR4); - omap_cfg_reg(C2_7XX_KBC0); - omap_cfg_reg(D3_7XX_KBC1); - omap_cfg_reg(E4_7XX_KBC2); - omap_cfg_reg(F4_7XX_KBC3); - omap_cfg_reg(E3_7XX_KBC4); - - platform_add_devices(devices, ARRAY_SIZE(devices)); - - omap_serial_init(); - omap_register_i2c_bus(1, 100, NULL, 0); - - omapfb_set_lcd_config(&fsample_lcd_config); -} - -/* Only FPGA needs to be mapped here. All others are done with ioremap */ -static struct map_desc omap_fsample_io_desc[] __initdata = { - { - .virtual = H2P2_DBG_FPGA_BASE, - .pfn = __phys_to_pfn(H2P2_DBG_FPGA_START), - .length = H2P2_DBG_FPGA_SIZE, - .type = MT_DEVICE - }, - { - .virtual = FSAMPLE_CPLD_BASE, - .pfn = __phys_to_pfn(FSAMPLE_CPLD_START), - .length = FSAMPLE_CPLD_SIZE, - .type = MT_DEVICE - } -}; - -static void __init omap_fsample_map_io(void) -{ - omap15xx_map_io(); - iotable_init(omap_fsample_io_desc, - ARRAY_SIZE(omap_fsample_io_desc)); -} - -MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample") -/* Maintainer: Brian Swetland */ - .atag_offset = 0x100, - .map_io = omap_fsample_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = omap_fsample_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c deleted file mode 100644 index 3b2bcaf4bb01..000000000000 --- a/arch/arm/mach-omap1/board-generic.c +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-generic.c - * - * Modified from board-innovator1510.c - * - * Code for generic OMAP board. Should work on many OMAP systems where - * the device drivers take care of all the necessary hardware initialization. - * Do not put any board specific code to this file; create a new machine - * type if you need custom low-level initializations. - */ -#include -#include -#include -#include - -#include -#include -#include - -#include "hardware.h" -#include "mux.h" -#include "usb.h" -#include "common.h" - -/* assume no Mini-AB port */ - -#ifdef CONFIG_ARCH_OMAP15XX -static struct omap_usb_config generic1510_usb_config __initdata = { - .register_host = 1, - .register_dev = 1, - .hmc_mode = 16, - .pins[0] = 3, -}; -#endif - -#if defined(CONFIG_ARCH_OMAP16XX) -static struct omap_usb_config generic1610_usb_config __initdata = { -#ifdef CONFIG_USB_OTG - .otg = 1, -#endif - .register_host = 1, - .register_dev = 1, - .hmc_mode = 16, - .pins[0] = 6, -}; -#endif - -static void __init omap_generic_init(void) -{ -#ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap15xx()) { - /* mux pins for uarts */ - omap_cfg_reg(UART1_TX); - omap_cfg_reg(UART1_RTS); - omap_cfg_reg(UART2_TX); - omap_cfg_reg(UART2_RTS); - omap_cfg_reg(UART3_TX); - omap_cfg_reg(UART3_RX); - - omap1_usb_init(&generic1510_usb_config); - } -#endif -#if defined(CONFIG_ARCH_OMAP16XX) - if (!cpu_is_omap1510()) { - omap1_usb_init(&generic1610_usb_config); - } -#endif - - omap_serial_init(); - omap_register_i2c_bus(1, 100, NULL, 0); -} - -MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710") - /* Maintainer: Tony Lindgren */ - .atag_offset = 0x100, - .map_io = omap16xx_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = omap_generic_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-h2-mmc.c b/arch/arm/mach-omap1/board-h2-mmc.c deleted file mode 100644 index 06c5404078aa..000000000000 --- a/arch/arm/mach-omap1/board-h2-mmc.c +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-h2-mmc.c - * - * Copyright (C) 2007 Instituto Nokia de Tecnologia - INdT - * Author: Felipe Balbi - * - * This code is based on linux/arch/arm/mach-omap2/board-n800-mmc.c, which is: - * Copyright (C) 2006 Nokia Corporation - */ -#include -#include -#include -#include - -#include "board-h2.h" -#include "mmc.h" - -#if IS_ENABLED(CONFIG_MMC_OMAP) - -static int mmc_set_power(struct device *dev, int slot, int power_on, - int vdd) -{ - gpio_set_value(H2_TPS_GPIO_MMC_PWR_EN, power_on); - return 0; -} - -static int mmc_late_init(struct device *dev) -{ - int ret = gpio_request(H2_TPS_GPIO_MMC_PWR_EN, "MMC power"); - if (ret < 0) - return ret; - - gpio_direction_output(H2_TPS_GPIO_MMC_PWR_EN, 0); - - return ret; -} - -static void mmc_cleanup(struct device *dev) -{ - gpio_free(H2_TPS_GPIO_MMC_PWR_EN); -} - -/* - * H2 could use the following functions tested: - * - mmc_get_cover_state that uses OMAP_MPUIO(1) - * - mmc_get_wp that uses OMAP_MPUIO(3) - */ -static struct omap_mmc_platform_data mmc1_data = { - .nr_slots = 1, - .init = mmc_late_init, - .cleanup = mmc_cleanup, - .slots[0] = { - .set_power = mmc_set_power, - .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, - .name = "mmcblk", - }, -}; - -static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC]; - -void __init h2_mmc_init(void) -{ - mmc_data[0] = &mmc1_data; - omap1_init_mmc(mmc_data, OMAP16XX_NR_MMC); -} - -#else - -void __init h2_mmc_init(void) -{ -} - -#endif diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c deleted file mode 100644 index f28a4c3ea501..000000000000 --- a/arch/arm/mach-omap1/board-h2.c +++ /dev/null @@ -1,448 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-h2.c - * - * Board specific inits for OMAP-1610 H2 - * - * Copyright (C) 2001 RidgeRun, Inc. - * Author: Greg Lonnon - * - * Copyright (C) 2002 MontaVista Software, Inc. - * - * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 - * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen - * - * H2 specific changes and cleanup - * Copyright (C) 2004 Nokia Corporation by Imre Deak - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "tc.h" -#include "mux.h" -#include "flash.h" -#include "hardware.h" -#include "usb.h" -#include "common.h" -#include "board-h2.h" - -/* The first 16 SoC GPIO lines are on this GPIO chip */ -#define OMAP_GPIO_LABEL "gpio-0-15" - -/* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */ -#define OMAP1610_ETHR_START 0x04000300 - -static const unsigned int h2_keymap[] = { - KEY(0, 0, KEY_LEFT), - KEY(1, 0, KEY_RIGHT), - KEY(2, 0, KEY_3), - KEY(3, 0, KEY_F10), - KEY(4, 0, KEY_F5), - KEY(5, 0, KEY_9), - KEY(0, 1, KEY_DOWN), - KEY(1, 1, KEY_UP), - KEY(2, 1, KEY_2), - KEY(3, 1, KEY_F9), - KEY(4, 1, KEY_F7), - KEY(5, 1, KEY_0), - KEY(0, 2, KEY_ENTER), - KEY(1, 2, KEY_6), - KEY(2, 2, KEY_1), - KEY(3, 2, KEY_F2), - KEY(4, 2, KEY_F6), - KEY(5, 2, KEY_HOME), - KEY(0, 3, KEY_8), - KEY(1, 3, KEY_5), - KEY(2, 3, KEY_F12), - KEY(3, 3, KEY_F3), - KEY(4, 3, KEY_F8), - KEY(5, 3, KEY_END), - KEY(0, 4, KEY_7), - KEY(1, 4, KEY_4), - KEY(2, 4, KEY_F11), - KEY(3, 4, KEY_F1), - KEY(4, 4, KEY_F4), - KEY(5, 4, KEY_ESC), - KEY(0, 5, KEY_F13), - KEY(1, 5, KEY_F14), - KEY(2, 5, KEY_F15), - KEY(3, 5, KEY_F16), - KEY(4, 5, KEY_SLEEP), -}; - -static struct mtd_partition h2_nor_partitions[] = { - /* bootloader (U-Boot, etc) in first sector */ - { - .name = "bootloader", - .offset = 0, - .size = SZ_128K, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - /* bootloader params in the next sector */ - { - .name = "params", - .offset = MTDPART_OFS_APPEND, - .size = SZ_128K, - .mask_flags = 0, - }, - /* kernel */ - { - .name = "kernel", - .offset = MTDPART_OFS_APPEND, - .size = SZ_2M, - .mask_flags = 0 - }, - /* file system */ - { - .name = "filesystem", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - .mask_flags = 0 - } -}; - -static struct physmap_flash_data h2_nor_data = { - .width = 2, - .set_vpp = omap1_set_vpp, - .parts = h2_nor_partitions, - .nr_parts = ARRAY_SIZE(h2_nor_partitions), -}; - -static struct resource h2_nor_resource = { - /* This is on CS3, wherever it's mapped */ - .flags = IORESOURCE_MEM, -}; - -static struct platform_device h2_nor_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &h2_nor_data, - }, - .num_resources = 1, - .resource = &h2_nor_resource, -}; - -static struct mtd_partition h2_nand_partitions[] = { -#if 0 - /* REVISIT: enable these partitions if you make NAND BOOT - * work on your H2 (rev C or newer); published versions of - * x-load only support P2 and H3. - */ - { - .name = "xloader", - .offset = 0, - .size = 64 * 1024, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { - .name = "bootloader", - .offset = MTDPART_OFS_APPEND, - .size = 256 * 1024, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { - .name = "params", - .offset = MTDPART_OFS_APPEND, - .size = 192 * 1024, - }, - { - .name = "kernel", - .offset = MTDPART_OFS_APPEND, - .size = 2 * SZ_1M, - }, -#endif - { - .name = "filesystem", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - }, -}; - -#define H2_NAND_RB_GPIO_PIN 62 - -static int h2_nand_dev_ready(struct nand_chip *chip) -{ - return gpio_get_value(H2_NAND_RB_GPIO_PIN); -} - -static struct platform_nand_data h2_nand_platdata = { - .chip = { - .nr_chips = 1, - .chip_offset = 0, - .nr_partitions = ARRAY_SIZE(h2_nand_partitions), - .partitions = h2_nand_partitions, - .options = NAND_SAMSUNG_LP_OPTIONS, - }, - .ctrl = { - .cmd_ctrl = omap1_nand_cmd_ctl, - .dev_ready = h2_nand_dev_ready, - }, -}; - -static struct resource h2_nand_resource = { - .flags = IORESOURCE_MEM, -}; - -static struct platform_device h2_nand_device = { - .name = "gen_nand", - .id = 0, - .dev = { - .platform_data = &h2_nand_platdata, - }, - .num_resources = 1, - .resource = &h2_nand_resource, -}; - -static struct smc91x_platdata h2_smc91x_info = { - .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, - .leda = RPC_LED_100_10, - .ledb = RPC_LED_TX_RX, -}; - -static struct resource h2_smc91x_resources[] = { - [0] = { - .start = OMAP1610_ETHR_START, /* Physical */ - .end = OMAP1610_ETHR_START + 0xf, - .flags = IORESOURCE_MEM, - }, - [1] = { - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, - }, -}; - -static struct platform_device h2_smc91x_device = { - .name = "smc91x", - .id = 0, - .dev = { - .platform_data = &h2_smc91x_info, - }, - .num_resources = ARRAY_SIZE(h2_smc91x_resources), - .resource = h2_smc91x_resources, -}; - -static struct resource h2_kp_resources[] = { - [0] = { - .start = INT_KEYBOARD, - .end = INT_KEYBOARD, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct matrix_keymap_data h2_keymap_data = { - .keymap = h2_keymap, - .keymap_size = ARRAY_SIZE(h2_keymap), -}; - -static struct omap_kp_platform_data h2_kp_data = { - .rows = 8, - .cols = 8, - .keymap_data = &h2_keymap_data, - .rep = true, - .delay = 9, - .dbounce = true, -}; - -static struct platform_device h2_kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &h2_kp_data, - }, - .num_resources = ARRAY_SIZE(h2_kp_resources), - .resource = h2_kp_resources, -}; - -static const struct gpio_led h2_gpio_led_pins[] = { - { - .name = "h2:red", - .default_trigger = "heartbeat", - .gpio = 3, - }, - { - .name = "h2:green", - .default_trigger = "cpu0", - .gpio = OMAP_MPUIO(4), - }, -}; - -static struct gpio_led_platform_data h2_gpio_led_data = { - .leds = h2_gpio_led_pins, - .num_leds = ARRAY_SIZE(h2_gpio_led_pins), -}; - -static struct platform_device h2_gpio_leds = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &h2_gpio_led_data, - }, -}; - -static struct platform_device *h2_devices[] __initdata = { - &h2_nor_device, - &h2_nand_device, - &h2_smc91x_device, - &h2_kp_device, - &h2_gpio_leds, -}; - -static void __init h2_init_smc91x(void) -{ - if (gpio_request(0, "SMC91x irq") < 0) { - printk("Error requesting gpio 0 for smc91x irq\n"); - return; - } -} - -static int tps_setup(struct i2c_client *client, void *context) -{ - if (!IS_BUILTIN(CONFIG_TPS65010)) - return -ENOSYS; - - tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | - TPS_LDO1_ENABLE | TPS_VLDO1_3_0V); - - return 0; -} - -static struct tps65010_board tps_board = { - .base = H2_TPS_GPIO_BASE, - .outmask = 0x0f, - .setup = tps_setup, -}; - -static struct i2c_board_info __initdata h2_i2c_board_info[] = { - { - I2C_BOARD_INFO("tps65010", 0x48), - .platform_data = &tps_board, - }, { - .type = "isp1301_omap", - .addr = 0x2d, - .dev_name = "isp1301", - }, -}; - -static struct gpiod_lookup_table isp1301_gpiod_table = { - .dev_id = "isp1301", - .table = { - /* Active low since the irq triggers on falling edge */ - GPIO_LOOKUP(OMAP_GPIO_LABEL, 2, - NULL, GPIO_ACTIVE_LOW), - { }, - }, -}; - -static struct omap_usb_config h2_usb_config __initdata = { - /* usb1 has a Mini-AB port and external isp1301 transceiver */ - .otg = 2, - -#if IS_ENABLED(CONFIG_USB_OMAP) - .hmc_mode = 19, /* 0:host(off) 1:dev|otg 2:disabled */ - /* .hmc_mode = 21,*/ /* 0:host(off) 1:dev(loopback) 2:host(loopback) */ -#elif IS_ENABLED(CONFIG_USB_OHCI_HCD) - /* needs OTG cable, or NONSTANDARD (B-to-MiniB) */ - .hmc_mode = 20, /* 1:dev|otg(off) 1:host 2:disabled */ -#endif - - .pins[1] = 3, -}; - -static const struct omap_lcd_config h2_lcd_config __initconst = { - .ctrl_name = "internal", -}; - -static void __init h2_init(void) -{ - h2_init_smc91x(); - - /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped - * to address 0 by a dip switch), NAND on CS2B. The NAND driver will - * notice whether a NAND chip is enabled at probe time. - * - * FIXME revC boards (and H3) support NAND-boot, with a dip switch to - * put NOR on CS2B and NAND (which on H2 may be 16bit) on CS3. Try - * detecting that in code here, to avoid probing every possible flash - * configuration... - */ - h2_nor_resource.end = h2_nor_resource.start = omap_cs3_phys(); - h2_nor_resource.end += SZ_32M - 1; - - h2_nand_resource.end = h2_nand_resource.start = OMAP_CS2B_PHYS; - h2_nand_resource.end += SZ_4K - 1; - BUG_ON(gpio_request(H2_NAND_RB_GPIO_PIN, "NAND ready") < 0); - gpio_direction_input(H2_NAND_RB_GPIO_PIN); - - gpiod_add_lookup_table(&isp1301_gpiod_table); - - omap_cfg_reg(L3_1610_FLASH_CS2B_OE); - omap_cfg_reg(M8_1610_FLASH_CS2B_WE); - - /* MMC: card detect and WP */ - /* omap_cfg_reg(U19_ARMIO1); */ /* CD */ - omap_cfg_reg(BALLOUT_V8_ARMIO3); /* WP */ - - /* Mux pins for keypad */ - omap_cfg_reg(F18_1610_KBC0); - omap_cfg_reg(D20_1610_KBC1); - omap_cfg_reg(D19_1610_KBC2); - omap_cfg_reg(E18_1610_KBC3); - omap_cfg_reg(C21_1610_KBC4); - omap_cfg_reg(G18_1610_KBR0); - omap_cfg_reg(F19_1610_KBR1); - omap_cfg_reg(H14_1610_KBR2); - omap_cfg_reg(E20_1610_KBR3); - omap_cfg_reg(E19_1610_KBR4); - omap_cfg_reg(N19_1610_KBR5); - - /* GPIO based LEDs */ - omap_cfg_reg(P18_1610_GPIO3); - omap_cfg_reg(MPUIO4); - - h2_smc91x_resources[1].start = gpio_to_irq(0); - h2_smc91x_resources[1].end = gpio_to_irq(0); - platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); - omap_serial_init(); - - /* ISP1301 IRQ wired at M14 */ - omap_cfg_reg(M14_1510_GPIO2); - h2_i2c_board_info[0].irq = gpio_to_irq(58); - omap_register_i2c_bus(1, 100, h2_i2c_board_info, - ARRAY_SIZE(h2_i2c_board_info)); - omap1_usb_init(&h2_usb_config); - h2_mmc_init(); - - omapfb_set_lcd_config(&h2_lcd_config); -} - -MACHINE_START(OMAP_H2, "TI-H2") - /* Maintainer: Imre Deak */ - .atag_offset = 0x100, - .map_io = omap16xx_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = h2_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-h2.h b/arch/arm/mach-omap1/board-h2.h deleted file mode 100644 index 315e2662547e..000000000000 --- a/arch/arm/mach-omap1/board-h2.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * arch/arm/mach-omap1/board-h2.h - * - * Hardware definitions for TI OMAP1610 H2 board. - * - * Cleanup for Linux-2.6 by Dirk Behme - * - * 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 SOFTWARE IS PROVIDED ``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 AUTHOR 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. - * - * 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 __ASM_ARCH_OMAP_H2_H -#define __ASM_ARCH_OMAP_H2_H - -#define H2_TPS_GPIO_BASE (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */) -# define H2_TPS_GPIO_MMC_PWR_EN (H2_TPS_GPIO_BASE + 3) - -extern void h2_mmc_init(void); - -#endif /* __ASM_ARCH_OMAP_H2_H */ - diff --git a/arch/arm/mach-omap1/board-h3-mmc.c b/arch/arm/mach-omap1/board-h3-mmc.c deleted file mode 100644 index f595bd4f5024..000000000000 --- a/arch/arm/mach-omap1/board-h3-mmc.c +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-h3-mmc.c - * - * Copyright (C) 2007 Instituto Nokia de Tecnologia - INdT - * Author: Felipe Balbi - * - * This code is based on linux/arch/arm/mach-omap2/board-n800-mmc.c, which is: - * Copyright (C) 2006 Nokia Corporation - */ -#include -#include - -#include - -#include "common.h" -#include "board-h3.h" -#include "mmc.h" - -#if IS_ENABLED(CONFIG_MMC_OMAP) - -static int mmc_set_power(struct device *dev, int slot, int power_on, - int vdd) -{ - gpio_set_value(H3_TPS_GPIO_MMC_PWR_EN, power_on); - return 0; -} - -/* - * H3 could use the following functions tested: - * - mmc_get_cover_state that uses OMAP_MPUIO(1) - * - mmc_get_wp that maybe uses OMAP_MPUIO(3) - */ -static struct omap_mmc_platform_data mmc1_data = { - .nr_slots = 1, - .slots[0] = { - .set_power = mmc_set_power, - .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, - .name = "mmcblk", - }, -}; - -static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC]; - -void __init h3_mmc_init(void) -{ - int ret; - - ret = gpio_request(H3_TPS_GPIO_MMC_PWR_EN, "MMC power"); - if (ret < 0) - return; - gpio_direction_output(H3_TPS_GPIO_MMC_PWR_EN, 0); - - mmc_data[0] = &mmc1_data; - omap1_init_mmc(mmc_data, OMAP16XX_NR_MMC); -} - -#else - -void __init h3_mmc_init(void) -{ -} - -#endif diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c deleted file mode 100644 index 1e4c57710fcc..000000000000 --- a/arch/arm/mach-omap1/board-h3.c +++ /dev/null @@ -1,455 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-h3.c - * - * This file contains OMAP1710 H3 specific code. - * - * Copyright (C) 2004 Texas Instruments, Inc. - * Copyright (C) 2002 MontaVista Software, Inc. - * Copyright (C) 2001 RidgeRun, Inc. - * Author: RidgeRun, Inc. - * Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.com - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "tc.h" -#include "mux.h" -#include "flash.h" -#include "hardware.h" -#include "irqs.h" -#include "usb.h" -#include "common.h" -#include "board-h3.h" - -/* In OMAP1710 H3 the Ethernet is directly connected to CS1 */ -#define OMAP1710_ETHR_START 0x04000300 - -#define H3_TS_GPIO 48 - -static const unsigned int h3_keymap[] = { - KEY(0, 0, KEY_LEFT), - KEY(1, 0, KEY_RIGHT), - KEY(2, 0, KEY_3), - KEY(3, 0, KEY_F10), - KEY(4, 0, KEY_F5), - KEY(5, 0, KEY_9), - KEY(0, 1, KEY_DOWN), - KEY(1, 1, KEY_UP), - KEY(2, 1, KEY_2), - KEY(3, 1, KEY_F9), - KEY(4, 1, KEY_F7), - KEY(5, 1, KEY_0), - KEY(0, 2, KEY_ENTER), - KEY(1, 2, KEY_6), - KEY(2, 2, KEY_1), - KEY(3, 2, KEY_F2), - KEY(4, 2, KEY_F6), - KEY(5, 2, KEY_HOME), - KEY(0, 3, KEY_8), - KEY(1, 3, KEY_5), - KEY(2, 3, KEY_F12), - KEY(3, 3, KEY_F3), - KEY(4, 3, KEY_F8), - KEY(5, 3, KEY_END), - KEY(0, 4, KEY_7), - KEY(1, 4, KEY_4), - KEY(2, 4, KEY_F11), - KEY(3, 4, KEY_F1), - KEY(4, 4, KEY_F4), - KEY(5, 4, KEY_ESC), - KEY(0, 5, KEY_F13), - KEY(1, 5, KEY_F14), - KEY(2, 5, KEY_F15), - KEY(3, 5, KEY_F16), - KEY(4, 5, KEY_SLEEP), -}; - - -static struct mtd_partition nor_partitions[] = { - /* bootloader (U-Boot, etc) in first sector */ - { - .name = "bootloader", - .offset = 0, - .size = SZ_128K, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - /* bootloader params in the next sector */ - { - .name = "params", - .offset = MTDPART_OFS_APPEND, - .size = SZ_128K, - .mask_flags = 0, - }, - /* kernel */ - { - .name = "kernel", - .offset = MTDPART_OFS_APPEND, - .size = SZ_2M, - .mask_flags = 0 - }, - /* file system */ - { - .name = "filesystem", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - .mask_flags = 0 - } -}; - -static struct physmap_flash_data nor_data = { - .width = 2, - .set_vpp = omap1_set_vpp, - .parts = nor_partitions, - .nr_parts = ARRAY_SIZE(nor_partitions), -}; - -static struct resource nor_resource = { - /* This is on CS3, wherever it's mapped */ - .flags = IORESOURCE_MEM, -}; - -static struct platform_device nor_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &nor_data, - }, - .num_resources = 1, - .resource = &nor_resource, -}; - -static struct mtd_partition nand_partitions[] = { -#if 0 - /* REVISIT: enable these partitions if you make NAND BOOT work */ - { - .name = "xloader", - .offset = 0, - .size = 64 * 1024, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { - .name = "bootloader", - .offset = MTDPART_OFS_APPEND, - .size = 256 * 1024, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { - .name = "params", - .offset = MTDPART_OFS_APPEND, - .size = 192 * 1024, - }, - { - .name = "kernel", - .offset = MTDPART_OFS_APPEND, - .size = 2 * SZ_1M, - }, -#endif - { - .name = "filesystem", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - }, -}; - -#define H3_NAND_RB_GPIO_PIN 10 - -static int nand_dev_ready(struct nand_chip *chip) -{ - return gpio_get_value(H3_NAND_RB_GPIO_PIN); -} - -static struct platform_nand_data nand_platdata = { - .chip = { - .nr_chips = 1, - .chip_offset = 0, - .nr_partitions = ARRAY_SIZE(nand_partitions), - .partitions = nand_partitions, - .options = NAND_SAMSUNG_LP_OPTIONS, - }, - .ctrl = { - .cmd_ctrl = omap1_nand_cmd_ctl, - .dev_ready = nand_dev_ready, - - }, -}; - -static struct resource nand_resource = { - .flags = IORESOURCE_MEM, -}; - -static struct platform_device nand_device = { - .name = "gen_nand", - .id = 0, - .dev = { - .platform_data = &nand_platdata, - }, - .num_resources = 1, - .resource = &nand_resource, -}; - -static struct smc91x_platdata smc91x_info = { - .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, - .leda = RPC_LED_100_10, - .ledb = RPC_LED_TX_RX, -}; - -static struct resource smc91x_resources[] = { - [0] = { - .start = OMAP1710_ETHR_START, /* Physical */ - .end = OMAP1710_ETHR_START + 0xf, - .flags = IORESOURCE_MEM, - }, - [1] = { - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, - }, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .dev = { - .platform_data = &smc91x_info, - }, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -static void __init h3_init_smc91x(void) -{ - omap_cfg_reg(W15_1710_GPIO40); - if (gpio_request(40, "SMC91x irq") < 0) { - printk("Error requesting gpio 40 for smc91x irq\n"); - return; - } -} - -#define GPTIMER_BASE 0xFFFB1400 -#define GPTIMER_REGS(x) (0xFFFB1400 + (x * 0x800)) -#define GPTIMER_REGS_SIZE 0x46 - -static struct resource intlat_resources[] = { - [0] = { - .start = GPTIMER_REGS(0), /* Physical */ - .end = GPTIMER_REGS(0) + GPTIMER_REGS_SIZE, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = INT_1610_GPTIMER1, - .end = INT_1610_GPTIMER1, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device intlat_device = { - .name = "omap_intlat", - .id = 0, - .num_resources = ARRAY_SIZE(intlat_resources), - .resource = intlat_resources, -}; - -static struct resource h3_kp_resources[] = { - [0] = { - .start = INT_KEYBOARD, - .end = INT_KEYBOARD, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct matrix_keymap_data h3_keymap_data = { - .keymap = h3_keymap, - .keymap_size = ARRAY_SIZE(h3_keymap), -}; - -static struct omap_kp_platform_data h3_kp_data = { - .rows = 8, - .cols = 8, - .keymap_data = &h3_keymap_data, - .rep = true, - .delay = 9, - .dbounce = true, -}; - -static struct platform_device h3_kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &h3_kp_data, - }, - .num_resources = ARRAY_SIZE(h3_kp_resources), - .resource = h3_kp_resources, -}; - -static struct platform_device h3_lcd_device = { - .name = "lcd_h3", - .id = -1, -}; - -static struct spi_board_info h3_spi_board_info[] __initdata = { - [0] = { - .modalias = "tsc2101", - .bus_num = 2, - .chip_select = 0, - .max_speed_hz = 16000000, - /* .platform_data = &tsc_platform_data, */ - }, -}; - -static const struct gpio_led h3_gpio_led_pins[] = { - { - .name = "h3:red", - .default_trigger = "heartbeat", - .gpio = 3, - }, - { - .name = "h3:green", - .default_trigger = "cpu0", - .gpio = OMAP_MPUIO(4), - }, -}; - -static struct gpio_led_platform_data h3_gpio_led_data = { - .leds = h3_gpio_led_pins, - .num_leds = ARRAY_SIZE(h3_gpio_led_pins), -}; - -static struct platform_device h3_gpio_leds = { - .name = "leds-gpio", - .id = -1, - .dev = { - .platform_data = &h3_gpio_led_data, - }, -}; - -static struct platform_device *devices[] __initdata = { - &nor_device, - &nand_device, - &smc91x_device, - &intlat_device, - &h3_kp_device, - &h3_lcd_device, - &h3_gpio_leds, -}; - -static struct omap_usb_config h3_usb_config __initdata = { - /* usb1 has a Mini-AB port and external isp1301 transceiver */ - .otg = 2, - -#if IS_ENABLED(CONFIG_USB_OMAP) - .hmc_mode = 19, /* 0:host(off) 1:dev|otg 2:disabled */ -#elif IS_ENABLED(CONFIG_USB_OHCI_HCD) - /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */ - .hmc_mode = 20, /* 1:dev|otg(off) 1:host 2:disabled */ -#endif - - .pins[1] = 3, -}; - -static const struct omap_lcd_config h3_lcd_config __initconst = { - .ctrl_name = "internal", -}; - -static struct i2c_board_info __initdata h3_i2c_board_info[] = { - { - I2C_BOARD_INFO("tps65013", 0x48), - }, - { - I2C_BOARD_INFO("isp1301_omap", 0x2d), - }, -}; - -static void __init h3_init(void) -{ - h3_init_smc91x(); - - /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped - * to address 0 by a dip switch), NAND on CS2B. The NAND driver will - * notice whether a NAND chip is enabled at probe time. - * - * H3 support NAND-boot, with a dip switch to put NOR on CS2B and NAND - * (which on H2 may be 16bit) on CS3. Try detecting that in code here, - * to avoid probing every possible flash configuration... - */ - nor_resource.end = nor_resource.start = omap_cs3_phys(); - nor_resource.end += SZ_32M - 1; - - nand_resource.end = nand_resource.start = OMAP_CS2B_PHYS; - nand_resource.end += SZ_4K - 1; - BUG_ON(gpio_request(H3_NAND_RB_GPIO_PIN, "NAND ready") < 0); - gpio_direction_input(H3_NAND_RB_GPIO_PIN); - - /* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */ - /* GPIO10 pullup/down register, Enable pullup on GPIO10 */ - omap_cfg_reg(V2_1710_GPIO10); - - /* Mux pins for keypad */ - omap_cfg_reg(F18_1610_KBC0); - omap_cfg_reg(D20_1610_KBC1); - omap_cfg_reg(D19_1610_KBC2); - omap_cfg_reg(E18_1610_KBC3); - omap_cfg_reg(C21_1610_KBC4); - omap_cfg_reg(G18_1610_KBR0); - omap_cfg_reg(F19_1610_KBR1); - omap_cfg_reg(H14_1610_KBR2); - omap_cfg_reg(E20_1610_KBR3); - omap_cfg_reg(E19_1610_KBR4); - omap_cfg_reg(N19_1610_KBR5); - - /* GPIO based LEDs */ - omap_cfg_reg(P18_1610_GPIO3); - omap_cfg_reg(MPUIO4); - - smc91x_resources[1].start = gpio_to_irq(40); - smc91x_resources[1].end = gpio_to_irq(40); - platform_add_devices(devices, ARRAY_SIZE(devices)); - h3_spi_board_info[0].irq = gpio_to_irq(H3_TS_GPIO); - spi_register_board_info(h3_spi_board_info, - ARRAY_SIZE(h3_spi_board_info)); - omap_serial_init(); - h3_i2c_board_info[1].irq = gpio_to_irq(14); - omap_register_i2c_bus(1, 100, h3_i2c_board_info, - ARRAY_SIZE(h3_i2c_board_info)); - omap1_usb_init(&h3_usb_config); - h3_mmc_init(); - - omapfb_set_lcd_config(&h3_lcd_config); -} - -MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board") - /* Maintainer: Texas Instruments, Inc. */ - .atag_offset = 0x100, - .map_io = omap16xx_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = h3_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-h3.h b/arch/arm/mach-omap1/board-h3.h deleted file mode 100644 index 78de535be3c5..000000000000 --- a/arch/arm/mach-omap1/board-h3.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * arch/arm/mach-omap1/board-h3.h - * - * Copyright (C) 2001 RidgeRun, Inc. - * Copyright (C) 2004 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 as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. - * - * 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 __ASM_ARCH_OMAP_H3_H -#define __ASM_ARCH_OMAP_H3_H - -#define H3_TPS_GPIO_BASE (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */) -# define H3_TPS_GPIO_MMC_PWR_EN (H3_TPS_GPIO_BASE + 4) - -extern void h3_mmc_init(void); - -#endif /* __ASM_ARCH_OMAP_H3_H */ diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c deleted file mode 100644 index 291d294b5824..000000000000 --- a/arch/arm/mach-omap1/board-htcherald.c +++ /dev/null @@ -1,585 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * HTC Herald board configuration - * Copyright (C) 2009 Cory Maccarrone - * Copyright (C) 2009 Wing Linux - * - * Based on the board-htcwizard.c file from the linwizard project: - * Copyright (C) 2006 Unai Uribarri - * Copyright (C) 2008 linwizard.sourceforge.net - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "hardware.h" -#include "omap7xx.h" -#include "mmc.h" -#include "irqs.h" -#include "usb.h" -#include "common.h" - -/* LCD register definition */ -#define OMAP_LCDC_CONTROL (0xfffec000 + 0x00) -#define OMAP_LCDC_STATUS (0xfffec000 + 0x10) -#define OMAP_DMA_LCD_CCR (0xfffee300 + 0xc2) -#define OMAP_DMA_LCD_CTRL (0xfffee300 + 0xc4) -#define OMAP_LCDC_CTRL_LCD_EN (1 << 0) -#define OMAP_LCDC_STAT_DONE (1 << 0) - -/* GPIO definitions for the power button and keyboard slide switch */ -#define HTCHERALD_GPIO_POWER 139 -#define HTCHERALD_GPIO_SLIDE 174 -#define HTCHERALD_GIRQ_BTNS 141 - -/* GPIO definitions for the touchscreen */ -#define HTCHERALD_GPIO_TS 76 - -/* HTCPLD definitions */ - -/* - * CPLD Logic - * - * Chip 3 - 0x03 - * - * Function 7 6 5 4 3 2 1 0 - * ------------------------------------ - * DPAD light x x x x x x x 1 - * SoundDev x x x x 1 x x x - * Screen white 1 x x x x x x x - * MMC power on x x x x x 1 x x - * Happy times (n) 0 x x x x 1 x x - * - * Chip 4 - 0x04 - * - * Function 7 6 5 4 3 2 1 0 - * ------------------------------------ - * Keyboard light x x x x x x x 1 - * LCD Bright (4) x x x x x 1 1 x - * LCD Bright (3) x x x x x 0 1 x - * LCD Bright (2) x x x x x 1 0 x - * LCD Bright (1) x x x x x 0 0 x - * LCD Off x x x x 0 x x x - * LCD image (fb) 1 x x x x x x x - * LCD image (white) 0 x x x x x x x - * Caps lock LED x x 1 x x x x x - * - * Chip 5 - 0x05 - * - * Function 7 6 5 4 3 2 1 0 - * ------------------------------------ - * Red (solid) x x x x x 1 x x - * Red (flash) x x x x x x 1 x - * Green (GSM flash) x x x x 1 x x x - * Green (GSM solid) x x x 1 x x x x - * Green (wifi flash) x x 1 x x x x x - * Blue (bt flash) x 1 x x x x x x - * DPAD Int Enable 1 x x x x x x 0 - * - * (Combinations of the above can be made for different colors.) - * The direction pad interrupt enable must be set each time the - * interrupt is handled. - * - * Chip 6 - 0x06 - * - * Function 7 6 5 4 3 2 1 0 - * ------------------------------------ - * Vibrator x x x x 1 x x x - * Alt LED x x x 1 x x x x - * Screen white 1 x x x x x x x - * Screen white x x 1 x x x x x - * Screen white x 0 x x x x x x - * Enable kbd dpad x x x x x x 0 x - * Happy Times 0 1 0 x x x 0 x - */ - -/* - * HTCPLD GPIO lines start 16 after OMAP_MAX_GPIO_LINES to account - * for the 16 MPUIO lines. - */ -#define HTCPLD_GPIO_START_OFFSET (OMAP_MAX_GPIO_LINES + 16) -#define HTCPLD_IRQ(chip, offset) (OMAP_IRQ_END + 8 * (chip) + (offset)) -#define HTCPLD_BASE(chip, offset) \ - (HTCPLD_GPIO_START_OFFSET + 8 * (chip) + (offset)) - -#define HTCPLD_GPIO_LED_DPAD HTCPLD_BASE(0, 0) -#define HTCPLD_GPIO_LED_KBD HTCPLD_BASE(1, 0) -#define HTCPLD_GPIO_LED_CAPS HTCPLD_BASE(1, 5) -#define HTCPLD_GPIO_LED_RED_FLASH HTCPLD_BASE(2, 1) -#define HTCPLD_GPIO_LED_RED_SOLID HTCPLD_BASE(2, 2) -#define HTCPLD_GPIO_LED_GREEN_FLASH HTCPLD_BASE(2, 3) -#define HTCPLD_GPIO_LED_GREEN_SOLID HTCPLD_BASE(2, 4) -#define HTCPLD_GPIO_LED_WIFI HTCPLD_BASE(2, 5) -#define HTCPLD_GPIO_LED_BT HTCPLD_BASE(2, 6) -#define HTCPLD_GPIO_LED_VIBRATE HTCPLD_BASE(3, 3) -#define HTCPLD_GPIO_LED_ALT HTCPLD_BASE(3, 4) - -#define HTCPLD_GPIO_RIGHT_KBD HTCPLD_BASE(6, 7) -#define HTCPLD_GPIO_UP_KBD HTCPLD_BASE(6, 6) -#define HTCPLD_GPIO_LEFT_KBD HTCPLD_BASE(6, 5) -#define HTCPLD_GPIO_DOWN_KBD HTCPLD_BASE(6, 4) - -#define HTCPLD_GPIO_RIGHT_DPAD HTCPLD_BASE(7, 7) -#define HTCPLD_GPIO_UP_DPAD HTCPLD_BASE(7, 6) -#define HTCPLD_GPIO_LEFT_DPAD HTCPLD_BASE(7, 5) -#define HTCPLD_GPIO_DOWN_DPAD HTCPLD_BASE(7, 4) -#define HTCPLD_GPIO_ENTER_DPAD HTCPLD_BASE(7, 3) - -/* Chip 5 */ -#define HTCPLD_IRQ_RIGHT_KBD HTCPLD_IRQ(0, 7) -#define HTCPLD_IRQ_UP_KBD HTCPLD_IRQ(0, 6) -#define HTCPLD_IRQ_LEFT_KBD HTCPLD_IRQ(0, 5) -#define HTCPLD_IRQ_DOWN_KBD HTCPLD_IRQ(0, 4) - -/* Chip 6 */ -#define HTCPLD_IRQ_RIGHT_DPAD HTCPLD_IRQ(1, 7) -#define HTCPLD_IRQ_UP_DPAD HTCPLD_IRQ(1, 6) -#define HTCPLD_IRQ_LEFT_DPAD HTCPLD_IRQ(1, 5) -#define HTCPLD_IRQ_DOWN_DPAD HTCPLD_IRQ(1, 4) -#define HTCPLD_IRQ_ENTER_DPAD HTCPLD_IRQ(1, 3) - -/* Keyboard definition */ - -static const unsigned int htc_herald_keymap[] = { - KEY(0, 0, KEY_RECORD), /* Mail button */ - KEY(1, 0, KEY_CAMERA), /* Camera */ - KEY(2, 0, KEY_PHONE), /* Send key */ - KEY(3, 0, KEY_VOLUMEUP), /* Volume up */ - KEY(4, 0, KEY_F2), /* Right bar (landscape) */ - KEY(5, 0, KEY_MAIL), /* Win key (portrait) */ - KEY(6, 0, KEY_DIRECTORY), /* Right bar (portrait) */ - KEY(0, 1, KEY_LEFTCTRL), /* Windows key */ - KEY(1, 1, KEY_COMMA), - KEY(2, 1, KEY_M), - KEY(3, 1, KEY_K), - KEY(4, 1, KEY_SLASH), /* OK key */ - KEY(5, 1, KEY_I), - KEY(6, 1, KEY_U), - KEY(0, 2, KEY_LEFTALT), - KEY(1, 2, KEY_TAB), - KEY(2, 2, KEY_N), - KEY(3, 2, KEY_J), - KEY(4, 2, KEY_ENTER), - KEY(5, 2, KEY_H), - KEY(6, 2, KEY_Y), - KEY(0, 3, KEY_SPACE), - KEY(1, 3, KEY_L), - KEY(2, 3, KEY_B), - KEY(3, 3, KEY_V), - KEY(4, 3, KEY_BACKSPACE), - KEY(5, 3, KEY_G), - KEY(6, 3, KEY_T), - KEY(0, 4, KEY_CAPSLOCK), /* Shift */ - KEY(1, 4, KEY_C), - KEY(2, 4, KEY_F), - KEY(3, 4, KEY_R), - KEY(4, 4, KEY_O), - KEY(5, 4, KEY_E), - KEY(6, 4, KEY_D), - KEY(0, 5, KEY_X), - KEY(1, 5, KEY_Z), - KEY(2, 5, KEY_S), - KEY(3, 5, KEY_W), - KEY(4, 5, KEY_P), - KEY(5, 5, KEY_Q), - KEY(6, 5, KEY_A), - KEY(0, 6, KEY_CONNECT), /* Voice button */ - KEY(2, 6, KEY_CANCEL), /* End key */ - KEY(3, 6, KEY_VOLUMEDOWN), /* Volume down */ - KEY(4, 6, KEY_F1), /* Left bar (landscape) */ - KEY(5, 6, KEY_WWW), /* OK button (portrait) */ - KEY(6, 6, KEY_CALENDAR), /* Left bar (portrait) */ -}; - -static const struct matrix_keymap_data htc_herald_keymap_data = { - .keymap = htc_herald_keymap, - .keymap_size = ARRAY_SIZE(htc_herald_keymap), -}; - -static struct omap_kp_platform_data htcherald_kp_data = { - .rows = 7, - .cols = 7, - .delay = 20, - .rep = true, - .keymap_data = &htc_herald_keymap_data, -}; - -static struct resource kp_resources[] = { - [0] = { - .start = INT_7XX_MPUIO_KEYPAD, - .end = INT_7XX_MPUIO_KEYPAD, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &htcherald_kp_data, - }, - .num_resources = ARRAY_SIZE(kp_resources), - .resource = kp_resources, -}; - -/* GPIO buttons for keyboard slide and power button */ -static struct gpio_keys_button herald_gpio_keys_table[] = { - {BTN_0, HTCHERALD_GPIO_POWER, 1, "POWER", EV_KEY, 1, 20}, - {SW_LID, HTCHERALD_GPIO_SLIDE, 0, "SLIDE", EV_SW, 1, 20}, - - {KEY_LEFT, HTCPLD_GPIO_LEFT_KBD, 1, "LEFT", EV_KEY, 1, 20}, - {KEY_RIGHT, HTCPLD_GPIO_RIGHT_KBD, 1, "RIGHT", EV_KEY, 1, 20}, - {KEY_UP, HTCPLD_GPIO_UP_KBD, 1, "UP", EV_KEY, 1, 20}, - {KEY_DOWN, HTCPLD_GPIO_DOWN_KBD, 1, "DOWN", EV_KEY, 1, 20}, - - {KEY_LEFT, HTCPLD_GPIO_LEFT_DPAD, 1, "DLEFT", EV_KEY, 1, 20}, - {KEY_RIGHT, HTCPLD_GPIO_RIGHT_DPAD, 1, "DRIGHT", EV_KEY, 1, 20}, - {KEY_UP, HTCPLD_GPIO_UP_DPAD, 1, "DUP", EV_KEY, 1, 20}, - {KEY_DOWN, HTCPLD_GPIO_DOWN_DPAD, 1, "DDOWN", EV_KEY, 1, 20}, - {KEY_ENTER, HTCPLD_GPIO_ENTER_DPAD, 1, "DENTER", EV_KEY, 1, 20}, -}; - -static struct gpio_keys_platform_data herald_gpio_keys_data = { - .buttons = herald_gpio_keys_table, - .nbuttons = ARRAY_SIZE(herald_gpio_keys_table), - .rep = true, -}; - -static struct platform_device herald_gpiokeys_device = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = &herald_gpio_keys_data, - }, -}; - -/* LEDs for the Herald. These connect to the HTCPLD GPIO device. */ -static const struct gpio_led gpio_leds[] = { - {"dpad", NULL, HTCPLD_GPIO_LED_DPAD, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"kbd", NULL, HTCPLD_GPIO_LED_KBD, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"vibrate", NULL, HTCPLD_GPIO_LED_VIBRATE, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"green_solid", NULL, HTCPLD_GPIO_LED_GREEN_SOLID, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"green_flash", NULL, HTCPLD_GPIO_LED_GREEN_FLASH, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"red_solid", "mmc0", HTCPLD_GPIO_LED_RED_SOLID, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"red_flash", NULL, HTCPLD_GPIO_LED_RED_FLASH, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"wifi", NULL, HTCPLD_GPIO_LED_WIFI, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"bt", NULL, HTCPLD_GPIO_LED_BT, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"caps", NULL, HTCPLD_GPIO_LED_CAPS, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, - {"alt", NULL, HTCPLD_GPIO_LED_ALT, 0, 0, LEDS_GPIO_DEFSTATE_OFF}, -}; - -static struct gpio_led_platform_data gpio_leds_data = { - .leds = gpio_leds, - .num_leds = ARRAY_SIZE(gpio_leds), -}; - -static struct platform_device gpio_leds_device = { - .name = "leds-gpio", - .id = 0, - .dev = { - .platform_data = &gpio_leds_data, - }, -}; - -/* HTC PLD chips */ - -static struct resource htcpld_resources[] = { - [0] = { - .flags = IORESOURCE_IRQ, - }, -}; - -static struct htcpld_chip_platform_data htcpld_chips[] = { - [0] = { - .addr = 0x03, - .reset = 0x04, - .num_gpios = 8, - .gpio_out_base = HTCPLD_BASE(0, 0), - .gpio_in_base = HTCPLD_BASE(4, 0), - }, - [1] = { - .addr = 0x04, - .reset = 0x8e, - .num_gpios = 8, - .gpio_out_base = HTCPLD_BASE(1, 0), - .gpio_in_base = HTCPLD_BASE(5, 0), - }, - [2] = { - .addr = 0x05, - .reset = 0x80, - .num_gpios = 8, - .gpio_out_base = HTCPLD_BASE(2, 0), - .gpio_in_base = HTCPLD_BASE(6, 0), - .irq_base = HTCPLD_IRQ(0, 0), - .num_irqs = 8, - }, - [3] = { - .addr = 0x06, - .reset = 0x40, - .num_gpios = 8, - .gpio_out_base = HTCPLD_BASE(3, 0), - .gpio_in_base = HTCPLD_BASE(7, 0), - .irq_base = HTCPLD_IRQ(1, 0), - .num_irqs = 8, - }, -}; - -static struct htcpld_core_platform_data htcpld_pfdata = { - .i2c_adapter_id = 1, - - .chip = htcpld_chips, - .num_chip = ARRAY_SIZE(htcpld_chips), -}; - -static struct platform_device htcpld_device = { - .name = "i2c-htcpld", - .id = -1, - .resource = htcpld_resources, - .num_resources = ARRAY_SIZE(htcpld_resources), - .dev = { - .platform_data = &htcpld_pfdata, - }, -}; - -/* USB Device */ -static struct omap_usb_config htcherald_usb_config __initdata = { - .otg = 0, - .register_host = 0, - .register_dev = 1, - .hmc_mode = 4, - .pins[0] = 2, -}; - -/* LCD Device resources */ -static const struct omap_lcd_config htcherald_lcd_config __initconst = { - .ctrl_name = "internal", -}; - -static struct platform_device lcd_device = { - .name = "lcd_htcherald", - .id = -1, -}; - -/* MMC Card */ -#if IS_ENABLED(CONFIG_MMC_OMAP) -static struct omap_mmc_platform_data htc_mmc1_data = { - .nr_slots = 1, - .switch_slot = NULL, - .slots[0] = { - .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, - .name = "mmcblk", - .nomux = 1, - .wires = 4, - .switch_pin = -1, - }, -}; - -static struct omap_mmc_platform_data *htc_mmc_data[1]; -#endif - - -/* Platform devices for the Herald */ -static struct platform_device *devices[] __initdata = { - &kp_device, - &lcd_device, - &htcpld_device, - &gpio_leds_device, - &herald_gpiokeys_device, -}; - -/* - * Touchscreen - */ -static const struct ads7846_platform_data htcherald_ts_platform_data = { - .model = 7846, - .keep_vref_on = 1, - .x_plate_ohms = 496, - .gpio_pendown = HTCHERALD_GPIO_TS, - .pressure_max = 10000, - .pressure_min = 5000, - .x_min = 528, - .x_max = 3760, - .y_min = 624, - .y_max = 3760, -}; - -static struct spi_board_info __initdata htcherald_spi_board_info[] = { - { - .modalias = "ads7846", - .platform_data = &htcherald_ts_platform_data, - .max_speed_hz = 2500000, - .bus_num = 2, - .chip_select = 1, - } -}; - -/* - * Init functions from here on - */ - -static void __init htcherald_lcd_init(void) -{ - u32 reg; - unsigned int tries = 200; - - /* disable controller if active */ - reg = omap_readl(OMAP_LCDC_CONTROL); - if (reg & OMAP_LCDC_CTRL_LCD_EN) { - reg &= ~OMAP_LCDC_CTRL_LCD_EN; - omap_writel(reg, OMAP_LCDC_CONTROL); - - /* wait for end of frame */ - while (!(omap_readl(OMAP_LCDC_STATUS) & OMAP_LCDC_STAT_DONE)) { - tries--; - if (!tries) - break; - } - if (!tries) - pr_err("Timeout waiting for end of frame -- LCD may not be available\n"); - - /* turn off DMA */ - reg = omap_readw(OMAP_DMA_LCD_CCR); - reg &= ~(1 << 7); - omap_writew(reg, OMAP_DMA_LCD_CCR); - - reg = omap_readw(OMAP_DMA_LCD_CTRL); - reg &= ~(1 << 8); - omap_writew(reg, OMAP_DMA_LCD_CTRL); - } -} - -static void __init htcherald_map_io(void) -{ - omap7xx_map_io(); - - /* - * The LCD panel must be disabled and DMA turned off here, as doing - * it later causes the LCD never to reinitialize. - */ - htcherald_lcd_init(); - - printk(KERN_INFO "htcherald_map_io done.\n"); -} - -static void __init htcherald_disable_watchdog(void) -{ - /* Disable watchdog if running */ - if (omap_readl(OMAP_WDT_TIMER_MODE) & 0x8000) { - /* - * disable a potentially running watchdog timer before - * it kills us. - */ - printk(KERN_WARNING "OMAP850 Watchdog seems to be activated, disabling it for now.\n"); - omap_writel(0xF5, OMAP_WDT_TIMER_MODE); - omap_writel(0xA0, OMAP_WDT_TIMER_MODE); - } -} - -#define HTCHERALD_GPIO_USB_EN1 33 -#define HTCHERALD_GPIO_USB_EN2 73 -#define HTCHERALD_GPIO_USB_DM 35 -#define HTCHERALD_GPIO_USB_DP 36 - -static void __init htcherald_usb_enable(void) -{ - unsigned int tries = 20; - unsigned int value = 0; - - /* Request the GPIOs we need to control here */ - if (gpio_request(HTCHERALD_GPIO_USB_EN1, "herald_usb") < 0) - goto err1; - - if (gpio_request(HTCHERALD_GPIO_USB_EN2, "herald_usb") < 0) - goto err2; - - if (gpio_request(HTCHERALD_GPIO_USB_DM, "herald_usb") < 0) - goto err3; - - if (gpio_request(HTCHERALD_GPIO_USB_DP, "herald_usb") < 0) - goto err4; - - /* force USB_EN GPIO to 0 */ - do { - /* output low */ - gpio_direction_output(HTCHERALD_GPIO_USB_EN1, 0); - } while ((value = gpio_get_value(HTCHERALD_GPIO_USB_EN1)) == 1 && - --tries); - - if (value == 1) - printk(KERN_WARNING "Unable to reset USB, trying to continue\n"); - - gpio_direction_output(HTCHERALD_GPIO_USB_EN2, 0); /* output low */ - gpio_direction_input(HTCHERALD_GPIO_USB_DM); /* input */ - gpio_direction_input(HTCHERALD_GPIO_USB_DP); /* input */ - - goto done; - -err4: - gpio_free(HTCHERALD_GPIO_USB_DM); -err3: - gpio_free(HTCHERALD_GPIO_USB_EN2); -err2: - gpio_free(HTCHERALD_GPIO_USB_EN1); -err1: - printk(KERN_ERR "Unabled to request GPIO for USB\n"); -done: - printk(KERN_INFO "USB setup complete.\n"); -} - -static void __init htcherald_init(void) -{ - printk(KERN_INFO "HTC Herald init.\n"); - - /* Do board initialization before we register all the devices */ - htcpld_resources[0].start = gpio_to_irq(HTCHERALD_GIRQ_BTNS); - htcpld_resources[0].end = gpio_to_irq(HTCHERALD_GIRQ_BTNS); - platform_add_devices(devices, ARRAY_SIZE(devices)); - - htcherald_disable_watchdog(); - - htcherald_usb_enable(); - omap1_usb_init(&htcherald_usb_config); - - htcherald_spi_board_info[0].irq = gpio_to_irq(HTCHERALD_GPIO_TS); - spi_register_board_info(htcherald_spi_board_info, - ARRAY_SIZE(htcherald_spi_board_info)); - - omap_register_i2c_bus(1, 100, NULL, 0); - -#if IS_ENABLED(CONFIG_MMC_OMAP) - htc_mmc_data[0] = &htc_mmc1_data; - omap1_init_mmc(htc_mmc_data, 1); -#endif - - omapfb_set_lcd_config(&htcherald_lcd_config); -} - -MACHINE_START(HERALD, "HTC Herald") - /* Maintainer: Cory Maccarrone */ - /* Maintainer: wing-linux.sourceforge.net */ - .atag_offset = 0x100, - .map_io = htcherald_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = htcherald_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c deleted file mode 100644 index 6deb4ca079e9..000000000000 --- a/arch/arm/mach-omap1/board-innovator.c +++ /dev/null @@ -1,481 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-innovator.c - * - * Board specific inits for OMAP-1510 and OMAP-1610 Innovator - * - * Copyright (C) 2001 RidgeRun, Inc. - * Author: Greg Lonnon - * - * Copyright (C) 2002 MontaVista Software, Inc. - * - * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 - * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "tc.h" -#include "mux.h" -#include "flash.h" -#include "hardware.h" -#include "usb.h" -#include "iomap.h" -#include "common.h" -#include "mmc.h" - -/* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */ -#define INNOVATOR1610_ETHR_START 0x04000300 - -static const unsigned int innovator_keymap[] = { - KEY(0, 0, KEY_F1), - KEY(3, 0, KEY_DOWN), - KEY(1, 1, KEY_F2), - KEY(2, 1, KEY_RIGHT), - KEY(0, 2, KEY_F3), - KEY(1, 2, KEY_F4), - KEY(2, 2, KEY_UP), - KEY(2, 3, KEY_ENTER), - KEY(3, 3, KEY_LEFT), -}; - -static struct mtd_partition innovator_partitions[] = { - /* bootloader (U-Boot, etc) in first sector */ - { - .name = "bootloader", - .offset = 0, - .size = SZ_128K, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - /* bootloader params in the next sector */ - { - .name = "params", - .offset = MTDPART_OFS_APPEND, - .size = SZ_128K, - .mask_flags = 0, - }, - /* kernel */ - { - .name = "kernel", - .offset = MTDPART_OFS_APPEND, - .size = SZ_2M, - .mask_flags = 0 - }, - /* rest of flash1 is a file system */ - { - .name = "rootfs", - .offset = MTDPART_OFS_APPEND, - .size = SZ_16M - SZ_2M - 2 * SZ_128K, - .mask_flags = 0 - }, - /* file system */ - { - .name = "filesystem", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - .mask_flags = 0 - } -}; - -static struct physmap_flash_data innovator_flash_data = { - .width = 2, - .set_vpp = omap1_set_vpp, - .parts = innovator_partitions, - .nr_parts = ARRAY_SIZE(innovator_partitions), -}; - -static struct resource innovator_flash_resource = { - .start = OMAP_CS0_PHYS, - .end = OMAP_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device innovator_flash_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &innovator_flash_data, - }, - .num_resources = 1, - .resource = &innovator_flash_resource, -}; - -static struct resource innovator_kp_resources[] = { - [0] = { - .start = INT_KEYBOARD, - .end = INT_KEYBOARD, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct matrix_keymap_data innovator_keymap_data = { - .keymap = innovator_keymap, - .keymap_size = ARRAY_SIZE(innovator_keymap), -}; - -static struct omap_kp_platform_data innovator_kp_data = { - .rows = 8, - .cols = 8, - .keymap_data = &innovator_keymap_data, - .delay = 4, -}; - -static struct platform_device innovator_kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &innovator_kp_data, - }, - .num_resources = ARRAY_SIZE(innovator_kp_resources), - .resource = innovator_kp_resources, -}; - -static struct smc91x_platdata innovator_smc91x_info = { - .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, - .leda = RPC_LED_100_10, - .ledb = RPC_LED_TX_RX, -}; - -#ifdef CONFIG_ARCH_OMAP15XX - -#include -#include - - -/* Only FPGA needs to be mapped here. All others are done with ioremap */ -static struct map_desc innovator1510_io_desc[] __initdata = { - { - .virtual = OMAP1510_FPGA_BASE, - .pfn = __phys_to_pfn(OMAP1510_FPGA_START), - .length = OMAP1510_FPGA_SIZE, - .type = MT_DEVICE - } -}; - -static struct resource innovator1510_smc91x_resources[] = { - [0] = { - .start = OMAP1510_FPGA_ETHR_START, /* Physical */ - .end = OMAP1510_FPGA_ETHR_START + 0xf, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = OMAP1510_INT_ETHER, - .end = OMAP1510_INT_ETHER, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, - }, -}; - -static struct platform_device innovator1510_smc91x_device = { - .name = "smc91x", - .id = 0, - .dev = { - .platform_data = &innovator_smc91x_info, - }, - .num_resources = ARRAY_SIZE(innovator1510_smc91x_resources), - .resource = innovator1510_smc91x_resources, -}; - -static struct platform_device innovator1510_lcd_device = { - .name = "lcd_inn1510", - .id = -1, - .dev = { - .platform_data = (void __force *)OMAP1510_FPGA_LCD_PANEL_CONTROL, - } -}; - -static struct platform_device innovator1510_spi_device = { - .name = "spi_inn1510", - .id = -1, -}; - -static struct platform_device *innovator1510_devices[] __initdata = { - &innovator_flash_device, - &innovator1510_smc91x_device, - &innovator_kp_device, - &innovator1510_lcd_device, - &innovator1510_spi_device, -}; - -static int innovator_get_pendown_state(void) -{ - return !(__raw_readb(OMAP1510_FPGA_TOUCHSCREEN) & (1 << 5)); -} - -static const struct ads7846_platform_data innovator1510_ts_info = { - .model = 7846, - .vref_delay_usecs = 100, /* internal, no capacitor */ - .x_plate_ohms = 419, - .y_plate_ohms = 486, - .get_pendown_state = innovator_get_pendown_state, -}; - -static struct spi_board_info __initdata innovator1510_boardinfo[] = { { - /* FPGA (bus "10") CS0 has an ads7846e */ - .modalias = "ads7846", - .platform_data = &innovator1510_ts_info, - .irq = OMAP1510_INT_FPGA_TS, - .max_speed_hz = 120000 /* max sample rate at 3V */ - * 26 /* command + data + overhead */, - .bus_num = 10, - .chip_select = 0, -} }; - -#endif /* CONFIG_ARCH_OMAP15XX */ - -#ifdef CONFIG_ARCH_OMAP16XX - -static struct resource innovator1610_smc91x_resources[] = { - [0] = { - .start = INNOVATOR1610_ETHR_START, /* Physical */ - .end = INNOVATOR1610_ETHR_START + 0xf, - .flags = IORESOURCE_MEM, - }, - [1] = { - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, - }, -}; - -static struct platform_device innovator1610_smc91x_device = { - .name = "smc91x", - .id = 0, - .dev = { - .platform_data = &innovator_smc91x_info, - }, - .num_resources = ARRAY_SIZE(innovator1610_smc91x_resources), - .resource = innovator1610_smc91x_resources, -}; - -static struct platform_device innovator1610_lcd_device = { - .name = "inn1610_lcd", - .id = -1, -}; - -static struct platform_device *innovator1610_devices[] __initdata = { - &innovator_flash_device, - &innovator1610_smc91x_device, - &innovator_kp_device, - &innovator1610_lcd_device, -}; - -#endif /* CONFIG_ARCH_OMAP16XX */ - -static void __init innovator_init_smc91x(void) -{ - if (cpu_is_omap1510()) { - __raw_writeb(__raw_readb(OMAP1510_FPGA_RST) & ~1, - OMAP1510_FPGA_RST); - udelay(750); - } else { - if (gpio_request(0, "SMC91x irq") < 0) { - printk("Error requesting gpio 0 for smc91x irq\n"); - return; - } - } -} - -#ifdef CONFIG_ARCH_OMAP15XX -/* - * Board specific gang-switched transceiver power on/off. - */ -static int innovator_omap_ohci_transceiver_power(int on) -{ - if (on) - __raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL) - | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), - INNOVATOR_FPGA_CAM_USB_CONTROL); - else - __raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL) - & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), - INNOVATOR_FPGA_CAM_USB_CONTROL); - - return 0; -} - -static struct omap_usb_config innovator1510_usb_config __initdata = { - /* for bundled non-standard host and peripheral cables */ - .hmc_mode = 4, - - .register_host = 1, - .pins[1] = 6, - .pins[2] = 6, /* Conflicts with UART2 */ - - .register_dev = 1, - .pins[0] = 2, - - .transceiver_power = innovator_omap_ohci_transceiver_power, -}; - -static const struct omap_lcd_config innovator1510_lcd_config __initconst = { - .ctrl_name = "internal", -}; -#endif - -#ifdef CONFIG_ARCH_OMAP16XX -static struct omap_usb_config h2_usb_config __initdata = { - /* usb1 has a Mini-AB port and external isp1301 transceiver */ - .otg = 2, - -#if IS_ENABLED(CONFIG_USB_OMAP) - .hmc_mode = 19, /* 0:host(off) 1:dev|otg 2:disabled */ - /* .hmc_mode = 21,*/ /* 0:host(off) 1:dev(loopback) 2:host(loopback) */ -#elif IS_ENABLED(CONFIG_USB_OHCI_HCD) - /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */ - .hmc_mode = 20, /* 1:dev|otg(off) 1:host 2:disabled */ -#endif - - .pins[1] = 3, -}; - -static const struct omap_lcd_config innovator1610_lcd_config __initconst = { - .ctrl_name = "internal", -}; -#endif - -#if IS_ENABLED(CONFIG_MMC_OMAP) - -static int mmc_set_power(struct device *dev, int slot, int power_on, - int vdd) -{ - if (power_on) - __raw_writeb(__raw_readb(OMAP1510_FPGA_POWER) | (1 << 3), - OMAP1510_FPGA_POWER); - else - __raw_writeb(__raw_readb(OMAP1510_FPGA_POWER) & ~(1 << 3), - OMAP1510_FPGA_POWER); - - return 0; -} - -/* - * Innovator could use the following functions tested: - * - mmc_get_wp that uses OMAP_MPUIO(3) - * - mmc_get_cover_state that uses FPGA F4 UIO43 - */ -static struct omap_mmc_platform_data mmc1_data = { - .nr_slots = 1, - .slots[0] = { - .set_power = mmc_set_power, - .wires = 4, - .name = "mmcblk", - }, -}; - -static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC]; - -static void __init innovator_mmc_init(void) -{ - mmc_data[0] = &mmc1_data; - omap1_init_mmc(mmc_data, OMAP15XX_NR_MMC); -} - -#else -static inline void innovator_mmc_init(void) -{ -} -#endif - -static void __init innovator_init(void) -{ - if (cpu_is_omap1510()) - omap1510_fpga_init_irq(); - innovator_init_smc91x(); - -#ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { - unsigned char reg; - - /* mux pins for uarts */ - omap_cfg_reg(UART1_TX); - omap_cfg_reg(UART1_RTS); - omap_cfg_reg(UART2_TX); - omap_cfg_reg(UART2_RTS); - omap_cfg_reg(UART3_TX); - omap_cfg_reg(UART3_RX); - - reg = __raw_readb(OMAP1510_FPGA_POWER); - reg |= OMAP1510_FPGA_PCR_COM1_EN; - __raw_writeb(reg, OMAP1510_FPGA_POWER); - udelay(10); - - reg = __raw_readb(OMAP1510_FPGA_POWER); - reg |= OMAP1510_FPGA_PCR_COM2_EN; - __raw_writeb(reg, OMAP1510_FPGA_POWER); - udelay(10); - - platform_add_devices(innovator1510_devices, ARRAY_SIZE(innovator1510_devices)); - spi_register_board_info(innovator1510_boardinfo, - ARRAY_SIZE(innovator1510_boardinfo)); - } -#endif -#ifdef CONFIG_ARCH_OMAP16XX - if (!cpu_is_omap1510()) { - innovator1610_smc91x_resources[1].start = gpio_to_irq(0); - innovator1610_smc91x_resources[1].end = gpio_to_irq(0); - platform_add_devices(innovator1610_devices, ARRAY_SIZE(innovator1610_devices)); - } -#endif - -#ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { - omap1_usb_init(&innovator1510_usb_config); - omapfb_set_lcd_config(&innovator1510_lcd_config); - } -#endif -#ifdef CONFIG_ARCH_OMAP16XX - if (cpu_is_omap1610()) { - omap1_usb_init(&h2_usb_config); - omapfb_set_lcd_config(&innovator1610_lcd_config); - } -#endif - omap_serial_init(); - omap_register_i2c_bus(1, 100, NULL, 0); - innovator_mmc_init(); -} - -/* - * REVISIT: Assume 15xx for now, we don't want to do revision check - * until later on. The right way to fix this is to set up a different - * machine_id for 16xx Innovator, or use device tree. - */ -static void __init innovator_map_io(void) -{ -#ifdef CONFIG_ARCH_OMAP15XX - omap15xx_map_io(); - - iotable_init(innovator1510_io_desc, ARRAY_SIZE(innovator1510_io_desc)); - udelay(10); /* Delay needed for FPGA */ - - /* Dump the Innovator FPGA rev early - useful info for support. */ - pr_debug("Innovator FPGA Rev %d.%d Board Rev %d\n", - __raw_readb(OMAP1510_FPGA_REV_HIGH), - __raw_readb(OMAP1510_FPGA_REV_LOW), - __raw_readb(OMAP1510_FPGA_BOARD_REV)); -#endif -} - -MACHINE_START(OMAP_INNOVATOR, "TI-Innovator") - /* Maintainer: MontaVista Software, Inc. */ - .atag_offset = 0x100, - .map_io = innovator_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = innovator_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-nand.c b/arch/arm/mach-omap1/board-nand.c deleted file mode 100644 index 479ab9be784d..000000000000 --- a/arch/arm/mach-omap1/board-nand.c +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-nand.c - * - * Common OMAP1 board NAND code - * - * Copyright (C) 2004, 2012 Texas Instruments, Inc. - * Copyright (C) 2002 MontaVista Software, Inc. - * Copyright (C) 2001 RidgeRun, Inc. - * Author: RidgeRun, Inc. - * Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.com - */ -#include -#include -#include -#include - -#include "common.h" - -void omap1_nand_cmd_ctl(struct nand_chip *this, int cmd, unsigned int ctrl) -{ - unsigned long mask; - - if (cmd == NAND_CMD_NONE) - return; - - mask = (ctrl & NAND_CLE) ? 0x02 : 0; - if (ctrl & NAND_ALE) - mask |= 0x04; - - writeb(cmd, this->legacy.IO_ADDR_W + mask); -} - diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c deleted file mode 100644 index 537f0e6a2ff7..000000000000 --- a/arch/arm/mach-omap1/board-palmtt.c +++ /dev/null @@ -1,285 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-palmtt.c - * - * Modified from board-palmtt2.c - * - * Modified and amended for Palm Tungsten|T - * by Marek Vasut - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "tc.h" -#include "flash.h" -#include "mux.h" -#include "hardware.h" -#include "usb.h" -#include "common.h" - -#define PALMTT_USBDETECT_GPIO 0 -#define PALMTT_CABLE_GPIO 1 -#define PALMTT_LED_GPIO 3 -#define PALMTT_PENIRQ_GPIO 6 -#define PALMTT_MMC_WP_GPIO 8 -#define PALMTT_HDQ_GPIO 11 - -static const unsigned int palmtt_keymap[] = { - KEY(0, 0, KEY_ESC), - KEY(1, 0, KEY_SPACE), - KEY(2, 0, KEY_LEFTCTRL), - KEY(3, 0, KEY_TAB), - KEY(4, 0, KEY_ENTER), - KEY(0, 1, KEY_LEFT), - KEY(1, 1, KEY_DOWN), - KEY(2, 1, KEY_UP), - KEY(3, 1, KEY_RIGHT), - KEY(0, 2, KEY_SLEEP), - KEY(4, 2, KEY_Y), -}; - -static struct mtd_partition palmtt_partitions[] = { - { - .name = "write8k", - .offset = 0, - .size = SZ_8K, - .mask_flags = 0, - }, - { - .name = "PalmOS-BootLoader(ro)", - .offset = SZ_8K, - .size = 7 * SZ_8K, - .mask_flags = MTD_WRITEABLE, - }, - { - .name = "u-boot", - .offset = MTDPART_OFS_APPEND, - .size = 8 * SZ_8K, - .mask_flags = 0, - }, - { - .name = "PalmOS-FS(ro)", - .offset = MTDPART_OFS_APPEND, - .size = 7 * SZ_1M + 4 * SZ_64K - 16 * SZ_8K, - .mask_flags = MTD_WRITEABLE, - }, - { - .name = "u-boot(rez)", - .offset = MTDPART_OFS_APPEND, - .size = SZ_128K, - .mask_flags = 0 - }, - { - .name = "empty", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - .mask_flags = 0 - } -}; - -static struct physmap_flash_data palmtt_flash_data = { - .width = 2, - .set_vpp = omap1_set_vpp, - .parts = palmtt_partitions, - .nr_parts = ARRAY_SIZE(palmtt_partitions), -}; - -static struct resource palmtt_flash_resource = { - .start = OMAP_CS0_PHYS, - .end = OMAP_CS0_PHYS + SZ_8M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device palmtt_flash_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &palmtt_flash_data, - }, - .num_resources = 1, - .resource = &palmtt_flash_resource, -}; - -static struct resource palmtt_kp_resources[] = { - [0] = { - .start = INT_KEYBOARD, - .end = INT_KEYBOARD, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct matrix_keymap_data palmtt_keymap_data = { - .keymap = palmtt_keymap, - .keymap_size = ARRAY_SIZE(palmtt_keymap), -}; - -static struct omap_kp_platform_data palmtt_kp_data = { - .rows = 6, - .cols = 3, - .keymap_data = &palmtt_keymap_data, -}; - -static struct platform_device palmtt_kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &palmtt_kp_data, - }, - .num_resources = ARRAY_SIZE(palmtt_kp_resources), - .resource = palmtt_kp_resources, -}; - -static struct platform_device palmtt_lcd_device = { - .name = "lcd_palmtt", - .id = -1, -}; - -static struct platform_device palmtt_spi_device = { - .name = "spi_palmtt", - .id = -1, -}; - -static struct omap_backlight_config palmtt_backlight_config = { - .default_intensity = 0xa0, -}; - -static struct platform_device palmtt_backlight_device = { - .name = "omap-bl", - .id = -1, - .dev = { - .platform_data= &palmtt_backlight_config, - }, -}; - -static struct omap_led_config palmtt_led_config[] = { - { - .cdev = { - .name = "palmtt:led0", - }, - .gpio = PALMTT_LED_GPIO, - }, -}; - -static struct omap_led_platform_data palmtt_led_data = { - .nr_leds = ARRAY_SIZE(palmtt_led_config), - .leds = palmtt_led_config, -}; - -static struct platform_device palmtt_led_device = { - .name = "omap-led", - .id = -1, - .dev = { - .platform_data = &palmtt_led_data, - }, -}; - -static struct platform_device *palmtt_devices[] __initdata = { - &palmtt_flash_device, - &palmtt_kp_device, - &palmtt_lcd_device, - &palmtt_spi_device, - &palmtt_backlight_device, - &palmtt_led_device, -}; - -static int palmtt_get_pendown_state(void) -{ - return !gpio_get_value(6); -} - -static const struct ads7846_platform_data palmtt_ts_info = { - .model = 7846, - .vref_delay_usecs = 100, /* internal, no capacitor */ - .x_plate_ohms = 419, - .y_plate_ohms = 486, - .get_pendown_state = palmtt_get_pendown_state, -}; - -static struct spi_board_info __initdata palmtt_boardinfo[] = { - { - /* MicroWire (bus 2) CS0 has an ads7846e */ - .modalias = "ads7846", - .platform_data = &palmtt_ts_info, - .max_speed_hz = 120000 /* max sample rate at 3V */ - * 26 /* command + data + overhead */, - .bus_num = 2, - .chip_select = 0, - } -}; - -static struct omap_usb_config palmtt_usb_config __initdata = { - .register_dev = 1, - .hmc_mode = 0, - .pins[0] = 2, -}; - -static const struct omap_lcd_config palmtt_lcd_config __initconst = { - .ctrl_name = "internal", -}; - -static void __init omap_mpu_wdt_mode(int mode) { - if (mode) - omap_writew(0x8000, OMAP_WDT_TIMER_MODE); - else { - omap_writew(0x00f5, OMAP_WDT_TIMER_MODE); - omap_writew(0x00a0, OMAP_WDT_TIMER_MODE); - } -} - -static void __init omap_palmtt_init(void) -{ - /* mux pins for uarts */ - omap_cfg_reg(UART1_TX); - omap_cfg_reg(UART1_RTS); - omap_cfg_reg(UART2_TX); - omap_cfg_reg(UART2_RTS); - omap_cfg_reg(UART3_TX); - omap_cfg_reg(UART3_RX); - - omap_mpu_wdt_mode(0); - - platform_add_devices(palmtt_devices, ARRAY_SIZE(palmtt_devices)); - - palmtt_boardinfo[0].irq = gpio_to_irq(6); - spi_register_board_info(palmtt_boardinfo,ARRAY_SIZE(palmtt_boardinfo)); - omap_serial_init(); - omap1_usb_init(&palmtt_usb_config); - omap_register_i2c_bus(1, 100, NULL, 0); - - omapfb_set_lcd_config(&palmtt_lcd_config); -} - -MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T") - .atag_offset = 0x100, - .map_io = omap15xx_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = omap_palmtt_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c deleted file mode 100644 index 47f08ae5a2f3..000000000000 --- a/arch/arm/mach-omap1/board-palmz71.c +++ /dev/null @@ -1,300 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-palmz71.c - * - * Modified from board-generic.c - * - * Support for the Palm Zire71 PDA. - * - * Original version : Laurent Gonzalez - * - * Modified for zire71 : Marek Vasut - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "tc.h" -#include "flash.h" -#include "mux.h" -#include "hardware.h" -#include "usb.h" -#include "common.h" - -#define PALMZ71_USBDETECT_GPIO 0 -#define PALMZ71_PENIRQ_GPIO 6 -#define PALMZ71_MMC_WP_GPIO 8 -#define PALMZ71_HDQ_GPIO 11 - -#define PALMZ71_HOTSYNC_GPIO OMAP_MPUIO(1) -#define PALMZ71_CABLE_GPIO OMAP_MPUIO(2) -#define PALMZ71_SLIDER_GPIO OMAP_MPUIO(3) -#define PALMZ71_MMC_IN_GPIO OMAP_MPUIO(4) - -static const unsigned int palmz71_keymap[] = { - KEY(0, 0, KEY_F1), - KEY(1, 0, KEY_F2), - KEY(2, 0, KEY_F3), - KEY(3, 0, KEY_F4), - KEY(4, 0, KEY_POWER), - KEY(0, 1, KEY_LEFT), - KEY(1, 1, KEY_DOWN), - KEY(2, 1, KEY_UP), - KEY(3, 1, KEY_RIGHT), - KEY(4, 1, KEY_ENTER), - KEY(0, 2, KEY_CAMERA), -}; - -static const struct matrix_keymap_data palmz71_keymap_data = { - .keymap = palmz71_keymap, - .keymap_size = ARRAY_SIZE(palmz71_keymap), -}; - -static struct omap_kp_platform_data palmz71_kp_data = { - .rows = 8, - .cols = 8, - .keymap_data = &palmz71_keymap_data, - .rep = true, - .delay = 80, -}; - -static struct resource palmz71_kp_resources[] = { - [0] = { - .start = INT_KEYBOARD, - .end = INT_KEYBOARD, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device palmz71_kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &palmz71_kp_data, - }, - .num_resources = ARRAY_SIZE(palmz71_kp_resources), - .resource = palmz71_kp_resources, -}; - -static struct mtd_partition palmz71_rom_partitions[] = { - /* PalmOS "Small ROM", contains the bootloader and the debugger */ - { - .name = "smallrom", - .offset = 0, - .size = 0xa000, - .mask_flags = MTD_WRITEABLE, - }, - /* PalmOS "Big ROM", a filesystem with all the OS code and data */ - { - .name = "bigrom", - .offset = SZ_128K, - /* - * 0x5f0000 bytes big in the multi-language ("EFIGS") version, - * 0x7b0000 bytes in the English-only ("enUS") version. - */ - .size = 0x7b0000, - .mask_flags = MTD_WRITEABLE, - }, -}; - -static struct physmap_flash_data palmz71_rom_data = { - .width = 2, - .set_vpp = omap1_set_vpp, - .parts = palmz71_rom_partitions, - .nr_parts = ARRAY_SIZE(palmz71_rom_partitions), -}; - -static struct resource palmz71_rom_resource = { - .start = OMAP_CS0_PHYS, - .end = OMAP_CS0_PHYS + SZ_8M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device palmz71_rom_device = { - .name = "physmap-flash", - .id = -1, - .dev = { - .platform_data = &palmz71_rom_data, - }, - .num_resources = 1, - .resource = &palmz71_rom_resource, -}; - -static struct platform_device palmz71_lcd_device = { - .name = "lcd_palmz71", - .id = -1, -}; - -static struct platform_device palmz71_spi_device = { - .name = "spi_palmz71", - .id = -1, -}; - -static struct omap_backlight_config palmz71_backlight_config = { - .default_intensity = 0xa0, -}; - -static struct platform_device palmz71_backlight_device = { - .name = "omap-bl", - .id = -1, - .dev = { - .platform_data = &palmz71_backlight_config, - }, -}; - -static struct platform_device *devices[] __initdata = { - &palmz71_rom_device, - &palmz71_kp_device, - &palmz71_lcd_device, - &palmz71_spi_device, - &palmz71_backlight_device, -}; - -static int -palmz71_get_pendown_state(void) -{ - return !gpio_get_value(PALMZ71_PENIRQ_GPIO); -} - -static const struct ads7846_platform_data palmz71_ts_info = { - .model = 7846, - .vref_delay_usecs = 100, /* internal, no capacitor */ - .x_plate_ohms = 419, - .y_plate_ohms = 486, - .get_pendown_state = palmz71_get_pendown_state, -}; - -static struct spi_board_info __initdata palmz71_boardinfo[] = { { - /* MicroWire (bus 2) CS0 has an ads7846e */ - .modalias = "ads7846", - .platform_data = &palmz71_ts_info, - .max_speed_hz = 120000 /* max sample rate at 3V */ - * 26 /* command + data + overhead */, - .bus_num = 2, - .chip_select = 0, -} }; - -static struct omap_usb_config palmz71_usb_config __initdata = { - .register_dev = 1, /* Mini-B only receptacle */ - .hmc_mode = 0, - .pins[0] = 2, -}; - -static const struct omap_lcd_config palmz71_lcd_config __initconst = { - .ctrl_name = "internal", -}; - -static irqreturn_t -palmz71_powercable(int irq, void *dev_id) -{ - if (gpio_get_value(PALMZ71_USBDETECT_GPIO)) { - printk(KERN_INFO "PM: Power cable connected\n"); - irq_set_irq_type(gpio_to_irq(PALMZ71_USBDETECT_GPIO), - IRQ_TYPE_EDGE_FALLING); - } else { - printk(KERN_INFO "PM: Power cable disconnected\n"); - irq_set_irq_type(gpio_to_irq(PALMZ71_USBDETECT_GPIO), - IRQ_TYPE_EDGE_RISING); - } - return IRQ_HANDLED; -} - -static void __init -omap_mpu_wdt_mode(int mode) -{ - if (mode) - omap_writew(0x8000, OMAP_WDT_TIMER_MODE); - else { - omap_writew(0x00f5, OMAP_WDT_TIMER_MODE); - omap_writew(0x00a0, OMAP_WDT_TIMER_MODE); - } -} - -static void __init -palmz71_gpio_setup(int early) -{ - if (early) { - /* Only set GPIO1 so we have a working serial */ - gpio_direction_output(1, 1); - } else { - /* Set MMC/SD host WP pin as input */ - if (gpio_request(PALMZ71_MMC_WP_GPIO, "MMC WP") < 0) { - printk(KERN_ERR "Could not reserve WP GPIO!\n"); - return; - } - gpio_direction_input(PALMZ71_MMC_WP_GPIO); - - /* Monitor the Power-cable-connected signal */ - if (gpio_request(PALMZ71_USBDETECT_GPIO, "USB detect") < 0) { - printk(KERN_ERR - "Could not reserve cable signal GPIO!\n"); - return; - } - gpio_direction_input(PALMZ71_USBDETECT_GPIO); - if (request_irq(gpio_to_irq(PALMZ71_USBDETECT_GPIO), - palmz71_powercable, 0, "palmz71-cable", NULL)) - printk(KERN_ERR - "IRQ request for power cable failed!\n"); - palmz71_powercable(gpio_to_irq(PALMZ71_USBDETECT_GPIO), NULL); - } -} - -static void __init -omap_palmz71_init(void) -{ - /* mux pins for uarts */ - omap_cfg_reg(UART1_TX); - omap_cfg_reg(UART1_RTS); - omap_cfg_reg(UART2_TX); - omap_cfg_reg(UART2_RTS); - omap_cfg_reg(UART3_TX); - omap_cfg_reg(UART3_RX); - - palmz71_gpio_setup(1); - omap_mpu_wdt_mode(0); - - platform_add_devices(devices, ARRAY_SIZE(devices)); - - palmz71_boardinfo[0].irq = gpio_to_irq(PALMZ71_PENIRQ_GPIO); - spi_register_board_info(palmz71_boardinfo, - ARRAY_SIZE(palmz71_boardinfo)); - omap1_usb_init(&palmz71_usb_config); - omap_serial_init(); - omap_register_i2c_bus(1, 100, NULL, 0); - palmz71_gpio_setup(0); - - omapfb_set_lcd_config(&palmz71_lcd_config); -} - -MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71") - .atag_offset = 0x100, - .map_io = omap15xx_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = omap_palmz71_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c deleted file mode 100644 index b041e6f6e9cf..000000000000 --- a/arch/arm/mach-omap1/board-perseus2.c +++ /dev/null @@ -1,333 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/board-perseus2.c - * - * Modified from board-generic.c - * - * Original OMAP730 support by Jean Pihet - * Updated for 2.6 by Kevin Hilman - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "tc.h" -#include "mux.h" -#include "flash.h" -#include "hardware.h" -#include "iomap.h" -#include "common.h" -#include "fpga.h" - -static const unsigned int p2_keymap[] = { - KEY(0, 0, KEY_UP), - KEY(1, 0, KEY_RIGHT), - KEY(2, 0, KEY_LEFT), - KEY(3, 0, KEY_DOWN), - KEY(4, 0, KEY_ENTER), - KEY(0, 1, KEY_F10), - KEY(1, 1, KEY_SEND), - KEY(2, 1, KEY_END), - KEY(3, 1, KEY_VOLUMEDOWN), - KEY(4, 1, KEY_VOLUMEUP), - KEY(5, 1, KEY_RECORD), - KEY(0, 2, KEY_F9), - KEY(1, 2, KEY_3), - KEY(2, 2, KEY_6), - KEY(3, 2, KEY_9), - KEY(4, 2, KEY_KPDOT), - KEY(0, 3, KEY_BACK), - KEY(1, 3, KEY_2), - KEY(2, 3, KEY_5), - KEY(3, 3, KEY_8), - KEY(4, 3, KEY_0), - KEY(5, 3, KEY_KPSLASH), - KEY(0, 4, KEY_HOME), - KEY(1, 4, KEY_1), - KEY(2, 4, KEY_4), - KEY(3, 4, KEY_7), - KEY(4, 4, KEY_KPASTERISK), - KEY(5, 4, KEY_POWER), -}; - -static struct smc91x_platdata smc91x_info = { - .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, - .leda = RPC_LED_100_10, - .ledb = RPC_LED_TX_RX, -}; - -static struct resource smc91x_resources[] = { - [0] = { - .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */ - .end = H2P2_DBG_FPGA_ETHR_START + 0xf, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = INT_7XX_MPU_EXT_NIRQ, - .end = 0, - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, - }, -}; - -static struct mtd_partition nor_partitions[] = { - /* bootloader (U-Boot, etc) in first sector */ - { - .name = "bootloader", - .offset = 0, - .size = SZ_128K, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - /* bootloader params in the next sector */ - { - .name = "params", - .offset = MTDPART_OFS_APPEND, - .size = SZ_128K, - .mask_flags = 0, - }, - /* kernel */ - { - .name = "kernel", - .offset = MTDPART_OFS_APPEND, - .size = SZ_2M, - .mask_flags = 0 - }, - /* rest of flash is a file system */ - { - .name = "rootfs", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - .mask_flags = 0 - }, -}; - -static struct physmap_flash_data nor_data = { - .width = 2, - .set_vpp = omap1_set_vpp, - .parts = nor_partitions, - .nr_parts = ARRAY_SIZE(nor_partitions), -}; - -static struct resource nor_resource = { - .start = OMAP_CS0_PHYS, - .end = OMAP_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device nor_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &nor_data, - }, - .num_resources = 1, - .resource = &nor_resource, -}; - -#define P2_NAND_RB_GPIO_PIN 62 - -static int nand_dev_ready(struct nand_chip *chip) -{ - return gpio_get_value(P2_NAND_RB_GPIO_PIN); -} - -static struct platform_nand_data nand_data = { - .chip = { - .nr_chips = 1, - .chip_offset = 0, - .options = NAND_SAMSUNG_LP_OPTIONS, - }, - .ctrl = { - .cmd_ctrl = omap1_nand_cmd_ctl, - .dev_ready = nand_dev_ready, - }, -}; - -static struct resource nand_resource = { - .start = OMAP_CS3_PHYS, - .end = OMAP_CS3_PHYS + SZ_4K - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device nand_device = { - .name = "gen_nand", - .id = 0, - .dev = { - .platform_data = &nand_data, - }, - .num_resources = 1, - .resource = &nand_resource, -}; - -static struct platform_device smc91x_device = { - .name = "smc91x", - .id = 0, - .dev = { - .platform_data = &smc91x_info, - }, - .num_resources = ARRAY_SIZE(smc91x_resources), - .resource = smc91x_resources, -}; - -static struct resource kp_resources[] = { - [0] = { - .start = INT_7XX_MPUIO_KEYPAD, - .end = INT_7XX_MPUIO_KEYPAD, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct matrix_keymap_data p2_keymap_data = { - .keymap = p2_keymap, - .keymap_size = ARRAY_SIZE(p2_keymap), -}; - -static struct omap_kp_platform_data kp_data = { - .rows = 8, - .cols = 8, - .keymap_data = &p2_keymap_data, - .delay = 4, - .dbounce = true, -}; - -static struct platform_device kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &kp_data, - }, - .num_resources = ARRAY_SIZE(kp_resources), - .resource = kp_resources, -}; - -static struct platform_device *devices[] __initdata = { - &nor_device, - &nand_device, - &smc91x_device, - &kp_device, -}; - -static const struct omap_lcd_config perseus2_lcd_config __initconst = { - .ctrl_name = "internal", -}; - -static void __init perseus2_init_smc91x(void) -{ - __raw_writeb(1, H2P2_DBG_FPGA_LAN_RESET); - mdelay(50); - __raw_writeb(__raw_readb(H2P2_DBG_FPGA_LAN_RESET) & ~1, - H2P2_DBG_FPGA_LAN_RESET); - mdelay(50); -} - -static void __init omap_perseus2_init(void) -{ - /* Early, board-dependent init */ - - /* - * Hold GSM Reset until needed - */ - omap_writew(omap_readw(OMAP7XX_DSP_M_CTL) & ~1, OMAP7XX_DSP_M_CTL); - - /* - * UARTs -> done automagically by 8250 driver - */ - - /* - * CSx timings, GPIO Mux ... setup - */ - - /* Flash: CS0 timings setup */ - omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_0); - omap_writel(0x00000088, OMAP7XX_FLASH_ACFG_0); - - /* - * Ethernet support through the debug board - * CS1 timings setup - */ - omap_writel(0x0000fff3, OMAP7XX_FLASH_CFG_1); - omap_writel(0x00000000, OMAP7XX_FLASH_ACFG_1); - - /* - * Configure MPU_EXT_NIRQ IO in IO_CONF9 register, - * It is used as the Ethernet controller interrupt - */ - omap_writel(omap_readl(OMAP7XX_IO_CONF_9) & 0x1FFFFFFF, - OMAP7XX_IO_CONF_9); - - perseus2_init_smc91x(); - - BUG_ON(gpio_request(P2_NAND_RB_GPIO_PIN, "NAND ready") < 0); - gpio_direction_input(P2_NAND_RB_GPIO_PIN); - - omap_cfg_reg(L3_1610_FLASH_CS2B_OE); - omap_cfg_reg(M8_1610_FLASH_CS2B_WE); - - /* Mux pins for keypad */ - omap_cfg_reg(E2_7XX_KBR0); - omap_cfg_reg(J7_7XX_KBR1); - omap_cfg_reg(E1_7XX_KBR2); - omap_cfg_reg(F3_7XX_KBR3); - omap_cfg_reg(D2_7XX_KBR4); - omap_cfg_reg(C2_7XX_KBC0); - omap_cfg_reg(D3_7XX_KBC1); - omap_cfg_reg(E4_7XX_KBC2); - omap_cfg_reg(F4_7XX_KBC3); - omap_cfg_reg(E3_7XX_KBC4); - - if (IS_ENABLED(CONFIG_SPI_OMAP_UWIRE)) { - /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */ - int val = omap_readl(OMAP7XX_IO_CONF_9) & ~0x00EEE000; - omap_writel(val | 0x00AAA000, OMAP7XX_IO_CONF_9); - } - - platform_add_devices(devices, ARRAY_SIZE(devices)); - - omap_serial_init(); - omap_register_i2c_bus(1, 100, NULL, 0); - - omapfb_set_lcd_config(&perseus2_lcd_config); -} - -/* Only FPGA needs to be mapped here. All others are done with ioremap */ -static struct map_desc omap_perseus2_io_desc[] __initdata = { - { - .virtual = H2P2_DBG_FPGA_BASE, - .pfn = __phys_to_pfn(H2P2_DBG_FPGA_START), - .length = H2P2_DBG_FPGA_SIZE, - .type = MT_DEVICE - } -}; - -static void __init omap_perseus2_map_io(void) -{ - omap7xx_map_io(); - iotable_init(omap_perseus2_io_desc, - ARRAY_SIZE(omap_perseus2_io_desc)); -} - -MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2") - /* Maintainer: Kevin Hilman */ - .atag_offset = 0x100, - .map_io = omap_perseus2_map_io, - .init_early = omap1_init_early, - .init_irq = omap1_init_irq, - .handle_irq = omap1_handle_irq, - .init_machine = omap_perseus2_init, - .init_late = omap1_init_late, - .init_time = omap1_timer_init, - .restart = omap1_restart, -MACHINE_END diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c deleted file mode 100644 index 4c71a195969f..000000000000 --- a/arch/arm/mach-omap1/fpga.c +++ /dev/null @@ -1,186 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-omap1/fpga.c - * - * Interrupt handler for OMAP-1510 Innovator FPGA - * - * Copyright (C) 2001 RidgeRun, Inc. - * Author: Greg Lonnon - * - * Copyright (C) 2002 MontaVista Software, Inc. - * - * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 - * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "hardware.h" -#include "iomap.h" -#include "common.h" -#include "fpga.h" - -static void fpga_mask_irq(struct irq_data *d) -{ - unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE; - - if (irq < 8) - __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) - & ~(1 << irq)), OMAP1510_FPGA_IMR_LO); - else if (irq < 16) - __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI) - & ~(1 << (irq - 8))), OMAP1510_FPGA_IMR_HI); - else - __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2) - & ~(1 << (irq - 16))), INNOVATOR_FPGA_IMR2); -} - - -static inline u32 get_fpga_unmasked_irqs(void) -{ - return - ((__raw_readb(OMAP1510_FPGA_ISR_LO) & - __raw_readb(OMAP1510_FPGA_IMR_LO))) | - ((__raw_readb(OMAP1510_FPGA_ISR_HI) & - __raw_readb(OMAP1510_FPGA_IMR_HI)) << 8) | - ((__raw_readb(INNOVATOR_FPGA_ISR2) & - __raw_readb(INNOVATOR_FPGA_IMR2)) << 16); -} - - -static void fpga_ack_irq(struct irq_data *d) -{ - /* Don't need to explicitly ACK FPGA interrupts */ -} - -static void fpga_unmask_irq(struct irq_data *d) -{ - unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE; - - if (irq < 8) - __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)), - OMAP1510_FPGA_IMR_LO); - else if (irq < 16) - __raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI) - | (1 << (irq - 8))), OMAP1510_FPGA_IMR_HI); - else - __raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2) - | (1 << (irq - 16))), INNOVATOR_FPGA_IMR2); -} - -static void fpga_mask_ack_irq(struct irq_data *d) -{ - fpga_mask_irq(d); - fpga_ack_irq(d); -} - -static void innovator_fpga_IRQ_demux(struct irq_desc *desc) -{ - u32 stat; - int fpga_irq; - - stat = get_fpga_unmasked_irqs(); - - if (!stat) - return; - - for (fpga_irq = OMAP_FPGA_IRQ_BASE; - (fpga_irq < OMAP_FPGA_IRQ_END) && stat; - fpga_irq++, stat >>= 1) { - if (stat & 1) { - generic_handle_irq(fpga_irq); - } - } -} - -static struct irq_chip omap_fpga_irq_ack = { - .name = "FPGA-ack", - .irq_ack = fpga_mask_ack_irq, - .irq_mask = fpga_mask_irq, - .irq_unmask = fpga_unmask_irq, -}; - - -static struct irq_chip omap_fpga_irq = { - .name = "FPGA", - .irq_ack = fpga_ack_irq, - .irq_mask = fpga_mask_irq, - .irq_unmask = fpga_unmask_irq, -}; - -/* - * All of the FPGA interrupt request inputs except for the touchscreen are - * edge-sensitive; the touchscreen is level-sensitive. The edge-sensitive - * interrupts are acknowledged as a side-effect of reading the interrupt - * status register from the FPGA. The edge-sensitive interrupt inputs - * cause a problem with level interrupt requests, such as Ethernet. The - * problem occurs when a level interrupt request is asserted while its - * interrupt input is masked in the FPGA, which results in a missed - * interrupt. - * - * In an attempt to workaround the problem with missed interrupts, the - * mask_ack routine for all of the FPGA interrupts has been changed from - * fpga_mask_ack_irq() to fpga_ack_irq() so that the specific FPGA interrupt - * being serviced is left unmasked. We can do this because the FPGA cascade - * interrupt is run with all interrupts masked. - * - * Limited testing indicates that this workaround appears to be effective - * for the smc9194 Ethernet driver used on the Innovator. It should work - * on other FPGA interrupts as well, but any drivers that explicitly mask - * interrupts at the interrupt controller via disable_irq/enable_irq - * could pose a problem. - */ -void omap1510_fpga_init_irq(void) -{ - int i, res; - - __raw_writeb(0, OMAP1510_FPGA_IMR_LO); - __raw_writeb(0, OMAP1510_FPGA_IMR_HI); - __raw_writeb(0, INNOVATOR_FPGA_IMR2); - - for (i = OMAP_FPGA_IRQ_BASE; i < OMAP_FPGA_IRQ_END; i++) { - - if (i == OMAP1510_INT_FPGA_TS) { - /* - * The touchscreen interrupt is level-sensitive, so - * we'll use the regular mask_ack routine for it. - */ - irq_set_chip(i, &omap_fpga_irq_ack); - } - else { - /* - * All FPGA interrupts except the touchscreen are - * edge-sensitive, so we won't mask them. - */ - irq_set_chip(i, &omap_fpga_irq); - } - - irq_set_handler(i, handle_edge_irq); - irq_clear_status_flags(i, IRQ_NOREQUEST); - } - - /* - * The FPGA interrupt line is connected to GPIO13. Claim this pin for - * the ARM. - * - * NOTE: For general GPIO/MPUIO access and interrupts, please see - * gpio.[ch] - */ - res = gpio_request(13, "FPGA irq"); - if (res) { - pr_err("%s failed to get gpio\n", __func__); - return; - } - gpio_direction_input(13); - irq_set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING); - irq_set_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux); -} diff --git a/arch/arm/mach-omap1/fpga.h b/arch/arm/mach-omap1/fpga.h deleted file mode 100644 index 7e7450edacc1..000000000000 --- a/arch/arm/mach-omap1/fpga.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Interrupt handler for OMAP-1510 FPGA - * - * Copyright (C) 2001 RidgeRun, Inc. - * Author: Greg Lonnon - * - * Copyright (C) 2002 MontaVista Software, Inc. - * - * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6 - * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen - */ - -#ifndef __ASM_ARCH_OMAP_FPGA_H -#define __ASM_ARCH_OMAP_FPGA_H - -/* - * --------------------------------------------------------------------------- - * H2/P2 Debug board FPGA - * --------------------------------------------------------------------------- - */ -/* maps in the FPGA registers and the ETHR registers */ -#define H2P2_DBG_FPGA_BASE 0xE8000000 /* VA */ -#define H2P2_DBG_FPGA_SIZE SZ_4K /* SIZE */ -#define H2P2_DBG_FPGA_START 0x04000000 /* PA */ - -#define H2P2_DBG_FPGA_ETHR_START (H2P2_DBG_FPGA_START + 0x300) -#define H2P2_DBG_FPGA_FPGA_REV IOMEM(H2P2_DBG_FPGA_BASE + 0x10) /* FPGA Revision */ -#define H2P2_DBG_FPGA_BOARD_REV IOMEM(H2P2_DBG_FPGA_BASE + 0x12) /* Board Revision */ -#define H2P2_DBG_FPGA_GPIO IOMEM(H2P2_DBG_FPGA_BASE + 0x14) /* GPIO outputs */ -#define H2P2_DBG_FPGA_LEDS IOMEM(H2P2_DBG_FPGA_BASE + 0x16) /* LEDs outputs */ -#define H2P2_DBG_FPGA_MISC_INPUTS IOMEM(H2P2_DBG_FPGA_BASE + 0x18) /* Misc inputs */ -#define H2P2_DBG_FPGA_LAN_STATUS IOMEM(H2P2_DBG_FPGA_BASE + 0x1A) /* LAN Status line */ -#define H2P2_DBG_FPGA_LAN_RESET IOMEM(H2P2_DBG_FPGA_BASE + 0x1C) /* LAN Reset line */ - -/* LEDs definition on debug board (16 LEDs, all physically green) */ -#define H2P2_DBG_FPGA_LED_GREEN (1 << 15) -#define H2P2_DBG_FPGA_LED_AMBER (1 << 14) -#define H2P2_DBG_FPGA_LED_RED (1 << 13) -#define H2P2_DBG_FPGA_LED_BLUE (1 << 12) -/* cpu0 load-meter LEDs */ -#define H2P2_DBG_FPGA_LOAD_METER (1 << 0) // A bit of fun on our board ... -#define H2P2_DBG_FPGA_LOAD_METER_SIZE 11 -#define H2P2_DBG_FPGA_LOAD_METER_MASK ((1 << H2P2_DBG_FPGA_LOAD_METER_SIZE) - 1) - -#define H2P2_DBG_FPGA_P2_LED_TIMER (1 << 0) -#define H2P2_DBG_FPGA_P2_LED_IDLE (1 << 1) - -#endif diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c deleted file mode 100644 index c372b357eab4..000000000000 --- a/arch/arm/mach-omap1/gpio7xx.c +++ /dev/null @@ -1,272 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * OMAP7xx specific gpio init - * - * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ - * - * Author: - * Charulatha V - */ - -#include -#include - -#include "irqs.h" -#include "soc.h" - -#define OMAP7XX_GPIO1_BASE 0xfffbc000 -#define OMAP7XX_GPIO2_BASE 0xfffbc800 -#define OMAP7XX_GPIO3_BASE 0xfffbd000 -#define OMAP7XX_GPIO4_BASE 0xfffbd800 -#define OMAP7XX_GPIO5_BASE 0xfffbe000 -#define OMAP7XX_GPIO6_BASE 0xfffbe800 -#define OMAP1_MPUIO_VBASE OMAP1_MPUIO_BASE - -/* mpu gpio */ -static struct resource omap7xx_mpu_gpio_resources[] = { - { - .start = OMAP1_MPUIO_VBASE, - .end = OMAP1_MPUIO_VBASE + SZ_2K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_7XX_MPUIO, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct omap_gpio_reg_offs omap7xx_mpuio_regs = { - .revision = USHRT_MAX, - .direction = OMAP_MPUIO_IO_CNTL / 2, - .datain = OMAP_MPUIO_INPUT_LATCH / 2, - .dataout = OMAP_MPUIO_OUTPUT / 2, - .irqstatus = OMAP_MPUIO_GPIO_INT / 2, - .irqenable = OMAP_MPUIO_GPIO_MASKIT / 2, - .irqenable_inv = true, - .irqctrl = OMAP_MPUIO_GPIO_INT_EDGE >> 1, -}; - -static struct omap_gpio_platform_data omap7xx_mpu_gpio_config = { - .is_mpuio = true, - .bank_width = 16, - .bank_stride = 2, - .regs = &omap7xx_mpuio_regs, -}; - -static struct platform_device omap7xx_mpu_gpio = { - .name = "omap_gpio", - .id = 0, - .dev = { - .platform_data = &omap7xx_mpu_gpio_config, - }, - .num_resources = ARRAY_SIZE(omap7xx_mpu_gpio_resources), - .resource = omap7xx_mpu_gpio_resources, -}; - -/* gpio1 */ -static struct resource omap7xx_gpio1_resources[] = { - { - .start = OMAP7XX_GPIO1_BASE, - .end = OMAP7XX_GPIO1_BASE + SZ_2K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_7XX_GPIO_BANK1, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct omap_gpio_reg_offs omap7xx_gpio_regs = { - .revision = USHRT_MAX, - .direction = OMAP7XX_GPIO_DIR_CONTROL, - .datain = OMAP7XX_GPIO_DATA_INPUT, - .dataout = OMAP7XX_GPIO_DATA_OUTPUT, - .irqstatus = OMAP7XX_GPIO_INT_STATUS, - .irqenable = OMAP7XX_GPIO_INT_MASK, - .irqenable_inv = true, - .irqctrl = OMAP7XX_GPIO_INT_CONTROL, -}; - -static struct omap_gpio_platform_data omap7xx_gpio1_config = { - .bank_width = 32, - .regs = &omap7xx_gpio_regs, -}; - -static struct platform_device omap7xx_gpio1 = { - .name = "omap_gpio", - .id = 1, - .dev = { - .platform_data = &omap7xx_gpio1_config, - }, - .num_resources = ARRAY_SIZE(omap7xx_gpio1_resources), - .resource = omap7xx_gpio1_resources, -}; - -/* gpio2 */ -static struct resource omap7xx_gpio2_resources[] = { - { - .start = OMAP7XX_GPIO2_BASE, - .end = OMAP7XX_GPIO2_BASE + SZ_2K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_7XX_GPIO_BANK2, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct omap_gpio_platform_data omap7xx_gpio2_config = { - .bank_width = 32, - .regs = &omap7xx_gpio_regs, -}; - -static struct platform_device omap7xx_gpio2 = { - .name = "omap_gpio", - .id = 2, - .dev = { - .platform_data = &omap7xx_gpio2_config, - }, - .num_resources = ARRAY_SIZE(omap7xx_gpio2_resources), - .resource = omap7xx_gpio2_resources, -}; - -/* gpio3 */ -static struct resource omap7xx_gpio3_resources[] = { - { - .start = OMAP7XX_GPIO3_BASE, - .end = OMAP7XX_GPIO3_BASE + SZ_2K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_7XX_GPIO_BANK3, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct omap_gpio_platform_data omap7xx_gpio3_config = { - .bank_width = 32, - .regs = &omap7xx_gpio_regs, -}; - -static struct platform_device omap7xx_gpio3 = { - .name = "omap_gpio", - .id = 3, - .dev = { - .platform_data = &omap7xx_gpio3_config, - }, - .num_resources = ARRAY_SIZE(omap7xx_gpio3_resources), - .resource = omap7xx_gpio3_resources, -}; - -/* gpio4 */ -static struct resource omap7xx_gpio4_resources[] = { - { - .start = OMAP7XX_GPIO4_BASE, - .end = OMAP7XX_GPIO4_BASE + SZ_2K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_7XX_GPIO_BANK4, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct omap_gpio_platform_data omap7xx_gpio4_config = { - .bank_width = 32, - .regs = &omap7xx_gpio_regs, -}; - -static struct platform_device omap7xx_gpio4 = { - .name = "omap_gpio", - .id = 4, - .dev = { - .platform_data = &omap7xx_gpio4_config, - }, - .num_resources = ARRAY_SIZE(omap7xx_gpio4_resources), - .resource = omap7xx_gpio4_resources, -}; - -/* gpio5 */ -static struct resource omap7xx_gpio5_resources[] = { - { - .start = OMAP7XX_GPIO5_BASE, - .end = OMAP7XX_GPIO5_BASE + SZ_2K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_7XX_GPIO_BANK5, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct omap_gpio_platform_data omap7xx_gpio5_config = { - .bank_width = 32, - .regs = &omap7xx_gpio_regs, -}; - -static struct platform_device omap7xx_gpio5 = { - .name = "omap_gpio", - .id = 5, - .dev = { - .platform_data = &omap7xx_gpio5_config, - }, - .num_resources = ARRAY_SIZE(omap7xx_gpio5_resources), - .resource = omap7xx_gpio5_resources, -}; - -/* gpio6 */ -static struct resource omap7xx_gpio6_resources[] = { - { - .start = OMAP7XX_GPIO6_BASE, - .end = OMAP7XX_GPIO6_BASE + SZ_2K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_7XX_GPIO_BANK6, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct omap_gpio_platform_data omap7xx_gpio6_config = { - .bank_width = 32, - .regs = &omap7xx_gpio_regs, -}; - -static struct platform_device omap7xx_gpio6 = { - .name = "omap_gpio", - .id = 6, - .dev = { - .platform_data = &omap7xx_gpio6_config, - }, - .num_resources = ARRAY_SIZE(omap7xx_gpio6_resources), - .resource = omap7xx_gpio6_resources, -}; - -static struct platform_device *omap7xx_gpio_dev[] __initdata = { - &omap7xx_mpu_gpio, - &omap7xx_gpio1, - &omap7xx_gpio2, - &omap7xx_gpio3, - &omap7xx_gpio4, - &omap7xx_gpio5, - &omap7xx_gpio6, -}; - -/* - * omap7xx_gpio_init needs to be done before - * machine_init functions access gpio APIs. - * Hence omap7xx_gpio_init is a postcore_initcall. - */ -static int __init omap7xx_gpio_init(void) -{ - int i; - - if (!cpu_is_omap7xx()) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(omap7xx_gpio_dev); i++) - platform_device_register(omap7xx_gpio_dev[i]); - - return 0; -} -postcore_initcall(omap7xx_gpio_init); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c6b498ebeb47..72b3b44b5be7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -874,7 +874,7 @@ config I2C_OCORES config I2C_OMAP tristate "OMAP I2C adapter" depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST - default y if MACH_OMAP_H3 || MACH_OMAP_OSK + default MACH_OMAP_OSK help If you say yes to this option, support will be included for the I2C interface on the Texas Instruments OMAP1/2 family of processors. diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 30db49f31866..e5ccea55b4ae 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1514,7 +1514,7 @@ config TPS6105X config TPS65010 tristate "TI TPS6501x Power Management chips" depends on I2C && GPIOLIB - default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK + default MACH_OMAP_OSK help If you say yes here you get support for the TPS6501x series of Power Management chips. These include voltage regulators, diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 30c9b168cac1..1eaebaef0b3e 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -489,7 +489,7 @@ config MMC_SDHCI_ST config MMC_OMAP tristate "TI OMAP Multimedia Card Interface support" depends on ARCH_OMAP - depends on TPS65010 || !MACH_OMAP_H2 + depends on TPS65010 help This selects the TI OMAP Multimedia card Interface. If you have an OMAP board with a Multimedia Card slot, diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index b3006d8b04ab..0c5640bd6c24 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -118,7 +118,6 @@ config USB_GR_UDC config USB_OMAP tristate "OMAP USB Device Controller" depends on ARCH_OMAP1 - depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) help Many Texas Instruments OMAP processors have flexible full speed USB device controllers, with support for up to 30 diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 0442dc4bc334..d81692cc2990 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -409,7 +409,6 @@ if USB_OHCI_HCD config USB_OHCI_HCD_OMAP1 tristate "OHCI support for OMAP1/2 chips" depends on ARCH_OMAP1 - depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) default y help Enables support for the OHCI controller on OMAP1/2 chips. diff --git a/include/linux/platform_data/leds-omap.h b/include/linux/platform_data/leds-omap.h deleted file mode 100644 index dd1a3ec86fe4..000000000000 --- a/include/linux/platform_data/leds-omap.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2006 Samsung Electronics - * Kyungmin Park - */ -#ifndef ASMARM_ARCH_LED_H -#define ASMARM_ARCH_LED_H - -struct omap_led_config { - struct led_classdev cdev; - s16 gpio; -}; - -struct omap_led_platform_data { - s16 nr_leds; - struct omap_led_config *leds; -}; - -#endif -- cgit v1.2.3 From 8825acd7cc8a13af7ae6c2c5e5025af38df6c2e4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 29 Sep 2022 16:19:44 +0200 Subject: ARM: omap1: remove dead code After the removal of the unused board files, I went through the omap1 code to look for code that no longer has any callers and remove that. In particular, support for the omap7xx/omap8xx family is now completely unused, so I'm only leaving omap15xx/omap16xx/omap59xx. Cc: Aaro Koskinen Cc: Janusz Krzysztofik Cc: linux-omap@vger.kernel.org Reviewed-by: Greg Kroah-Hartman Acked-by: Tony Lindgren Acked-by: Kevin Hilman Signed-off-by: Arnd Bergmann --- arch/arm/mach-omap1/clock_data.c | 17 +------ arch/arm/mach-omap1/common.h | 8 ---- arch/arm/mach-omap1/devices.c | 58 ++---------------------- arch/arm/mach-omap1/dma.c | 25 +---------- arch/arm/mach-omap1/i2c.c | 14 ++---- arch/arm/mach-omap1/io.c | 28 ------------ arch/arm/mach-omap1/irq.c | 20 +-------- arch/arm/mach-omap1/irqs.h | 9 ---- arch/arm/mach-omap1/mcbsp.c | 76 ------------------------------- arch/arm/mach-omap1/mtd-xip.h | 4 -- arch/arm/mach-omap1/mux.c | 52 ---------------------- arch/arm/mach-omap1/pm.c | 76 +++++-------------------------- arch/arm/mach-omap1/pm.h | 35 --------------- arch/arm/mach-omap1/serial.c | 15 ------- arch/arm/mach-omap1/sleep.S | 80 --------------------------------- arch/arm/mach-omap1/sram-init.c | 7 +-- arch/arm/mach-omap1/usb.c | 34 +++----------- drivers/spi/spi-omap-uwire.c | 16 +------ drivers/usb/gadget/udc/omap_udc.c | 24 ++-------- drivers/usb/host/ohci-omap.c | 6 +-- drivers/usb/phy/phy-isp1301-omap.c | 91 +------------------------------------- drivers/video/fbdev/omap/lcdc.c | 2 - include/linux/soc/ti/omap1-soc.h | 35 --------------- 23 files changed, 36 insertions(+), 696 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c index 96d846c37c43..c58d200e4816 100644 --- a/arch/arm/mach-omap1/clock_data.c +++ b/arch/arm/mach-omap1/clock_data.c @@ -720,8 +720,6 @@ int __init omap1_clk_init(void) cpu_mask |= CK_16XX; if (cpu_is_omap1510()) cpu_mask |= CK_1510; - if (cpu_is_omap7xx()) - cpu_mask |= CK_7XX; if (cpu_is_omap310()) cpu_mask |= CK_310; @@ -730,9 +728,6 @@ int __init omap1_clk_init(void) ck_dpll1_p = &ck_dpll1; ck_ref_p = &ck_ref; - if (cpu_is_omap7xx()) - ck_ref.rate = 13000000; - pr_info("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n", omap_readw(ARM_SYSST), omap_readw(DPLL_CTL), omap_readw(ARM_CKCTL)); @@ -771,12 +766,6 @@ int __init omap1_clk_init(void) } } - if (machine_is_omap_perseus2() || machine_is_omap_fsample()) { - /* Select slicer output as OMAP input clock */ - omap_writew(omap_readw(OMAP7XX_PCC_UPLD_CTRL) & ~0x1, - OMAP7XX_PCC_UPLD_CTRL); - } - /* Amstrad Delta wants BCLK high when inactive */ if (machine_is_ams_delta()) omap_writel(omap_readl(ULPD_CLOCK_CTRL) | @@ -784,11 +773,7 @@ int __init omap1_clk_init(void) ULPD_CLOCK_CTRL); /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */ - /* (on 730, bit 13 must not be cleared) */ - if (cpu_is_omap7xx()) - omap_writew(omap_readw(ARM_CKCTL) & 0x2fff, ARM_CKCTL); - else - omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); + omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); /* Put DSP/MPUI into reset until needed */ omap_writew(0, ARM_RSTCT1); diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h index 5ceff05e15c0..3fd9ed9efb12 100644 --- a/arch/arm/mach-omap1/common.h +++ b/arch/arm/mach-omap1/common.h @@ -35,14 +35,6 @@ #include "soc.h" #include "i2c.h" -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) -void omap7xx_map_io(void); -#else -static inline void omap7xx_map_io(void) -{ -} -#endif - #ifdef CONFIG_ARCH_OMAP15XX void omap1510_fpga_init_irq(void); void omap15xx_map_io(void); diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index 80e94770582a..42d1631cecc0 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -63,8 +63,6 @@ static void omap_init_rtc(void) static inline void omap_init_rtc(void) {} #endif -static inline void omap_init_mbox(void) { } - /*-------------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_MMC_OMAP) @@ -73,22 +71,16 @@ static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller, int controller_nr) { if (controller_nr == 0) { - if (cpu_is_omap7xx()) { - omap_cfg_reg(MMC_7XX_CMD); - omap_cfg_reg(MMC_7XX_CLK); - omap_cfg_reg(MMC_7XX_DAT0); - } else { - omap_cfg_reg(MMC_CMD); - omap_cfg_reg(MMC_CLK); - omap_cfg_reg(MMC_DAT0); - } + omap_cfg_reg(MMC_CMD); + omap_cfg_reg(MMC_CLK); + omap_cfg_reg(MMC_DAT0); if (cpu_is_omap1710()) { omap_cfg_reg(M15_1710_MMC_CLKI); omap_cfg_reg(P19_1710_MMC_CMDDIR); omap_cfg_reg(P20_1710_MMC_DATDIR0); } - if (mmc_controller->slots[0].wires == 4 && !cpu_is_omap7xx()) { + if (mmc_controller->slots[0].wires == 4) { omap_cfg_reg(MMC_DAT1); /* NOTE: DAT2 can be on W10 (here) or M15 */ if (!mmc_controller->slots[0].nomux) @@ -154,8 +146,6 @@ static int __init omap_mmc_add(const char *name, int id, unsigned long base, res[3].name = "tx"; res[3].flags = IORESOURCE_DMA; - if (cpu_is_omap7xx()) - data->slots[0].features = MMC_OMAP7XX; if (cpu_is_omap15xx()) data->slots[0].features = MMC_OMAP15XX; if (cpu_is_omap16xx()) @@ -224,43 +214,6 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, /*-------------------------------------------------------------------------*/ -/* OMAP7xx SPI support */ -#if IS_ENABLED(CONFIG_SPI_OMAP_100K) - -struct platform_device omap_spi1 = { - .name = "omap1_spi100k", - .id = 1, -}; - -struct platform_device omap_spi2 = { - .name = "omap1_spi100k", - .id = 2, -}; - -static void omap_init_spi100k(void) -{ - if (!cpu_is_omap7xx()) - return; - - omap_spi1.dev.platform_data = ioremap(OMAP7XX_SPI1_BASE, 0x7ff); - if (omap_spi1.dev.platform_data) - platform_device_register(&omap_spi1); - - omap_spi2.dev.platform_data = ioremap(OMAP7XX_SPI2_BASE, 0x7ff); - if (omap_spi2.dev.platform_data) - platform_device_register(&omap_spi2); -} - -#else -static inline void omap_init_spi100k(void) -{ -} -#endif - -/*-------------------------------------------------------------------------*/ - -static inline void omap_init_sti(void) {} - /* Numbering for the SPI-capable controllers when used for SPI: * spi = 1 * uwire = 2 @@ -363,10 +316,7 @@ static int __init omap1_init_devices(void) * in alphabetical order so they're easier to sort through. */ - omap_init_mbox(); omap_init_rtc(); - omap_init_spi100k(); - omap_init_sti(); omap_init_uwire(); omap1_init_rng(); diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c index c3f280c3c5d7..756966cb715f 100644 --- a/arch/arm/mach-omap1/dma.c +++ b/arch/arm/mach-omap1/dma.c @@ -261,22 +261,6 @@ static const struct platform_device_info omap_dma_dev_info = { .num_res = 1, }; -/* OMAP730, OMAP850 */ -static const struct dma_slave_map omap7xx_sdma_map[] = { - { "omap-mcbsp.1", "tx", SDMA_FILTER_PARAM(8) }, - { "omap-mcbsp.1", "rx", SDMA_FILTER_PARAM(9) }, - { "omap-mcbsp.2", "tx", SDMA_FILTER_PARAM(10) }, - { "omap-mcbsp.2", "rx", SDMA_FILTER_PARAM(11) }, - { "mmci-omap.0", "tx", SDMA_FILTER_PARAM(21) }, - { "mmci-omap.0", "rx", SDMA_FILTER_PARAM(22) }, - { "omap_udc", "rx0", SDMA_FILTER_PARAM(26) }, - { "omap_udc", "rx1", SDMA_FILTER_PARAM(27) }, - { "omap_udc", "rx2", SDMA_FILTER_PARAM(28) }, - { "omap_udc", "tx0", SDMA_FILTER_PARAM(29) }, - { "omap_udc", "tx1", SDMA_FILTER_PARAM(30) }, - { "omap_udc", "tx2", SDMA_FILTER_PARAM(31) }, -}; - /* OMAP1510, OMAP1610*/ static const struct dma_slave_map omap1xxx_sdma_map[] = { { "omap-mcbsp.1", "tx", SDMA_FILTER_PARAM(8) }, @@ -371,13 +355,8 @@ static int __init omap1_system_dma_init(void) p.dma_attr = d; p.errata = configure_dma_errata(); - if (cpu_is_omap7xx()) { - p.slave_map = omap7xx_sdma_map; - p.slavecnt = ARRAY_SIZE(omap7xx_sdma_map); - } else { - p.slave_map = omap1xxx_sdma_map; - p.slavecnt = ARRAY_SIZE(omap1xxx_sdma_map); - } + p.slave_map = omap1xxx_sdma_map; + p.slavecnt = ARRAY_SIZE(omap1xxx_sdma_map); ret = platform_device_add_data(pdev, &p, sizeof(p)); if (ret) { diff --git a/arch/arm/mach-omap1/i2c.c b/arch/arm/mach-omap1/i2c.c index 22f945360599..94d3e7883e02 100644 --- a/arch/arm/mach-omap1/i2c.c +++ b/arch/arm/mach-omap1/i2c.c @@ -25,13 +25,8 @@ static struct platform_device omap_i2c_devices[1] = { static void __init omap1_i2c_mux_pins(int bus_id) { - if (cpu_is_omap7xx()) { - omap_cfg_reg(I2C_7XX_SDA); - omap_cfg_reg(I2C_7XX_SCL); - } else { - omap_cfg_reg(I2C_SDA); - omap_cfg_reg(I2C_SCL); - } + omap_cfg_reg(I2C_SDA); + omap_cfg_reg(I2C_SCL); } int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *pdata, @@ -68,10 +63,7 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *pdata, /* how the cpu bus is wired up differs for 7xx only */ - if (cpu_is_omap7xx()) - pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_1; - else - pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_2; + pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_2; pdev->dev.platform_data = pdata; diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c index 0074b011a05a..a08406cb2303 100644 --- a/arch/arm/mach-omap1/io.c +++ b/arch/arm/mach-omap1/io.c @@ -22,27 +22,6 @@ * The machine specific code may provide the extra mapping besides the * default mapping provided here. */ -#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850) -static struct map_desc omap7xx_io_desc[] __initdata = { - { - .virtual = OMAP1_IO_VIRT, - .pfn = __phys_to_pfn(OMAP1_IO_PHYS), - .length = OMAP1_IO_SIZE, - .type = MT_DEVICE - }, - { - .virtual = OMAP7XX_DSP_BASE, - .pfn = __phys_to_pfn(OMAP7XX_DSP_START), - .length = OMAP7XX_DSP_SIZE, - .type = MT_DEVICE - }, { - .virtual = OMAP7XX_DSPREG_BASE, - .pfn = __phys_to_pfn(OMAP7XX_DSPREG_START), - .length = OMAP7XX_DSPREG_SIZE, - .type = MT_DEVICE - } -}; -#endif #ifdef CONFIG_ARCH_OMAP15XX static struct map_desc omap1510_io_desc[] __initdata = { @@ -88,13 +67,6 @@ static struct map_desc omap16xx_io_desc[] __initdata = { }; #endif -#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850) -void __init omap7xx_map_io(void) -{ - iotable_init(omap7xx_io_desc, ARRAY_SIZE(omap7xx_io_desc)); -} -#endif - #ifdef CONFIG_ARCH_OMAP15XX void __init omap15xx_map_io(void) { diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c index 70868e9f19ac..9ccc784fd614 100644 --- a/arch/arm/mach-omap1/irq.c +++ b/arch/arm/mach-omap1/irq.c @@ -110,14 +110,6 @@ static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger) irq_bank_writel(val, bank, offset); } -#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850) -static struct omap_irq_bank omap7xx_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 }, - { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0x800040f3 }, -}; -#endif - #ifdef CONFIG_ARCH_OMAP15XX static struct omap_irq_bank omap1510_irq_banks[] = { { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff }, @@ -194,12 +186,6 @@ void __init omap1_init_irq(void) int i, j, irq_base; unsigned long nr_irqs; -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) - if (cpu_is_omap7xx()) { - irq_banks = omap7xx_irq_banks; - irq_bank_count = ARRAY_SIZE(omap7xx_irq_banks); - } -#endif #ifdef CONFIG_ARCH_OMAP15XX if (cpu_is_omap1510()) { irq_banks = omap1510_irq_banks; @@ -230,7 +216,7 @@ void __init omap1_init_irq(void) pr_warn("Couldn't allocate IRQ numbers\n"); irq_base = 0; } - omap_l2_irq = cpu_is_omap7xx() ? irq_base + 1 : irq_base; + omap_l2_irq = irq_base; omap_l2_irq -= NR_IRQS_LEGACY; domain = irq_domain_add_legacy(NULL, nr_irqs, irq_base, 0, @@ -249,10 +235,6 @@ void __init omap1_init_irq(void) irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET); irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET); - /* Enable interrupts in global mask */ - if (cpu_is_omap7xx()) - irq_bank_writel(0x0, 0, IRQ_GMR_REG_OFFSET); - /* Install the interrupt handlers for each bank */ for (i = 0; i < irq_bank_count; i++) { for (j = i * 32; j < (i + 1) * 32; j++) { diff --git a/arch/arm/mach-omap1/irqs.h b/arch/arm/mach-omap1/irqs.h index 2851acfe5ff3..3ab7050b1b6b 100644 --- a/arch/arm/mach-omap1/irqs.h +++ b/arch/arm/mach-omap1/irqs.h @@ -231,15 +231,6 @@ #define IH_MPUIO_BASE (OMAP_MAX_GPIO_LINES + IH_GPIO_BASE) #define OMAP_IRQ_END (IH_MPUIO_BASE + 16) -/* External FPGA handles interrupts on Innovator boards */ -#define OMAP_FPGA_IRQ_BASE (OMAP_IRQ_END) -#ifdef CONFIG_MACH_OMAP_INNOVATOR -#define OMAP_FPGA_NR_IRQS 24 -#else -#define OMAP_FPGA_NR_IRQS 0 -#endif -#define OMAP_FPGA_IRQ_END (OMAP_FPGA_IRQ_BASE + OMAP_FPGA_NR_IRQS) - #define OMAP_IRQ_BIT(irq) (1 << ((irq - NR_IRQS_LEGACY) % 32)) #ifdef CONFIG_FIQ diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c index b1632cbe37e6..37863bdce9ea 100644 --- a/arch/arm/mach-omap1/mcbsp.c +++ b/arch/arm/mach-omap1/mcbsp.c @@ -89,76 +89,6 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = { #define OMAP1610_MCBSP2_BASE 0xfffb1000 #define OMAP1610_MCBSP3_BASE 0xe1017000 -struct resource omap7xx_mcbsp_res[][6] = { - { - { - .start = OMAP7XX_MCBSP1_BASE, - .end = OMAP7XX_MCBSP1_BASE + SZ_256, - .flags = IORESOURCE_MEM, - }, - { - .name = "rx", - .start = INT_7XX_McBSP1RX, - .flags = IORESOURCE_IRQ, - }, - { - .name = "tx", - .start = INT_7XX_McBSP1TX, - .flags = IORESOURCE_IRQ, - }, - { - .name = "rx", - .start = 9, - .flags = IORESOURCE_DMA, - }, - { - .name = "tx", - .start = 8, - .flags = IORESOURCE_DMA, - }, - }, - { - { - .start = OMAP7XX_MCBSP2_BASE, - .end = OMAP7XX_MCBSP2_BASE + SZ_256, - .flags = IORESOURCE_MEM, - }, - { - .name = "rx", - .start = INT_7XX_McBSP2RX, - .flags = IORESOURCE_IRQ, - }, - { - .name = "tx", - .start = INT_7XX_McBSP2TX, - .flags = IORESOURCE_IRQ, - }, - { - .name = "rx", - .start = 11, - .flags = IORESOURCE_DMA, - }, - { - .name = "tx", - .start = 10, - .flags = IORESOURCE_DMA, - }, - }, -}; - -#define omap7xx_mcbsp_res_0 omap7xx_mcbsp_res[0] - -static struct omap_mcbsp_platform_data omap7xx_mcbsp_pdata[] = { - { - .ops = &omap1_mcbsp_ops, - }, - { - .ops = &omap1_mcbsp_ops, - }, -}; -#define OMAP7XX_MCBSP_RES_SZ ARRAY_SIZE(omap7xx_mcbsp_res[1]) -#define OMAP7XX_MCBSP_COUNT ARRAY_SIZE(omap7xx_mcbsp_res) - struct resource omap15xx_mcbsp_res[][6] = { { { @@ -397,12 +327,6 @@ static int __init omap1_mcbsp_init(void) if (!cpu_class_is_omap1()) return -ENODEV; - if (cpu_is_omap7xx()) - omap_mcbsp_register_board_cfg(omap7xx_mcbsp_res_0, - OMAP7XX_MCBSP_RES_SZ, - omap7xx_mcbsp_pdata, - OMAP7XX_MCBSP_COUNT); - if (cpu_is_omap15xx()) omap_mcbsp_register_board_cfg(omap15xx_mcbsp_res_0, OMAP15XX_MCBSP_RES_SZ, diff --git a/arch/arm/mach-omap1/mtd-xip.h b/arch/arm/mach-omap1/mtd-xip.h index 5ae312ff08a1..cbeda46dd526 100644 --- a/arch/arm/mach-omap1/mtd-xip.h +++ b/arch/arm/mach-omap1/mtd-xip.h @@ -42,11 +42,7 @@ static inline unsigned long xip_omap_mpu_timer_read(int nr) * (see linux/mtd/xip.h) */ -#ifdef CONFIG_MACH_OMAP_PERSEUS2 -#define xip_elapsed_since(x) (signed)((~xip_omap_mpu_timer_read(0) - (x)) / 7) -#else #define xip_elapsed_since(x) (signed)((~xip_omap_mpu_timer_read(0) - (x)) / 6) -#endif /* * xip_cpu_idle() is used when waiting for a delay equal or larger than diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c index 2d9458ff1d29..4456fbc8aa3d 100644 --- a/arch/arm/mach-omap1/mux.c +++ b/arch/arm/mach-omap1/mux.c @@ -21,52 +21,6 @@ static struct omap_mux_cfg arch_mux_cfg; -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) -static struct pin_config omap7xx_pins[] = { -MUX_CFG_7XX("E2_7XX_KBR0", 12, 21, 0, 20, 1, 0) -MUX_CFG_7XX("J7_7XX_KBR1", 12, 25, 0, 24, 1, 0) -MUX_CFG_7XX("E1_7XX_KBR2", 12, 29, 0, 28, 1, 0) -MUX_CFG_7XX("F3_7XX_KBR3", 13, 1, 0, 0, 1, 0) -MUX_CFG_7XX("D2_7XX_KBR4", 13, 5, 0, 4, 1, 0) -MUX_CFG_7XX("C2_7XX_KBC0", 13, 9, 0, 8, 1, 0) -MUX_CFG_7XX("D3_7XX_KBC1", 13, 13, 0, 12, 1, 0) -MUX_CFG_7XX("E4_7XX_KBC2", 13, 17, 0, 16, 1, 0) -MUX_CFG_7XX("F4_7XX_KBC3", 13, 21, 0, 20, 1, 0) -MUX_CFG_7XX("E3_7XX_KBC4", 13, 25, 0, 24, 1, 0) - -MUX_CFG_7XX("AA17_7XX_USB_DM", 2, 21, 0, 20, 0, 0) -MUX_CFG_7XX("W16_7XX_USB_PU_EN", 2, 25, 0, 24, 0, 0) -MUX_CFG_7XX("W17_7XX_USB_VBUSI", 2, 29, 6, 28, 1, 0) -MUX_CFG_7XX("W18_7XX_USB_DMCK_OUT",3, 3, 1, 2, 0, 0) -MUX_CFG_7XX("W19_7XX_USB_DCRST", 3, 7, 1, 6, 0, 0) - -/* MMC Pins */ -MUX_CFG_7XX("MMC_7XX_CMD", 2, 9, 0, 8, 1, 0) -MUX_CFG_7XX("MMC_7XX_CLK", 2, 13, 0, 12, 1, 0) -MUX_CFG_7XX("MMC_7XX_DAT0", 2, 17, 0, 16, 1, 0) - -/* I2C interface */ -MUX_CFG_7XX("I2C_7XX_SCL", 5, 1, 0, 0, 1, 0) -MUX_CFG_7XX("I2C_7XX_SDA", 5, 5, 0, 0, 1, 0) - -/* SPI pins */ -MUX_CFG_7XX("SPI_7XX_1", 6, 5, 4, 4, 1, 0) -MUX_CFG_7XX("SPI_7XX_2", 6, 9, 4, 8, 1, 0) -MUX_CFG_7XX("SPI_7XX_3", 6, 13, 4, 12, 1, 0) -MUX_CFG_7XX("SPI_7XX_4", 6, 17, 4, 16, 1, 0) -MUX_CFG_7XX("SPI_7XX_5", 8, 25, 0, 24, 0, 0) -MUX_CFG_7XX("SPI_7XX_6", 9, 5, 0, 4, 0, 0) - -/* UART pins */ -MUX_CFG_7XX("UART_7XX_1", 3, 21, 0, 20, 0, 0) -MUX_CFG_7XX("UART_7XX_2", 8, 1, 6, 0, 0, 0) -}; -#define OMAP7XX_PINS_SZ ARRAY_SIZE(omap7xx_pins) -#else -#define omap7xx_pins NULL -#define OMAP7XX_PINS_SZ 0 -#endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */ - #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) static struct pin_config omap1xxx_pins[] = { /* @@ -489,12 +443,6 @@ EXPORT_SYMBOL(omap_cfg_reg); int __init omap1_mux_init(void) { - if (cpu_is_omap7xx()) { - arch_mux_cfg.pins = omap7xx_pins; - arch_mux_cfg.size = OMAP7XX_PINS_SZ; - arch_mux_cfg.cfg_reg = omap1_cfg_reg; - } - if (cpu_is_omap15xx() || cpu_is_omap16xx()) { arch_mux_cfg.pins = omap1xxx_pins; arch_mux_cfg.size = OMAP1XXX_PINS_SZ; diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index fce7d2b572bf..9761d8404949 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -69,7 +69,6 @@ static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE]; static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; -static unsigned int mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_SIZE]; static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE]; static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; @@ -166,10 +165,7 @@ static void omap_pm_wakeup_setup(void) * drivers must still separately call omap_set_gpio_wakeup() to * wake up to a GPIO interrupt. */ - if (cpu_is_omap7xx()) - level1_wake = OMAP_IRQ_BIT(INT_7XX_GPIO_BANK1) | - OMAP_IRQ_BIT(INT_7XX_IH2_IRQ); - else if (cpu_is_omap15xx()) + if (cpu_is_omap15xx()) level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | OMAP_IRQ_BIT(INT_1510_IH2_IRQ); else if (cpu_is_omap16xx()) @@ -178,12 +174,7 @@ static void omap_pm_wakeup_setup(void) omap_writel(~level1_wake, OMAP_IH1_MIR); - if (cpu_is_omap7xx()) { - omap_writel(~level2_wake, OMAP_IH2_0_MIR); - omap_writel(~(OMAP_IRQ_BIT(INT_7XX_WAKE_UP_REQ) | - OMAP_IRQ_BIT(INT_7XX_MPUIO_KEYPAD)), - OMAP_IH2_1_MIR); - } else if (cpu_is_omap15xx()) { + if (cpu_is_omap15xx()) { level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); omap_writel(~level2_wake, OMAP_IH2_MIR); } else if (cpu_is_omap16xx()) { @@ -236,17 +227,7 @@ void omap1_pm_suspend(void) * Save interrupt, MPUI, ARM and UPLD control registers. */ - if (cpu_is_omap7xx()) { - MPUI7XX_SAVE(OMAP_IH1_MIR); - MPUI7XX_SAVE(OMAP_IH2_0_MIR); - MPUI7XX_SAVE(OMAP_IH2_1_MIR); - MPUI7XX_SAVE(MPUI_CTRL); - MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG); - MPUI7XX_SAVE(MPUI_DSP_API_CONFIG); - MPUI7XX_SAVE(EMIFS_CONFIG); - MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG); - - } else if (cpu_is_omap15xx()) { + if (cpu_is_omap15xx()) { MPUI1510_SAVE(OMAP_IH1_MIR); MPUI1510_SAVE(OMAP_IH2_MIR); MPUI1510_SAVE(MPUI_CTRL); @@ -288,9 +269,8 @@ void omap1_pm_suspend(void) /* stop DSP */ omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1); - /* shut down dsp_ck */ - if (!cpu_is_omap7xx()) - omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL); + /* shut down dsp_ck */ + omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL); /* temporarily enabling api_ck to access DSP registers */ omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); @@ -366,13 +346,7 @@ void omap1_pm_suspend(void) ULPD_RESTORE(ULPD_CLOCK_CTRL); ULPD_RESTORE(ULPD_STATUS_REQ); - if (cpu_is_omap7xx()) { - MPUI7XX_RESTORE(EMIFS_CONFIG); - MPUI7XX_RESTORE(EMIFF_SDRAM_CONFIG); - MPUI7XX_RESTORE(OMAP_IH1_MIR); - MPUI7XX_RESTORE(OMAP_IH2_0_MIR); - MPUI7XX_RESTORE(OMAP_IH2_1_MIR); - } else if (cpu_is_omap15xx()) { + if (cpu_is_omap15xx()) { MPUI1510_RESTORE(MPUI_CTRL); MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG); MPUI1510_RESTORE(MPUI_DSP_API_CONFIG); @@ -433,14 +407,7 @@ static int omap_pm_debug_show(struct seq_file *m, void *v) ULPD_SAVE(ULPD_DPLL_CTRL); ULPD_SAVE(ULPD_POWER_CTRL); - if (cpu_is_omap7xx()) { - MPUI7XX_SAVE(MPUI_CTRL); - MPUI7XX_SAVE(MPUI_DSP_STATUS); - MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG); - MPUI7XX_SAVE(MPUI_DSP_API_CONFIG); - MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG); - MPUI7XX_SAVE(EMIFS_CONFIG); - } else if (cpu_is_omap15xx()) { + if (cpu_is_omap15xx()) { MPUI1510_SAVE(MPUI_CTRL); MPUI1510_SAVE(MPUI_DSP_STATUS); MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); @@ -486,21 +453,7 @@ static int omap_pm_debug_show(struct seq_file *m, void *v) ULPD_SHOW(ULPD_STATUS_REQ), ULPD_SHOW(ULPD_POWER_CTRL)); - if (cpu_is_omap7xx()) { - seq_printf(m, - "MPUI7XX_CTRL_REG 0x%-8x \n" - "MPUI7XX_DSP_STATUS_REG: 0x%-8x \n" - "MPUI7XX_DSP_BOOT_CONFIG_REG: 0x%-8x \n" - "MPUI7XX_DSP_API_CONFIG_REG: 0x%-8x \n" - "MPUI7XX_SDRAM_CONFIG_REG: 0x%-8x \n" - "MPUI7XX_EMIFS_CONFIG_REG: 0x%-8x \n", - MPUI7XX_SHOW(MPUI_CTRL), - MPUI7XX_SHOW(MPUI_DSP_STATUS), - MPUI7XX_SHOW(MPUI_DSP_BOOT_CONFIG), - MPUI7XX_SHOW(MPUI_DSP_API_CONFIG), - MPUI7XX_SHOW(EMIFF_SDRAM_CONFIG), - MPUI7XX_SHOW(EMIFS_CONFIG)); - } else if (cpu_is_omap15xx()) { + if (cpu_is_omap15xx()) { seq_printf(m, "MPUI1510_CTRL_REG 0x%-8x \n" "MPUI1510_DSP_STATUS_REG: 0x%-8x \n" @@ -634,10 +587,7 @@ static int __init omap_pm_init(void) * These routines need to be in SRAM as that's the only * memory the MPU can see when it wakes up. */ - if (cpu_is_omap7xx()) { - omap_sram_suspend = omap_sram_push(omap7xx_cpu_suspend, - omap7xx_cpu_suspend_sz); - } else if (cpu_is_omap15xx()) { + if (cpu_is_omap15xx()) { omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend, omap1510_cpu_suspend_sz); } else if (cpu_is_omap16xx()) { @@ -652,9 +602,7 @@ static int __init omap_pm_init(void) arm_pm_idle = omap1_pm_idle; - if (cpu_is_omap7xx()) - irq = INT_7XX_WAKE_UP_REQ; - else if (cpu_is_omap16xx()) + if (cpu_is_omap16xx()) irq = INT_1610_WAKE_UP_REQ; else irq = -1; @@ -673,9 +621,7 @@ static int __init omap_pm_init(void) omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL); /* Configure IDLECT3 */ - if (cpu_is_omap7xx()) - omap_writel(OMAP7XX_IDLECT3_VAL, OMAP7XX_IDLECT3); - else if (cpu_is_omap16xx()) + if (cpu_is_omap16xx()) omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3); suspend_set_ops(&omap_pm_ops); diff --git a/arch/arm/mach-omap1/pm.h b/arch/arm/mach-omap1/pm.h index 0d1f092821ff..d4373a5c4697 100644 --- a/arch/arm/mach-omap1/pm.h +++ b/arch/arm/mach-omap1/pm.h @@ -100,12 +100,6 @@ #define OMAP1610_IDLECT3 0xfffece24 #define OMAP1610_IDLE_LOOP_REQUEST 0x0400 -#define OMAP7XX_IDLECT1_SLEEP_VAL 0x16c7 -#define OMAP7XX_IDLECT2_SLEEP_VAL 0x09c7 -#define OMAP7XX_IDLECT3_VAL 0x3f -#define OMAP7XX_IDLECT3 0xfffece24 -#define OMAP7XX_IDLE_LOOP_REQUEST 0x0C00 - #ifndef __ASSEMBLER__ #include @@ -118,17 +112,13 @@ extern void allow_idle_sleep(void); extern void omap1_pm_idle(void); extern void omap1_pm_suspend(void); -extern void omap7xx_cpu_suspend(unsigned long, unsigned long); extern void omap1510_cpu_suspend(unsigned long, unsigned long); extern void omap1610_cpu_suspend(unsigned long, unsigned long); -extern void omap7xx_idle_loop_suspend(void); extern void omap1510_idle_loop_suspend(void); extern void omap1610_idle_loop_suspend(void); -extern unsigned int omap7xx_cpu_suspend_sz; extern unsigned int omap1510_cpu_suspend_sz; extern unsigned int omap1610_cpu_suspend_sz; -extern unsigned int omap7xx_idle_loop_suspend_sz; extern unsigned int omap1510_idle_loop_suspend_sz; extern unsigned int omap1610_idle_loop_suspend_sz; @@ -151,10 +141,6 @@ extern void omap_serial_wake_trigger(int enable); #define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x)) #define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] -#define MPUI7XX_SAVE(x) mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x] = omap_readl(x) -#define MPUI7XX_RESTORE(x) omap_writel((mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x]), (x)) -#define MPUI7XX_SHOW(x) mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x] - #define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x) #define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x)) #define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] @@ -228,27 +214,6 @@ enum mpui1510_save_state { #endif }; -enum mpui7xx_save_state { - MPUI7XX_SLEEP_SAVE_START = 0, - /* - * MPUI registers 32 bits - */ - MPUI7XX_SLEEP_SAVE_MPUI_CTRL, - MPUI7XX_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG, - MPUI7XX_SLEEP_SAVE_MPUI_DSP_API_CONFIG, - MPUI7XX_SLEEP_SAVE_MPUI_DSP_STATUS, - MPUI7XX_SLEEP_SAVE_EMIFF_SDRAM_CONFIG, - MPUI7XX_SLEEP_SAVE_EMIFS_CONFIG, - MPUI7XX_SLEEP_SAVE_OMAP_IH1_MIR, - MPUI7XX_SLEEP_SAVE_OMAP_IH2_0_MIR, - MPUI7XX_SLEEP_SAVE_OMAP_IH2_1_MIR, -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) - MPUI7XX_SLEEP_SAVE_SIZE -#else - MPUI7XX_SLEEP_SAVE_SIZE = 0 -#endif -}; - enum mpui1610_save_state { MPUI1610_SLEEP_SAVE_START = 0, /* diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 88928fc33b2e..c7f590645774 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -106,13 +106,6 @@ void __init omap_serial_init(void) { int i; - if (cpu_is_omap7xx()) { - serial_platform_data[0].regshift = 0; - serial_platform_data[1].regshift = 0; - serial_platform_data[0].irq = INT_7XX_UART_MODEM_1; - serial_platform_data[1].irq = INT_7XX_UART_MODEM_IRDA_2; - } - if (cpu_is_omap15xx()) { serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16; serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16; @@ -120,14 +113,6 @@ void __init omap_serial_init(void) } for (i = 0; i < ARRAY_SIZE(serial_platform_data) - 1; i++) { - - /* Don't look at UARTs higher than 2 for omap7xx */ - if (cpu_is_omap7xx() && i > 1) { - serial_platform_data[i].membase = NULL; - serial_platform_data[i].mapbase = 0; - continue; - } - /* Static mapping, never released */ serial_platform_data[i].membase = ioremap(serial_platform_data[i].mapbase, SZ_2K); diff --git a/arch/arm/mach-omap1/sleep.S b/arch/arm/mach-omap1/sleep.S index f111b79512ce..6192f52d531a 100644 --- a/arch/arm/mach-omap1/sleep.S +++ b/arch/arm/mach-omap1/sleep.S @@ -61,86 +61,6 @@ * */ -#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) - .align 3 -ENTRY(omap7xx_cpu_suspend) - - @ save registers on stack - stmfd sp!, {r0 - r12, lr} - - @ Drain write cache - mov r4, #0 - mcr p15, 0, r0, c7, c10, 4 - nop - - @ load base address of Traffic Controller - mov r6, #TCMIF_ASM_BASE & 0xff000000 - orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 - orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 - - @ prepare to put SDRAM into self-refresh manually - ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 - orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff - str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - - @ prepare to put EMIFS to Sleep - ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff - str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - - @ turn off clock domains - @ do not disable PERCK (0x04) - mov r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff - orr r5, r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff00 - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - - @ request ARM idle - mov r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff - orr r3, r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff00 - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - @ disable instruction cache - mrc p15, 0, r9, c1, c0, 0 - bic r2, r9, #0x1000 - mcr p15, 0, r2, c1, c0, 0 - nop - -/* - * Let's wait for the next wake up event to wake us up. r0 can't be - * used here because r0 holds ARM_IDLECT1 - */ - mov r2, #0 - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt -/* - * omap7xx_cpu_suspend()'s resume point. - * - * It will just start executing here, so we'll restore stuff from the - * stack. - */ - @ re-enable Icache - mcr p15, 0, r9, c1, c0, 0 - - @ reset the ARM_IDLECT1 and ARM_IDLECT2. - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - @ Restore EMIFF controls - str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ restore regs and return - ldmfd sp!, {r0 - r12, pc} - -ENTRY(omap7xx_cpu_suspend_sz) - .word . - omap7xx_cpu_suspend -#endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */ - #ifdef CONFIG_ARCH_OMAP15XX .align 3 ENTRY(omap1510_cpu_suspend) diff --git a/arch/arm/mach-omap1/sram-init.c b/arch/arm/mach-omap1/sram-init.c index dabf0c4defeb..26427d6be896 100644 --- a/arch/arm/mach-omap1/sram-init.c +++ b/arch/arm/mach-omap1/sram-init.c @@ -94,9 +94,7 @@ static void __init omap_detect_and_map_sram(void) omap_sram_skip = SRAM_BOOTLOADER_SZ; omap_sram_start = OMAP1_SRAM_PA; - if (cpu_is_omap7xx()) - omap_sram_size = 0x32000; /* 200K */ - else if (cpu_is_omap15xx()) + if (cpu_is_omap15xx()) omap_sram_size = 0x30000; /* 192K */ else if (cpu_is_omap1610() || cpu_is_omap1611() || cpu_is_omap1621() || cpu_is_omap1710()) @@ -133,9 +131,6 @@ static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl); void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl) { BUG_ON(!_omap_sram_reprogram_clock); - /* On 730, bit 13 must always be 1 */ - if (cpu_is_omap7xx()) - ckctl |= 0x2000; _omap_sram_reprogram_clock(dpllctl, ckctl); } diff --git a/arch/arm/mach-omap1/usb.c b/arch/arm/mach-omap1/usb.c index 0119f3ddb7a6..08d42abc4a0f 100644 --- a/arch/arm/mach-omap1/usb.c +++ b/arch/arm/mach-omap1/usb.c @@ -190,12 +190,6 @@ static struct platform_device udc_device = { static inline void udc_device_init(struct omap_usb_config *pdata) { - /* IRQ numbers for omap7xx */ - if(cpu_is_omap7xx()) { - udc_resources[1].start = INT_7XX_USB_GENI; - udc_resources[2].start = INT_7XX_USB_NON_ISO; - udc_resources[3].start = INT_7XX_USB_ISO; - } pdata->udc_device = &udc_device; } @@ -238,8 +232,6 @@ static inline void ohci_device_init(struct omap_usb_config *pdata) if (!IS_ENABLED(CONFIG_USB_OHCI_HCD)) return; - if (cpu_is_omap7xx()) - ohci_resources[1].start = INT_7XX_USB_HHC_1; pdata->ohci_device = &ohci_device; pdata->ocpi_enable = &ocpi_enable; } @@ -267,8 +259,6 @@ static struct platform_device otg_device = { static inline void otg_device_init(struct omap_usb_config *pdata) { - if (cpu_is_omap7xx()) - otg_resources[1].start = INT_7XX_USB_OTG; pdata->otg_device = &otg_device; } @@ -297,14 +287,7 @@ static u32 __init omap1_usb0_init(unsigned nwires, unsigned is_device) } if (is_device) { - if (cpu_is_omap7xx()) { - omap_cfg_reg(AA17_7XX_USB_DM); - omap_cfg_reg(W16_7XX_USB_PU_EN); - omap_cfg_reg(W17_7XX_USB_VBUSI); - omap_cfg_reg(W18_7XX_USB_DMCK_OUT); - omap_cfg_reg(W19_7XX_USB_DCRST); - } else - omap_cfg_reg(W4_USB_PUEN); + omap_cfg_reg(W4_USB_PUEN); } if (nwires == 2) { @@ -324,14 +307,11 @@ static u32 __init omap1_usb0_init(unsigned nwires, unsigned is_device) * - OTG support on this port not yet written */ - /* Don't do this for omap7xx -- it causes USB to not work correctly */ - if (!cpu_is_omap7xx()) { - l = omap_readl(USB_TRANSCEIVER_CTRL); - l &= ~(7 << 4); - if (!is_device) - l |= (3 << 1); - omap_writel(l, USB_TRANSCEIVER_CTRL); - } + l = omap_readl(USB_TRANSCEIVER_CTRL); + l &= ~(7 << 4); + if (!is_device) + l |= (3 << 1); + omap_writel(l, USB_TRANSCEIVER_CTRL); return 3 << 16; } @@ -698,7 +678,7 @@ void __init omap1_usb_init(struct omap_usb_config *_pdata) ohci_device_init(pdata); otg_device_init(pdata); - if (cpu_is_omap7xx() || cpu_is_omap16xx()) + if (cpu_is_omap16xx()) omap_otg_init(pdata); else if (cpu_is_omap15xx()) omap_1510_usb_init(pdata); diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 29198e6815b2..20c87163d612 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -99,7 +99,7 @@ struct uwire_state { * Or, put it in a structure which is used throughout the driver; * that avoids having to issue two loads for each bit of static data. */ -static unsigned int uwire_idx_shift; +static unsigned int uwire_idx_shift = 2; static void __iomem *uwire_base; static inline void uwire_write_reg(int idx, u16 val) @@ -481,11 +481,6 @@ static int uwire_probe(struct platform_device *pdev) } clk_prepare_enable(uwire->ck); - if (cpu_is_omap7xx()) - uwire_idx_shift = 1; - else - uwire_idx_shift = 2; - uwire_write_reg(UWIRE_SR3, 1); /* the spi->mode bits understood by this driver: */ @@ -536,15 +531,6 @@ static struct platform_driver uwire_driver = { static int __init omap_uwire_init(void) { - /* FIXME move these into the relevant board init code. also, include - * H3 support; it uses tsc2101 like H2 (on a different chipselect). - */ - - if (machine_is_omap_h2()) { - /* defaults: W21 SDO, U18 SDI, V19 SCL */ - omap_cfg_reg(N14_1610_UWIRE_CS0); - omap_cfg_reg(N15_1610_UWIRE_CS1); - } return platform_driver_register(&uwire_driver); } diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index bea346e362b2..1be8c19f2a04 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2036,12 +2036,7 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev) static inline int machine_without_vbus_sense(void) { - return machine_is_omap_innovator() - || machine_is_omap_osk() - || machine_is_omap_palmte() - || machine_is_sx1() - /* No known omap7xx boards with vbus sense */ - || cpu_is_omap7xx(); + return machine_is_omap_osk() || machine_is_sx1(); } static int omap_udc_start(struct usb_gadget *g, @@ -2759,9 +2754,6 @@ static int omap_udc_probe(struct platform_device *pdev) struct clk *dc_clk = NULL; struct clk *hhc_clk = NULL; - if (cpu_is_omap7xx()) - use_dma = 0; - /* NOTE: "knows" the order of the resources! */ if (!request_mem_region(pdev->resource[0].start, resource_size(&pdev->resource[0]), @@ -2780,16 +2772,6 @@ static int omap_udc_probe(struct platform_device *pdev) udelay(100); } - if (cpu_is_omap7xx()) { - dc_clk = clk_get(&pdev->dev, "usb_dc_ck"); - hhc_clk = clk_get(&pdev->dev, "l3_ocpi_ck"); - BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); - /* can't use omap_udc_enable_clock yet */ - clk_prepare_enable(dc_clk); - clk_prepare_enable(hhc_clk); - udelay(100); - } - INFO("OMAP UDC rev %d.%d%s\n", omap_readw(UDC_REV) >> 4, omap_readw(UDC_REV) & 0xf, config->otg ? ", Mini-AB" : ""); @@ -2914,7 +2896,7 @@ bad_on_1710: goto cleanup1; } #endif - if (cpu_is_omap16xx() || cpu_is_omap7xx()) { + if (cpu_is_omap16xx()) { udc->dc_clk = dc_clk; udc->hhc_clk = hhc_clk; clk_disable(hhc_clk); @@ -2933,7 +2915,7 @@ cleanup0: if (!IS_ERR_OR_NULL(xceiv)) usb_put_phy(xceiv); - if (cpu_is_omap16xx() || cpu_is_omap7xx()) { + if (cpu_is_omap16xx()) { clk_disable_unprepare(hhc_clk); clk_disable_unprepare(dc_clk); clk_put(hhc_clk); diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index cb29701df911..d7f594db56c6 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -107,10 +107,6 @@ static int ohci_omap_reset(struct usb_hcd *hcd) hcd->power_budget = 8; } - /* boards can use OTG transceivers in non-OTG modes */ - need_transceiver = need_transceiver - || machine_is_omap_h2() || machine_is_omap_h3(); - /* XXX OMAP16xx only */ if (config->ocpi_enable) config->ocpi_enable(); @@ -150,7 +146,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) } /* board-specific power switching and overcurrent support */ - if (machine_is_omap_osk() || machine_is_omap_innovator()) { + if (machine_is_omap_osk()) { u32 rh = roothub_a (ohci); /* power switching (ganged by default) */ diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index 931610b76f3d..57cf9d88814b 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -77,51 +77,6 @@ struct isp1301 { /*-------------------------------------------------------------------------*/ -/* board-specific PM hooks */ - -#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) - -#if IS_REACHABLE(CONFIG_TPS65010) - -#include - -#else - -static inline int tps65010_set_vbus_draw(unsigned mA) -{ - pr_debug("tps65010: draw %d mA (STUB)\n", mA); - return 0; -} - -#endif - -static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) -{ - int status = tps65010_set_vbus_draw(mA); - if (status < 0) - pr_debug(" VBUS %d mA error %d\n", mA, status); -} - -#else - -static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) -{ - /* H4 controls this by DIP switch S2.4; no soft control. - * ON means the charger is always enabled. Leave it OFF - * unless the OTG port is used only in B-peripheral mode. - */ -} - -#endif - -static void enable_vbus_source(struct isp1301 *isp) -{ - /* this board won't supply more than 8mA vbus power. - * some boards can switch a 100ma "unit load" (or more). - */ -} - - /* products will deliver OTG messages with LEDs, GUI, etc */ static inline void notresponding(struct isp1301 *isp) { @@ -916,10 +871,8 @@ static void b_peripheral(struct isp1301 *isp) usb_gadget_vbus_connect(isp->phy.otg->gadget); #ifdef CONFIG_USB_OTG - enable_vbus_draw(isp, 8); otg_update_isp(isp); #else - enable_vbus_draw(isp, 100); /* UDC driver just set OTG_BSESSVLD */ isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN); @@ -947,7 +900,6 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) a_idle(isp, "idle"); fallthrough; case OTG_STATE_A_IDLE: - enable_vbus_source(isp); fallthrough; case OTG_STATE_A_WAIT_VRISE: /* we skip over OTG_STATE_A_WAIT_BCON, since @@ -1023,7 +975,6 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) case OTG_STATE_B_HOST: if (likely(isp_bstat & OTG_B_SESS_VLD)) break; - enable_vbus_draw(isp, 0); #ifndef CONFIG_USB_OTG /* UDC driver will clear OTG_BSESSVLD */ isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, @@ -1283,9 +1234,6 @@ isp1301_set_host(struct usb_otg *otg, struct usb_bus *host) power_up(isp); - if (machine_is_omap_h2()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - dev_info(&isp->client->dev, "A-Host sessions ok\n"); isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, INTR_ID_GND); @@ -1320,8 +1268,6 @@ isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) if (!gadget) { omap_writew(0, OTG_IRQ_EN); - if (!otg->default_a) - enable_vbus_draw(isp, 0); usb_gadget_vbus_disconnect(otg->gadget); otg->gadget = NULL; power_down(isp); @@ -1352,9 +1298,6 @@ isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) power_up(isp); isp->phy.otg->state = OTG_STATE_B_IDLE; - if (machine_is_omap_h2() || machine_is_omap_h3()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, INTR_SESS_VLD); isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, @@ -1380,16 +1323,6 @@ isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ -static int -isp1301_set_power(struct usb_phy *dev, unsigned mA) -{ - if (!the_transceiver) - return -ENODEV; - if (dev->otg->state == OTG_STATE_B_PERIPHERAL) - enable_vbus_draw(the_transceiver, mA); - return 0; -} - static int isp1301_start_srp(struct usb_otg *otg) { @@ -1538,26 +1471,7 @@ isp1301_probe(struct i2c_client *i2c) } #endif - if (machine_is_omap_h2()) { - struct gpio_desc *gpiod; - - /* full speed signaling by default */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_SPEED); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, - MC2_SPD_SUSP_CTRL); - - gpiod = devm_gpiod_get(&i2c->dev, NULL, GPIOD_IN); - if (IS_ERR(gpiod)) { - dev_err(&i2c->dev, "cannot obtain H2 GPIO\n"); - goto fail; - } - gpiod_set_consumer_name(gpiod, "isp1301"); - irq = gpiod_to_irq(gpiod); - isp->irq_type = IRQF_TRIGGER_FALLING; - } else { - irq = i2c->irq; - } + irq = i2c->irq; status = request_irq(irq, isp1301_irq, isp->irq_type, DRIVER_NAME, isp); @@ -1569,15 +1483,12 @@ isp1301_probe(struct i2c_client *i2c) isp->phy.dev = &i2c->dev; isp->phy.label = DRIVER_NAME; - isp->phy.set_power = isp1301_set_power; - isp->phy.otg->usb_phy = &isp->phy; isp->phy.otg->set_host = isp1301_set_host; isp->phy.otg->set_peripheral = isp1301_set_peripheral; isp->phy.otg->start_srp = isp1301_start_srp; isp->phy.otg->start_hnp = isp1301_start_hnp; - enable_vbus_draw(isp, 0); power_down(isp); the_transceiver = isp; diff --git a/drivers/video/fbdev/omap/lcdc.c b/drivers/video/fbdev/omap/lcdc.c index e7ce783e5215..abb8b11464e8 100644 --- a/drivers/video/fbdev/omap/lcdc.c +++ b/drivers/video/fbdev/omap/lcdc.c @@ -706,8 +706,6 @@ static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode, if (machine_is_ams_delta()) rate /= 4; - if (machine_is_omap_h3()) - rate /= 3; r = clk_set_rate(lcdc.lcd_ck, rate); if (r) { dev_err(fbdev->dev, "failed to adjust LCD rate\n"); diff --git a/include/linux/soc/ti/omap1-soc.h b/include/linux/soc/ti/omap1-soc.h index 81008d400bb6..a42d9aa68648 100644 --- a/include/linux/soc/ti/omap1-soc.h +++ b/include/linux/soc/ti/omap1-soc.h @@ -20,22 +20,6 @@ #undef MULTI_OMAP1 #undef OMAP_NAME -#ifdef CONFIG_ARCH_OMAP730 -# ifdef OMAP_NAME -# undef MULTI_OMAP1 -# define MULTI_OMAP1 -# else -# define OMAP_NAME omap730 -# endif -#endif -#ifdef CONFIG_ARCH_OMAP850 -# ifdef OMAP_NAME -# undef MULTI_OMAP1 -# define MULTI_OMAP1 -# else -# define OMAP_NAME omap850 -# endif -#endif #ifdef CONFIG_ARCH_OMAP15XX # ifdef OMAP_NAME # undef MULTI_OMAP1 @@ -69,7 +53,6 @@ unsigned int omap_rev(void); /* * Macros to group OMAP into cpu classes. * These can be used in most places. - * cpu_is_omap7xx(): True for OMAP730, OMAP850 * cpu_is_omap15xx(): True for OMAP1510, OMAP5910 and OMAP310 * cpu_is_omap16xx(): True for OMAP1610, OMAP5912 and OMAP1710 */ @@ -89,23 +72,13 @@ static inline int is_omap ##subclass (void) \ return (GET_OMAP_SUBCLASS == (id)) ? 1 : 0; \ } -IS_OMAP_CLASS(7xx, 0x07) IS_OMAP_CLASS(15xx, 0x15) IS_OMAP_CLASS(16xx, 0x16) -#define cpu_is_omap7xx() 0 #define cpu_is_omap15xx() 0 #define cpu_is_omap16xx() 0 #if defined(MULTI_OMAP1) -# if defined(CONFIG_ARCH_OMAP730) -# undef cpu_is_omap7xx -# define cpu_is_omap7xx() is_omap7xx() -# endif -# if defined(CONFIG_ARCH_OMAP850) -# undef cpu_is_omap7xx -# define cpu_is_omap7xx() is_omap7xx() -# endif # if defined(CONFIG_ARCH_OMAP15XX) # undef cpu_is_omap15xx # define cpu_is_omap15xx() is_omap15xx() @@ -115,14 +88,6 @@ IS_OMAP_CLASS(16xx, 0x16) # define cpu_is_omap16xx() is_omap16xx() # endif #else -# if defined(CONFIG_ARCH_OMAP730) -# undef cpu_is_omap7xx -# define cpu_is_omap7xx() 1 -# endif -# if defined(CONFIG_ARCH_OMAP850) -# undef cpu_is_omap7xx -# define cpu_is_omap7xx() 1 -# endif # if defined(CONFIG_ARCH_OMAP15XX) # undef cpu_is_omap15xx # define cpu_is_omap15xx() 1 -- cgit v1.2.3 From c3848db316d51dcc0fb10554151b1e7e8ff8c3e2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 29 Sep 2022 16:14:18 +0200 Subject: ARM: davinci: drop DAVINCI_DMxxx references Support for all the dm3xx/dm64xx SoCs is no longer available, so drop all other references to those. Acked-by: Stephen Boyd Signed-off-by: Arnd Bergmann --- arch/arm/mach-davinci/cputype.h | 32 -------------------------------- arch/arm/mach-davinci/serial.c | 4 ---- arch/arm/mach-davinci/usb.c | 13 ------------- drivers/clk/davinci/pll.c | 8 -------- drivers/clk/davinci/pll.h | 5 ----- drivers/clk/davinci/psc.c | 6 ------ drivers/clk/davinci/psc.h | 7 ------- include/linux/clk/davinci.h | 9 --------- 8 files changed, 84 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-davinci/cputype.h b/arch/arm/mach-davinci/cputype.h index 4590afdbe449..87ee56068a16 100644 --- a/arch/arm/mach-davinci/cputype.h +++ b/arch/arm/mach-davinci/cputype.h @@ -25,10 +25,6 @@ struct davinci_id { }; /* Can use lower 16 bits of cpu id for a variant when required */ -#define DAVINCI_CPU_ID_DM6446 0x64460000 -#define DAVINCI_CPU_ID_DM6467 0x64670000 -#define DAVINCI_CPU_ID_DM355 0x03550000 -#define DAVINCI_CPU_ID_DM365 0x03650000 #define DAVINCI_CPU_ID_DA830 0x08300000 #define DAVINCI_CPU_ID_DA850 0x08500000 @@ -38,37 +34,9 @@ static inline int is_davinci_ ##type(void) \ return (davinci_soc_info.cpu_id == (id)); \ } -IS_DAVINCI_CPU(dm644x, DAVINCI_CPU_ID_DM6446) -IS_DAVINCI_CPU(dm646x, DAVINCI_CPU_ID_DM6467) -IS_DAVINCI_CPU(dm355, DAVINCI_CPU_ID_DM355) -IS_DAVINCI_CPU(dm365, DAVINCI_CPU_ID_DM365) IS_DAVINCI_CPU(da830, DAVINCI_CPU_ID_DA830) IS_DAVINCI_CPU(da850, DAVINCI_CPU_ID_DA850) -#ifdef CONFIG_ARCH_DAVINCI_DM644x -#define cpu_is_davinci_dm644x() is_davinci_dm644x() -#else -#define cpu_is_davinci_dm644x() 0 -#endif - -#ifdef CONFIG_ARCH_DAVINCI_DM646x -#define cpu_is_davinci_dm646x() is_davinci_dm646x() -#else -#define cpu_is_davinci_dm646x() 0 -#endif - -#ifdef CONFIG_ARCH_DAVINCI_DM355 -#define cpu_is_davinci_dm355() is_davinci_dm355() -#else -#define cpu_is_davinci_dm355() 0 -#endif - -#ifdef CONFIG_ARCH_DAVINCI_DM365 -#define cpu_is_davinci_dm365() is_davinci_dm365() -#else -#define cpu_is_davinci_dm365() 0 -#endif - #ifdef CONFIG_ARCH_DAVINCI_DA830 #define cpu_is_davinci_da830() is_davinci_da830() #else diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c index 7f7814807bb5..ac1929bb0ef2 100644 --- a/arch/arm/mach-davinci/serial.c +++ b/arch/arm/mach-davinci/serial.c @@ -40,10 +40,6 @@ static void __init davinci_serial_reset(struct plat_serial8250_port *p) pwremu |= (0x3 << 13); pwremu |= 0x1; serial_write_reg(p, UART_DAVINCI_PWREMU, pwremu); - - if (cpu_is_davinci_dm646x()) - serial_write_reg(p, UART_DM646X_SCR, - UART_DM646X_SCR_TX_WATERMARK); } int __init davinci_serial_init(struct platform_device *serial_dev) diff --git a/arch/arm/mach-davinci/usb.c b/arch/arm/mach-davinci/usb.c index a9e5c6e91e5d..9dc14c7977b3 100644 --- a/arch/arm/mach-davinci/usb.c +++ b/arch/arm/mach-davinci/usb.c @@ -41,11 +41,6 @@ static struct resource usb_resources[] = { .flags = IORESOURCE_IRQ, .name = "mc" }, - { - /* placeholder for the dedicated CPPI IRQ */ - .flags = IORESOURCE_IRQ, - .name = "dma" - }, }; static u64 usb_dmamask = DMA_BIT_MASK(32); @@ -67,14 +62,6 @@ void __init davinci_setup_usb(unsigned mA, unsigned potpgt_ms) usb_data.power = mA > 510 ? 255 : mA / 2; usb_data.potpgt = (potpgt_ms + 1) / 2; - if (cpu_is_davinci_dm646x()) { - /* Override the defaults as DM6467 uses different IRQs. */ - usb_dev.resource[1].start = DAVINCI_INTC_IRQ(IRQ_DM646X_USBINT); - usb_dev.resource[2].start = DAVINCI_INTC_IRQ( - IRQ_DM646X_USBDMAINT); - } else /* other devices don't have dedicated CPPI IRQ */ - usb_dev.num_resources = 2; - platform_device_register(&usb_dev); } diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index f862f5e2b3fc..87bdf8879045 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -881,14 +881,6 @@ static const struct platform_device_id davinci_pll_id_table[] = { #ifdef CONFIG_ARCH_DAVINCI_DA850 { .name = "da850-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init }, { .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init }, -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 - { .name = "dm355-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init }, - { .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init }, -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM365 - { .name = "dm365-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init }, - { .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init }, #endif { } }; diff --git a/drivers/clk/davinci/pll.h b/drivers/clk/davinci/pll.h index 1773277bc690..20bfcec2d3b5 100644 --- a/drivers/clk/davinci/pll.h +++ b/drivers/clk/davinci/pll.h @@ -122,13 +122,8 @@ int of_davinci_pll_init(struct device *dev, struct device_node *node, /* Platform-specific callbacks */ -#ifdef CONFIG_ARCH_DAVINCI_DA850 int da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); void of_da850_pll0_init(struct device_node *node); int of_da850_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 -int dm355_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); -#endif #endif /* __CLK_DAVINCI_PLL_H___ */ diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index 42a59dbd49c8..cd85d9f158b0 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -510,12 +510,6 @@ static const struct platform_device_id davinci_psc_id_table[] = { #ifdef CONFIG_ARCH_DAVINCI_DA850 { .name = "da850-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data }, { .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data }, -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 - { .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data }, -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM365 - { .name = "dm365-psc", .driver_data = (kernel_ulong_t)&dm365_psc_init_data }, #endif { } }; diff --git a/drivers/clk/davinci/psc.h b/drivers/clk/davinci/psc.h index 5e382b675518..bd23f6fd56df 100644 --- a/drivers/clk/davinci/psc.h +++ b/drivers/clk/davinci/psc.h @@ -104,11 +104,4 @@ extern const struct davinci_psc_init_data da850_psc1_init_data; extern const struct davinci_psc_init_data of_da850_psc0_init_data; extern const struct davinci_psc_init_data of_da850_psc1_init_data; #endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 -extern const struct davinci_psc_init_data dm355_psc_init_data; -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM365 -extern const struct davinci_psc_init_data dm365_psc_init_data; -#endif - #endif /* __CLK_DAVINCI_PSC_H__ */ diff --git a/include/linux/clk/davinci.h b/include/linux/clk/davinci.h index f6ebab6228c2..e1d37451e03f 100644 --- a/include/linux/clk/davinci.h +++ b/include/linux/clk/davinci.h @@ -19,14 +19,5 @@ int da830_pll_init(struct device *dev, void __iomem *base, struct regmap *cfgchi #ifdef CONFIG_ARCH_DAVINCI_DA850 int da850_pll0_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); #endif -#ifdef CONFIG_ARCH_DAVINCI_DM355 -int dm355_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); -int dm355_psc_init(struct device *dev, void __iomem *base); -#endif -#ifdef CONFIG_ARCH_DAVINCI_DM365 -int dm365_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); -int dm365_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip); -int dm365_psc_init(struct device *dev, void __iomem *base); -#endif #endif /* __LINUX_CLK_DAVINCI_PLL_H___ */ -- cgit v1.2.3 From 582603a957343430cc519539d5dcaa0a0bb1327a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 6 Oct 2022 17:08:22 +0200 Subject: staging: media: remove davinci vpfe_capture driver This driver was for the davinci dm644x and dm3xx platforms that are now removed from the kernel, so there are no more users. Acked-by: Hans Verkuil Acked-by: Lad Prabhakar Acked-by: Greg Kroah-Hartman Signed-off-by: Arnd Bergmann --- Documentation/userspace-api/ioctl/ioctl-number.rst | 1 - MAINTAINERS | 1 - drivers/staging/media/Kconfig | 1 - drivers/staging/media/Makefile | 1 - .../staging/media/deprecated/vpfe_capture/Kconfig | 58 - .../staging/media/deprecated/vpfe_capture/Makefile | 4 - drivers/staging/media/deprecated/vpfe_capture/TODO | 7 - .../media/deprecated/vpfe_capture/ccdc_hw_device.h | 80 - .../media/deprecated/vpfe_capture/dm355_ccdc.c | 934 ---------- .../media/deprecated/vpfe_capture/dm355_ccdc.h | 308 ---- .../deprecated/vpfe_capture/dm355_ccdc_regs.h | 297 --- .../media/deprecated/vpfe_capture/dm644x_ccdc.c | 879 --------- .../media/deprecated/vpfe_capture/dm644x_ccdc.h | 171 -- .../deprecated/vpfe_capture/dm644x_ccdc_regs.h | 140 -- .../staging/media/deprecated/vpfe_capture/isif.c | 1127 ------------ .../staging/media/deprecated/vpfe_capture/isif.h | 518 ------ .../media/deprecated/vpfe_capture/isif_regs.h | 256 --- .../media/deprecated/vpfe_capture/vpfe_capture.c | 1902 -------------------- include/media/davinci/vpfe_capture.h | 177 -- 19 files changed, 6862 deletions(-) delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/Kconfig delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/Makefile delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/TODO delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/isif.c delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/isif.h delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/isif_regs.h delete mode 100644 drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c delete mode 100644 include/media/davinci/vpfe_capture.h (limited to 'include') diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index eb045fc495a4..362bee0be8ab 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -201,7 +201,6 @@ Code Seq# Include File Comments 'V' all linux/videodev2.h conflict! 'V' C0 linux/ivtvfb.h conflict! 'V' C0 linux/ivtv.h conflict! -'V' C0 media/davinci/vpfe_capture.h conflict! 'V' C0 media/si4713.h conflict! 'W' 00-1F linux/watchdog.h conflict! 'W' 00-1F linux/wanrouter.h conflict! (pre 3.9) diff --git a/MAINTAINERS b/MAINTAINERS index 5d323d8c626e..370f438b1070 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20790,7 +20790,6 @@ W: https://linuxtv.org Q: http://patchwork.linuxtv.org/project/linux-media/list/ T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git F: drivers/media/platform/ti/davinci/ -F: drivers/staging/media/deprecated/vpfe_capture/ F: include/media/davinci/ TI ENHANCED CAPTURE (eCAP) DRIVER diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index b79f93684c4f..617012e09a37 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -58,7 +58,6 @@ source "drivers/staging/media/deprecated/meye/Kconfig" source "drivers/staging/media/deprecated/saa7146/Kconfig" source "drivers/staging/media/deprecated/stkwebcam/Kconfig" source "drivers/staging/media/deprecated/tm6000/Kconfig" -source "drivers/staging/media/deprecated/vpfe_capture/Kconfig" source "drivers/staging/media/deprecated/zr364xx/Kconfig" endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 54bbdd4b0d08..1e14edc2d44c 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -15,5 +15,4 @@ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_VIDEO_TM6000) += deprecated/tm6000/ obj-$(CONFIG_VIDEO_VIU) += deprecated/fsl-viu/ obj-$(CONFIG_USB_ZR364XX) += deprecated/zr364xx/ -obj-y += deprecated/vpfe_capture/ obj-y += deprecated/saa7146/ diff --git a/drivers/staging/media/deprecated/vpfe_capture/Kconfig b/drivers/staging/media/deprecated/vpfe_capture/Kconfig deleted file mode 100644 index 10250e7e566b..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/Kconfig +++ /dev/null @@ -1,58 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_DM6446_CCDC - tristate "TI DM6446 CCDC video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from slave decoders. - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - To compile this driver as a module, choose M here. There will - be two modules called vpfe_capture.ko and dm644x_ccdc.ko - -config VIDEO_DM355_CCDC - tristate "TI DM355 CCDC video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables DM355 CCD hw module. DM355 CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from a slave decoders - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - To compile this driver as a module, choose M here. There will - be two modules called vpfe_capture.ko and dm355_ccdc.ko - -config VIDEO_DM365_ISIF - tristate "TI DM365 ISIF video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables ISIF hw module. This is the hardware module for - configuring ISIF in VPFE to capture Raw Bayer RGB data from - a image sensor or YUV data from a YUV source. - - This driver is deprecated and is scheduled for removal by - the beginning of 2023. See the TODO file for more information. - - To compile this driver as a module, choose M here. There will - be two modules called vpfe_capture.ko and isif.ko diff --git a/drivers/staging/media/deprecated/vpfe_capture/Makefile b/drivers/staging/media/deprecated/vpfe_capture/Makefile deleted file mode 100644 index 609e8dc09ce7..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_DM6446_CCDC) += vpfe_capture.o dm644x_ccdc.o -obj-$(CONFIG_VIDEO_DM355_CCDC) += vpfe_capture.o dm355_ccdc.o -obj-$(CONFIG_VIDEO_DM365_ISIF) += vpfe_capture.o isif.o diff --git a/drivers/staging/media/deprecated/vpfe_capture/TODO b/drivers/staging/media/deprecated/vpfe_capture/TODO deleted file mode 100644 index ce654d7337af..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/TODO +++ /dev/null @@ -1,7 +0,0 @@ -These are one of the few drivers still not using the vb2 -framework, so these drivers are now deprecated with the intent of -removing them altogether by the beginning of 2023. - -In order to keep these drivers they have to be converted to vb2. -If someone is interested in doing this work, then contact the -linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h b/drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h deleted file mode 100644 index a545052a95a9..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * ccdc device API - */ -#ifndef _CCDC_HW_DEVICE_H -#define _CCDC_HW_DEVICE_H - -#ifdef __KERNEL__ -#include -#include -#include -#include - -/* - * ccdc hw operations - */ -struct ccdc_hw_ops { - /* Pointer to initialize function to initialize ccdc device */ - int (*open) (struct device *dev); - /* Pointer to deinitialize function */ - int (*close) (struct device *dev); - /* set ccdc base address */ - void (*set_ccdc_base)(void *base, int size); - /* Pointer to function to enable or disable ccdc */ - void (*enable) (int en); - /* reset sbl. only for 6446 */ - void (*reset) (void); - /* enable output to sdram */ - void (*enable_out_to_sdram) (int en); - /* Pointer to function to set hw parameters */ - int (*set_hw_if_params) (struct vpfe_hw_if_param *param); - /* get interface parameters */ - int (*get_hw_if_params) (struct vpfe_hw_if_param *param); - /* Pointer to function to configure ccdc */ - int (*configure) (void); - - /* Pointer to function to set buffer type */ - int (*set_buftype) (enum ccdc_buftype buf_type); - /* Pointer to function to get buffer type */ - enum ccdc_buftype (*get_buftype) (void); - /* Pointer to function to set frame format */ - int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); - /* Pointer to function to get frame format */ - enum ccdc_frmfmt (*get_frame_format) (void); - /* enumerate hw pix formats */ - int (*enum_pix)(u32 *hw_pix, int i); - /* Pointer to function to set buffer type */ - u32 (*get_pixel_format) (void); - /* Pointer to function to get pixel format. */ - int (*set_pixel_format) (u32 pixfmt); - /* Pointer to function to set image window */ - int (*set_image_window) (struct v4l2_rect *win); - /* Pointer to function to set image window */ - void (*get_image_window) (struct v4l2_rect *win); - /* Pointer to function to get line length */ - unsigned int (*get_line_length) (void); - - /* Pointer to function to set frame buffer address */ - void (*setfbaddr) (unsigned long addr); - /* Pointer to function to get field id */ - int (*getfid) (void); -}; - -struct ccdc_hw_device { - /* ccdc device name */ - char name[32]; - /* module owner */ - struct module *owner; - /* hw ops */ - struct ccdc_hw_ops hw_ops; -}; - -/* Used by CCDC module to register & unregister with vpfe capture driver */ -int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev); -void vpfe_unregister_ccdc_device(const struct ccdc_hw_device *dev); - -#endif -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c deleted file mode 100644 index da8db53e9498..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c +++ /dev/null @@ -1,934 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - * - * CCDC hardware module for DM355 - * ------------------------------ - * - * This module is for configuring DM355 CCD controller of VPFE to capture - * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules - * such as Defect Pixel Correction, Color Space Conversion etc to - * pre-process the Bayer RGB data, before writing it to SDRAM. - * - * TODO: 1) Raw bayer parameter settings and bayer capture - * 2) Split module parameter structure to module specific ioctl structs - * 3) add support for lense shading correction - * 4) investigate if enum used for user space type definition - * to be replaced by #defines or integer - */ -#include -#include -#include -#include -#include - -#include "dm355_ccdc.h" -#include - -#include "dm355_ccdc_regs.h" -#include "ccdc_hw_device.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CCDC Driver for DM355"); -MODULE_AUTHOR("Texas Instruments"); - -static struct ccdc_oper_config { - struct device *dev; - /* CCDC interface type */ - enum vpfe_hw_if_type if_type; - /* Raw Bayer configuration */ - struct ccdc_params_raw bayer; - /* YCbCr configuration */ - struct ccdc_params_ycbcr ycbcr; - /* ccdc base address */ - void __iomem *base_addr; -} ccdc_cfg = { - /* Raw configurations */ - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = 256, - .gb_g = 256, - .gr_cy = 256, - .b_mg = 256 - }, - .config_params = { - .datasft = 2, - .mfilt1 = CCDC_NO_MEDIAN_FILTER1, - .mfilt2 = CCDC_NO_MEDIAN_FILTER2, - .alaw = { - .gamma_wd = 2, - }, - .blk_clamp = { - .sample_pixel = 1, - .dc_sub = 25 - }, - .col_pat_field0 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED - }, - .col_pat_field1 = { - .olop = CCDC_GREEN_BLUE, - .olep = CCDC_BLUE, - .elop = CCDC_RED, - .elep = CCDC_GREEN_RED - }, - }, - }, - /* YCbCr configuration */ - .ycbcr = { - .win = CCDC_WIN_PAL, - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED - }, -}; - - -/* Raw Bayer formats */ -static u32 ccdc_raw_bayer_pix_formats[] = - {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static u32 ccdc_raw_yuv_pix_formats[] = - {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(ccdc_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, ccdc_cfg.base_addr + offset); -} - -static void ccdc_enable(int en) -{ - unsigned int temp; - temp = regr(SYNCEN); - temp &= (~CCDC_SYNCEN_VDHDEN_MASK); - temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); - regw(temp, SYNCEN); -} - -static void ccdc_enable_output_to_sdram(int en) -{ - unsigned int temp; - temp = regr(SYNCEN); - temp &= (~(CCDC_SYNCEN_WEN_MASK)); - temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); - regw(temp, SYNCEN); -} - -static void ccdc_config_gain_offset(void) -{ - /* configure gain */ - regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); - regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); - regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); - regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); - /* configure offset */ - regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); -} - -/* - * ccdc_restore_defaults() - * This function restore power on defaults in the ccdc registers - */ -static int ccdc_restore_defaults(void) -{ - int i; - - dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); - /* set all registers to zero */ - for (i = 0; i <= CCDC_REG_LAST; i += 4) - regw(0, i); - - /* now override the values with power on defaults in registers */ - regw(MODESET_DEFAULT, MODESET); - /* no culling support */ - regw(CULH_DEFAULT, CULH); - regw(CULV_DEFAULT, CULV); - /* Set default Gain and Offset */ - ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; - ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; - ccdc_config_gain_offset(); - regw(OUTCLIP_DEFAULT, OUTCLIP); - regw(LSCCFG2_DEFAULT, LSCCFG2); - /* select ccdc input */ - if (vpss_select_ccdc_source(VPSS_CCDCIN)) { - dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); - return -EFAULT; - } - /* select ccdc clock */ - if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { - dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); - return -EFAULT; - } - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); - return 0; -} - -static int ccdc_open(struct device *device) -{ - return ccdc_restore_defaults(); -} - -static int ccdc_close(struct device *device) -{ - /* disable clock */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 0); - /* do nothing for now */ - return 0; -} -/* - * ccdc_setwin() - * This function will configure the window size to - * be capture in CCDC reg. - */ -static void ccdc_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int mid_img = 0; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); - - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; - - /* Writing the horizontal info into the registers */ - regw(horz_start, SPH); - regw(horz_nr_pixels, NPH); - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* Since first line doesn't have any data */ - vert_start += 1; - /* configure VDINT0 and VDINT1 */ - regw(vert_start, VDINT0); - } else { - /* Since first line doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - regw(vert_start, VDINT0); - regw(mid_img, VDINT1); - } - regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); - regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); - regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); -} - -/* This function will configure CCDC for YCbCr video capture */ -static void ccdc_config_ycbcr(void) -{ - struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; - u32 temp; - - /* first set the CCDC power on defaults values in all registers */ - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); - ccdc_restore_defaults(); - - /* configure pixel format & video frame format */ - temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << - CCDC_INPUT_MODE_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << - CCDC_FRM_FMT_SHIFT)); - - /* setup BT.656 sync mode */ - if (params->bt656_enable) { - regw(CCDC_REC656IF_BT656_EN, REC656IF); - /* - * configure the FID, VD, HD pin polarity fld,hd pol positive, - * vd negative, 8-bit pack mode - */ - temp |= CCDC_VD_POL_NEGATIVE; - } else { /* y/c external sync mode */ - temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << - CCDC_FID_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << - CCDC_HD_POL_SHIFT) | - ((params->vd_pol & CCDC_VD_POL_MASK) << - CCDC_VD_POL_SHIFT)); - } - - /* pack the data to 8-bit */ - temp |= CCDC_DATA_PACK_ENABLE; - - regw(temp, MODESET); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 2); - - /* configure the order of y cb cr in SD-RAM */ - temp = (params->pix_order << CCDC_Y8POS_SHIFT); - temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; - regw(temp, CCDCFG); - - /* - * configure the horizontal line offset. This is done by rounding up - * width to a multiple of 16 pixels and multiply by two to account for - * y:cb:cr 4:2:2 data - */ - regw(((params->win.width * 2 + 31) >> 5), HSIZE); - - /* configure the memory line offset */ - if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { - /* two fields are interleaved in memory */ - regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); - } - - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); -} - -/* - * ccdc_config_black_clamp() - * configure parameters for Optical Black Clamp - */ -static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) -{ - u32 val; - - if (!bclamp->b_clamp_enable) { - /* configure DCSub */ - regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); - regw(0x0000, CLAMP); - return; - } - /* Enable the Black clamping, set sample lines and pixels */ - val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | - ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << - CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; - regw(val, CLAMP); - - /* If Black clamping is enable then make dcsub 0 */ - val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) - << CCDC_NUM_LINE_CALC_SHIFT; - regw(val, DCSUB); -} - -/* - * ccdc_config_black_compense() - * configure parameters for Black Compensation - */ -static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) -{ - u32 val; - - val = (bcomp->b & CCDC_BLK_COMP_MASK) | - ((bcomp->gb & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GB_COMP_SHIFT); - regw(val, BLKCMP1); - - val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GR_COMP_SHIFT) | - ((bcomp->r & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_R_COMP_SHIFT); - regw(val, BLKCMP0); -} - -/* - * ccdc_write_dfc_entry() - * write an entry in the dfc table. - */ -static int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) -{ -/* TODO This is to be re-visited and adjusted */ -#define DFC_WRITE_WAIT_COUNT 1000 - u32 val, count = DFC_WRITE_WAIT_COUNT; - - regw(dfc->dft_corr_vert[index], DFCMEM0); - regw(dfc->dft_corr_horz[index], DFCMEM1); - regw(dfc->dft_corr_sub1[index], DFCMEM2); - regw(dfc->dft_corr_sub2[index], DFCMEM3); - regw(dfc->dft_corr_sub3[index], DFCMEM4); - /* set WR bit to write */ - val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; - regw(val, DFCMEMCTL); - - /* - * Assume, it is very short. If we get an error, we need to - * adjust this value - */ - while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) - count--; - /* - * TODO We expect the count to be non-zero to be successful. Adjust - * the count if write requires more time - */ - - if (count) { - dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); - return -1; - } - return 0; -} - -/* - * ccdc_config_vdfc() - * configure parameters for Vertical Defect Correction - */ -static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) -{ - u32 val; - int i; - - /* Configure General Defect Correction. The table used is from IPIPE */ - val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; - - /* Configure Vertical Defect Correction if needed */ - if (!dfc->ver_dft_en) { - /* Enable only General Defect Correction */ - regw(val, DFCCTL); - return 0; - } - - if (dfc->table_size > CCDC_DFT_TABLE_SIZE) - return -EINVAL; - - val |= CCDC_DFCCTL_VDFC_DISABLE; - val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << - CCDC_DFCCTL_VDFCSL_SHIFT; - val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << - CCDC_DFCCTL_VDFCUDA_SHIFT; - val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << - CCDC_DFCCTL_VDFLSFT_SHIFT; - regw(val , DFCCTL); - - /* clear address ptr to offset 0 */ - val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; - - /* write defect table entries */ - for (i = 0; i < dfc->table_size; i++) { - /* increment address for non zero index */ - if (i != 0) - val = CCDC_DFCMEMCTL_INC_ADDR; - regw(val, DFCMEMCTL); - if (ccdc_write_dfc_entry(i, dfc) < 0) - return -EFAULT; - } - - /* update saturation level and enable dfc */ - regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); - val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << - CCDC_DFCCTL_VDFCEN_SHIFT); - regw(val, DFCCTL); - return 0; -} - -/* - * ccdc_config_csc() - * configure parameters for color space conversion - * Each register CSCM0-7 has two values in S8Q5 format. - */ -static void ccdc_config_csc(struct ccdc_csc *csc) -{ - u32 val1 = 0, val2; - int i; - - if (!csc->enable) - return; - - /* Enable the CSC sub-module */ - regw(CCDC_CSC_ENABLE, CSCCTL); - - /* Converting the co-eff as per the format of the register */ - for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = (csc->coeff[i].integer & - CCDC_CSC_COEF_INTEG_MASK) - << CCDC_CSC_COEF_INTEG_SHIFT; - /* - * convert decimal part to binary. Use 2 decimal - * precision, user values range from .00 - 0.99 - */ - val1 |= (((csc->coeff[i].decimal & - CCDC_CSC_COEF_DECIMAL_MASK) * - CCDC_CSC_DEC_MAX) / 100); - } else { - - /* CSCM - MSB */ - val2 = (csc->coeff[i].integer & - CCDC_CSC_COEF_INTEG_MASK) - << CCDC_CSC_COEF_INTEG_SHIFT; - val2 |= (((csc->coeff[i].decimal & - CCDC_CSC_COEF_DECIMAL_MASK) * - CCDC_CSC_DEC_MAX) / 100); - val2 <<= CCDC_CSCM_MSB_SHIFT; - val2 |= val1; - regw(val2, (CSCM0 + ((i - 1) << 1))); - } - } -} - -/* - * ccdc_config_color_patterns() - * configure parameters for color patterns - */ -static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, - struct ccdc_col_pat *pat1) -{ - u32 val; - - val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | - (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | - (pat1->elop << 12) | (pat1->elep << 14)); - regw(val, COLPTN); -} - -/* This function will configure CCDC for Raw mode image capture */ -static int ccdc_config_raw(void) -{ - struct ccdc_params_raw *params = &ccdc_cfg.bayer; - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int val; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); - - /* restore power on defaults to register */ - ccdc_restore_defaults(); - - /* CCDCFG register: - * set CCD Not to swap input since input is RAW data - * set FID detection function to Latch at V-Sync - * set WENLOG - ccdc valid area to AND - * set TRGSEL to WENBIT - * set EXTRG to DISABLE - * disable latching function on VSYNC - shadowed registers - */ - regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | - CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | - CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); - - /* - * Set VDHD direction to input, input type to raw input - * normal data polarity, do not use external WEN - */ - val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | - CCDC_EXWEN_DISABLE); - - /* - * Configure the vertical sync polarity (MODESET.VDPOL), horizontal - * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), - * frame format(progressive or interlace), & pixel format (Input mode) - */ - val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | - ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | - ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); - - /* set pack for alaw compression */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - val |= CCDC_DATA_PACK_ENABLE; - - /* Configure for LPF */ - if (config_params->lpf_enable) - val |= (config_params->lpf_enable & CCDC_LPF_MASK) << - CCDC_LPF_SHIFT; - - /* Configure the data shift */ - val |= (config_params->datasft & CCDC_DATASFT_MASK) << - CCDC_DATASFT_SHIFT; - regw(val , MODESET); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); - - /* Configure the Median Filter threshold */ - regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); - - /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ - val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | - CCDC_CFA_MOSAIC; - - /* Enable and configure aLaw register if needed */ - if (config_params->alaw.enable) { - val |= (CCDC_ALAW_ENABLE | - ((config_params->alaw.gamma_wd & - CCDC_ALAW_GAMMA_WD_MASK) << - CCDC_GAMMAWD_INPUT_SHIFT)); - } - - /* Configure Median filter1 & filter2 */ - val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | - (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); - - regw(val, GAMMAWD); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 1); - - /* Optical Clamp Averaging */ - ccdc_config_black_clamp(&config_params->blk_clamp); - - /* Black level compensation */ - ccdc_config_black_compense(&config_params->blk_comp); - - /* Vertical Defect Correction if needed */ - if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) - return -EFAULT; - - /* color space conversion */ - ccdc_config_csc(&config_params->csc); - - /* color pattern */ - ccdc_config_color_patterns(&config_params->col_pat_field0, - &config_params->col_pat_field1); - - /* Configure the Gain & offset control */ - ccdc_config_gain_offset(); - - dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); - - /* Configure DATAOFST register */ - val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << - CCDC_DATAOFST_H_SHIFT; - val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << - CCDC_DATAOFST_V_SHIFT; - regw(val, DATAOFST); - - /* configuring HSIZE register */ - val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) << - CCDC_HSIZE_FLIP_SHIFT; - - /* If pack 8 is enable then 1 pixel will take 1 byte */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) { - val |= (((params->win.width) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK; - - /* adjust to multiple of 32 */ - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", - (((params->win.width) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK); - } else { - /* else one pixel will take 2 byte */ - val |= (((params->win.width * 2) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK; - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", - (((params->win.width * 2) + 31) >> 5) & - CCDC_HSIZE_VAL_MASK); - } - regw(val, HSIZE); - - /* Configure SDOFST register */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_enable) { - /* For interlace inverse mode */ - regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_INTERLACE_INVERSE); - } else { - /* For interlace non inverse mode */ - regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_INTERLACE_NORMAL); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - if (params->image_invert_enable) { - /* For progessive inverse mode */ - regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_PROGRESSIVE_INVERSE); - } else { - /* For progessive non inverse mode */ - regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", - CCDC_SDOFST_PROGRESSIVE_NORMAL); - } - } - dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); - return 0; -} - -static int ccdc_configure(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_config_raw(); - else - ccdc_config_ycbcr(); - return 0; -} - -static int ccdc_set_buftype(enum ccdc_buftype buf_type) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.buf_type = buf_type; - else - ccdc_cfg.ycbcr.buf_type = buf_type; - return 0; -} -static enum ccdc_buftype ccdc_get_buftype(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.buf_type; - return ccdc_cfg.ycbcr.buf_type; -} - -static int ccdc_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { - *pix = ccdc_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { - *pix = ccdc_raw_yuv_pix_formats[i]; - ret = 0; - } - } - return ret; -} - -static int ccdc_set_pixel_format(u32 pixfmt) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - if (pixfmt == V4L2_PIX_FMT_SBGGR8) - alaw->enable = 1; - else if (pixfmt != V4L2_PIX_FMT_SBGGR16) - return -EINVAL; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - } - return 0; -} -static u32 ccdc_get_pixel_format(void) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - u32 pixfmt; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - if (alaw->enable) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} -static int ccdc_set_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.win = *win; - else - ccdc_cfg.ycbcr.win = *win; - return 0; -} - -static void ccdc_get_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - *win = ccdc_cfg.bayer.win; - else - *win = ccdc_cfg.ycbcr.win; -} - -static unsigned int ccdc_get_line_length(void) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int len; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if ((config_params->alaw.enable) || - (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_cfg.bayer.win.width; - else - len = ccdc_cfg.bayer.win.width * 2; - } else - len = ccdc_cfg.ycbcr.win.width * 2; - return ALIGN(len, 32); -} - -static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.frm_fmt = frm_fmt; - else - ccdc_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} - -static enum ccdc_frmfmt ccdc_get_frame_format(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.frm_fmt; - else - return ccdc_cfg.ycbcr.frm_fmt; -} - -static int ccdc_getfid(void) -{ - return (regr(MODESET) >> 15) & 1; -} - -/* misc operations */ -static inline void ccdc_setfbaddr(unsigned long addr) -{ - regw((addr >> 21) & 0x007f, STADRH); - regw((addr >> 5) & 0x0ffff, STADRL); -} - -static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - ccdc_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_YCBCR_SYNC_16: - case VPFE_YCBCR_SYNC_8: - ccdc_cfg.ycbcr.vd_pol = params->vdpol; - ccdc_cfg.ycbcr.hd_pol = params->hdpol; - break; - default: - /* TODO add support for raw bayer here */ - return -EINVAL; - } - return 0; -} - -static const struct ccdc_hw_device ccdc_hw_dev = { - .name = "DM355 CCDC", - .owner = THIS_MODULE, - .hw_ops = { - .open = ccdc_open, - .close = ccdc_close, - .enable = ccdc_enable, - .enable_out_to_sdram = ccdc_enable_output_to_sdram, - .set_hw_if_params = ccdc_set_hw_if_params, - .configure = ccdc_configure, - .set_buftype = ccdc_set_buftype, - .get_buftype = ccdc_get_buftype, - .enum_pix = ccdc_enum_pix, - .set_pixel_format = ccdc_set_pixel_format, - .get_pixel_format = ccdc_get_pixel_format, - .set_frame_format = ccdc_set_frame_format, - .get_frame_format = ccdc_get_frame_format, - .set_image_window = ccdc_set_image_window, - .get_image_window = ccdc_get_image_window, - .get_line_length = ccdc_get_line_length, - .setfbaddr = ccdc_setfbaddr, - .getfid = ccdc_getfid, - }, -}; - -static int dm355_ccdc_probe(struct platform_device *pdev) -{ - void (*setup_pinmux)(void); - struct resource *res; - int status = 0; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&ccdc_hw_dev); - if (status < 0) - return status; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - status = -ENODEV; - goto fail_nores; - } - - res = request_mem_region(res->start, resource_size(res), res->name); - if (!res) { - status = -EBUSY; - goto fail_nores; - } - - ccdc_cfg.base_addr = ioremap(res->start, resource_size(res)); - if (!ccdc_cfg.base_addr) { - status = -ENOMEM; - goto fail_nomem; - } - - /* Platform data holds setup_pinmux function ptr */ - if (NULL == pdev->dev.platform_data) { - status = -ENODEV; - goto fail_nomap; - } - setup_pinmux = pdev->dev.platform_data; - /* - * setup Mux configuration for ccdc which may be different for - * different SoCs using this CCDC - */ - setup_pinmux(); - ccdc_cfg.dev = &pdev->dev; - printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); - return 0; -fail_nomap: - iounmap(ccdc_cfg.base_addr); -fail_nomem: - release_mem_region(res->start, resource_size(res)); -fail_nores: - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return status; -} - -static int dm355_ccdc_remove(struct platform_device *pdev) -{ - struct resource *res; - - iounmap(ccdc_cfg.base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return 0; -} - -static struct platform_driver dm355_ccdc_driver = { - .driver = { - .name = "dm355_ccdc", - }, - .remove = dm355_ccdc_remove, - .probe = dm355_ccdc_probe, -}; - -module_platform_driver(dm355_ccdc_driver); diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h deleted file mode 100644 index 1f3d00aa46d1..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h +++ /dev/null @@ -1,308 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - */ -#ifndef _DM355_CCDC_H -#define _DM355_CCDC_H -#include -#include - -/* enum for No of pixel per line to be avg. in Black Clamping */ -enum ccdc_sample_length { - CCDC_SAMPLE_1PIXELS, - CCDC_SAMPLE_2PIXELS, - CCDC_SAMPLE_4PIXELS, - CCDC_SAMPLE_8PIXELS, - CCDC_SAMPLE_16PIXELS -}; - -/* enum for No of lines in Black Clamping */ -enum ccdc_sample_line { - CCDC_SAMPLE_1LINES, - CCDC_SAMPLE_2LINES, - CCDC_SAMPLE_4LINES, - CCDC_SAMPLE_8LINES, - CCDC_SAMPLE_16LINES -}; - -/* enum for Alaw gamma width */ -enum ccdc_gamma_width { - CCDC_GAMMA_BITS_13_4, - CCDC_GAMMA_BITS_12_3, - CCDC_GAMMA_BITS_11_2, - CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 -}; - -enum ccdc_colpats { - CCDC_RED, - CCDC_GREEN_RED, - CCDC_GREEN_BLUE, - CCDC_BLUE -}; - -struct ccdc_col_pat { - enum ccdc_colpats olop; - enum ccdc_colpats olep; - enum ccdc_colpats elop; - enum ccdc_colpats elep; -}; - -enum ccdc_datasft { - CCDC_DATA_NO_SHIFT, - CCDC_DATA_SHIFT_1BIT, - CCDC_DATA_SHIFT_2BIT, - CCDC_DATA_SHIFT_3BIT, - CCDC_DATA_SHIFT_4BIT, - CCDC_DATA_SHIFT_5BIT, - CCDC_DATA_SHIFT_6BIT -}; - -enum ccdc_data_size { - CCDC_DATA_16BITS, - CCDC_DATA_15BITS, - CCDC_DATA_14BITS, - CCDC_DATA_13BITS, - CCDC_DATA_12BITS, - CCDC_DATA_11BITS, - CCDC_DATA_10BITS, - CCDC_DATA_8BITS -}; -enum ccdc_mfilt1 { - CCDC_NO_MEDIAN_FILTER1, - CCDC_AVERAGE_FILTER1, - CCDC_MEDIAN_FILTER1 -}; - -enum ccdc_mfilt2 { - CCDC_NO_MEDIAN_FILTER2, - CCDC_AVERAGE_FILTER2, - CCDC_MEDIAN_FILTER2 -}; - -/* structure for ALaw */ -struct ccdc_a_law { - /* Enable/disable A-Law */ - unsigned char enable; - /* Gamma Width Input */ - enum ccdc_gamma_width gamma_wd; -}; - -/* structure for Black Clamping */ -struct ccdc_black_clamp { - /* only if bClampEnable is TRUE */ - unsigned char b_clamp_enable; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_length sample_pixel; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_line sample_ln; - /* only if bClampEnable is TRUE */ - unsigned short start_pixel; - /* only if bClampEnable is FALSE */ - unsigned short sgain; - unsigned short dc_sub; -}; - -/* structure for Black Level Compensation */ -struct ccdc_black_compensation { - /* Constant value to subtract from Red component */ - unsigned char r; - /* Constant value to subtract from Gr component */ - unsigned char gr; - /* Constant value to subtract from Blue component */ - unsigned char b; - /* Constant value to subtract from Gb component */ - unsigned char gb; -}; - -struct ccdc_float { - int integer; - unsigned int decimal; -}; - -#define CCDC_CSC_COEFF_TABLE_SIZE 16 -/* structure for color space converter */ -struct ccdc_csc { - unsigned char enable; - /* - * S8Q5. Use 2 decimal precision, user values range from -3.00 to 3.99. - * example - to use 1.03, set integer part as 1, and decimal part as 3 - * to use -1.03, set integer part as -1 and decimal part as 3 - */ - struct ccdc_float coeff[CCDC_CSC_COEFF_TABLE_SIZE]; -}; - -/* Structures for Vertical Defect Correction*/ -enum ccdc_vdf_csl { - CCDC_VDF_NORMAL, - CCDC_VDF_HORZ_INTERPOL_SAT, - CCDC_VDF_HORZ_INTERPOL -}; - -enum ccdc_vdf_cuda { - CCDC_VDF_WHOLE_LINE_CORRECT, - CCDC_VDF_UPPER_DISABLE -}; - -enum ccdc_dfc_mwr { - CCDC_DFC_MWR_WRITE_COMPLETE, - CCDC_DFC_WRITE_REG -}; - -enum ccdc_dfc_mrd { - CCDC_DFC_READ_COMPLETE, - CCDC_DFC_READ_REG -}; - -enum ccdc_dfc_ma_rst { - CCDC_DFC_INCR_ADDR, - CCDC_DFC_CLR_ADDR -}; - -enum ccdc_dfc_mclr { - CCDC_DFC_CLEAR_COMPLETE, - CCDC_DFC_CLEAR -}; - -struct ccdc_dft_corr_ctl { - enum ccdc_vdf_csl vdfcsl; - enum ccdc_vdf_cuda vdfcuda; - unsigned int vdflsft; -}; - -struct ccdc_dft_corr_mem_ctl { - enum ccdc_dfc_mwr dfcmwr; - enum ccdc_dfc_mrd dfcmrd; - enum ccdc_dfc_ma_rst dfcmarst; - enum ccdc_dfc_mclr dfcmclr; -}; - -#define CCDC_DFT_TABLE_SIZE 16 -/* - * Main Structure for vertical defect correction. Vertical defect - * correction can correct up to 16 defects if defects less than 16 - * then pad the rest with 0 - */ -struct ccdc_vertical_dft { - unsigned char ver_dft_en; - unsigned char gen_dft_en; - unsigned int saturation_ctl; - struct ccdc_dft_corr_ctl dft_corr_ctl; - struct ccdc_dft_corr_mem_ctl dft_corr_mem_ctl; - int table_size; - unsigned int dft_corr_horz[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_vert[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub1[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub2[CCDC_DFT_TABLE_SIZE]; - unsigned int dft_corr_sub3[CCDC_DFT_TABLE_SIZE]; -}; - -struct ccdc_data_offset { - unsigned char horz_offset; - unsigned char vert_offset; -}; - -/* - * Structure for CCDC configuration parameters for raw capture mode passed - * by application - */ -struct ccdc_config_params_raw { - /* data shift to be applied before storing */ - enum ccdc_datasft datasft; - /* data size value from 8 to 16 bits */ - enum ccdc_data_size data_sz; - /* median filter for sdram */ - enum ccdc_mfilt1 mfilt1; - enum ccdc_mfilt2 mfilt2; - /* low pass filter enable/disable */ - unsigned char lpf_enable; - /* Threshold of median filter */ - int med_filt_thres; - /* - * horz and vertical data offset. Applicable for defect correction - * and lsc - */ - struct ccdc_data_offset data_offset; - /* Structure for Optional A-Law */ - struct ccdc_a_law alaw; - /* Structure for Optical Black Clamp */ - struct ccdc_black_clamp blk_clamp; - /* Structure for Black Compensation */ - struct ccdc_black_compensation blk_comp; - /* structure for vertical Defect Correction Module Configuration */ - struct ccdc_vertical_dft vertical_dft; - /* structure for color space converter Module Configuration */ - struct ccdc_csc csc; - /* color patters for bayer capture */ - struct ccdc_col_pat col_pat_field0; - struct ccdc_col_pat col_pat_field1; -}; - -#ifdef __KERNEL__ -#include - -#define CCDC_WIN_PAL {0, 0, 720, 576} -#define CCDC_WIN_VGA {0, 0, 640, 480} - -struct ccdc_params_ycbcr { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* enable BT.656 embedded sync mode */ - int bt656_enable; - /* cb:y:cr:y or y:cb:y:cr in memory */ - enum ccdc_pixorder pix_order; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; -}; - -/* Gain applied to Raw Bayer data */ -struct ccdc_gain { - unsigned short r_ye; - unsigned short gr_cy; - unsigned short gb_g; - unsigned short b_mg; -}; - -/* Structure for CCDC configuration parameters for raw capture mode */ -struct ccdc_params_raw { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; - /* Gain values */ - struct ccdc_gain gain; - /* offset */ - unsigned int ccdc_offset; - /* horizontal flip enable */ - unsigned char horz_flip_enable; - /* - * enable to store the image in inverse order in memory - * (bottom to top) - */ - unsigned char image_invert_enable; - /* Configurable part of raw data */ - struct ccdc_config_params_raw config_params; -}; - -#endif -#endif /* DM355_CCDC_H */ diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h deleted file mode 100644 index eb381f075245..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h +++ /dev/null @@ -1,297 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005-2009 Texas Instruments Inc - */ -#ifndef _DM355_CCDC_REGS_H -#define _DM355_CCDC_REGS_H - -/**************************************************************************\ -* Register OFFSET Definitions -\**************************************************************************/ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDWIDTH 0x08 -#define VDWIDTH 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define NPH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define NLV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define STADRH 0x3c -#define STADRL 0x40 -#define CLAMP 0x44 -#define DCSUB 0x48 -#define COLPTN 0x4c -#define BLKCMP0 0x50 -#define BLKCMP1 0x54 -#define MEDFILT 0x58 -#define RYEGAIN 0x5c -#define GRCYGAIN 0x60 -#define GBGGAIN 0x64 -#define BMGGAIN 0x68 -#define OFFSET 0x6c -#define OUTCLIP 0x70 -#define VDINT0 0x74 -#define VDINT1 0x78 -#define RSV0 0x7c -#define GAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -#define FMTCFG 0x8c -#define FMTPLEN 0x90 -#define FMTSPH 0x94 -#define FMTLNH 0x98 -#define FMTSLV 0x9c -#define FMTLNV 0xa0 -#define FMTRLEN 0xa4 -#define FMTHCNT 0xa8 -#define FMT_ADDR_PTR_B 0xac -#define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4)) -#define FMTPGM_VF0 0xcc -#define FMTPGM_VF1 0xd0 -#define FMTPGM_AP0 0xd4 -#define FMTPGM_AP1 0xd8 -#define FMTPGM_AP2 0xdc -#define FMTPGM_AP3 0xe0 -#define FMTPGM_AP4 0xe4 -#define FMTPGM_AP5 0xe8 -#define FMTPGM_AP6 0xec -#define FMTPGM_AP7 0xf0 -#define LSCCFG1 0xf4 -#define LSCCFG2 0xf8 -#define LSCH0 0xfc -#define LSCV0 0x100 -#define LSCKH 0x104 -#define LSCKV 0x108 -#define LSCMEMCTL 0x10c -#define LSCMEMD 0x110 -#define LSCMEMQ 0x114 -#define DFCCTL 0x118 -#define DFCVSAT 0x11c -#define DFCMEMCTL 0x120 -#define DFCMEM0 0x124 -#define DFCMEM1 0x128 -#define DFCMEM2 0x12c -#define DFCMEM3 0x130 -#define DFCMEM4 0x134 -#define CSCCTL 0x138 -#define CSCM0 0x13c -#define CSCM1 0x140 -#define CSCM2 0x144 -#define CSCM3 0x148 -#define CSCM4 0x14c -#define CSCM5 0x150 -#define CSCM6 0x154 -#define CSCM7 0x158 -#define DATAOFST 0x15c -#define CCDC_REG_LAST DATAOFST -/************************************************************** -* Define for various register bit mask and shifts for CCDC -* -**************************************************************/ -#define CCDC_RAW_IP_MODE 0 -#define CCDC_VDHDOUT_INPUT 0 -#define CCDC_YCINSWP_RAW (0 << 4) -#define CCDC_EXWEN_DISABLE 0 -#define CCDC_DATAPOL_NORMAL 0 -#define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0 -#define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6) -#define CCDC_CCDCFG_WENLOG_AND 0 -#define CCDC_CCDCFG_TRGSEL_WEN 0 -#define CCDC_CCDCFG_EXTRG_DISABLE 0 -#define CCDC_CFA_MOSAIC 0 -#define CCDC_Y8POS_SHIFT 11 - -#define CCDC_VDC_DFCVSAT_MASK 0x3fff -#define CCDC_DATAOFST_MASK 0x0ff -#define CCDC_DATAOFST_H_SHIFT 0 -#define CCDC_DATAOFST_V_SHIFT 8 -#define CCDC_GAMMAWD_CFA_MASK 1 -#define CCDC_GAMMAWD_CFA_SHIFT 5 -#define CCDC_GAMMAWD_INPUT_SHIFT 2 -#define CCDC_FID_POL_MASK 1 -#define CCDC_FID_POL_SHIFT 4 -#define CCDC_HD_POL_MASK 1 -#define CCDC_HD_POL_SHIFT 3 -#define CCDC_VD_POL_MASK 1 -#define CCDC_VD_POL_SHIFT 2 -#define CCDC_VD_POL_NEGATIVE (1 << 2) -#define CCDC_FRM_FMT_MASK 1 -#define CCDC_FRM_FMT_SHIFT 7 -#define CCDC_DATA_SZ_MASK 7 -#define CCDC_DATA_SZ_SHIFT 8 -#define CCDC_VDHDOUT_MASK 1 -#define CCDC_VDHDOUT_SHIFT 0 -#define CCDC_EXWEN_MASK 1 -#define CCDC_EXWEN_SHIFT 5 -#define CCDC_INPUT_MODE_MASK 3 -#define CCDC_INPUT_MODE_SHIFT 12 -#define CCDC_PIX_FMT_MASK 3 -#define CCDC_PIX_FMT_SHIFT 12 -#define CCDC_DATAPOL_MASK 1 -#define CCDC_DATAPOL_SHIFT 6 -#define CCDC_WEN_ENABLE (1 << 1) -#define CCDC_VDHDEN_ENABLE (1 << 16) -#define CCDC_LPF_ENABLE (1 << 14) -#define CCDC_ALAW_ENABLE 1 -#define CCDC_ALAW_GAMMA_WD_MASK 7 -#define CCDC_REC656IF_BT656_EN 3 - -#define CCDC_FMTCFG_FMTMODE_MASK 3 -#define CCDC_FMTCFG_FMTMODE_SHIFT 1 -#define CCDC_FMTCFG_LNUM_MASK 3 -#define CCDC_FMTCFG_LNUM_SHIFT 4 -#define CCDC_FMTCFG_ADDRINC_MASK 7 -#define CCDC_FMTCFG_ADDRINC_SHIFT 8 - -#define CCDC_CCDCFG_FIDMD_SHIFT 6 -#define CCDC_CCDCFG_WENLOG_SHIFT 8 -#define CCDC_CCDCFG_TRGSEL_SHIFT 9 -#define CCDC_CCDCFG_EXTRG_SHIFT 10 -#define CCDC_CCDCFG_MSBINVI_SHIFT 13 - -#define CCDC_HSIZE_FLIP_SHIFT 12 -#define CCDC_HSIZE_FLIP_MASK 1 -#define CCDC_HSIZE_VAL_MASK 0xFFF -#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 -#define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D -#define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D -#define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000 -#define CCDC_SDOFST_PROGRESSIVE_NORMAL 0 -#define CCDC_START_PX_HOR_MASK 0x7FFF -#define CCDC_NUM_PX_HOR_MASK 0x7FFF -#define CCDC_START_VER_ONE_MASK 0x7FFF -#define CCDC_START_VER_TWO_MASK 0x7FFF -#define CCDC_NUM_LINES_VER 0x7FFF - -#define CCDC_BLK_CLAMP_ENABLE (1 << 15) -#define CCDC_BLK_SGAIN_MASK 0x1F -#define CCDC_BLK_ST_PXL_MASK 0x1FFF -#define CCDC_BLK_SAMPLE_LN_MASK 3 -#define CCDC_BLK_SAMPLE_LN_SHIFT 13 - -#define CCDC_NUM_LINE_CALC_MASK 3 -#define CCDC_NUM_LINE_CALC_SHIFT 14 - -#define CCDC_BLK_DC_SUB_MASK 0x3FFF -#define CCDC_BLK_COMP_MASK 0xFF -#define CCDC_BLK_COMP_GB_COMP_SHIFT 8 -#define CCDC_BLK_COMP_GR_COMP_SHIFT 0 -#define CCDC_BLK_COMP_R_COMP_SHIFT 8 -#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) -#define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15) -#define CCDC_FPC_ENABLE (1 << 15) -#define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE (1 << 11) -#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 -#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_SHIFT 16 -#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF -#define CCDC_VP_OUT_VERT_NUM_SHIFT 17 -#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF -#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 -#define CCDC_VP_OUT_HORZ_ST_MASK 0xF - -#define CCDC_CSC_COEF_INTEG_MASK 7 -#define CCDC_CSC_COEF_DECIMAL_MASK 0x1f -#define CCDC_CSC_COEF_INTEG_SHIFT 5 -#define CCDC_CSCM_MSB_SHIFT 8 -#define CCDC_CSC_ENABLE 1 -#define CCDC_CSC_DEC_MAX 32 - -#define CCDC_MFILT1_SHIFT 10 -#define CCDC_MFILT2_SHIFT 8 -#define CCDC_MED_FILT_THRESH 0x3FFF -#define CCDC_LPF_MASK 1 -#define CCDC_LPF_SHIFT 14 -#define CCDC_OFFSET_MASK 0x3FF -#define CCDC_DATASFT_MASK 7 -#define CCDC_DATASFT_SHIFT 8 - -#define CCDC_DF_ENABLE 1 - -#define CCDC_FMTPLEN_P0_MASK 0xF -#define CCDC_FMTPLEN_P1_MASK 0xF -#define CCDC_FMTPLEN_P2_MASK 7 -#define CCDC_FMTPLEN_P3_MASK 7 -#define CCDC_FMTPLEN_P0_SHIFT 0 -#define CCDC_FMTPLEN_P1_SHIFT 4 -#define CCDC_FMTPLEN_P2_SHIFT 8 -#define CCDC_FMTPLEN_P3_SHIFT 12 - -#define CCDC_FMTSPH_MASK 0x1FFF -#define CCDC_FMTLNH_MASK 0x1FFF -#define CCDC_FMTSLV_MASK 0x1FFF -#define CCDC_FMTLNV_MASK 0x7FFF -#define CCDC_FMTRLEN_MASK 0x1FFF -#define CCDC_FMTHCNT_MASK 0x1FFF - -#define CCDC_ADP_INIT_MASK 0x1FFF -#define CCDC_ADP_LINE_SHIFT 13 -#define CCDC_ADP_LINE_MASK 3 -#define CCDC_FMTPGN_APTR_MASK 7 - -#define CCDC_DFCCTL_GDFCEN_MASK 1 -#define CCDC_DFCCTL_VDFCEN_MASK 1 -#define CCDC_DFCCTL_VDFC_DISABLE (0 << 4) -#define CCDC_DFCCTL_VDFCEN_SHIFT 4 -#define CCDC_DFCCTL_VDFCSL_MASK 3 -#define CCDC_DFCCTL_VDFCSL_SHIFT 5 -#define CCDC_DFCCTL_VDFCUDA_MASK 1 -#define CCDC_DFCCTL_VDFCUDA_SHIFT 7 -#define CCDC_DFCCTL_VDFLSFT_MASK 3 -#define CCDC_DFCCTL_VDFLSFT_SHIFT 8 -#define CCDC_DFCMEMCTL_DFCMARST_MASK 1 -#define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2 -#define CCDC_DFCMEMCTL_DFCMWR_MASK 1 -#define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0 -#define CCDC_DFCMEMCTL_INC_ADDR (0 << 2) - -#define CCDC_LSCCFG_GFTSF_MASK 7 -#define CCDC_LSCCFG_GFTSF_SHIFT 1 -#define CCDC_LSCCFG_GFTINV_MASK 0xf -#define CCDC_LSCCFG_GFTINV_SHIFT 4 -#define CCDC_LSC_GFTABLE_SEL_MASK 3 -#define CCDC_LSC_GFTABLE_EPEL_SHIFT 8 -#define CCDC_LSC_GFTABLE_OPEL_SHIFT 10 -#define CCDC_LSC_GFTABLE_EPOL_SHIFT 12 -#define CCDC_LSC_GFTABLE_OPOL_SHIFT 14 -#define CCDC_LSC_GFMODE_MASK 3 -#define CCDC_LSC_GFMODE_SHIFT 4 -#define CCDC_LSC_DISABLE 0 -#define CCDC_LSC_ENABLE 1 -#define CCDC_LSC_TABLE1_SLC 0 -#define CCDC_LSC_TABLE2_SLC 1 -#define CCDC_LSC_TABLE3_SLC 2 -#define CCDC_LSC_MEMADDR_RESET (1 << 2) -#define CCDC_LSC_MEMADDR_INCR (0 << 2) -#define CCDC_LSC_FRAC_MASK_T1 0xFF -#define CCDC_LSC_INT_MASK 3 -#define CCDC_LSC_FRAC_MASK 0x3FFF -#define CCDC_LSC_CENTRE_MASK 0x3FFF -#define CCDC_LSC_COEF_MASK 0xff -#define CCDC_LSC_COEFL_SHIFT 0 -#define CCDC_LSC_COEFU_SHIFT 8 -#define CCDC_GAIN_MASK 0x7FF -#define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) -#define CCDC_SYNCEN_WEN_MASK (1 << 1) -#define CCDC_SYNCEN_WEN_SHIFT 1 - -/* Power on Defaults in hardware */ -#define MODESET_DEFAULT 0x200 -#define CULH_DEFAULT 0xFFFF -#define CULV_DEFAULT 0xFF -#define GAIN_DEFAULT 256 -#define OUTCLIP_DEFAULT 0x3FFF -#define LSCCFG2_DEFAULT 0xE - -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c deleted file mode 100644 index 4a93e5ad6415..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c +++ /dev/null @@ -1,879 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - * - * CCDC hardware module for DM6446 - * ------------------------------ - * - * This module is for configuring CCD controller of DM6446 VPFE to capture - * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules - * such as Defect Pixel Correction, Color Space Conversion etc to - * pre-process the Raw Bayer RGB data, before writing it to SDRAM. - * This file is named DM644x so that other variants such DM6443 - * may be supported using the same module. - * - * TODO: Test Raw bayer parameter settings and bayer capture - * Split module parameter structure to module specific ioctl structs - * investigate if enum used for user space type definition - * to be replaced by #defines or integer - */ -#include -#include -#include -#include -#include -#include - -#include "dm644x_ccdc.h" -#include - -#include "dm644x_ccdc_regs.h" -#include "ccdc_hw_device.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CCDC Driver for DM6446"); -MODULE_AUTHOR("Texas Instruments"); - -static struct ccdc_oper_config { - struct device *dev; - /* CCDC interface type */ - enum vpfe_hw_if_type if_type; - /* Raw Bayer configuration */ - struct ccdc_params_raw bayer; - /* YCbCr configuration */ - struct ccdc_params_ycbcr ycbcr; - /* ccdc base address */ - void __iomem *base_addr; -} ccdc_cfg = { - /* Raw configurations */ - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = CCDC_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .config_params = { - .data_sz = CCDC_DATA_10BITS, - }, - }, - .ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = CCDC_WIN_PAL, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .bt656_enable = 1, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED - }, -}; - -#define CCDC_MAX_RAW_YUV_FORMATS 2 - -/* Raw Bayer formats */ -static u32 ccdc_raw_bayer_pix_formats[] = - {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static u32 ccdc_raw_yuv_pix_formats[] = - {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* CCDC Save/Restore context */ -static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)]; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(ccdc_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, ccdc_cfg.base_addr + offset); -} - -static void ccdc_enable(int flag) -{ - regw(flag, CCDC_PCR); -} - -static void ccdc_enable_vport(int flag) -{ - if (flag) - /* enable video port */ - regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); - else - regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); -} - -/* - * ccdc_setwin() - * This function will configure the window size - * to be capture in CCDC reg - */ -static void ccdc_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, - int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int val = 0, mid_img = 0; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; - regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels, - CCDC_HORZ_INFO); - - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* Since first line doesn't have any data */ - vert_start += 1; - /* configure VDINT0 */ - val = (vert_start << CCDC_VDINT_VDINT0_SHIFT); - regw(val, CCDC_VDINT); - - } else { - /* Since first line doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* - * configure VDINT0 and VDINT1. VDINT1 will be at half - * of image height - */ - mid_img = vert_start + (image_win->height / 2); - val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) | - (mid_img & CCDC_VDINT_VDINT1_MASK); - regw(val, CCDC_VDINT); - - } - regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, - CCDC_VERT_START); - regw(vert_nr_lines, CCDC_VERT_LINES); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); -} - -static void ccdc_readregs(void) -{ - unsigned int val = 0; - - val = regr(CCDC_ALAW); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); - val = regr(CCDC_CLAMP); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); - val = regr(CCDC_DCSUB); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); - val = regr(CCDC_BLKCMP); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); - val = regr(CCDC_FPC_ADDR); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); - val = regr(CCDC_FPC); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); - val = regr(CCDC_FMTCFG); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); - val = regr(CCDC_COLPTN); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); - val = regr(CCDC_FMT_HORZ); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); - val = regr(CCDC_FMT_VERT); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); - val = regr(CCDC_HSIZE_OFF); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); - val = regr(CCDC_SDOFST); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); - val = regr(CCDC_VP_OUT); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); - val = regr(CCDC_SYN_MODE); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); - val = regr(CCDC_HORZ_INFO); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); - val = regr(CCDC_VERT_START); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); - val = regr(CCDC_VERT_LINES); - dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); -} - -static int ccdc_close(struct device *dev) -{ - return 0; -} - -/* - * ccdc_restore_defaults() - * This function will write defaults to all CCDC registers - */ -static void ccdc_restore_defaults(void) -{ - int i; - - /* disable CCDC */ - ccdc_enable(0); - /* set all registers to default value */ - for (i = 4; i <= 0x94; i += 4) - regw(0, i); - regw(CCDC_NO_CULLING, CCDC_CULLING); - regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); -} - -static int ccdc_open(struct device *device) -{ - ccdc_restore_defaults(); - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_enable_vport(1); - return 0; -} - -static void ccdc_sbl_reset(void) -{ - vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); -} - -/* - * ccdc_config_ycbcr() - * This function will configure CCDC for YCbCr video capture - */ -static void ccdc_config_ycbcr(void) -{ - struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; - u32 syn_mode; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); - /* - * first restore the CCDC registers to default values - * This is important since we assume default values to be set in - * a lot of registers that we didn't touch - */ - ccdc_restore_defaults(); - - /* - * configure pixel format, frame format, configure video frame - * format, enable output to SDRAM, enable internal timing generator - * and 8bit pack mode - */ - syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << - CCDC_SYN_MODE_INPMOD_SHIFT) | - ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << - CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | - CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); - - /* setup BT.656 sync mode */ - if (params->bt656_enable) { - regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); - - /* - * configure the FID, VD, HD pin polarity, - * fld,hd pol positive, vd negative, 8-bit data - */ - syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE; - if (ccdc_cfg.if_type == VPFE_BT656_10BIT) - syn_mode |= CCDC_SYN_MODE_10BITS; - else - syn_mode |= CCDC_SYN_MODE_8BITS; - } else { - /* y/c external sync mode */ - syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << - CCDC_FID_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << - CCDC_HD_POL_SHIFT) | - ((params->vd_pol & CCDC_VD_POL_MASK) << - CCDC_VD_POL_SHIFT)); - } - regw(syn_mode, CCDC_SYN_MODE); - - /* configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, 2); - - /* - * configure the order of y cb cr in SDRAM, and disable latch - * internal register on vsync - */ - if (ccdc_cfg.if_type == VPFE_BT656_10BIT) - regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | - CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT, - CCDC_CCDCFG); - else - regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | - CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); - - /* - * configure the horizontal line offset. This should be a - * on 32 byte boundary. So clear LSB 5 bits - */ - regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); - - /* configure the memory line offset */ - if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) - /* two fields are interleaved in memory */ - regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); - - ccdc_sbl_reset(); - dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); -} - -static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) -{ - u32 val; - - if (!bclamp->enable) { - /* configure DCSub */ - val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; - regw(val, CCDC_DCSUB); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); - regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); - return; - } - /* - * Configure gain, Start pixel, No of line to be avg, - * No of pixel/line to be avg, & Enable the Black clamping - */ - val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | - ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << - CCDC_BLK_ST_PXL_SHIFT) | - ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << - CCDC_BLK_SAMPLE_LINE_SHIFT) | - ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << - CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); - regw(val, CCDC_CLAMP); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); - /* If Black clamping is enable then make dcsub 0 */ - regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); -} - -static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) -{ - u32 val; - - val = ((bcomp->b & CCDC_BLK_COMP_MASK) | - ((bcomp->gb & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GB_COMP_SHIFT) | - ((bcomp->gr & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_GR_COMP_SHIFT) | - ((bcomp->r & CCDC_BLK_COMP_MASK) << - CCDC_BLK_COMP_R_COMP_SHIFT)); - regw(val, CCDC_BLKCMP); -} - -/* - * ccdc_config_raw() - * This function will configure CCDC for Raw capture mode - */ -static void ccdc_config_raw(void) -{ - struct ccdc_params_raw *params = &ccdc_cfg.bayer; - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int syn_mode = 0; - unsigned int val; - - dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); - - /* Reset CCDC */ - ccdc_restore_defaults(); - - /* Disable latching function registers on VSYNC */ - regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); - - /* - * Configure the vertical sync polarity(SYN_MODE.VDPOL), - * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity - * (SYN_MODE.FLDPOL), frame format(progressive or interlace), - * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output - * SDRAM, enable internal timing generator - */ - syn_mode = - (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | - ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | - ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | - ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | - ((config_params->data_sz & CCDC_DATA_SZ_MASK) << - CCDC_DATA_SZ_SHIFT) | - ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | - CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); - - /* Enable and configure aLaw register if needed */ - if (config_params->alaw.enable) { - val = ((config_params->alaw.gamma_wd & - CCDC_ALAW_GAMMA_WD_MASK) | CCDC_ALAW_ENABLE); - regw(val, CCDC_ALAW); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); - } - - /* Configure video window */ - ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW); - - /* Configure Black Clamp */ - ccdc_config_black_clamp(&config_params->blk_clamp); - - /* Configure Black level compensation */ - ccdc_config_black_compense(&config_params->blk_comp); - - /* If data size is 8 bit then pack the data */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - syn_mode |= CCDC_DATA_PACK_ENABLE; - - /* disable video port */ - val = CCDC_DISABLE_VIDEO_PORT; - - if (config_params->data_sz == CCDC_DATA_8BITS) - val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) - << CCDC_FMTCFG_VPIN_SHIFT; - else - val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) - << CCDC_FMTCFG_VPIN_SHIFT; - /* Write value in FMTCFG */ - regw(val, CCDC_FMTCFG); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); - /* Configure the color pattern according to mt9t001 sensor */ - regw(CCDC_COLPTN_VAL, CCDC_COLPTN); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); - /* - * Configure Data formatter(Video port) pixel selection - * (FMT_HORZ, FMT_VERT) - */ - val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << - CCDC_FMT_HORZ_FMTSPH_SHIFT) | - (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); - regw(val, CCDC_FMT_HORZ); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); - val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) - << CCDC_FMT_VERT_FMTSLV_SHIFT; - if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) - val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK; - else - val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; - - dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", - params->win.height); - regw(val, CCDC_FMT_VERT); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); - - dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); - - /* - * Configure Horizontal offset register. If pack 8 is enabled then - * 1 pixel will take 1 byte - */ - if ((config_params->data_sz == CCDC_DATA_8BITS) || - config_params->alaw.enable) - regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & - CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); - else - /* else one pixel will take 2 byte */ - regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + - CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, - CCDC_HSIZE_OFF); - - /* Set value for SDOFST */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_enable) { - /* For intelace inverse mode */ - regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); - } - - else { - /* For intelace non inverse mode */ - regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n"); - } - - /* - * Configure video port pixel selection (VPOUT) - * Here -1 is to make the height value less than FMT_VERT.FMTLNV - */ - if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) - val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) - << CCDC_VP_OUT_VERT_NUM_SHIFT; - else - val = - ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) - - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) << - CCDC_VP_OUT_VERT_NUM_SHIFT; - - val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK) - << CCDC_VP_OUT_HORZ_NUM_SHIFT; - val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; - regw(val, CCDC_VP_OUT); - - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); - regw(syn_mode, CCDC_SYN_MODE); - dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); - - ccdc_sbl_reset(); - dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); - ccdc_readregs(); -} - -static int ccdc_configure(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_config_raw(); - else - ccdc_config_ycbcr(); - return 0; -} - -static int ccdc_set_buftype(enum ccdc_buftype buf_type) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.buf_type = buf_type; - else - ccdc_cfg.ycbcr.buf_type = buf_type; - return 0; -} - -static enum ccdc_buftype ccdc_get_buftype(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.buf_type; - return ccdc_cfg.ycbcr.buf_type; -} - -static int ccdc_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { - *pix = ccdc_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { - *pix = ccdc_raw_yuv_pix_formats[i]; - ret = 0; - } - } - return ret; -} - -static int ccdc_set_pixel_format(u32 pixfmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - if (pixfmt == V4L2_PIX_FMT_SBGGR8) - ccdc_cfg.bayer.config_params.alaw.enable = 1; - else if (pixfmt != V4L2_PIX_FMT_SBGGR16) - return -EINVAL; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - } - return 0; -} - -static u32 ccdc_get_pixel_format(void) -{ - struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; - u32 pixfmt; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - if (alaw->enable) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} - -static int ccdc_set_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.win = *win; - else - ccdc_cfg.ycbcr.win = *win; - return 0; -} - -static void ccdc_get_image_window(struct v4l2_rect *win) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - *win = ccdc_cfg.bayer.win; - else - *win = ccdc_cfg.ycbcr.win; -} - -static unsigned int ccdc_get_line_length(void) -{ - struct ccdc_config_params_raw *config_params = - &ccdc_cfg.bayer.config_params; - unsigned int len; - - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { - if ((config_params->alaw.enable) || - (config_params->data_sz == CCDC_DATA_8BITS)) - len = ccdc_cfg.bayer.win.width; - else - len = ccdc_cfg.bayer.win.width * 2; - } else - len = ccdc_cfg.ycbcr.win.width * 2; - return ALIGN(len, 32); -} - -static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - ccdc_cfg.bayer.frm_fmt = frm_fmt; - else - ccdc_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} - -static enum ccdc_frmfmt ccdc_get_frame_format(void) -{ - if (ccdc_cfg.if_type == VPFE_RAW_BAYER) - return ccdc_cfg.bayer.frm_fmt; - else - return ccdc_cfg.ycbcr.frm_fmt; -} - -static int ccdc_getfid(void) -{ - return (regr(CCDC_SYN_MODE) >> 15) & 1; -} - -/* misc operations */ -static inline void ccdc_setfbaddr(unsigned long addr) -{ - regw(addr & 0xffffffe0, CCDC_SDR_ADDR); -} - -static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - ccdc_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_YCBCR_SYNC_16: - case VPFE_YCBCR_SYNC_8: - case VPFE_BT656_10BIT: - ccdc_cfg.ycbcr.vd_pol = params->vdpol; - ccdc_cfg.ycbcr.hd_pol = params->hdpol; - break; - default: - /* TODO add support for raw bayer here */ - return -EINVAL; - } - return 0; -} - -static void ccdc_save_context(void) -{ - ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR); - ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE); - ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID); - ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES); - ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO); - ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START); - ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES); - ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING); - ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF); - ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST); - ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR); - ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP); - ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB); - ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN); - ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP); - ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC); - ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR); - ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT); - ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW); - ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF); - ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG); - ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG); - ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ); - ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT); - ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0); - ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1); - ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2); - ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3); - ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4); - ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5); - ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6); - ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7); - ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0); - ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1); - ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0); - ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1); - ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT); -} - -static void ccdc_restore_context(void) -{ - regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE); - regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID); - regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES); - regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO); - regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START); - regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES); - regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING); - regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF); - regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST); - regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR); - regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP); - regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB); - regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN); - regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP); - regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC); - regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR); - regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT); - regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW); - regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF); - regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG); - regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG); - regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ); - regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT); - regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0); - regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1); - regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2); - regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3); - regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4); - regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5); - regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6); - regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7); - regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0); - regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1); - regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0); - regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1); - regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); - regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); -} -static const struct ccdc_hw_device ccdc_hw_dev = { - .name = "DM6446 CCDC", - .owner = THIS_MODULE, - .hw_ops = { - .open = ccdc_open, - .close = ccdc_close, - .reset = ccdc_sbl_reset, - .enable = ccdc_enable, - .set_hw_if_params = ccdc_set_hw_if_params, - .configure = ccdc_configure, - .set_buftype = ccdc_set_buftype, - .get_buftype = ccdc_get_buftype, - .enum_pix = ccdc_enum_pix, - .set_pixel_format = ccdc_set_pixel_format, - .get_pixel_format = ccdc_get_pixel_format, - .set_frame_format = ccdc_set_frame_format, - .get_frame_format = ccdc_get_frame_format, - .set_image_window = ccdc_set_image_window, - .get_image_window = ccdc_get_image_window, - .get_line_length = ccdc_get_line_length, - .setfbaddr = ccdc_setfbaddr, - .getfid = ccdc_getfid, - }, -}; - -static int dm644x_ccdc_probe(struct platform_device *pdev) -{ - struct resource *res; - int status = 0; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&ccdc_hw_dev); - if (status < 0) - return status; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - status = -ENODEV; - goto fail_nores; - } - - res = request_mem_region(res->start, resource_size(res), res->name); - if (!res) { - status = -EBUSY; - goto fail_nores; - } - - ccdc_cfg.base_addr = ioremap(res->start, resource_size(res)); - if (!ccdc_cfg.base_addr) { - status = -ENOMEM; - goto fail_nomem; - } - - ccdc_cfg.dev = &pdev->dev; - printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); - return 0; -fail_nomem: - release_mem_region(res->start, resource_size(res)); -fail_nores: - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return status; -} - -static int dm644x_ccdc_remove(struct platform_device *pdev) -{ - struct resource *res; - - iounmap(ccdc_cfg.base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - vpfe_unregister_ccdc_device(&ccdc_hw_dev); - return 0; -} - -static int dm644x_ccdc_suspend(struct device *dev) -{ - /* Save CCDC context */ - ccdc_save_context(); - /* Disable CCDC */ - ccdc_enable(0); - - return 0; -} - -static int dm644x_ccdc_resume(struct device *dev) -{ - /* Restore CCDC context */ - ccdc_restore_context(); - - return 0; -} - -static const struct dev_pm_ops dm644x_ccdc_pm_ops = { - .suspend = dm644x_ccdc_suspend, - .resume = dm644x_ccdc_resume, -}; - -static struct platform_driver dm644x_ccdc_driver = { - .driver = { - .name = "dm644x_ccdc", - .pm = &dm644x_ccdc_pm_ops, - }, - .remove = dm644x_ccdc_remove, - .probe = dm644x_ccdc_probe, -}; - -module_platform_driver(dm644x_ccdc_driver); diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h deleted file mode 100644 index c20dba3d76d6..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h +++ /dev/null @@ -1,171 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - */ -#ifndef _DM644X_CCDC_H -#define _DM644X_CCDC_H -#include -#include - -/* enum for No of pixel per line to be avg. in Black Clamping*/ -enum ccdc_sample_length { - CCDC_SAMPLE_1PIXELS, - CCDC_SAMPLE_2PIXELS, - CCDC_SAMPLE_4PIXELS, - CCDC_SAMPLE_8PIXELS, - CCDC_SAMPLE_16PIXELS -}; - -/* enum for No of lines in Black Clamping */ -enum ccdc_sample_line { - CCDC_SAMPLE_1LINES, - CCDC_SAMPLE_2LINES, - CCDC_SAMPLE_4LINES, - CCDC_SAMPLE_8LINES, - CCDC_SAMPLE_16LINES -}; - -/* enum for Alaw gamma width */ -enum ccdc_gamma_width { - CCDC_GAMMA_BITS_15_6, /* use bits 15-6 for gamma */ - CCDC_GAMMA_BITS_14_5, - CCDC_GAMMA_BITS_13_4, - CCDC_GAMMA_BITS_12_3, - CCDC_GAMMA_BITS_11_2, - CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 /* use bits 9-0 for gamma */ -}; - -/* returns the highest bit used for the gamma */ -static inline u8 ccdc_gamma_width_max_bit(enum ccdc_gamma_width width) -{ - return 15 - width; -} - -enum ccdc_data_size { - CCDC_DATA_16BITS, - CCDC_DATA_15BITS, - CCDC_DATA_14BITS, - CCDC_DATA_13BITS, - CCDC_DATA_12BITS, - CCDC_DATA_11BITS, - CCDC_DATA_10BITS, - CCDC_DATA_8BITS -}; - -/* returns the highest bit used for this data size */ -static inline u8 ccdc_data_size_max_bit(enum ccdc_data_size sz) -{ - return sz == CCDC_DATA_8BITS ? 7 : 15 - sz; -} - -/* structure for ALaw */ -struct ccdc_a_law { - /* Enable/disable A-Law */ - unsigned char enable; - /* Gamma Width Input */ - enum ccdc_gamma_width gamma_wd; -}; - -/* structure for Black Clamping */ -struct ccdc_black_clamp { - unsigned char enable; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_length sample_pixel; - /* only if bClampEnable is TRUE */ - enum ccdc_sample_line sample_ln; - /* only if bClampEnable is TRUE */ - unsigned short start_pixel; - /* only if bClampEnable is TRUE */ - unsigned short sgain; - /* only if bClampEnable is FALSE */ - unsigned short dc_sub; -}; - -/* structure for Black Level Compensation */ -struct ccdc_black_compensation { - /* Constant value to subtract from Red component */ - char r; - /* Constant value to subtract from Gr component */ - char gr; - /* Constant value to subtract from Blue component */ - char b; - /* Constant value to subtract from Gb component */ - char gb; -}; - -/* Structure for CCDC configuration parameters for raw capture mode passed - * by application - */ -struct ccdc_config_params_raw { - /* data size value from 8 to 16 bits */ - enum ccdc_data_size data_sz; - /* Structure for Optional A-Law */ - struct ccdc_a_law alaw; - /* Structure for Optical Black Clamp */ - struct ccdc_black_clamp blk_clamp; - /* Structure for Black Compensation */ - struct ccdc_black_compensation blk_comp; -}; - - -#ifdef __KERNEL__ -#include -/* Define to enable/disable video port */ -#define FP_NUM_BYTES 4 -/* Define for extra pixel/line and extra lines/frame */ -#define NUM_EXTRAPIXELS 8 -#define NUM_EXTRALINES 8 - -/* settings for commonly used video formats */ -#define CCDC_WIN_PAL {0, 0, 720, 576} -/* ntsc square pixel */ -#define CCDC_WIN_VGA {0, 0, (640 + NUM_EXTRAPIXELS), (480 + NUM_EXTRALINES)} - -/* Structure for CCDC configuration parameters for raw capture mode */ -struct ccdc_params_raw { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; - /* - * enable to store the image in inverse - * order in memory(bottom to top) - */ - unsigned char image_invert_enable; - /* configurable parameters */ - struct ccdc_config_params_raw config_params; -}; - -struct ccdc_params_ycbcr { - /* pixel format */ - enum ccdc_pixfmt pix_fmt; - /* progressive or interlaced frame */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field id polarity */ - enum vpfe_pin_pol fid_pol; - /* vertical sync polarity */ - enum vpfe_pin_pol vd_pol; - /* horizontal sync polarity */ - enum vpfe_pin_pol hd_pol; - /* enable BT.656 embedded sync mode */ - int bt656_enable; - /* cb:y:cr:y or y:cb:y:cr in memory */ - enum ccdc_pixorder pix_order; - /* interleaved or separated fields */ - enum ccdc_buftype buf_type; -}; -#endif -#endif /* _DM644X_CCDC_H */ diff --git a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h deleted file mode 100644 index c4894f6a254e..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h +++ /dev/null @@ -1,140 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2006-2009 Texas Instruments Inc - */ -#ifndef _DM644X_CCDC_REGS_H -#define _DM644X_CCDC_REGS_H - -/**************************************************************************\ -* Register OFFSET Definitions -\**************************************************************************/ -#define CCDC_PID 0x0 -#define CCDC_PCR 0x4 -#define CCDC_SYN_MODE 0x8 -#define CCDC_HD_VD_WID 0xc -#define CCDC_PIX_LINES 0x10 -#define CCDC_HORZ_INFO 0x14 -#define CCDC_VERT_START 0x18 -#define CCDC_VERT_LINES 0x1c -#define CCDC_CULLING 0x20 -#define CCDC_HSIZE_OFF 0x24 -#define CCDC_SDOFST 0x28 -#define CCDC_SDR_ADDR 0x2c -#define CCDC_CLAMP 0x30 -#define CCDC_DCSUB 0x34 -#define CCDC_COLPTN 0x38 -#define CCDC_BLKCMP 0x3c -#define CCDC_FPC 0x40 -#define CCDC_FPC_ADDR 0x44 -#define CCDC_VDINT 0x48 -#define CCDC_ALAW 0x4c -#define CCDC_REC656IF 0x50 -#define CCDC_CCDCFG 0x54 -#define CCDC_FMTCFG 0x58 -#define CCDC_FMT_HORZ 0x5c -#define CCDC_FMT_VERT 0x60 -#define CCDC_FMT_ADDR0 0x64 -#define CCDC_FMT_ADDR1 0x68 -#define CCDC_FMT_ADDR2 0x6c -#define CCDC_FMT_ADDR3 0x70 -#define CCDC_FMT_ADDR4 0x74 -#define CCDC_FMT_ADDR5 0x78 -#define CCDC_FMT_ADDR6 0x7c -#define CCDC_FMT_ADDR7 0x80 -#define CCDC_PRGEVEN_0 0x84 -#define CCDC_PRGEVEN_1 0x88 -#define CCDC_PRGODD_0 0x8c -#define CCDC_PRGODD_1 0x90 -#define CCDC_VP_OUT 0x94 -#define CCDC_REG_END 0x98 - -/*************************************************************** -* Define for various register bit mask and shifts for CCDC -****************************************************************/ -#define CCDC_FID_POL_MASK 1 -#define CCDC_FID_POL_SHIFT 4 -#define CCDC_HD_POL_MASK 1 -#define CCDC_HD_POL_SHIFT 3 -#define CCDC_VD_POL_MASK 1 -#define CCDC_VD_POL_SHIFT 2 -#define CCDC_HSIZE_OFF_MASK 0xffffffe0 -#define CCDC_32BYTE_ALIGN_VAL 31 -#define CCDC_FRM_FMT_MASK 0x1 -#define CCDC_FRM_FMT_SHIFT 7 -#define CCDC_DATA_SZ_MASK 7 -#define CCDC_DATA_SZ_SHIFT 8 -#define CCDC_PIX_FMT_MASK 3 -#define CCDC_PIX_FMT_SHIFT 12 -#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF -#define CCDC_WEN_ENABLE BIT(17) -#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF -#define CCDC_VDHDEN_ENABLE BIT(16) -#define CCDC_LPF_ENABLE BIT(14) -#define CCDC_ALAW_ENABLE BIT(3) -#define CCDC_ALAW_GAMMA_WD_MASK 7 -#define CCDC_BLK_CLAMP_ENABLE BIT(31) -#define CCDC_BLK_SGAIN_MASK 0x1F -#define CCDC_BLK_ST_PXL_MASK 0x7FFF -#define CCDC_BLK_ST_PXL_SHIFT 10 -#define CCDC_BLK_SAMPLE_LN_MASK 7 -#define CCDC_BLK_SAMPLE_LN_SHIFT 28 -#define CCDC_BLK_SAMPLE_LINE_MASK 7 -#define CCDC_BLK_SAMPLE_LINE_SHIFT 25 -#define CCDC_BLK_DC_SUB_MASK 0x03FFF -#define CCDC_BLK_COMP_MASK 0xFF -#define CCDC_BLK_COMP_GB_COMP_SHIFT 8 -#define CCDC_BLK_COMP_GR_COMP_SHIFT 16 -#define CCDC_BLK_COMP_R_COMP_SHIFT 24 -#define CCDC_LATCH_ON_VSYNC_DISABLE BIT(15) -#define CCDC_FPC_ENABLE BIT(15) -#define CCDC_FPC_DISABLE 0 -#define CCDC_FPC_FPC_NUM_MASK 0x7FFF -#define CCDC_DATA_PACK_ENABLE BIT(11) -#define CCDC_FMTCFG_VPIN_MASK 7 -#define CCDC_FMTCFG_VPIN_SHIFT 12 -#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF -#define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 -#define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF -#define CCDC_FMT_VERT_FMTSLV_SHIFT 16 -#define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF -#define CCDC_VP_OUT_VERT_NUM_SHIFT 17 -#define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF -#define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 -#define CCDC_VP_OUT_HORZ_ST_MASK 0xF -#define CCDC_HORZ_INFO_SPH_SHIFT 16 -#define CCDC_VERT_START_SLV0_SHIFT 16 -#define CCDC_VDINT_VDINT0_SHIFT 16 -#define CCDC_VDINT_VDINT1_MASK 0xFFFF -#define CCDC_PPC_RAW 1 -#define CCDC_DCSUB_DEFAULT_VAL 0 -#define CCDC_CLAMP_DEFAULT_VAL 0 -#define CCDC_ENABLE_VIDEO_PORT 0x8000 -#define CCDC_DISABLE_VIDEO_PORT 0 -#define CCDC_COLPTN_VAL 0xBB11BB11 -#define CCDC_TWO_BYTES_PER_PIXEL 2 -#define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D -#define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249 -#define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000 -#define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0 -#define CCDC_INTERLACED_HEIGHT_SHIFT 1 -#define CCDC_SYN_MODE_INPMOD_SHIFT 12 -#define CCDC_SYN_MODE_INPMOD_MASK 3 -#define CCDC_SYN_MODE_8BITS (7 << 8) -#define CCDC_SYN_MODE_10BITS (6 << 8) -#define CCDC_SYN_MODE_11BITS (5 << 8) -#define CCDC_SYN_MODE_12BITS (4 << 8) -#define CCDC_SYN_MODE_13BITS (3 << 8) -#define CCDC_SYN_MODE_14BITS (2 << 8) -#define CCDC_SYN_MODE_15BITS (1 << 8) -#define CCDC_SYN_MODE_16BITS (0 << 8) -#define CCDC_SYN_FLDMODE_MASK 1 -#define CCDC_SYN_FLDMODE_SHIFT 7 -#define CCDC_REC656IF_BT656_EN 3 -#define CCDC_SYN_MODE_VD_POL_NEGATIVE BIT(2) -#define CCDC_CCDCFG_Y8POS_SHIFT 11 -#define CCDC_CCDCFG_BW656_10BIT BIT(5) -#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 -#define CCDC_NO_CULLING 0xffff00ff -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/isif.c b/drivers/staging/media/deprecated/vpfe_capture/isif.c deleted file mode 100644 index 4059891c2824..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/isif.c +++ /dev/null @@ -1,1127 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * Image Sensor Interface (ISIF) driver - * - * This driver is for configuring the ISIF IP available on DM365 or any other - * TI SoCs. This is used for capturing yuv or bayer video or image data - * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 - * and DM6446, but with enhanced or additional ip blocks. The driver - * configures the ISIF upon commands from the vpfe bridge driver through - * ccdc_hw_device interface. - * - * TODO: 1) Raw bayer parameter settings and bayer capture - * 2) Add support for control ioctl - */ -#include -#include -#include -#include -#include -#include -#include - -#include "isif.h" -#include - -#include "isif_regs.h" -#include "ccdc_hw_device.h" - -/* Defaults for module configuration parameters */ -static const struct isif_config_params_raw isif_config_defaults = { - .linearize = { - .en = 0, - .corr_shft = ISIF_NO_SHIFT, - .scale_fact = {1, 0}, - }, - .df_csc = { - .df_or_csc = 0, - .csc = { - .en = 0, - }, - }, - .dfc = { - .en = 0, - }, - .bclamp = { - .en = 0, - }, - .gain_offset = { - .gain = { - .r_ye = {1, 0}, - .gr_cy = {1, 0}, - .gb_g = {1, 0}, - .b_mg = {1, 0}, - }, - }, - .culling = { - .hcpat_odd = 0xff, - .hcpat_even = 0xff, - .vcpat = 0xff, - }, - .compress = { - .alg = ISIF_ALAW, - }, -}; - -/* ISIF operation configuration */ -static struct isif_oper_config { - struct device *dev; - enum vpfe_hw_if_type if_type; - struct isif_ycbcr_config ycbcr; - struct isif_params_raw bayer; - enum isif_data_pack data_pack; - /* ISIF base address */ - void __iomem *base_addr; - /* ISIF Linear Table 0 */ - void __iomem *linear_tbl0_addr; - /* ISIF Linear Table 1 */ - void __iomem *linear_tbl1_addr; -} isif_cfg = { - .ycbcr = { - .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, - .frm_fmt = CCDC_FRMFMT_INTERLACED, - .win = ISIF_WIN_NTSC, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .pix_order = CCDC_PIXORDER_CBYCRY, - .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, - }, - .bayer = { - .pix_fmt = CCDC_PIXFMT_RAW, - .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, - .win = ISIF_WIN_VGA, - .fid_pol = VPFE_PINPOL_POSITIVE, - .vd_pol = VPFE_PINPOL_POSITIVE, - .hd_pol = VPFE_PINPOL_POSITIVE, - .gain = { - .r_ye = {1, 0}, - .gr_cy = {1, 0}, - .gb_g = {1, 0}, - .b_mg = {1, 0}, - }, - .cfa_pat = ISIF_CFA_PAT_MOSAIC, - .data_msb = ISIF_BIT_MSB_11, - .config_params = { - .data_shift = ISIF_NO_SHIFT, - .col_pat_field0 = { - .olop = ISIF_GREEN_BLUE, - .olep = ISIF_BLUE, - .elop = ISIF_RED, - .elep = ISIF_GREEN_RED, - }, - .col_pat_field1 = { - .olop = ISIF_GREEN_BLUE, - .olep = ISIF_BLUE, - .elop = ISIF_RED, - .elep = ISIF_GREEN_RED, - }, - .test_pat_gen = 0, - }, - }, - .data_pack = ISIF_DATA_PACK8, -}; - -/* Raw Bayer formats */ -static const u32 isif_raw_bayer_pix_formats[] = { - V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; - -/* Raw YUV formats */ -static const u32 isif_raw_yuv_pix_formats[] = { - V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; - -/* register access routines */ -static inline u32 regr(u32 offset) -{ - return __raw_readl(isif_cfg.base_addr + offset); -} - -static inline void regw(u32 val, u32 offset) -{ - __raw_writel(val, isif_cfg.base_addr + offset); -} - -/* reg_modify() - read, modify and write register */ -static inline u32 reg_modify(u32 mask, u32 val, u32 offset) -{ - u32 new_val = (regr(offset) & ~mask) | (val & mask); - - regw(new_val, offset); - return new_val; -} - -static inline void regw_lin_tbl(u32 val, u32 offset, int i) -{ - if (!i) - __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); - else - __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); -} - -static void isif_disable_all_modules(void) -{ - /* disable BC */ - regw(0, CLAMPCFG); - /* disable vdfc */ - regw(0, DFCCTL); - /* disable CSC */ - regw(0, CSCCTL); - /* disable linearization */ - regw(0, LINCFG0); - /* disable other modules here as they are supported */ -} - -static void isif_enable(int en) -{ - if (!en) { - /* Before disable isif, disable all ISIF modules */ - isif_disable_all_modules(); - /* - * wait for next VD. Assume lowest scan rate is 12 Hz. So - * 100 msec delay is good enough - */ - msleep(100); - } - reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); -} - -static void isif_enable_output_to_sdram(int en) -{ - reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); -} - -static void isif_config_culling(struct isif_cul *cul) -{ - u32 val; - - /* Horizontal pattern */ - val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; - regw(val, CULH); - - /* vertical pattern */ - regw(cul->vcpat, CULV); - - /* LPF */ - reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, - cul->en_lpf << ISIF_LPF_SHIFT, MODESET); -} - -static void isif_config_gain_offset(void) -{ - struct isif_gain_offsets_adj *gain_off_p = - &isif_cfg.bayer.config_params.gain_offset; - u32 val; - - val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | - (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | - (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | - (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | - (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | - (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); - - reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); - - val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.r_ye.decimal; - regw(val, CRGAIN); - - val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.gr_cy.decimal; - regw(val, CGRGAIN); - - val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.gb_g.decimal; - regw(val, CGBGAIN); - - val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | - gain_off_p->gain.b_mg.decimal; - regw(val, CBGAIN); - - regw(gain_off_p->offset, COFSTA); -} - -static void isif_restore_defaults(void) -{ - enum vpss_ccdc_source_sel source = VPSS_CCDCIN; - - dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); - isif_cfg.bayer.config_params = isif_config_defaults; - /* Enable clock to ISIF, IPIPEIF and BL */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 1); - vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); - vpss_enable_clock(VPSS_BL_CLOCK, 1); - /* Set default offset and gain */ - isif_config_gain_offset(); - vpss_select_ccdc_source(source); - dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); -} - -static int isif_open(struct device *device) -{ - isif_restore_defaults(); - return 0; -} - -/* This function will configure the window size to be capture in ISIF reg */ -static void isif_setwin(struct v4l2_rect *image_win, - enum ccdc_frmfmt frm_fmt, int ppc) -{ - int horz_start, horz_nr_pixels; - int vert_start, vert_nr_lines; - int mid_img = 0; - - dev_dbg(isif_cfg.dev, "\nStarting isif_setwin..."); - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; - - /* Writing the horizontal info into the registers */ - regw(horz_start & START_PX_HOR_MASK, SPH); - regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); - vert_start = image_win->top; - - if (frm_fmt == CCDC_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - } else { - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - regw(mid_img, VDINT1); - } - - regw(0, VDINT0); - regw(vert_start & START_VER_ONE_MASK, SLV0); - regw(vert_start & START_VER_TWO_MASK, SLV1); - regw(vert_nr_lines & NUM_LINES_VER, LNV); -} - -static void isif_config_bclamp(struct isif_black_clamp *bc) -{ - u32 val; - - /* - * DC Offset is always added to image data irrespective of bc enable - * status - */ - regw(bc->dc_offset, CLDCOFST); - - if (bc->en) { - val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; - - /* Enable BC and horizontal clamp calculation parameters */ - val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); - - regw(val, CLAMPCFG); - - if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { - /* - * Window count for calculation - * Base window selection - * pixel limit - * Horizontal size of window - * vertical size of the window - * Horizontal start position of the window - * Vertical start position of the window - */ - val = bc->horz.win_count_calc | - ((!!bc->horz.base_win_sel_calc) << - ISIF_HORZ_BC_WIN_SEL_SHIFT) | - ((!!bc->horz.clamp_pix_limit) << - ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | - (bc->horz.win_h_sz_calc << - ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | - (bc->horz.win_v_sz_calc << - ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); - regw(val, CLHWIN0); - - regw(bc->horz.win_start_h_calc, CLHWIN1); - regw(bc->horz.win_start_v_calc, CLHWIN2); - } - - /* vertical clamp calculation parameters */ - - /* Reset clamp value sel for previous line */ - val |= - (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | - (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); - regw(val, CLVWIN0); - - /* Optical Black horizontal start position */ - regw(bc->vert.ob_start_h, CLVWIN1); - /* Optical Black vertical start position */ - regw(bc->vert.ob_start_v, CLVWIN2); - /* Optical Black vertical size for calculation */ - regw(bc->vert.ob_v_sz_calc, CLVWIN3); - /* Vertical start position for BC subtraction */ - regw(bc->vert_start_sub, CLSV); - } -} - -static void isif_config_linearization(struct isif_linearize *linearize) -{ - u32 val, i; - - if (!linearize->en) { - regw(0, LINCFG0); - return; - } - - /* shift value for correction & enable linearization (set lsb) */ - val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; - regw(val, LINCFG0); - - /* Scale factor */ - val = ((!!linearize->scale_fact.integer) << - ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | - linearize->scale_fact.decimal; - regw(val, LINCFG1); - - for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { - if (i % 2) - regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); - else - regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); - } -} - -static int isif_config_dfc(struct isif_dfc *vdfc) -{ - /* initialize retries to loop for max ~ 250 usec */ - u32 val, count, retries = loops_per_jiffy / (4000/HZ); - int i; - - if (!vdfc->en) - return 0; - - /* Correction mode */ - val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); - - /* Correct whole line or partial */ - if (vdfc->corr_whole_line) - val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; - - /* level shift value */ - val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; - - regw(val, DFCCTL); - - /* Defect saturation level */ - regw(vdfc->def_sat_level, VDFSATLV); - - regw(vdfc->table[0].pos_vert, DFCMEM0); - regw(vdfc->table[0].pos_horz, DFCMEM1); - if (vdfc->corr_mode == ISIF_VDFC_NORMAL || - vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - regw(vdfc->table[0].level_at_pos, DFCMEM2); - regw(vdfc->table[0].level_up_pixels, DFCMEM3); - regw(vdfc->table[0].level_low_pixels, DFCMEM4); - } - - /* set DFCMARST and set DFCMWR */ - val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; - regw(val, DFCMEMCTL); - - count = retries; - while (count && (regr(DFCMEMCTL) & 0x1)) - count--; - - if (!count) { - dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); - return -1; - } - - for (i = 1; i < vdfc->num_vdefects; i++) { - regw(vdfc->table[i].pos_vert, DFCMEM0); - regw(vdfc->table[i].pos_horz, DFCMEM1); - if (vdfc->corr_mode == ISIF_VDFC_NORMAL || - vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - regw(vdfc->table[i].level_at_pos, DFCMEM2); - regw(vdfc->table[i].level_up_pixels, DFCMEM3); - regw(vdfc->table[i].level_low_pixels, DFCMEM4); - } - val = regr(DFCMEMCTL); - /* clear DFCMARST and set DFCMWR */ - val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); - val |= 1; - regw(val, DFCMEMCTL); - - count = retries; - while (count && (regr(DFCMEMCTL) & 0x1)) - count--; - - if (!count) { - dev_err(isif_cfg.dev, - "defect table write timeout !!!\n"); - return -1; - } - } - if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { - /* Extra cycle needed */ - regw(0, DFCMEM0); - regw(0x1FFF, DFCMEM1); - regw(1, DFCMEMCTL); - } - - /* enable VDFC */ - reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), - DFCCTL); - return 0; -} - -static void isif_config_csc(struct isif_df_csc *df_csc) -{ - u32 val1 = 0, val2 = 0, i; - - if (!df_csc->csc.en) { - regw(0, CSCCTL); - return; - } - for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = (df_csc->csc.coeff[i].integer << - ISIF_CSC_COEF_INTEG_SHIFT) | - df_csc->csc.coeff[i].decimal; - } else { - - /* CSCM - MSB */ - val2 = (df_csc->csc.coeff[i].integer << - ISIF_CSC_COEF_INTEG_SHIFT) | - df_csc->csc.coeff[i].decimal; - val2 <<= ISIF_CSCM_MSB_SHIFT; - val2 |= val1; - regw(val2, (CSCM0 + ((i - 1) << 1))); - } - } - - /* program the active area */ - regw(df_csc->start_pix, FMTSPH); - /* - * one extra pixel as required for CSC. Actually number of - * pixel - 1 should be configured in this register. So we - * need to subtract 1 before writing to FMTSPH, but we will - * not do this since csc requires one extra pixel - */ - regw(df_csc->num_pixels, FMTLNH); - regw(df_csc->start_line, FMTSLV); - /* - * one extra line as required for CSC. See reason documented for - * num_pixels - */ - regw(df_csc->num_lines, FMTLNV); - - /* Enable CSC */ - regw(1, CSCCTL); -} - -static int isif_config_raw(void) -{ - struct isif_params_raw *params = &isif_cfg.bayer; - struct isif_config_params_raw *module_params = - &isif_cfg.bayer.config_params; - struct vpss_pg_frame_size frame_size; - struct vpss_sync_pol sync; - u32 val; - - dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); - - /* - * Configure CCDCFG register:- - * Set CCD Not to swap input since input is RAW data - * Set FID detection function to Latch at V-Sync - * Set WENLOG - isif valid area - * Set TRGSEL - * Set EXTRG - * Packed to 8 or 16 bits - */ - - val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | - ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | - ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; - - dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); - regw(val, CCDCFG); - - /* - * Configure the vertical sync polarity(MODESET.VDPOL) - * Configure the horizontal sync polarity (MODESET.HDPOL) - * Configure frame id polarity (MODESET.FLDPOL) - * Configure data polarity - * Configure External WEN Selection - * Configure frame format(progressive or interlace) - * Configure pixel format (Input mode) - * Configure the data shift - */ - - val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | - (params->hd_pol << ISIF_HD_POL_SHIFT) | - (params->fid_pol << ISIF_FID_POL_SHIFT) | - (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | - (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | - (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | - (params->pix_fmt << ISIF_INPUT_SHIFT) | - (params->config_params.data_shift << ISIF_DATASFT_SHIFT); - - regw(val, MODESET); - dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); - - /* - * Configure GAMMAWD register - * CFA pattern setting - */ - val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; - - /* Gamma msb */ - if (module_params->compress.alg == ISIF_ALAW) - val |= ISIF_ALAW_ENABLE; - - val |= (params->data_msb << ISIF_ALAW_GAMMA_WD_SHIFT); - regw(val, CGAMMAWD); - - /* Configure DPCM compression settings */ - if (module_params->compress.alg == ISIF_DPCM) { - val = BIT(ISIF_DPCM_EN_SHIFT) | - (module_params->compress.pred << - ISIF_DPCM_PREDICTOR_SHIFT); - } - - regw(val, MISC); - - /* Configure Gain & Offset */ - isif_config_gain_offset(); - - /* Configure Color pattern */ - val = (params->config_params.col_pat_field0.olop) | - (params->config_params.col_pat_field0.olep << 2) | - (params->config_params.col_pat_field0.elop << 4) | - (params->config_params.col_pat_field0.elep << 6) | - (params->config_params.col_pat_field1.olop << 8) | - (params->config_params.col_pat_field1.olep << 10) | - (params->config_params.col_pat_field1.elop << 12) | - (params->config_params.col_pat_field1.elep << 14); - regw(val, CCOLP); - dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); - - /* Configure HSIZE register */ - val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; - - /* calculate line offset in 32 bytes based on pack value */ - if (isif_cfg.data_pack == ISIF_PACK_8BIT) - val |= ((params->win.width + 31) >> 5); - else if (isif_cfg.data_pack == ISIF_PACK_12BIT) - val |= (((params->win.width + - (params->win.width >> 2)) + 31) >> 5); - else - val |= (((params->win.width * 2) + 31) >> 5); - regw(val, HSIZE); - - /* Configure SDOFST register */ - if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { - if (params->image_invert_en) { - /* For interlace inverse mode */ - regw(0x4B6D, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); - } else { - /* For interlace non inverse mode */ - regw(0x0B6D, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); - } - } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { - if (params->image_invert_en) { - /* For progressive inverse mode */ - regw(0x4000, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); - } else { - /* For progressive non inverse mode */ - regw(0x0000, SDOFST); - dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); - } - } - - /* Configure video window */ - isif_setwin(¶ms->win, params->frm_fmt, 1); - - /* Configure Black Clamp */ - isif_config_bclamp(&module_params->bclamp); - - /* Configure Vertical Defection Pixel Correction */ - if (isif_config_dfc(&module_params->dfc) < 0) - return -EFAULT; - - if (!module_params->df_csc.df_or_csc) - /* Configure Color Space Conversion */ - isif_config_csc(&module_params->df_csc); - - isif_config_linearization(&module_params->linearize); - - /* Configure Culling */ - isif_config_culling(&module_params->culling); - - /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ - regw(module_params->horz_offset, DATAHOFST); - regw(module_params->vert_offset, DATAVOFST); - - /* Setup test pattern if enabled */ - if (params->config_params.test_pat_gen) { - /* Use the HD/VD pol settings from user */ - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - frame_size.hlpfr = isif_cfg.bayer.win.width; - frame_size.pplen = isif_cfg.bayer.win.height; - dm365_vpss_set_pg_frame_size(frame_size); - vpss_select_ccdc_source(VPSS_PGLPBK); - } - - dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); - return 0; -} - -static int isif_set_buftype(enum ccdc_buftype buf_type) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - isif_cfg.bayer.buf_type = buf_type; - else - isif_cfg.ycbcr.buf_type = buf_type; - - return 0; - -} -static enum ccdc_buftype isif_get_buftype(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_cfg.bayer.buf_type; - - return isif_cfg.ycbcr.buf_type; -} - -static int isif_enum_pix(u32 *pix, int i) -{ - int ret = -EINVAL; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { - *pix = isif_raw_bayer_pix_formats[i]; - ret = 0; - } - } else { - if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { - *pix = isif_raw_yuv_pix_formats[i]; - ret = 0; - } - } - - return ret; -} - -static int isif_set_pixel_format(unsigned int pixfmt) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (pixfmt == V4L2_PIX_FMT_SBGGR8) { - if ((isif_cfg.bayer.config_params.compress.alg != - ISIF_ALAW) && - (isif_cfg.bayer.config_params.compress.alg != - ISIF_DPCM)) { - dev_dbg(isif_cfg.dev, - "Either configure A-Law or DPCM\n"); - return -EINVAL; - } - isif_cfg.data_pack = ISIF_PACK_8BIT; - } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { - isif_cfg.bayer.config_params.compress.alg = - ISIF_NO_COMPRESSION; - isif_cfg.data_pack = ISIF_PACK_16BIT; - } else - return -EINVAL; - isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - else - return -EINVAL; - isif_cfg.data_pack = ISIF_PACK_8BIT; - } - return 0; -} - -static u32 isif_get_pixel_format(void) -{ - u32 pixfmt; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) - if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || - isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) - pixfmt = V4L2_PIX_FMT_SBGGR8; - else - pixfmt = V4L2_PIX_FMT_SBGGR16; - else { - if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) - pixfmt = V4L2_PIX_FMT_YUYV; - else - pixfmt = V4L2_PIX_FMT_UYVY; - } - return pixfmt; -} - -static int isif_set_image_window(struct v4l2_rect *win) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - isif_cfg.bayer.win.top = win->top; - isif_cfg.bayer.win.left = win->left; - isif_cfg.bayer.win.width = win->width; - isif_cfg.bayer.win.height = win->height; - } else { - isif_cfg.ycbcr.win.top = win->top; - isif_cfg.ycbcr.win.left = win->left; - isif_cfg.ycbcr.win.width = win->width; - isif_cfg.ycbcr.win.height = win->height; - } - return 0; -} - -static void isif_get_image_window(struct v4l2_rect *win) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - *win = isif_cfg.bayer.win; - else - *win = isif_cfg.ycbcr.win; -} - -static unsigned int isif_get_line_length(void) -{ - unsigned int len; - - if (isif_cfg.if_type == VPFE_RAW_BAYER) { - if (isif_cfg.data_pack == ISIF_PACK_8BIT) - len = ((isif_cfg.bayer.win.width)); - else if (isif_cfg.data_pack == ISIF_PACK_12BIT) - len = (((isif_cfg.bayer.win.width * 2) + - (isif_cfg.bayer.win.width >> 2))); - else - len = (((isif_cfg.bayer.win.width * 2))); - } else - len = (((isif_cfg.ycbcr.win.width * 2))); - return ALIGN(len, 32); -} - -static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - isif_cfg.bayer.frm_fmt = frm_fmt; - else - isif_cfg.ycbcr.frm_fmt = frm_fmt; - return 0; -} -static enum ccdc_frmfmt isif_get_frame_format(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_cfg.bayer.frm_fmt; - return isif_cfg.ycbcr.frm_fmt; -} - -static int isif_getfid(void) -{ - return (regr(MODESET) >> 15) & 0x1; -} - -/* misc operations */ -static void isif_setfbaddr(unsigned long addr) -{ - regw((addr >> 21) & 0x07ff, CADU); - regw((addr >> 5) & 0x0ffff, CADL); -} - -static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) -{ - isif_cfg.if_type = params->if_type; - - switch (params->if_type) { - case VPFE_BT656: - case VPFE_BT656_10BIT: - case VPFE_YCBCR_SYNC_8: - isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - break; - case VPFE_BT1120: - case VPFE_YCBCR_SYNC_16: - isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; - isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; - break; - case VPFE_RAW_BAYER: - isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; - break; - default: - dev_dbg(isif_cfg.dev, "Invalid interface type\n"); - return -EINVAL; - } - - return 0; -} - -/* This function will configure ISIF for YCbCr parameters. */ -static int isif_config_ycbcr(void) -{ - struct isif_ycbcr_config *params = &isif_cfg.ycbcr; - u32 modeset = 0, ccdcfg = 0; - - dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); - - /* configure pixel format or input mode */ - modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | - (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | - (params->fid_pol << ISIF_FID_POL_SHIFT) | - (params->hd_pol << ISIF_HD_POL_SHIFT) | - (params->vd_pol << ISIF_VD_POL_SHIFT); - - /* pack the data to 8-bit ISIFCFG */ - switch (isif_cfg.if_type) { - case VPFE_BT656: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); - regw(3, REC656IF); - ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; - break; - case VPFE_BT656_10BIT: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* setup BT.656, embedded sync */ - regw(3, REC656IF); - /* enable 10 bit mode in ccdcfg */ - ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | - ISIF_BW656_ENABLE; - break; - case VPFE_BT1120: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - regw(3, REC656IF); - break; - - case VPFE_YCBCR_SYNC_8: - ccdcfg |= ISIF_DATA_PACK8; - ccdcfg |= ISIF_YCINSWP_YCBCR; - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - case VPFE_YCBCR_SYNC_16: - if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { - dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - default: - /* should never come here */ - dev_dbg(isif_cfg.dev, "Invalid interface type\n"); - return -EINVAL; - } - - regw(modeset, MODESET); - - /* Set up pix order */ - ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; - - regw(ccdcfg, CCDCFG); - - /* configure video window */ - if ((isif_cfg.if_type == VPFE_BT1120) || - (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) - isif_setwin(¶ms->win, params->frm_fmt, 1); - else - isif_setwin(¶ms->win, params->frm_fmt, 2); - - /* - * configure the horizontal line offset - * this is done by rounding up width to a multiple of 16 pixels - * and multiply by two to account for y:cb:cr 4:2:2 data - */ - regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); - - /* configure the memory line offset */ - if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) && - (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) - /* two fields are interleaved in memory */ - regw(0x00000249, SDOFST); - - return 0; -} - -static int isif_configure(void) -{ - if (isif_cfg.if_type == VPFE_RAW_BAYER) - return isif_config_raw(); - return isif_config_ycbcr(); -} - -static int isif_close(struct device *device) -{ - /* copy defaults to module params */ - isif_cfg.bayer.config_params = isif_config_defaults; - return 0; -} - -static const struct ccdc_hw_device isif_hw_dev = { - .name = "ISIF", - .owner = THIS_MODULE, - .hw_ops = { - .open = isif_open, - .close = isif_close, - .enable = isif_enable, - .enable_out_to_sdram = isif_enable_output_to_sdram, - .set_hw_if_params = isif_set_hw_if_params, - .configure = isif_configure, - .set_buftype = isif_set_buftype, - .get_buftype = isif_get_buftype, - .enum_pix = isif_enum_pix, - .set_pixel_format = isif_set_pixel_format, - .get_pixel_format = isif_get_pixel_format, - .set_frame_format = isif_set_frame_format, - .get_frame_format = isif_get_frame_format, - .set_image_window = isif_set_image_window, - .get_image_window = isif_get_image_window, - .get_line_length = isif_get_line_length, - .setfbaddr = isif_setfbaddr, - .getfid = isif_getfid, - }, -}; - -static int isif_probe(struct platform_device *pdev) -{ - void (*setup_pinmux)(void); - struct resource *res; - void __iomem *addr; - int status = 0, i; - - /* Platform data holds setup_pinmux function ptr */ - if (!pdev->dev.platform_data) - return -ENODEV; - - /* - * first try to register with vpfe. If not correct platform, then we - * don't have to iomap - */ - status = vpfe_register_ccdc_device(&isif_hw_dev); - if (status < 0) - return status; - - setup_pinmux = pdev->dev.platform_data; - /* - * setup Mux configuration for ccdc which may be different for - * different SoCs using this CCDC - */ - setup_pinmux(); - - i = 0; - /* Get the ISIF base address, linearization table0 and table1 addr. */ - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) { - status = -ENODEV; - goto fail_nobase_res; - } - res = request_mem_region(res->start, resource_size(res), - res->name); - if (!res) { - status = -EBUSY; - goto fail_nobase_res; - } - addr = ioremap(res->start, resource_size(res)); - if (!addr) { - status = -ENOMEM; - goto fail_base_iomap; - } - switch (i) { - case 0: - /* ISIF base address */ - isif_cfg.base_addr = addr; - break; - case 1: - /* ISIF linear tbl0 address */ - isif_cfg.linear_tbl0_addr = addr; - break; - default: - /* ISIF linear tbl0 address */ - isif_cfg.linear_tbl1_addr = addr; - break; - } - i++; - } - isif_cfg.dev = &pdev->dev; - - printk(KERN_NOTICE "%s is registered with vpfe.\n", - isif_hw_dev.name); - return 0; -fail_base_iomap: - release_mem_region(res->start, resource_size(res)); - i--; -fail_nobase_res: - if (isif_cfg.base_addr) { - iounmap(isif_cfg.base_addr); - isif_cfg.base_addr = NULL; - } - if (isif_cfg.linear_tbl0_addr) { - iounmap(isif_cfg.linear_tbl0_addr); - isif_cfg.linear_tbl0_addr = NULL; - } - - while (i >= 0) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res) - release_mem_region(res->start, resource_size(res)); - i--; - } - vpfe_unregister_ccdc_device(&isif_hw_dev); - return status; -} - -static int isif_remove(struct platform_device *pdev) -{ - struct resource *res; - int i = 0; - - iounmap(isif_cfg.base_addr); - isif_cfg.base_addr = NULL; - iounmap(isif_cfg.linear_tbl0_addr); - isif_cfg.linear_tbl0_addr = NULL; - iounmap(isif_cfg.linear_tbl1_addr); - isif_cfg.linear_tbl1_addr = NULL; - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - release_mem_region(res->start, resource_size(res)); - i++; - } - vpfe_unregister_ccdc_device(&isif_hw_dev); - return 0; -} - -static struct platform_driver isif_driver = { - .driver = { - .name = "isif", - }, - .remove = isif_remove, - .probe = isif_probe, -}; - -module_platform_driver(isif_driver); - -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/deprecated/vpfe_capture/isif.h b/drivers/staging/media/deprecated/vpfe_capture/isif.h deleted file mode 100644 index 8369acd26e7e..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/isif.h +++ /dev/null @@ -1,518 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * isif header file - */ -#ifndef _ISIF_H -#define _ISIF_H - -#include -#include - -/* isif float type S8Q8/U8Q8 */ -struct isif_float_8 { - /* 8 bit integer part */ - __u8 integer; - /* 8 bit decimal part */ - __u8 decimal; -}; - -/* isif float type U16Q16/S16Q16 */ -struct isif_float_16 { - /* 16 bit integer part */ - __u16 integer; - /* 16 bit decimal part */ - __u16 decimal; -}; - -/************************************************************************ - * Vertical Defect Correction parameters - ***********************************************************************/ -/* Defect Correction (DFC) table entry */ -struct isif_vdfc_entry { - /* vertical position of defect */ - __u16 pos_vert; - /* horizontal position of defect */ - __u16 pos_horz; - /* - * Defect level of Vertical line defect position. This is subtracted - * from the data at the defect position - */ - __u8 level_at_pos; - /* - * Defect level of the pixels upper than the vertical line defect. - * This is subtracted from the data - */ - __u8 level_up_pixels; - /* - * Defect level of the pixels lower than the vertical line defect. - * This is subtracted from the data - */ - __u8 level_low_pixels; -}; - -#define ISIF_VDFC_TABLE_SIZE 8 -struct isif_dfc { - /* enable vertical defect correction */ - __u8 en; - /* Defect level subtraction. Just fed through if saturating */ -#define ISIF_VDFC_NORMAL 0 - /* - * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2 - * if data saturating - */ -#define ISIF_VDFC_HORZ_INTERPOL_IF_SAT 1 - /* Horizontal interpolation (((i-2)+(i+2))/2) */ -#define ISIF_VDFC_HORZ_INTERPOL 2 - /* one of the vertical defect correction modes above */ - __u8 corr_mode; - /* 0 - whole line corrected, 1 - not pixels upper than the defect */ - __u8 corr_whole_line; -#define ISIF_VDFC_NO_SHIFT 0 -#define ISIF_VDFC_SHIFT_1 1 -#define ISIF_VDFC_SHIFT_2 2 -#define ISIF_VDFC_SHIFT_3 3 -#define ISIF_VDFC_SHIFT_4 4 - /* - * defect level shift value. level_at_pos, level_upper_pos, - * and level_lower_pos can be shifted up by this value. Choose - * one of the values above - */ - __u8 def_level_shift; - /* defect saturation level */ - __u16 def_sat_level; - /* number of vertical defects. Max is ISIF_VDFC_TABLE_SIZE */ - __u16 num_vdefects; - /* VDFC table ptr */ - struct isif_vdfc_entry table[ISIF_VDFC_TABLE_SIZE]; -}; - -struct isif_horz_bclamp { - - /* Horizontal clamp disabled. Only vertical clamp value is subtracted */ -#define ISIF_HORZ_BC_DISABLE 0 - /* - * Horizontal clamp value is calculated and subtracted from image data - * along with vertical clamp value - */ -#define ISIF_HORZ_BC_CLAMP_CALC_ENABLED 1 - /* - * Horizontal clamp value calculated from previous image is subtracted - * from image data along with vertical clamp value. - */ -#define ISIF_HORZ_BC_CLAMP_NOT_UPDATED 2 - /* horizontal clamp mode. One of the values above */ - __u8 mode; - /* - * pixel value limit enable. - * 0 - limit disabled - * 1 - pixel value limited to 1023 - */ - __u8 clamp_pix_limit; - /* Select Most left window for bc calculation */ -#define ISIF_SEL_MOST_LEFT_WIN 0 - /* Select Most right window for bc calculation */ -#define ISIF_SEL_MOST_RIGHT_WIN 1 - /* Select most left or right window for clamp val calculation */ - __u8 base_win_sel_calc; - /* Window count per color for calculation. range 1-32 */ - __u8 win_count_calc; - /* Window start position - horizontal for calculation. 0 - 8191 */ - __u16 win_start_h_calc; - /* Window start position - vertical for calculation 0 - 8191 */ - __u16 win_start_v_calc; -#define ISIF_HORZ_BC_SZ_H_2PIXELS 0 -#define ISIF_HORZ_BC_SZ_H_4PIXELS 1 -#define ISIF_HORZ_BC_SZ_H_8PIXELS 2 -#define ISIF_HORZ_BC_SZ_H_16PIXELS 3 - /* Width of the sample window in pixels for calculation */ - __u8 win_h_sz_calc; -#define ISIF_HORZ_BC_SZ_V_32PIXELS 0 -#define ISIF_HORZ_BC_SZ_V_64PIXELS 1 -#define ISIF_HORZ_BC_SZ_V_128PIXELS 2 -#define ISIF_HORZ_BC_SZ_V_256PIXELS 3 - /* Height of the sample window in pixels for calculation */ - __u8 win_v_sz_calc; -}; - -/************************************************************************ - * Black Clamp parameters - ***********************************************************************/ -struct isif_vert_bclamp { - /* Reset value used is the clamp value calculated */ -#define ISIF_VERT_BC_USE_HORZ_CLAMP_VAL 0 - /* Reset value used is reset_clamp_val configured */ -#define ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL 1 - /* No update, previous image value is used */ -#define ISIF_VERT_BC_NO_UPDATE 2 - /* - * Reset value selector for vertical clamp calculation. Use one of - * the above values - */ - __u8 reset_val_sel; - /* U8Q8. Line average coefficient used in vertical clamp calculation */ - __u8 line_ave_coef; - /* Height of the optical black region for calculation */ - __u16 ob_v_sz_calc; - /* Optical black region start position - horizontal. 0 - 8191 */ - __u16 ob_start_h; - /* Optical black region start position - vertical 0 - 8191 */ - __u16 ob_start_v; -}; - -struct isif_black_clamp { - /* - * This offset value is added irrespective of the clamp enable status. - * S13 - */ - __u16 dc_offset; - /* - * Enable black/digital clamp value to be subtracted from the image data - */ - __u8 en; - /* - * black clamp mode. same/separate clamp for 4 colors - * 0 - disable - same clamp value for all colors - * 1 - clamp value calculated separately for all colors - */ - __u8 bc_mode_color; - /* Vertical start position for bc subtraction */ - __u16 vert_start_sub; - /* Black clamp for horizontal direction */ - struct isif_horz_bclamp horz; - /* Black clamp for vertical direction */ - struct isif_vert_bclamp vert; -}; - -/************************************************************************* -** Color Space Conversion (CSC) -*************************************************************************/ -#define ISIF_CSC_NUM_COEFF 16 -struct isif_color_space_conv { - /* Enable color space conversion */ - __u8 en; - /* - * csc coefficient table. S8Q5, M00 at index 0, M01 at index 1, and - * so forth - */ - struct isif_float_8 coeff[ISIF_CSC_NUM_COEFF]; -}; - - -/************************************************************************* -** Black Compensation parameters -*************************************************************************/ -struct isif_black_comp { - /* Comp for Red */ - __s8 r_comp; - /* Comp for Gr */ - __s8 gr_comp; - /* Comp for Blue */ - __s8 b_comp; - /* Comp for Gb */ - __s8 gb_comp; -}; - -/************************************************************************* -** Gain parameters -*************************************************************************/ -struct isif_gain { - /* Gain for Red or ye */ - struct isif_float_16 r_ye; - /* Gain for Gr or cy */ - struct isif_float_16 gr_cy; - /* Gain for Gb or g */ - struct isif_float_16 gb_g; - /* Gain for Blue or mg */ - struct isif_float_16 b_mg; -}; - -#define ISIF_LINEAR_TAB_SIZE 192 -/************************************************************************* -** Linearization parameters -*************************************************************************/ -struct isif_linearize { - /* Enable or Disable linearization of data */ - __u8 en; - /* Shift value applied */ - __u8 corr_shft; - /* scale factor applied U11Q10 */ - struct isif_float_16 scale_fact; - /* Size of the linear table */ - __u16 table[ISIF_LINEAR_TAB_SIZE]; -}; - -/* Color patterns */ -#define ISIF_RED 0 -#define ISIF_GREEN_RED 1 -#define ISIF_GREEN_BLUE 2 -#define ISIF_BLUE 3 -struct isif_col_pat { - __u8 olop; - __u8 olep; - __u8 elop; - __u8 elep; -}; - -/************************************************************************* -** Data formatter parameters -*************************************************************************/ -struct isif_fmtplen { - /* - * number of program entries for SET0, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen0; - /* - * number of program entries for SET1, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen1; - /** - * number of program entries for SET2, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen2; - /** - * number of program entries for SET3, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - __u16 plen3; -}; - -struct isif_fmt_cfg { -#define ISIF_SPLIT 0 -#define ISIF_COMBINE 1 - /* Split or combine or line alternate */ - __u8 fmtmode; - /* enable or disable line alternating mode */ - __u8 ln_alter_en; -#define ISIF_1LINE 0 -#define ISIF_2LINES 1 -#define ISIF_3LINES 2 -#define ISIF_4LINES 3 - /* Split/combine line number */ - __u8 lnum; - /* Address increment Range 1 - 16 */ - __u8 addrinc; -}; - -struct isif_fmt_addr_ptr { - /* Initial address */ - __u32 init_addr; - /* output line number */ -#define ISIF_1STLINE 0 -#define ISIF_2NDLINE 1 -#define ISIF_3RDLINE 2 -#define ISIF_4THLINE 3 - __u8 out_line; -}; - -struct isif_fmtpgm_ap { - /* program address pointer */ - __u8 pgm_aptr; - /* program address increment or decrement */ - __u8 pgmupdt; -}; - -struct isif_data_formatter { - /* Enable/Disable data formatter */ - __u8 en; - /* data formatter configuration */ - struct isif_fmt_cfg cfg; - /* Formatter program entries length */ - struct isif_fmtplen plen; - /* first pixel in a line fed to formatter */ - __u16 fmtrlen; - /* HD interval for output line. Only valid when split line */ - __u16 fmthcnt; - /* formatter address pointers */ - struct isif_fmt_addr_ptr fmtaddr_ptr[16]; - /* program enable/disable */ - __u8 pgm_en[32]; - /* program address pointers */ - struct isif_fmtpgm_ap fmtpgm_ap[32]; -}; - -struct isif_df_csc { - /* Color Space Conversion configuration, 0 - csc, 1 - df */ - __u8 df_or_csc; - /* csc configuration valid if df_or_csc is 0 */ - struct isif_color_space_conv csc; - /* data formatter configuration valid if df_or_csc is 1 */ - struct isif_data_formatter df; - /* start pixel in a line at the input */ - __u32 start_pix; - /* number of pixels in input line */ - __u32 num_pixels; - /* start line at the input */ - __u32 start_line; - /* number of lines at the input */ - __u32 num_lines; -}; - -struct isif_gain_offsets_adj { - /* Gain adjustment per color */ - struct isif_gain gain; - /* Offset adjustment */ - __u16 offset; - /* Enable or Disable Gain adjustment for SDRAM data */ - __u8 gain_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - __u8 gain_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - __u8 gain_h3a_en; - /* Enable or Disable Gain adjustment for SDRAM data */ - __u8 offset_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - __u8 offset_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - __u8 offset_h3a_en; -}; - -struct isif_cul { - /* Horizontal Cull pattern for odd lines */ - __u8 hcpat_odd; - /* Horizontal Cull pattern for even lines */ - __u8 hcpat_even; - /* Vertical Cull pattern */ - __u8 vcpat; - /* Enable or disable lpf. Apply when cull is enabled */ - __u8 en_lpf; -}; - -struct isif_compress { -#define ISIF_ALAW 0 -#define ISIF_DPCM 1 -#define ISIF_NO_COMPRESSION 2 - /* Compression Algorithm used */ - __u8 alg; - /* Choose Predictor1 for DPCM compression */ -#define ISIF_DPCM_PRED1 0 - /* Choose Predictor2 for DPCM compression */ -#define ISIF_DPCM_PRED2 1 - /* Predictor for DPCM compression */ - __u8 pred; -}; - -/* all the stuff in this struct will be provided by userland */ -struct isif_config_params_raw { - /* Linearization parameters for image sensor data input */ - struct isif_linearize linearize; - /* Data formatter or CSC */ - struct isif_df_csc df_csc; - /* Defect Pixel Correction (DFC) configuration */ - struct isif_dfc dfc; - /* Black/Digital Clamp configuration */ - struct isif_black_clamp bclamp; - /* Gain, offset adjustments */ - struct isif_gain_offsets_adj gain_offset; - /* Culling */ - struct isif_cul culling; - /* A-Law and DPCM compression options */ - struct isif_compress compress; - /* horizontal offset for Gain/LSC/DFC */ - __u16 horz_offset; - /* vertical offset for Gain/LSC/DFC */ - __u16 vert_offset; - /* color pattern for field 0 */ - struct isif_col_pat col_pat_field0; - /* color pattern for field 1 */ - struct isif_col_pat col_pat_field1; -#define ISIF_NO_SHIFT 0 -#define ISIF_1BIT_SHIFT 1 -#define ISIF_2BIT_SHIFT 2 -#define ISIF_3BIT_SHIFT 3 -#define ISIF_4BIT_SHIFT 4 -#define ISIF_5BIT_SHIFT 5 -#define ISIF_6BIT_SHIFT 6 - /* Data shift applied before storing to SDRAM */ - __u8 data_shift; - /* enable input test pattern generation */ - __u8 test_pat_gen; -}; - -#ifdef __KERNEL__ -struct isif_ycbcr_config { - /* isif pixel format */ - enum ccdc_pixfmt pix_fmt; - /* isif frame format */ - enum ccdc_frmfmt frm_fmt; - /* ISIF crop window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* isif pix order. Only used for ycbcr capture */ - enum ccdc_pixorder pix_order; - /* isif buffer type. Only used for ycbcr capture */ - enum ccdc_buftype buf_type; -}; - -/* MSB of image data connected to sensor port */ -enum isif_data_msb { - ISIF_BIT_MSB_15, - ISIF_BIT_MSB_14, - ISIF_BIT_MSB_13, - ISIF_BIT_MSB_12, - ISIF_BIT_MSB_11, - ISIF_BIT_MSB_10, - ISIF_BIT_MSB_9, - ISIF_BIT_MSB_8, - ISIF_BIT_MSB_7 -}; - -enum isif_cfa_pattern { - ISIF_CFA_PAT_MOSAIC, - ISIF_CFA_PAT_STRIPE -}; - -struct isif_params_raw { - /* isif pixel format */ - enum ccdc_pixfmt pix_fmt; - /* isif frame format */ - enum ccdc_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* buffer type. Applicable for interlaced mode */ - enum ccdc_buftype buf_type; - /* Gain values */ - struct isif_gain gain; - /* cfa pattern */ - enum isif_cfa_pattern cfa_pat; - /* Data MSB position */ - enum isif_data_msb data_msb; - /* Enable horizontal flip */ - unsigned char horz_flip_en; - /* Enable image invert vertically */ - unsigned char image_invert_en; - - /* all the userland defined stuff*/ - struct isif_config_params_raw config_params; -}; - -enum isif_data_pack { - ISIF_PACK_16BIT, - ISIF_PACK_12BIT, - ISIF_PACK_8BIT -}; - -#define ISIF_WIN_NTSC {0, 0, 720, 480} -#define ISIF_WIN_VGA {0, 0, 640, 480} - -#endif -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/isif_regs.h b/drivers/staging/media/deprecated/vpfe_capture/isif_regs.h deleted file mode 100644 index d68d38841ae7..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/isif_regs.h +++ /dev/null @@ -1,256 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - */ -#ifndef _ISIF_REGS_H -#define _ISIF_REGS_H - -/* ISIF registers relative offsets */ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDW 0x08 -#define VDW 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define LNH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define LNV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define CADU 0x3c -#define CADL 0x40 -#define LINCFG0 0x44 -#define LINCFG1 0x48 -#define CCOLP 0x4c -#define CRGAIN 0x50 -#define CGRGAIN 0x54 -#define CGBGAIN 0x58 -#define CBGAIN 0x5c -#define COFSTA 0x60 -#define FLSHCFG0 0x64 -#define FLSHCFG1 0x68 -#define FLSHCFG2 0x6c -#define VDINT0 0x70 -#define VDINT1 0x74 -#define VDINT2 0x78 -#define MISC 0x7c -#define CGAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -/***************************************************** -* Defect Correction registers -*****************************************************/ -#define DFCCTL 0x8c -#define VDFSATLV 0x90 -#define DFCMEMCTL 0x94 -#define DFCMEM0 0x98 -#define DFCMEM1 0x9c -#define DFCMEM2 0xa0 -#define DFCMEM3 0xa4 -#define DFCMEM4 0xa8 -/**************************************************** -* Black Clamp registers -****************************************************/ -#define CLAMPCFG 0xac -#define CLDCOFST 0xb0 -#define CLSV 0xb4 -#define CLHWIN0 0xb8 -#define CLHWIN1 0xbc -#define CLHWIN2 0xc0 -#define CLVRV 0xc4 -#define CLVWIN0 0xc8 -#define CLVWIN1 0xcc -#define CLVWIN2 0xd0 -#define CLVWIN3 0xd4 -/**************************************************** -* Lense Shading Correction -****************************************************/ -#define DATAHOFST 0xd8 -#define DATAVOFST 0xdc -#define LSCHVAL 0xe0 -#define LSCVVAL 0xe4 -#define TWODLSCCFG 0xe8 -#define TWODLSCOFST 0xec -#define TWODLSCINI 0xf0 -#define TWODLSCGRBU 0xf4 -#define TWODLSCGRBL 0xf8 -#define TWODLSCGROF 0xfc -#define TWODLSCORBU 0x100 -#define TWODLSCORBL 0x104 -#define TWODLSCOROF 0x108 -#define TWODLSCIRQEN 0x10c -#define TWODLSCIRQST 0x110 -/**************************************************** -* Data formatter -****************************************************/ -#define FMTCFG 0x114 -#define FMTPLEN 0x118 -#define FMTSPH 0x11c -#define FMTLNH 0x120 -#define FMTSLV 0x124 -#define FMTLNV 0x128 -#define FMTRLEN 0x12c -#define FMTHCNT 0x130 -#define FMTAPTR_BASE 0x134 -/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ -#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) -#define FMTPGMVF0 0x174 -#define FMTPGMVF1 0x178 -#define FMTPGMAPU0 0x17c -#define FMTPGMAPU1 0x180 -#define FMTPGMAPS0 0x184 -#define FMTPGMAPS1 0x188 -#define FMTPGMAPS2 0x18c -#define FMTPGMAPS3 0x190 -#define FMTPGMAPS4 0x194 -#define FMTPGMAPS5 0x198 -#define FMTPGMAPS6 0x19c -#define FMTPGMAPS7 0x1a0 -/************************************************ -* Color Space Converter -************************************************/ -#define CSCCTL 0x1a4 -#define CSCM0 0x1a8 -#define CSCM1 0x1ac -#define CSCM2 0x1b0 -#define CSCM3 0x1b4 -#define CSCM4 0x1b8 -#define CSCM5 0x1bc -#define CSCM6 0x1c0 -#define CSCM7 0x1c4 -#define OBWIN0 0x1c8 -#define OBWIN1 0x1cc -#define OBWIN2 0x1d0 -#define OBWIN3 0x1d4 -#define OBVAL0 0x1d8 -#define OBVAL1 0x1dc -#define OBVAL2 0x1e0 -#define OBVAL3 0x1e4 -#define OBVAL4 0x1e8 -#define OBVAL5 0x1ec -#define OBVAL6 0x1f0 -#define OBVAL7 0x1f4 -#define CLKCTL 0x1f8 - -/* Masks & Shifts below */ -#define START_PX_HOR_MASK 0x7FFF -#define NUM_PX_HOR_MASK 0x7FFF -#define START_VER_ONE_MASK 0x7FFF -#define START_VER_TWO_MASK 0x7FFF -#define NUM_LINES_VER 0x7FFF - -/* gain - offset masks */ -#define GAIN_INTEGER_SHIFT 9 -#define OFFSET_MASK 0xFFF -#define GAIN_SDRAM_EN_SHIFT 12 -#define GAIN_IPIPE_EN_SHIFT 13 -#define GAIN_H3A_EN_SHIFT 14 -#define OFST_SDRAM_EN_SHIFT 8 -#define OFST_IPIPE_EN_SHIFT 9 -#define OFST_H3A_EN_SHIFT 10 -#define GAIN_OFFSET_EN_MASK 0x7700 - -/* Culling */ -#define CULL_PAT_EVEN_LINE_SHIFT 8 - -/* CCDCFG register */ -#define ISIF_YCINSWP_RAW (0x00 << 4) -#define ISIF_YCINSWP_YCBCR (0x01 << 4) -#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) -#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) -#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) -#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) -#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) -#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) -#define ISIF_DATA_PACK_MASK 3 -#define ISIF_DATA_PACK16 0 -#define ISIF_DATA_PACK12 1 -#define ISIF_DATA_PACK8 2 -#define ISIF_PIX_ORDER_SHIFT 11 -#define ISIF_BW656_ENABLE (0x01 << 5) - -/* MODESET registers */ -#define ISIF_VDHDOUT_INPUT (0x00 << 0) -#define ISIF_INPUT_SHIFT 12 -#define ISIF_RAW_INPUT_MODE 0 -#define ISIF_FID_POL_SHIFT 4 -#define ISIF_HD_POL_SHIFT 3 -#define ISIF_VD_POL_SHIFT 2 -#define ISIF_DATAPOL_NORMAL 0 -#define ISIF_DATAPOL_SHIFT 6 -#define ISIF_EXWEN_DISABLE 0 -#define ISIF_EXWEN_SHIFT 5 -#define ISIF_FRM_FMT_SHIFT 7 -#define ISIF_DATASFT_SHIFT 8 -#define ISIF_LPF_SHIFT 14 -#define ISIF_LPF_MASK 1 - -/* GAMMAWD registers */ -#define ISIF_ALAW_GAMMA_WD_MASK 0xF -#define ISIF_ALAW_GAMMA_WD_SHIFT 1 -#define ISIF_ALAW_ENABLE 1 -#define ISIF_GAMMAWD_CFA_SHIFT 5 - -/* HSIZE registers */ -#define ISIF_HSIZE_FLIP_MASK 1 -#define ISIF_HSIZE_FLIP_SHIFT 12 - -/* MISC registers */ -#define ISIF_DPCM_EN_SHIFT 12 -#define ISIF_DPCM_PREDICTOR_SHIFT 13 - -/* Black clamp related */ -#define ISIF_BC_MODE_COLOR_SHIFT 4 -#define ISIF_HORZ_BC_MODE_SHIFT 1 -#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 -#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 -#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 -#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 -#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 -#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 - -/* VDFC registers */ -#define ISIF_VDFC_EN_SHIFT 4 -#define ISIF_VDFC_CORR_MOD_SHIFT 5 -#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 -#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 -#define ISIF_VDFC_POS_MASK 0x1FFF -#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 - -/* CSC registers */ -#define ISIF_CSC_COEF_INTEG_MASK 7 -#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f -#define ISIF_CSC_COEF_INTEG_SHIFT 5 -#define ISIF_CSCM_MSB_SHIFT 8 -#define ISIF_DF_CSC_SPH_MASK 0x1FFF -#define ISIF_DF_CSC_LNH_MASK 0x1FFF -#define ISIF_DF_CSC_SLV_MASK 0x1FFF -#define ISIF_DF_CSC_LNV_MASK 0x1FFF -#define ISIF_DF_NUMLINES 0x7FFF -#define ISIF_DF_NUMPIX 0x1FFF - -/* Offsets for LSC/DFC/Gain */ -#define ISIF_DATA_H_OFFSET_MASK 0x1FFF -#define ISIF_DATA_V_OFFSET_MASK 0x1FFF - -/* Linearization */ -#define ISIF_LIN_CORRSFT_SHIFT 4 -#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 - - -/* Pattern registers */ -#define ISIF_PG_EN (1 << 3) -#define ISIF_SEL_PG_SRC (3 << 4) -#define ISIF_PG_VD_POL_SHIFT 0 -#define ISIF_PG_HD_POL_SHIFT 1 - -/*random other junk*/ -#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) -#define ISIF_SYNCEN_WEN_MASK (1 << 1) -#define ISIF_SYNCEN_WEN_SHIFT 1 - -#endif diff --git a/drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c b/drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c deleted file mode 100644 index 0a2226b321d7..000000000000 --- a/drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c +++ /dev/null @@ -1,1902 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - * - * Driver name : VPFE Capture driver - * VPFE Capture driver allows applications to capture and stream video - * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as - * TVP5146 or Raw Bayer RGB image data from an image sensor - * such as Microns' MT9T001, MT9T031 etc. - * - * These SoCs have, in common, a Video Processing Subsystem (VPSS) that - * consists of a Video Processing Front End (VPFE) for capturing - * video/raw image data and Video Processing Back End (VPBE) for displaying - * YUV data through an in-built analog encoder or Digital LCD port. This - * driver is for capture through VPFE. A typical EVM using these SoCs have - * following high level configuration. - * - * decoder(TVP5146/ YUV/ - * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) - * data input | | - * V | - * SDRAM | - * V - * Image Processor - * | - * V - * SDRAM - * The data flow happens from a decoder connected to the VPFE over a - * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface - * and to the input of VPFE through an optional MUX (if more inputs are - * to be interfaced on the EVM). The input data is first passed through - * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC - * does very little or no processing on YUV data and does pre-process Raw - * Bayer RGB data through modules such as Defect Pixel Correction (DFC) - * Color Space Conversion (CSC), data gain/offset etc. After this, data - * can be written to SDRAM or can be connected to the image processing - * block such as IPIPE (on DM355 only). - * - * Features supported - * - MMAP IO - * - Capture using TVP5146 over BT.656 - * - support for interfacing decoders using sub device model - * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV - * data capture to SDRAM. - * TODO list - * - Support multiple REQBUF after open - * - Support for de-allocating buffers through REQBUF - * - Support for Raw Bayer RGB capture - * - Support for chaining Image Processor - * - Support for static allocation of buffers - * - Support for USERPTR IO - * - Support for STREAMON before QBUF - * - Support for control ioctls - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "ccdc_hw_device.h" - -static int debug; -static u32 numbuffers = 3; -static u32 bufsize = (720 * 576 * 2); - -module_param(numbuffers, uint, S_IRUGO); -module_param(bufsize, uint, S_IRUGO); -module_param(debug, int, 0644); - -MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); -MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); - -/* standard information */ -struct vpfe_standard { - v4l2_std_id std_id; - unsigned int width; - unsigned int height; - struct v4l2_fract pixelaspect; - /* 0 - progressive, 1 - interlaced */ - int frame_format; -}; - -/* ccdc configuration */ -struct ccdc_config { - /* This make sure vpfe is probed and ready to go */ - int vpfe_probed; - /* name of ccdc device */ - char name[32]; -}; - -/* data structures */ -static struct vpfe_config_params config_params = { - .min_numbuffers = 3, - .numbuffers = 3, - .min_bufsize = 720 * 480 * 2, - .device_bufsize = 720 * 576 * 2, -}; - -/* ccdc device registered */ -static const struct ccdc_hw_device *ccdc_dev; -/* lock for accessing ccdc information */ -static DEFINE_MUTEX(ccdc_lock); -/* ccdc configuration */ -static struct ccdc_config *ccdc_cfg; - -static const struct vpfe_standard vpfe_standards[] = { - {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, - {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, -}; - -/* Used when raw Bayer image from ccdc is directly captured to SDRAM */ -static const struct vpfe_pixel_format vpfe_pix_fmts[] = { - { - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .bpp = 1, - }, - { - .pixelformat = V4L2_PIX_FMT_SBGGR16, - .bpp = 2, - }, - { - .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, - .bpp = 1, - }, - { - .pixelformat = V4L2_PIX_FMT_UYVY, - .bpp = 2, - }, - { - .pixelformat = V4L2_PIX_FMT_YUYV, - .bpp = 2, - }, - { - .pixelformat = V4L2_PIX_FMT_NV12, - .bpp = 1, - }, -}; - -/* - * vpfe_lookup_pix_format() - * lookup an entry in the vpfe pix format table based on pix_format - */ -static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { - if (pix_format == vpfe_pix_fmts[i].pixelformat) - return &vpfe_pix_fmts[i]; - } - return NULL; -} - -/* - * vpfe_register_ccdc_device. CCDC module calls this to - * register with vpfe capture - */ -int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev) -{ - int ret = 0; - printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); - - if (!dev->hw_ops.open || - !dev->hw_ops.enable || - !dev->hw_ops.set_hw_if_params || - !dev->hw_ops.configure || - !dev->hw_ops.set_buftype || - !dev->hw_ops.get_buftype || - !dev->hw_ops.enum_pix || - !dev->hw_ops.set_frame_format || - !dev->hw_ops.get_frame_format || - !dev->hw_ops.get_pixel_format || - !dev->hw_ops.set_pixel_format || - !dev->hw_ops.set_image_window || - !dev->hw_ops.get_image_window || - !dev->hw_ops.get_line_length || - !dev->hw_ops.getfid) - return -EINVAL; - - mutex_lock(&ccdc_lock); - if (!ccdc_cfg) { - /* - * TODO. Will this ever happen? if so, we need to fix it. - * Probably we need to add the request to a linked list and - * walk through it during vpfe probe - */ - printk(KERN_ERR "vpfe capture not initialized\n"); - ret = -EFAULT; - goto unlock; - } - - if (strcmp(dev->name, ccdc_cfg->name)) { - /* ignore this ccdc */ - ret = -EINVAL; - goto unlock; - } - - if (ccdc_dev) { - printk(KERN_ERR "ccdc already registered\n"); - ret = -EINVAL; - goto unlock; - } - - ccdc_dev = dev; -unlock: - mutex_unlock(&ccdc_lock); - return ret; -} -EXPORT_SYMBOL(vpfe_register_ccdc_device); - -/* - * vpfe_unregister_ccdc_device. CCDC module calls this to - * unregister with vpfe capture - */ -void vpfe_unregister_ccdc_device(const struct ccdc_hw_device *dev) -{ - if (!dev) { - printk(KERN_ERR "invalid ccdc device ptr\n"); - return; - } - - printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n", - dev->name); - - if (strcmp(dev->name, ccdc_cfg->name)) { - /* ignore this ccdc */ - return; - } - - mutex_lock(&ccdc_lock); - ccdc_dev = NULL; - mutex_unlock(&ccdc_lock); -} -EXPORT_SYMBOL(vpfe_unregister_ccdc_device); - -/* - * vpfe_config_ccdc_image_format() - * For a pix format, configure ccdc to setup the capture - */ -static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; - int ret = 0; - - if (ccdc_dev->hw_ops.set_pixel_format( - vpfe_dev->fmt.fmt.pix.pixelformat) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "couldn't set pix format in ccdc\n"); - return -EINVAL; - } - /* configure the image window */ - ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop); - - switch (vpfe_dev->fmt.fmt.pix.field) { - case V4L2_FIELD_INTERLACED: - /* do nothing, since it is default */ - ret = ccdc_dev->hw_ops.set_buftype( - CCDC_BUFTYPE_FLD_INTERLEAVED); - break; - case V4L2_FIELD_NONE: - frm_fmt = CCDC_FRMFMT_PROGRESSIVE; - /* buffer type only applicable for interlaced scan */ - break; - case V4L2_FIELD_SEQ_TB: - ret = ccdc_dev->hw_ops.set_buftype( - CCDC_BUFTYPE_FLD_SEPARATED); - break; - default: - return -EINVAL; - } - - /* set the frame format */ - if (!ret) - ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt); - return ret; -} -/* - * vpfe_config_image_format() - * For a given standard, this functions sets up the default - * pix format & crop values in the vpfe device and ccdc. It first - * starts with defaults based values from the standard table. - * It then checks if sub device supports get_fmt and then override the - * values based on that.Sets crop values to match with scan resolution - * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the - * values in ccdc - */ -static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, - v4l2_std_id std_id) -{ - struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; - struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix; - int i, ret; - - for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { - if (vpfe_standards[i].std_id & std_id) { - vpfe_dev->std_info.active_pixels = - vpfe_standards[i].width; - vpfe_dev->std_info.active_lines = - vpfe_standards[i].height; - vpfe_dev->std_info.frame_format = - vpfe_standards[i].frame_format; - vpfe_dev->std_index = i; - break; - } - } - - if (i == ARRAY_SIZE(vpfe_standards)) { - v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n"); - return -EINVAL; - } - - vpfe_dev->crop.top = 0; - vpfe_dev->crop.left = 0; - vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels; - vpfe_dev->crop.height = vpfe_dev->std_info.active_lines; - pix->width = vpfe_dev->crop.width; - pix->height = vpfe_dev->crop.height; - - /* first field and frame format based on standard frame format */ - if (vpfe_dev->std_info.frame_format) { - pix->field = V4L2_FIELD_INTERLACED; - /* assume V4L2_PIX_FMT_UYVY as default */ - pix->pixelformat = V4L2_PIX_FMT_UYVY; - v4l2_fill_mbus_format(mbus_fmt, pix, - MEDIA_BUS_FMT_YUYV10_2X10); - } else { - pix->field = V4L2_FIELD_NONE; - /* assume V4L2_PIX_FMT_SBGGR8 */ - pix->pixelformat = V4L2_PIX_FMT_SBGGR8; - v4l2_fill_mbus_format(mbus_fmt, pix, - MEDIA_BUS_FMT_SBGGR8_1X8); - } - - /* if sub device supports get_fmt, override the defaults */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, pad, get_fmt, NULL, &fmt); - - if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&vpfe_dev->v4l2_dev, - "error in getting get_fmt from sub device\n"); - return ret; - } - v4l2_fill_pix_format(pix, mbus_fmt); - pix->bytesperline = pix->width * 2; - pix->sizeimage = pix->bytesperline * pix->height; - - /* Sets the values in CCDC */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); - if (ret) - return ret; - - /* Update the values of sizeimage and bytesperline */ - pix->bytesperline = ccdc_dev->hw_ops.get_line_length(); - pix->sizeimage = pix->bytesperline * pix->height; - - return 0; -} - -static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) -{ - int ret; - - /* set first input of current subdevice as the current input */ - vpfe_dev->current_input = 0; - - /* set default standard */ - vpfe_dev->std_index = 0; - - /* Configure the default format information */ - ret = vpfe_config_image_format(vpfe_dev, - vpfe_standards[vpfe_dev->std_index].std_id); - if (ret) - return ret; - - /* now open the ccdc device to initialize it */ - mutex_lock(&ccdc_lock); - if (!ccdc_dev) { - v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); - ret = -ENODEV; - goto unlock; - } - - if (!try_module_get(ccdc_dev->owner)) { - v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n"); - ret = -ENODEV; - goto unlock; - } - ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev); - if (!ret) - vpfe_dev->initialized = 1; - - /* Clear all VPFE/CCDC interrupts */ - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(-1); - -unlock: - mutex_unlock(&ccdc_lock); - return ret; -} - -/* - * vpfe_open : It creates object of file handle structure and - * stores it in private_data member of filepointer - */ -static int vpfe_open(struct file *file) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct vpfe_fh *fh; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n"); - - if (!vpfe_dev->cfg->num_subdevs) { - v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n"); - return -ENODEV; - } - - /* Allocate memory for the file handle object */ - fh = kmalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) - return -ENOMEM; - - /* store pointer to fh in private_data member of file */ - file->private_data = fh; - fh->vpfe_dev = vpfe_dev; - v4l2_fh_init(&fh->fh, vdev); - mutex_lock(&vpfe_dev->lock); - /* If decoder is not initialized. initialize it */ - if (!vpfe_dev->initialized) { - if (vpfe_initialize_device(vpfe_dev)) { - mutex_unlock(&vpfe_dev->lock); - v4l2_fh_exit(&fh->fh); - kfree(fh); - return -ENODEV; - } - } - /* Increment device usrs counter */ - vpfe_dev->usrs++; - /* Set io_allowed member to false */ - fh->io_allowed = 0; - v4l2_fh_add(&fh->fh); - mutex_unlock(&vpfe_dev->lock); - return 0; -} - -static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) -{ - unsigned long addr; - - vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vpfe_dev->next_frm->queue); - vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; - addr = videobuf_to_dma_contig(vpfe_dev->next_frm); - - ccdc_dev->hw_ops.setfbaddr(addr); -} - -static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) -{ - unsigned long addr; - - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); - addr += vpfe_dev->field_off; - ccdc_dev->hw_ops.setfbaddr(addr); -} - -static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) -{ - vpfe_dev->cur_frm->ts = ktime_get_ns(); - vpfe_dev->cur_frm->state = VIDEOBUF_DONE; - vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; - wake_up_interruptible(&vpfe_dev->cur_frm->done); - vpfe_dev->cur_frm = vpfe_dev->next_frm; -} - -/* ISR for VINT0*/ -static irqreturn_t vpfe_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - enum v4l2_field field; - int fid; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); - field = vpfe_dev->fmt.fmt.pix.field; - - /* if streaming not started, don't do anything */ - if (!vpfe_dev->started) - goto clear_intr; - - /* only for 6446 this will be applicable */ - if (ccdc_dev->hw_ops.reset) - ccdc_dev->hw_ops.reset(); - - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "frame format is progressive...\n"); - if (vpfe_dev->cur_frm != vpfe_dev->next_frm) - vpfe_process_buffer_complete(vpfe_dev); - goto clear_intr; - } - - /* interlaced or TB capture check which field we are in hardware */ - fid = ccdc_dev->hw_ops.getfid(); - - /* switch the software maintained field id */ - vpfe_dev->field_id ^= 1; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n", - fid, vpfe_dev->field_id); - if (fid == vpfe_dev->field_id) { - /* we are in-sync here,continue */ - if (fid == 0) { - /* - * One frame is just being captured. If the next frame - * is available, release the current frame and move on - */ - if (vpfe_dev->cur_frm != vpfe_dev->next_frm) - vpfe_process_buffer_complete(vpfe_dev); - /* - * based on whether the two fields are stored - * interleavely or separately in memory, reconfigure - * the CCDC memory address - */ - if (field == V4L2_FIELD_SEQ_TB) - vpfe_schedule_bottom_field(vpfe_dev); - goto clear_intr; - } - /* - * if one field is just being captured configure - * the next frame get the next frame from the empty - * queue if no frame is available hold on to the - * current buffer - */ - spin_lock(&vpfe_dev->dma_queue_lock); - if (!list_empty(&vpfe_dev->dma_queue) && - vpfe_dev->cur_frm == vpfe_dev->next_frm) - vpfe_schedule_next_buffer(vpfe_dev); - spin_unlock(&vpfe_dev->dma_queue_lock); - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - vpfe_dev->field_id = fid; - } -clear_intr: - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - - return IRQ_HANDLED; -} - -/* vdint1_isr - isr handler for VINT1 interrupt */ -static irqreturn_t vdint1_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n"); - - /* if streaming not started, don't do anything */ - if (!vpfe_dev->started) { - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - return IRQ_HANDLED; - } - - spin_lock(&vpfe_dev->dma_queue_lock); - if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) && - !list_empty(&vpfe_dev->dma_queue) && - vpfe_dev->cur_frm == vpfe_dev->next_frm) - vpfe_schedule_next_buffer(vpfe_dev); - spin_unlock(&vpfe_dev->dma_queue_lock); - - if (vpfe_dev->cfg->clr_intr) - vpfe_dev->cfg->clr_intr(irq); - - return IRQ_HANDLED; -} - -static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frame_format; - - frame_format = ccdc_dev->hw_ops.get_frame_format(); - if (frame_format == CCDC_FRMFMT_PROGRESSIVE) - free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); -} - -static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) -{ - enum ccdc_frmfmt frame_format; - - frame_format = ccdc_dev->hw_ops.get_frame_format(); - if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { - return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr, - 0, "vpfe_capture1", - vpfe_dev); - } - return 0; -} - -/* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */ -static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev) -{ - vpfe_dev->started = 0; - ccdc_dev->hw_ops.enable(0); - if (ccdc_dev->hw_ops.enable_out_to_sdram) - ccdc_dev->hw_ops.enable_out_to_sdram(0); -} - -/* - * vpfe_release : This function deletes buffer queue, frees the - * buffers and the vpfe file handle - */ -static int vpfe_release(struct file *file) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); - - /* Get the device lock */ - mutex_lock(&vpfe_dev->lock); - /* if this instance is doing IO */ - if (fh->io_allowed) { - if (vpfe_dev->started) { - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, - video, s_stream, 0); - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&vpfe_dev->v4l2_dev, - "stream off failed in subdev\n"); - vpfe_stop_ccdc_capture(vpfe_dev); - vpfe_detach_irq(vpfe_dev); - videobuf_streamoff(&vpfe_dev->buffer_queue); - } - vpfe_dev->io_usrs = 0; - vpfe_dev->numbuffers = config_params.numbuffers; - videobuf_stop(&vpfe_dev->buffer_queue); - videobuf_mmap_free(&vpfe_dev->buffer_queue); - } - - /* Decrement device usrs counter */ - vpfe_dev->usrs--; - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - /* If this is the last file handle */ - if (!vpfe_dev->usrs) { - vpfe_dev->initialized = 0; - if (ccdc_dev->hw_ops.close) - ccdc_dev->hw_ops.close(vpfe_dev->pdev); - module_put(ccdc_dev->owner); - } - mutex_unlock(&vpfe_dev->lock); - file->private_data = NULL; - /* Free memory allocated to file handle object */ - kfree(fh); - return 0; -} - -/* - * vpfe_mmap : It is used to map kernel space buffers - * into user spaces - */ -static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) -{ - /* Get the device object and file handle object */ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); - - return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma); -} - -/* - * vpfe_poll: It is used for select/poll system call - */ -static __poll_t vpfe_poll(struct file *file, poll_table *wait) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); - - if (vpfe_dev->started) - return videobuf_poll_stream(file, - &vpfe_dev->buffer_queue, wait); - return 0; -} - -/* vpfe capture driver file operations */ -static const struct v4l2_file_operations vpfe_fops = { - .owner = THIS_MODULE, - .open = vpfe_open, - .release = vpfe_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vpfe_mmap, - .poll = vpfe_poll -}; - -/* - * vpfe_check_format() - * This function adjust the input pixel format as per hardware - * capabilities and update the same in pixfmt. - * Following algorithm used :- - * - * If given pixformat is not in the vpfe list of pix formats or not - * supported by the hardware, current value of pixformat in the device - * is used - * If given field is not supported, then current field is used. If field - * is different from current, then it is matched with that from sub device. - * Minimum height is 2 lines for interlaced or tb field and 1 line for - * progressive. Maximum height is clamped to active active lines of scan - * Minimum width is 32 bytes in memory and width is clamped to active - * pixels of scan. - * bytesperline is a multiple of 32. - */ -static const struct vpfe_pixel_format * - vpfe_check_format(struct vpfe_device *vpfe_dev, - struct v4l2_pix_format *pixfmt) -{ - u32 min_height = 1, min_width = 32, max_width, max_height; - const struct vpfe_pixel_format *vpfe_pix_fmt; - u32 pix; - int temp, found; - - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - if (!vpfe_pix_fmt) { - /* - * use current pixel format in the vpfe device. We - * will find this pix format in the table - */ - pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - } - - /* check if hw supports it */ - temp = 0; - found = 0; - while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { - if (vpfe_pix_fmt->pixelformat == pix) { - found = 1; - break; - } - temp++; - } - - if (!found) { - /* use current pixel format */ - pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; - /* - * Since this is currently used in the vpfe device, we - * will find this pix format in the table - */ - vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - } - - /* check what field format is supported */ - if (pixfmt->field == V4L2_FIELD_ANY) { - /* if field is any, use current value as default */ - pixfmt->field = vpfe_dev->fmt.fmt.pix.field; - } - - /* - * if field is not same as current field in the vpfe device - * try matching the field with the sub device field - */ - if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) { - /* - * If field value is not in the supported fields, use current - * field used in the device as default - */ - switch (pixfmt->field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_SEQ_TB: - /* if sub device is supporting progressive, use that */ - if (!vpfe_dev->std_info.frame_format) - pixfmt->field = V4L2_FIELD_NONE; - break; - case V4L2_FIELD_NONE: - if (vpfe_dev->std_info.frame_format) - pixfmt->field = V4L2_FIELD_INTERLACED; - break; - - default: - /* use current field as default */ - pixfmt->field = vpfe_dev->fmt.fmt.pix.field; - break; - } - } - - /* Now adjust image resolutions supported */ - if (pixfmt->field == V4L2_FIELD_INTERLACED || - pixfmt->field == V4L2_FIELD_SEQ_TB) - min_height = 2; - - max_width = vpfe_dev->std_info.active_pixels; - max_height = vpfe_dev->std_info.active_lines; - min_width /= vpfe_pix_fmt->bpp; - - v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n", - pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp); - - pixfmt->width = clamp((pixfmt->width), min_width, max_width); - pixfmt->height = clamp((pixfmt->height), min_height, max_height); - - /* If interlaced, adjust height to be a multiple of 2 */ - if (pixfmt->field == V4L2_FIELD_INTERLACED) - pixfmt->height &= (~1); - /* - * recalculate bytesperline and sizeimage since width - * and height might have changed - */ - pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31) - & ~31); - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) - pixfmt->sizeimage = - pixfmt->bytesperline * pixfmt->height + - ((pixfmt->bytesperline * pixfmt->height) >> 1); - else - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - - v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height = %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", - pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, - pixfmt->bytesperline, pixfmt->sizeimage); - return vpfe_pix_fmt; -} - -static int vpfe_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - - strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); - strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); - strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); - return 0; -} - -static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); - /* Fill in the information about format */ - *fmt = vpfe_dev->fmt; - return 0; -} - -static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmt; - u32 pix; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); - - if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0) - return -EINVAL; - - /* Fill in the information about format */ - pix_fmt = vpfe_lookup_pix_format(pix); - if (pix_fmt) { - fmt->pixelformat = pix_fmt->pixelformat; - return 0; - } - return -EINVAL; -} - -static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmts; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); - - /* If streaming is started, return error */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); - return -EBUSY; - } - - /* Check for valid frame format */ - pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); - if (!pix_fmts) - return -EINVAL; - - /* store the pixel format in the device object */ - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - /* First detach any IRQ if currently attached */ - vpfe_detach_irq(vpfe_dev); - vpfe_dev->fmt = *fmt; - /* set image capture parameters in the ccdc */ - ret = vpfe_config_ccdc_image_format(vpfe_dev); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - const struct vpfe_pixel_format *pix_fmts; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); - - pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); - if (!pix_fmts) - return -EINVAL; - return 0; -} - -/* - * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a - * given app input index - */ -static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev, - int *subdev_index, - int *subdev_input_index, - int app_input_index) -{ - struct vpfe_config *cfg = vpfe_dev->cfg; - struct vpfe_subdev_info *sdinfo; - int i, j = 0; - - for (i = 0; i < cfg->num_subdevs; i++) { - sdinfo = &cfg->sub_devs[i]; - if (app_input_index < (j + sdinfo->num_inputs)) { - *subdev_index = i; - *subdev_input_index = app_input_index - j; - return 0; - } - j += sdinfo->num_inputs; - } - return -EINVAL; -} - -/* - * vpfe_get_app_input - Get app input index for a given subdev input index - * driver stores the input index of the current sub device and translate it - * when application request the current input - */ -static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, - int *app_input_index) -{ - struct vpfe_config *cfg = vpfe_dev->cfg; - struct vpfe_subdev_info *sdinfo; - int i, j = 0; - - for (i = 0; i < cfg->num_subdevs; i++) { - sdinfo = &cfg->sub_devs[i]; - if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { - if (vpfe_dev->current_input >= sdinfo->num_inputs) - return -1; - *app_input_index = j + vpfe_dev->current_input; - return 0; - } - j += sdinfo->num_inputs; - } - return -EINVAL; -} - -static int vpfe_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int subdev, index ; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); - - if (vpfe_get_subdev_input_index(vpfe_dev, - &subdev, - &index, - inp->index) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "input information not found for the subdev\n"); - return -EINVAL; - } - sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; - *inp = sdinfo->inputs[index]; - return 0; -} - -static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); - - return vpfe_get_app_input_index(vpfe_dev, index); -} - - -static int vpfe_s_input(struct file *file, void *priv, unsigned int index) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct v4l2_subdev *sd; - struct vpfe_subdev_info *sdinfo; - int subdev_index, inp_index; - struct vpfe_route *route; - u32 input, output; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - /* - * If streaming is started return device busy - * error - */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); - ret = -EBUSY; - goto unlock_out; - } - ret = vpfe_get_subdev_input_index(vpfe_dev, - &subdev_index, - &inp_index, - index); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); - goto unlock_out; - } - - sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; - sd = vpfe_dev->sd[subdev_index]; - route = &sdinfo->routes[inp_index]; - if (route && sdinfo->can_route) { - input = route->input; - output = route->output; - } else { - input = 0; - output = 0; - } - - if (sd) - ret = v4l2_subdev_call(sd, video, s_routing, input, output, 0); - - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, - "vpfe_doioctl:error in setting input in decoder\n"); - ret = -EINVAL; - goto unlock_out; - } - vpfe_dev->current_subdev = sdinfo; - if (sd) - vpfe_dev->v4l2_dev.ctrl_handler = sd->ctrl_handler; - vpfe_dev->current_input = index; - vpfe_dev->std_index = 0; - - /* set the bus/interface parameter for the sub device in ccdc */ - ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); - if (ret) - goto unlock_out; - - /* set the default image parameters in the device */ - ret = vpfe_config_image_format(vpfe_dev, - vpfe_standards[vpfe_dev->std_index].std_id); -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - sdinfo = vpfe_dev->current_subdev; - if (ret) - return ret; - /* Call querystd function of decoder device */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, querystd, std_id); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); - - /* Call decoder driver function to set the standard */ - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - sdinfo = vpfe_dev->current_subdev; - /* If streaming is started, return device busy error */ - if (vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); - ret = -EBUSY; - goto unlock_out; - } - - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_std, std_id); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); - goto unlock_out; - } - ret = vpfe_config_image_format(vpfe_dev, std_id); - -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); - - *std_id = vpfe_standards[vpfe_dev->std_index].std_id; - return 0; -} -/* - * Videobuf operations - */ -static int vpfe_videobuf_setup(struct videobuf_queue *vq, - unsigned int *count, - unsigned int *size) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); - *size = vpfe_dev->fmt.fmt.pix.sizeimage; - if (vpfe_dev->memory == V4L2_MEMORY_MMAP && - vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize) - *size = config_params.device_bufsize; - - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "count=%d, size=%d\n", *count, *size); - return 0; -} - -static int vpfe_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long addr; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); - - /* If buffer is not initialized, initialize it */ - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = vpfe_dev->fmt.fmt.pix.width; - vb->height = vpfe_dev->fmt.fmt.pix.height; - vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; - vb->field = field; - - ret = videobuf_iolock(vq, vb, NULL); - if (ret < 0) - return ret; - - addr = videobuf_to_dma_contig(vb); - /* Make sure user addresses are aligned to 32 bytes */ - if (!ALIGN(addr, 32)) - return -EINVAL; - - vb->state = VIDEOBUF_PREPARED; - } - return 0; -} - -static void vpfe_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - /* Get the file handle object and device object */ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n"); - - /* add the buffer to the DMA queue */ - spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); - list_add_tail(&vb->queue, &vpfe_dev->dma_queue); - spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); - - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; -} - -static void vpfe_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct vpfe_fh *fh = vq->priv_data; - struct vpfe_device *vpfe_dev = fh->vpfe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n"); - - /* - * We need to flush the buffer from the dma queue since - * they are de-allocated - */ - spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); - INIT_LIST_HEAD(&vpfe_dev->dma_queue); - spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static const struct videobuf_queue_ops vpfe_videobuf_qops = { - .buf_setup = vpfe_videobuf_setup, - .buf_prepare = vpfe_videobuf_prepare, - .buf_queue = vpfe_videobuf_queue, - .buf_release = vpfe_videobuf_release, -}; - -/* - * vpfe_reqbufs. currently support REQBUF only once opening - * the device. - */ -static int vpfe_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req_buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - if (vpfe_dev->io_usrs != 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); - ret = -EBUSY; - goto unlock_out; - } - - vpfe_dev->memory = req_buf->memory; - videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue, - &vpfe_videobuf_qops, - vpfe_dev->pdev, - &vpfe_dev->irqlock, - req_buf->type, - vpfe_dev->fmt.fmt.pix.field, - sizeof(struct videobuf_buffer), - fh, NULL); - - fh->io_allowed = 1; - vpfe_dev->io_usrs = 1; - INIT_LIST_HEAD(&vpfe_dev->dma_queue); - ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf); -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - if (vpfe_dev->memory != V4L2_MEMORY_MMAP) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); - return -EINVAL; - } - /* Call videobuf_querybuf to get information */ - return videobuf_querybuf(&vpfe_dev->buffer_queue, buf); -} - -static int vpfe_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* - * If this file handle is not allowed to do IO, - * return error - */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - return videobuf_qbuf(&vpfe_dev->buffer_queue, p); -} - -static int vpfe_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - return videobuf_dqbuf(&vpfe_dev->buffer_queue, - buf, file->f_flags & O_NONBLOCK); -} - -/* - * vpfe_calculate_offsets : This function calculates buffers offset - * for top and bottom field - */ -static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev) -{ - struct v4l2_rect image_win; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n"); - - ccdc_dev->hw_ops.get_image_window(&image_win); - vpfe_dev->field_off = image_win.height * image_win.width; -} - -/* vpfe_start_ccdc_capture: start streaming in ccdc/isif */ -static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev) -{ - ccdc_dev->hw_ops.enable(1); - if (ccdc_dev->hw_ops.enable_out_to_sdram) - ccdc_dev->hw_ops.enable_out_to_sdram(1); - vpfe_dev->started = 1; -} - -/* - * vpfe_streamon. Assume the DMA queue is not empty. - * application is expected to call QBUF before calling - * this ioctl. If not, driver returns error - */ -static int vpfe_streamon(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - unsigned long addr; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If file handle is not allowed IO, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_stream, 1); - - if (ret && (ret != -ENOIOCTLCMD)) { - v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n"); - return -EINVAL; - } - - /* If buffer queue is empty, return error */ - if (list_empty(&vpfe_dev->buffer_queue.stream)) { - v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); - return -EIO; - } - - /* Call videobuf_streamon to start streaming * in videobuf */ - ret = videobuf_streamon(&vpfe_dev->buffer_queue); - if (ret) - return ret; - - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - goto streamoff; - /* Get the next frame from the buffer queue */ - vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, - struct videobuf_buffer, queue); - vpfe_dev->cur_frm = vpfe_dev->next_frm; - /* Remove buffer from the buffer queue */ - list_del(&vpfe_dev->cur_frm->queue); - /* Mark state of the current frame to active */ - vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - vpfe_dev->field_id = 0; - addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); - - /* Calculate field offset */ - vpfe_calculate_offsets(vpfe_dev); - - if (vpfe_attach_irq(vpfe_dev) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in attaching interrupt handle\n"); - ret = -EFAULT; - goto unlock_out; - } - if (ccdc_dev->hw_ops.configure() < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error in configuring ccdc\n"); - ret = -EINVAL; - goto unlock_out; - } - ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr)); - vpfe_start_ccdc_capture(vpfe_dev); - mutex_unlock(&vpfe_dev->lock); - return ret; -unlock_out: - mutex_unlock(&vpfe_dev->lock); -streamoff: - videobuf_streamoff(&vpfe_dev->buffer_queue); - return ret; -} - -static int vpfe_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_fh *fh = file->private_data; - struct vpfe_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If io is allowed for this file handle, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - /* If streaming is not started, return error */ - if (!vpfe_dev->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "device started\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - vpfe_stop_ccdc_capture(vpfe_dev); - vpfe_detach_irq(vpfe_dev); - - sdinfo = vpfe_dev->current_subdev; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_stream, 0); - - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n"); - ret = videobuf_streamoff(&vpfe_dev->buffer_queue); - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -static int vpfe_g_pixelaspect(struct file *file, void *priv, - int type, struct v4l2_fract *f) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_pixelaspect\n"); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - /* If std_index is invalid, then just return (== 1:1 aspect) */ - if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) - return 0; - - *f = vpfe_standards[vpfe_dev->std_index].pixelaspect; - return 0; -} - -static int vpfe_g_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_selection\n"); - - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - sel->r = vpfe_dev->crop; - break; - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.width = vpfe_standards[vpfe_dev->std_index].width; - sel->r.height = vpfe_standards[vpfe_dev->std_index].height; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vpfe_s_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct v4l2_rect rect = sel->r; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_selection\n"); - - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - if (vpfe_dev->started) { - /* make sure streaming is not started */ - v4l2_err(&vpfe_dev->v4l2_dev, - "Cannot change crop when streaming is ON\n"); - return -EBUSY; - } - - ret = mutex_lock_interruptible(&vpfe_dev->lock); - if (ret) - return ret; - - if (rect.top < 0 || rect.left < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "doesn't support negative values for top & left\n"); - ret = -EINVAL; - goto unlock_out; - } - - /* adjust the width to 16 pixel boundary */ - rect.width = ((rect.width + 15) & ~0xf); - - /* make sure parameters are valid */ - if ((rect.left + rect.width > - vpfe_dev->std_info.active_pixels) || - (rect.top + rect.height > - vpfe_dev->std_info.active_lines)) { - v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_SELECTION params\n"); - ret = -EINVAL; - goto unlock_out; - } - ccdc_dev->hw_ops.set_image_window(&rect); - vpfe_dev->fmt.fmt.pix.width = rect.width; - vpfe_dev->fmt.fmt.pix.height = rect.height; - vpfe_dev->fmt.fmt.pix.bytesperline = - ccdc_dev->hw_ops.get_line_length(); - vpfe_dev->fmt.fmt.pix.sizeimage = - vpfe_dev->fmt.fmt.pix.bytesperline * - vpfe_dev->fmt.fmt.pix.height; - vpfe_dev->crop = rect; - sel->r = rect; -unlock_out: - mutex_unlock(&vpfe_dev->lock); - return ret; -} - -/* vpfe capture ioctl operations */ -static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { - .vidioc_querycap = vpfe_querycap, - .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap, - .vidioc_enum_input = vpfe_enum_input, - .vidioc_g_input = vpfe_g_input, - .vidioc_s_input = vpfe_s_input, - .vidioc_querystd = vpfe_querystd, - .vidioc_s_std = vpfe_s_std, - .vidioc_g_std = vpfe_g_std, - .vidioc_reqbufs = vpfe_reqbufs, - .vidioc_querybuf = vpfe_querybuf, - .vidioc_qbuf = vpfe_qbuf, - .vidioc_dqbuf = vpfe_dqbuf, - .vidioc_streamon = vpfe_streamon, - .vidioc_streamoff = vpfe_streamoff, - .vidioc_g_pixelaspect = vpfe_g_pixelaspect, - .vidioc_g_selection = vpfe_g_selection, - .vidioc_s_selection = vpfe_s_selection, -}; - -static struct vpfe_device *vpfe_initialize(void) -{ - struct vpfe_device *vpfe_dev; - - /* Default number of buffers should be 3 */ - if ((numbuffers > 0) && - (numbuffers < config_params.min_numbuffers)) - numbuffers = config_params.min_numbuffers; - - /* - * Set buffer size to min buffers size if invalid buffer size is - * given - */ - if (bufsize < config_params.min_bufsize) - bufsize = config_params.min_bufsize; - - config_params.numbuffers = numbuffers; - - if (numbuffers) - config_params.device_bufsize = bufsize; - - /* Allocate memory for device objects */ - vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); - - return vpfe_dev; -} - -/* - * vpfe_probe : This function creates device entries by register - * itself to the V4L2 driver and initializes fields of each - * device objects - */ -static int vpfe_probe(struct platform_device *pdev) -{ - struct vpfe_subdev_info *sdinfo; - struct vpfe_config *vpfe_cfg; - struct resource *res1; - struct vpfe_device *vpfe_dev; - struct i2c_adapter *i2c_adap; - struct video_device *vfd; - int ret, i, j; - int num_subdevs = 0; - - /* Get the pointer to the device object */ - vpfe_dev = vpfe_initialize(); - - if (!vpfe_dev) { - v4l2_err(pdev->dev.driver, - "Failed to allocate memory for vpfe_dev\n"); - return -ENOMEM; - } - - vpfe_dev->pdev = &pdev->dev; - - if (!pdev->dev.platform_data) { - v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); - ret = -ENODEV; - goto probe_free_dev_mem; - } - - vpfe_cfg = pdev->dev.platform_data; - vpfe_dev->cfg = vpfe_cfg; - if (!vpfe_cfg->ccdc || !vpfe_cfg->card_name || !vpfe_cfg->sub_devs) { - v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - - /* Allocate memory for ccdc configuration */ - ccdc_cfg = kmalloc(sizeof(*ccdc_cfg), GFP_KERNEL); - if (!ccdc_cfg) { - ret = -ENOMEM; - goto probe_free_dev_mem; - } - - mutex_lock(&ccdc_lock); - - strscpy(ccdc_cfg->name, vpfe_cfg->ccdc, sizeof(ccdc_cfg->name)); - /* Get VINT0 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT0\n"); - ret = -ENODEV; - goto probe_free_ccdc_cfg_mem; - } - vpfe_dev->ccdc_irq0 = res1->start; - - /* Get VINT1 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT1\n"); - ret = -ENODEV; - goto probe_free_ccdc_cfg_mem; - } - vpfe_dev->ccdc_irq1 = res1->start; - - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, 0, - "vpfe_capture0", vpfe_dev); - - if (0 != ret) { - v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); - goto probe_free_ccdc_cfg_mem; - } - - vfd = &vpfe_dev->video_dev; - /* Initialize field of video device */ - vfd->release = video_device_release_empty; - vfd->fops = &vpfe_fops; - vfd->ioctl_ops = &vpfe_ioctl_ops; - vfd->tvnorms = 0; - vfd->v4l2_dev = &vpfe_dev->v4l2_dev; - vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - snprintf(vfd->name, sizeof(vfd->name), - "%s_V%d.%d.%d", - CAPTURE_DRV_NAME, - (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, - (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, - (VPFE_CAPTURE_VERSION_CODE) & 0xff); - - ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register v4l2 device.\n"); - goto probe_out_release_irq; - } - v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); - spin_lock_init(&vpfe_dev->irqlock); - spin_lock_init(&vpfe_dev->dma_queue_lock); - mutex_init(&vpfe_dev->lock); - - /* Initialize field of the device objects */ - vpfe_dev->numbuffers = config_params.numbuffers; - - /* register video device */ - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "trying to register vpfe device.\n"); - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "video_dev=%p\n", &vpfe_dev->video_dev); - vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = video_register_device(&vpfe_dev->video_dev, - VFL_TYPE_VIDEO, -1); - - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register video device.\n"); - goto probe_out_v4l2_unregister; - } - - v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n"); - /* set the driver data in platform device */ - platform_set_drvdata(pdev, vpfe_dev); - /* set driver private data */ - video_set_drvdata(&vpfe_dev->video_dev, vpfe_dev); - i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); - num_subdevs = vpfe_cfg->num_subdevs; - vpfe_dev->sd = kmalloc_array(num_subdevs, - sizeof(*vpfe_dev->sd), - GFP_KERNEL); - if (!vpfe_dev->sd) { - ret = -ENOMEM; - goto probe_out_video_unregister; - } - - for (i = 0; i < num_subdevs; i++) { - struct v4l2_input *inps; - - sdinfo = &vpfe_cfg->sub_devs[i]; - - /* Load up the subdevice */ - vpfe_dev->sd[i] = - v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, - i2c_adap, - &sdinfo->board_info, - NULL); - if (vpfe_dev->sd[i]) { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - sdinfo->name); - vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; - /* update tvnorms from the sub devices */ - for (j = 0; j < sdinfo->num_inputs; j++) { - inps = &sdinfo->inputs[j]; - vfd->tvnorms |= inps->std; - } - } else { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s register fails\n", - sdinfo->name); - ret = -ENXIO; - goto probe_sd_out; - } - } - - /* set first sub device as current one */ - vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; - vpfe_dev->v4l2_dev.ctrl_handler = vpfe_dev->sd[0]->ctrl_handler; - - /* We have at least one sub device to work with */ - mutex_unlock(&ccdc_lock); - return 0; - -probe_sd_out: - kfree(vpfe_dev->sd); -probe_out_video_unregister: - video_unregister_device(&vpfe_dev->video_dev); -probe_out_v4l2_unregister: - v4l2_device_unregister(&vpfe_dev->v4l2_dev); -probe_out_release_irq: - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); -probe_free_ccdc_cfg_mem: - kfree(ccdc_cfg); - mutex_unlock(&ccdc_lock); -probe_free_dev_mem: - kfree(vpfe_dev); - return ret; -} - -/* - * vpfe_remove : It un-register device from V4L2 driver - */ -static int vpfe_remove(struct platform_device *pdev) -{ - struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - - v4l2_info(pdev->dev.driver, "vpfe_remove\n"); - - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - kfree(vpfe_dev->sd); - v4l2_device_unregister(&vpfe_dev->v4l2_dev); - video_unregister_device(&vpfe_dev->video_dev); - kfree(vpfe_dev); - kfree(ccdc_cfg); - return 0; -} - -static int vpfe_suspend(struct device *dev) -{ - return 0; -} - -static int vpfe_resume(struct device *dev) -{ - return 0; -} - -static const struct dev_pm_ops vpfe_dev_pm_ops = { - .suspend = vpfe_suspend, - .resume = vpfe_resume, -}; - -static struct platform_driver vpfe_driver = { - .driver = { - .name = CAPTURE_DRV_NAME, - .pm = &vpfe_dev_pm_ops, - }, - .probe = vpfe_probe, - .remove = vpfe_remove, -}; - -module_platform_driver(vpfe_driver); diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h deleted file mode 100644 index 4ad53031e2f7..000000000000 --- a/include/media/davinci/vpfe_capture.h +++ /dev/null @@ -1,177 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008-2009 Texas Instruments Inc - */ - -#ifndef _VPFE_CAPTURE_H -#define _VPFE_CAPTURE_H - -#ifdef __KERNEL__ - -/* Header files */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VPFE_CAPTURE_NUM_DECODERS 5 - -/* Macros */ -#define VPFE_MAJOR_RELEASE 0 -#define VPFE_MINOR_RELEASE 0 -#define VPFE_BUILD 1 -#define VPFE_CAPTURE_VERSION_CODE ((VPFE_MAJOR_RELEASE << 16) | \ - (VPFE_MINOR_RELEASE << 8) | \ - VPFE_BUILD) - -#define CAPTURE_DRV_NAME "vpfe-capture" - -struct vpfe_pixel_format { - u32 pixelformat; - /* bytes per pixel */ - int bpp; -}; - -struct vpfe_std_info { - int active_pixels; - int active_lines; - /* current frame format */ - int frame_format; -}; - -struct vpfe_route { - u32 input; - u32 output; -}; - -struct vpfe_subdev_info { - /* Sub device name */ - char name[32]; - /* Sub device group id */ - int grp_id; - /* Number of inputs supported */ - int num_inputs; - /* inputs available at the sub device */ - struct v4l2_input *inputs; - /* Sub dev routing information for each input */ - struct vpfe_route *routes; - /* check if sub dev supports routing */ - int can_route; - /* ccdc bus/interface configuration */ - struct vpfe_hw_if_param ccdc_if_params; - /* i2c subdevice board info */ - struct i2c_board_info board_info; -}; - -struct vpfe_config { - /* Number of sub devices connected to vpfe */ - int num_subdevs; - /* i2c bus adapter no */ - int i2c_adapter_id; - /* information about each subdev */ - struct vpfe_subdev_info *sub_devs; - /* evm card info */ - char *card_name; - /* ccdc name */ - char *ccdc; - /* vpfe clock */ - struct clk *vpssclk; - struct clk *slaveclk; - /* Function for Clearing the interrupt */ - void (*clr_intr)(int vdint); -}; - -struct vpfe_device { - /* V4l2 specific parameters */ - /* Identifies video device for this channel */ - struct video_device video_dev; - /* sub devices */ - struct v4l2_subdev **sd; - /* vpfe cfg */ - struct vpfe_config *cfg; - /* V4l2 device */ - struct v4l2_device v4l2_dev; - /* parent device */ - struct device *pdev; - /* number of open instances of the channel */ - u32 usrs; - /* Indicates id of the field which is being displayed */ - u32 field_id; - /* flag to indicate whether decoder is initialized */ - u8 initialized; - /* current interface type */ - struct vpfe_hw_if_param vpfe_if_params; - /* ptr to currently selected sub device */ - struct vpfe_subdev_info *current_subdev; - /* current input at the sub device */ - int current_input; - /* Keeps track of the information about the standard */ - struct vpfe_std_info std_info; - /* std index into std table */ - int std_index; - /* CCDC IRQs used when CCDC/ISIF output to SDRAM */ - unsigned int ccdc_irq0; - unsigned int ccdc_irq1; - /* number of buffers in fbuffers */ - u32 numbuffers; - /* List of buffer pointers for storing frames */ - u8 *fbuffers[VIDEO_MAX_FRAME]; - /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *cur_frm; - /* Pointer pointing to next v4l2_buffer */ - struct videobuf_buffer *next_frm; - /* - * This field keeps track of type of buffer exchange mechanism - * user has selected - */ - enum v4l2_memory memory; - /* Used to store pixel format */ - struct v4l2_format fmt; - /* - * used when IMP is chained to store the crop window which - * is different from the image window - */ - struct v4l2_rect crop; - /* Buffer queue used in video-buf */ - struct videobuf_queue buffer_queue; - /* Queue of filled frames */ - struct list_head dma_queue; - /* Used in video-buf */ - spinlock_t irqlock; - /* IRQ lock for DMA queue */ - spinlock_t dma_queue_lock; - /* lock used to access this structure */ - struct mutex lock; - /* number of users performing IO */ - u32 io_usrs; - /* Indicates whether streaming started */ - u8 started; - /* - * offset where second field starts from the starting of the - * buffer for field separated YCbCr formats - */ - u32 field_off; -}; - -/* File handle structure */ -struct vpfe_fh { - struct v4l2_fh fh; - struct vpfe_device *vpfe_dev; - /* Indicates whether this file handle is doing IO */ - u8 io_allowed; -}; - -struct vpfe_config_params { - u8 min_numbuffers; - u8 numbuffers; - u32 min_bufsize; - u32 device_bufsize; -}; - -#endif /* End of __KERNEL__ */ -#endif /* _DAVINCI_VPFE_H */ -- cgit v1.2.3 From eeee6973935357c96715deb3829058dbea8803f0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 6 Oct 2022 17:15:30 +0200 Subject: media: davinci: remove vpbe support The davinci dm3xx/dm644x platforms are gone now, and the remaining da8xx platforms do not use the vpbe driver, so the driver can be removed as well. Acked-by: Lad Prabhakar Signed-off-by: Arnd Bergmann --- Documentation/admin-guide/media/davinci-vpbe.rst | 65 - .../admin-guide/media/platform-cardlist.rst | 1 - Documentation/admin-guide/media/v4l-drivers.rst | 1 - .../media/drivers/davinci-vpbe-devel.rst | 39 - Documentation/driver-api/media/drivers/index.rst | 1 - drivers/media/platform/ti/davinci/Kconfig | 16 - drivers/media/platform/ti/davinci/Makefile | 3 - drivers/media/platform/ti/davinci/vpbe.c | 840 ----------- drivers/media/platform/ti/davinci/vpbe_display.c | 1510 ------------------- drivers/media/platform/ti/davinci/vpbe_osd.c | 1582 -------------------- drivers/media/platform/ti/davinci/vpbe_osd_regs.h | 352 ----- drivers/media/platform/ti/davinci/vpbe_venc.c | 676 --------- drivers/media/platform/ti/davinci/vpbe_venc_regs.h | 165 -- drivers/media/platform/ti/davinci/vpss.c | 529 ------- include/media/davinci/vpbe.h | 184 --- include/media/davinci/vpbe_display.h | 122 -- include/media/davinci/vpbe_osd.h | 382 ----- include/media/davinci/vpbe_types.h | 74 - include/media/davinci/vpbe_venc.h | 37 - include/media/davinci/vpss.h | 111 -- 20 files changed, 6690 deletions(-) delete mode 100644 Documentation/admin-guide/media/davinci-vpbe.rst delete mode 100644 Documentation/driver-api/media/drivers/davinci-vpbe-devel.rst delete mode 100644 drivers/media/platform/ti/davinci/vpbe.c delete mode 100644 drivers/media/platform/ti/davinci/vpbe_display.c delete mode 100644 drivers/media/platform/ti/davinci/vpbe_osd.c delete mode 100644 drivers/media/platform/ti/davinci/vpbe_osd_regs.h delete mode 100644 drivers/media/platform/ti/davinci/vpbe_venc.c delete mode 100644 drivers/media/platform/ti/davinci/vpbe_venc_regs.h delete mode 100644 drivers/media/platform/ti/davinci/vpss.c delete mode 100644 include/media/davinci/vpbe.h delete mode 100644 include/media/davinci/vpbe_display.h delete mode 100644 include/media/davinci/vpbe_osd.h delete mode 100644 include/media/davinci/vpbe_types.h delete mode 100644 include/media/davinci/vpbe_venc.h delete mode 100644 include/media/davinci/vpss.h (limited to 'include') diff --git a/Documentation/admin-guide/media/davinci-vpbe.rst b/Documentation/admin-guide/media/davinci-vpbe.rst deleted file mode 100644 index 9e6360fd02db..000000000000 --- a/Documentation/admin-guide/media/davinci-vpbe.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -The VPBE V4L2 driver design -=========================== - -Functional partitioning ------------------------ - -Consists of the following: - - 1. V4L2 display driver - - Implements creation of video2 and video3 device nodes and - provides v4l2 device interface to manage VID0 and VID1 layers. - - 2. Display controller - - Loads up VENC, OSD and external encoders such as ths8200. It provides - a set of API calls to V4L2 drivers to set the output/standards - in the VENC or external sub devices. It also provides - a device object to access the services from OSD subdevice - using sub device ops. The connection of external encoders to VENC LCD - controller port is done at init time based on default output and standard - selection or at run time when application change the output through - V4L2 IOCTLs. - - When connected to an external encoder, vpbe controller is also responsible - for setting up the interface between VENC and external encoders based on - board specific settings (specified in board-xxx-evm.c). This allows - interfacing external encoders such as ths8200. The setup_if_config() - is implemented for this as well as configure_venc() (part of the next patch) - API to set timings in VENC for a specific display resolution. As of this - patch series, the interconnection and enabling and setting of the external - encoders is not present, and would be a part of the next patch series. - - 3. VENC subdevice module - - Responsible for setting outputs provided through internal DACs and also - setting timings at LCD controller port when external encoders are connected - at the port or LCD panel timings required. When external encoder/LCD panel - is connected, the timings for a specific standard/preset is retrieved from - the board specific table and the values are used to set the timings in - venc using non-standard timing mode. - - Support LCD Panel displays using the VENC. For example to support a Logic - PD display, it requires setting up the LCD controller port with a set of - timings for the resolution supported and setting the dot clock. So we could - add the available outputs as a board specific entry (i.e add the "LogicPD" - output name to board-xxx-evm.c). A table of timings for various LCDs - supported can be maintained in the board specific setup file to support - various LCD displays.As of this patch a basic driver is present, and this - support for external encoders and displays forms a part of the next - patch series. - - 4. OSD module - - OSD module implements all OSD layer management and hardware specific - features. The VPBE module interacts with the OSD for enabling and - disabling appropriate features of the OSD. - -Current status --------------- - -A fully functional working version of the V4L2 driver is available. This -driver has been tested with NTSC and PAL standards and buffer streaming. diff --git a/Documentation/admin-guide/media/platform-cardlist.rst b/Documentation/admin-guide/media/platform-cardlist.rst index ac73c4166d1e..8ef57cd13dec 100644 --- a/Documentation/admin-guide/media/platform-cardlist.rst +++ b/Documentation/admin-guide/media/platform-cardlist.rst @@ -73,7 +73,6 @@ via-camera VIAFB camera controller video-mux Video Multiplexer vpif_display TI DaVinci VPIF V4L2-Display vpif_capture TI DaVinci VPIF video capture -vpss TI DaVinci VPBE V4L2-Display vsp1 Renesas VSP1 Video Processing Engine xilinx-tpg Xilinx Video Test Pattern Generator xilinx-video Xilinx Video IP (EXPERIMENTAL) diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst index 90a026ee05c6..734e18c310bd 100644 --- a/Documentation/admin-guide/media/v4l-drivers.rst +++ b/Documentation/admin-guide/media/v4l-drivers.rst @@ -13,7 +13,6 @@ Video4Linux (V4L) driver-specific documentation cafe_ccic cpia2 cx88 - davinci-vpbe fimc imx imx7 diff --git a/Documentation/driver-api/media/drivers/davinci-vpbe-devel.rst b/Documentation/driver-api/media/drivers/davinci-vpbe-devel.rst deleted file mode 100644 index 4e87bdbc7ae4..000000000000 --- a/Documentation/driver-api/media/drivers/davinci-vpbe-devel.rst +++ /dev/null @@ -1,39 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -The VPBE V4L2 driver design -=========================== - -File partitioning ------------------ - - V4L2 display device driver - drivers/media/platform/ti/davinci/vpbe_display.c - drivers/media/platform/ti/davinci/vpbe_display.h - - VPBE display controller - drivers/media/platform/ti/davinci/vpbe.c - drivers/media/platform/ti/davinci/vpbe.h - - VPBE venc sub device driver - drivers/media/platform/ti/davinci/vpbe_venc.c - drivers/media/platform/ti/davinci/vpbe_venc.h - drivers/media/platform/ti/davinci/vpbe_venc_regs.h - - VPBE osd driver - drivers/media/platform/ti/davinci/vpbe_osd.c - drivers/media/platform/ti/davinci/vpbe_osd.h - drivers/media/platform/ti/davinci/vpbe_osd_regs.h - -To be done ----------- - -vpbe display controller - - Add support for external encoders. - - add support for selecting external encoder as default at probe time. - -vpbe venc sub device - - add timings for supporting ths8200 - - add support for LogicPD LCD. - -FB drivers - - Add support for fbdev drivers.- Ready and part of subsequent patches. diff --git a/Documentation/driver-api/media/drivers/index.rst b/Documentation/driver-api/media/drivers/index.rst index 32406490557c..3c17d48f83c0 100644 --- a/Documentation/driver-api/media/drivers/index.rst +++ b/Documentation/driver-api/media/drivers/index.rst @@ -16,7 +16,6 @@ Video4Linux (V4L) drivers cpia2_devel cx2341x-devel cx88-devel - davinci-vpbe-devel fimc-devel pvrusb2 pxa_camera diff --git a/drivers/media/platform/ti/davinci/Kconfig b/drivers/media/platform/ti/davinci/Kconfig index 96d4bed7fe9e..542a602e66be 100644 --- a/drivers/media/platform/ti/davinci/Kconfig +++ b/drivers/media/platform/ti/davinci/Kconfig @@ -31,19 +31,3 @@ config VIDEO_DAVINCI_VPIF_CAPTURE To compile this driver as a module, choose M here. There will be two modules called vpif.ko and vpif_capture.ko - -config VIDEO_DAVINCI_VPBE_DISPLAY - tristate "TI DaVinci VPBE V4L2-Display driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF2_DMA_CONTIG - help - Enables Davinci VPBE module used for display devices. - This module is used for display on TI DM644x/DM365/DM355 - based display devices. - - To compile this driver as a module, choose M here. There will - be five modules created called vpss.ko, vpbe.ko, vpbe_osd.ko, - vpbe_venc.ko and vpbe_display.ko diff --git a/drivers/media/platform/ti/davinci/Makefile b/drivers/media/platform/ti/davinci/Makefile index b20a91653162..512f03369bae 100644 --- a/drivers/media/platform/ti/davinci/Makefile +++ b/drivers/media/platform/ti/davinci/Makefile @@ -7,6 +7,3 @@ obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif.o vpif_display.o #VPIF Capture driver obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif.o vpif_capture.o - -obj-$(CONFIG_VIDEO_DAVINCI_VPBE_DISPLAY) += vpss.o vpbe.o vpbe_osd.o \ - vpbe_venc.o vpbe_display.o diff --git a/drivers/media/platform/ti/davinci/vpbe.c b/drivers/media/platform/ti/davinci/vpbe.c deleted file mode 100644 index 509ecc84624e..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe.c +++ /dev/null @@ -1,840 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010 Texas Instruments Inc - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define VPBE_DEFAULT_OUTPUT "Composite" -#define VPBE_DEFAULT_MODE "ntsc" - -static char *def_output = VPBE_DEFAULT_OUTPUT; -static char *def_mode = VPBE_DEFAULT_MODE; -static int debug; - -module_param(def_output, charp, S_IRUGO); -module_param(def_mode, charp, S_IRUGO); -module_param(debug, int, 0644); - -MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); -MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc"); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); - -/** - * vpbe_current_encoder_info - Get config info for current encoder - * @vpbe_dev: vpbe device ptr - * - * Return ptr to current encoder config info - */ -static struct encoder_config_info* -vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int index = vpbe_dev->current_sd_index; - - return ((index == 0) ? &cfg->venc : - &cfg->ext_encoders[index-1]); -} - -/** - * vpbe_find_encoder_sd_index - Given a name find encoder sd index - * - * @cfg: ptr to vpbe cfg - * @index: index used by application - * - * Return sd index of the encoder - */ -static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg, - int index) -{ - char *encoder_name = cfg->outputs[index].subdev_name; - int i; - - /* Venc is always first */ - if (!strcmp(encoder_name, cfg->venc.module_name)) - return 0; - - for (i = 0; i < cfg->num_ext_encoders; i++) { - if (!strcmp(encoder_name, - cfg->ext_encoders[i].module_name)) - return i+1; - } - - return -EINVAL; -} - -/** - * vpbe_enum_outputs - enumerate outputs - * @vpbe_dev: vpbe device ptr - * @output: ptr to v4l2_output structure - * - * Enumerates the outputs available at the vpbe display - * returns the status, -EINVAL if end of output list - */ -static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, - struct v4l2_output *output) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - unsigned int temp_index = output->index; - - if (temp_index >= cfg->num_outputs) - return -EINVAL; - - *output = cfg->outputs[temp_index].output; - output->index = temp_index; - - return 0; -} - -static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode, - int output_index) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = output_index; - int i; - - if (!mode) - return -EINVAL; - - for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if (!strcmp(mode, var.name)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - -static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, - struct vpbe_enc_mode_info *mode_info) -{ - if (!mode_info) - return -EINVAL; - - *mode_info = vpbe_dev->current_timings; - - return 0; -} - -/* Get std by std id */ -static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, - v4l2_std_id std_id) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; - int i; - - for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if ((var.timings_type & VPBE_ENC_STD) && - (var.std_id & std_id)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - -static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, - char *std_name) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; - int i; - - for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if (!strcmp(var.name, std_name)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - -/** - * vpbe_set_output - Set output - * @vpbe_dev: vpbe device ptr - * @index: index of output - * - * Set vpbe output to the output specified by the index - */ -static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) -{ - struct encoder_config_info *curr_enc_info = - vpbe_current_encoder_info(vpbe_dev); - struct vpbe_config *cfg = vpbe_dev->cfg; - struct venc_platform_data *venc_device = vpbe_dev->venc_device; - int enc_out_index; - int sd_index; - int ret; - - if (index >= cfg->num_outputs) - return -EINVAL; - - mutex_lock(&vpbe_dev->lock); - - sd_index = vpbe_dev->current_sd_index; - enc_out_index = cfg->outputs[index].output.index; - /* - * Currently we switch the encoder based on output selected - * by the application. If media controller is implemented later - * there is will be an API added to setup_link between venc - * and external encoder. So in that case below comparison always - * match and encoder will not be switched. But if application - * chose not to use media controller, then this provides current - * way of switching encoder at the venc output. - */ - if (strcmp(curr_enc_info->module_name, - cfg->outputs[index].subdev_name)) { - /* Need to switch the encoder at the output */ - sd_index = vpbe_find_encoder_sd_index(cfg, index); - if (sd_index < 0) { - ret = -EINVAL; - goto unlock; - } - - ret = venc_device->setup_if_config(cfg->outputs[index].if_params); - if (ret) - goto unlock; - } - - /* Set output at the encoder */ - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_routing, 0, enc_out_index, 0); - if (ret) - goto unlock; - - /* - * It is assumed that venc or external encoder will set a default - * mode in the sub device. For external encoder or LCD pannel output, - * we also need to set up the lcd port for the required mode. So setup - * the lcd port for the default mode that is configured in the board - * arch/arm/mach-davinci/board-dm355-evm.setup file for the external - * encoder. - */ - ret = vpbe_get_mode_info(vpbe_dev, - cfg->outputs[index].default_mode, index); - if (!ret) { - struct osd_state *osd_device = vpbe_dev->osd_device; - - osd_device->ops.set_left_margin(osd_device, - vpbe_dev->current_timings.left_margin); - osd_device->ops.set_top_margin(osd_device, - vpbe_dev->current_timings.upper_margin); - vpbe_dev->current_sd_index = sd_index; - vpbe_dev->current_out_index = index; - } -unlock: - mutex_unlock(&vpbe_dev->lock); - return ret; -} - -static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int i; - - for (i = 0; i < cfg->num_outputs; i++) { - if (!strcmp(def_output, - cfg->outputs[i].output.name)) { - int ret = vpbe_set_output(vpbe_dev, i); - - if (!ret) - vpbe_dev->current_out_index = i; - return ret; - } - } - return 0; -} - -/** - * vpbe_get_output - Get output - * @vpbe_dev: vpbe device ptr - * - * return current vpbe output to the index - */ -static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) -{ - return vpbe_dev->current_out_index; -} - -/* - * vpbe_s_dv_timings - Set the given preset timings in the encoder - * - * Sets the timings if supported by the current encoder. Return the status. - * 0 - success & -EINVAL on error - */ -static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, - struct v4l2_dv_timings *dv_timings) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - struct vpbe_output *output = &cfg->outputs[out_index]; - int sd_index = vpbe_dev->current_sd_index; - int ret, i; - - - if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_DV_TIMINGS)) - return -ENODATA; - - for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS && - !memcmp(&output->modes[i].dv_timings, - dv_timings, sizeof(*dv_timings))) - break; - } - if (i >= output->num_modes) - return -EINVAL; - vpbe_dev->current_timings = output->modes[i]; - mutex_lock(&vpbe_dev->lock); - - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_dv_timings, dv_timings); - if (!ret && vpbe_dev->amp) { - /* Call amplifier subdevice */ - ret = v4l2_subdev_call(vpbe_dev->amp, video, - s_dv_timings, dv_timings); - } - /* set the lcd controller output for the given mode */ - if (!ret) { - struct osd_state *osd_device = vpbe_dev->osd_device; - - osd_device->ops.set_left_margin(osd_device, - vpbe_dev->current_timings.left_margin); - osd_device->ops.set_top_margin(osd_device, - vpbe_dev->current_timings.upper_margin); - } - mutex_unlock(&vpbe_dev->lock); - - return ret; -} - -/* - * vpbe_g_dv_timings - Get the timings in the current encoder - * - * Get the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev, - struct v4l2_dv_timings *dv_timings) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - - if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_DV_TIMINGS)) - return -ENODATA; - - if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_TIMINGS) { - *dv_timings = vpbe_dev->current_timings.dv_timings; - return 0; - } - - return -EINVAL; -} - -/* - * vpbe_enum_dv_timings - Enumerate the dv timings in the current encoder - * - * Get the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, - struct v4l2_enum_dv_timings *timings) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - struct vpbe_output *output = &cfg->outputs[out_index]; - int j = 0; - int i; - - if (!(output->output.capabilities & V4L2_OUT_CAP_DV_TIMINGS)) - return -ENODATA; - - for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS) { - if (j == timings->index) - break; - j++; - } - } - - if (i == output->num_modes) - return -EINVAL; - timings->timings = output->modes[i].dv_timings; - return 0; -} - -/* - * vpbe_s_std - Set the given standard in the encoder - * - * Sets the standard if supported by the current encoder. Return the status. - * 0 - success & -EINVAL on error - */ -static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - int sd_index = vpbe_dev->current_sd_index; - int ret; - - if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_STD)) - return -ENODATA; - - ret = vpbe_get_std_info(vpbe_dev, std_id); - if (ret) - return ret; - - mutex_lock(&vpbe_dev->lock); - - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_std_output, std_id); - /* set the lcd controller output for the given mode */ - if (!ret) { - struct osd_state *osd_device = vpbe_dev->osd_device; - - osd_device->ops.set_left_margin(osd_device, - vpbe_dev->current_timings.left_margin); - osd_device->ops.set_top_margin(osd_device, - vpbe_dev->current_timings.upper_margin); - } - mutex_unlock(&vpbe_dev->lock); - - return ret; -} - -/* - * vpbe_g_std - Get the standard in the current encoder - * - * Get the standard in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) -{ - struct vpbe_enc_mode_info *cur_timings = &vpbe_dev->current_timings; - struct vpbe_config *cfg = vpbe_dev->cfg; - int out_index = vpbe_dev->current_out_index; - - if (!(cfg->outputs[out_index].output.capabilities & V4L2_OUT_CAP_STD)) - return -ENODATA; - - if (cur_timings->timings_type & VPBE_ENC_STD) { - *std_id = cur_timings->std_id; - return 0; - } - - return -EINVAL; -} - -/* - * vpbe_set_mode - Set mode in the current encoder using mode info - * - * Use the mode string to decide what timings to set in the encoder - * This is typically useful when fbset command is used to change the current - * timings by specifying a string to indicate the timings. - */ -static int vpbe_set_mode(struct vpbe_device *vpbe_dev, - struct vpbe_enc_mode_info *mode_info) -{ - struct vpbe_enc_mode_info *preset_mode = NULL; - struct vpbe_config *cfg = vpbe_dev->cfg; - struct v4l2_dv_timings dv_timings; - struct osd_state *osd_device; - int out_index = vpbe_dev->current_out_index; - int i; - - if (!mode_info || !mode_info->name) - return -EINVAL; - - for (i = 0; i < cfg->outputs[out_index].num_modes; i++) { - if (!strcmp(mode_info->name, - cfg->outputs[out_index].modes[i].name)) { - preset_mode = &cfg->outputs[out_index].modes[i]; - /* - * it may be one of the 3 timings type. Check and - * invoke right API - */ - if (preset_mode->timings_type & VPBE_ENC_STD) - return vpbe_s_std(vpbe_dev, - preset_mode->std_id); - if (preset_mode->timings_type & - VPBE_ENC_DV_TIMINGS) { - dv_timings = - preset_mode->dv_timings; - return vpbe_s_dv_timings(vpbe_dev, &dv_timings); - } - } - } - - /* Only custom timing should reach here */ - if (!preset_mode) - return -EINVAL; - - mutex_lock(&vpbe_dev->lock); - - osd_device = vpbe_dev->osd_device; - vpbe_dev->current_timings = *preset_mode; - osd_device->ops.set_left_margin(osd_device, - vpbe_dev->current_timings.left_margin); - osd_device->ops.set_top_margin(osd_device, - vpbe_dev->current_timings.upper_margin); - - mutex_unlock(&vpbe_dev->lock); - return 0; -} - -static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) -{ - int ret; - - ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); - if (ret) - return ret; - - /* set the default mode in the encoder */ - return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); -} - -static int platform_device_get(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct vpbe_device *vpbe_dev = data; - - if (strstr(pdev->name, "vpbe-osd")) - vpbe_dev->osd_device = platform_get_drvdata(pdev); - if (strstr(pdev->name, "vpbe-venc")) - vpbe_dev->venc_device = dev_get_platdata(&pdev->dev); - - return 0; -} - -/** - * vpbe_initialize() - Initialize the vpbe display controller - * @dev: Master and slave device ptr - * @vpbe_dev: vpbe device ptr - * - * Master frame buffer device drivers calls this to initialize vpbe - * display controller. This will then registers v4l2 device and the sub - * devices and sets a current encoder sub device for display. v4l2 display - * device driver is the master and frame buffer display device driver is - * the slave. Frame buffer display driver checks the initialized during - * probe and exit if not initialized. Returns status. - */ -static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) -{ - struct encoder_config_info *enc_info; - struct amp_config_info *amp_info; - struct v4l2_subdev **enc_subdev; - struct osd_state *osd_device; - struct i2c_adapter *i2c_adap; - int num_encoders; - int ret = 0; - int err; - int i; - - /* - * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer - * from the platform device by iteration of platform drivers and - * matching with device name - */ - if (!vpbe_dev || !dev) { - printk(KERN_ERR "Null device pointers.\n"); - return -ENODEV; - } - - if (vpbe_dev->initialized) - return 0; - - mutex_lock(&vpbe_dev->lock); - - if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { - /* We have dac clock available for platform */ - vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); - if (IS_ERR(vpbe_dev->dac_clk)) { - ret = PTR_ERR(vpbe_dev->dac_clk); - goto fail_mutex_unlock; - } - if (clk_prepare_enable(vpbe_dev->dac_clk)) { - ret = -ENODEV; - clk_put(vpbe_dev->dac_clk); - goto fail_mutex_unlock; - } - } - - /* first enable vpss clocks */ - vpss_enable_clock(VPSS_VPBE_CLOCK, 1); - - /* First register a v4l2 device */ - ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); - if (ret) { - v4l2_err(dev->driver, - "Unable to register v4l2 device.\n"); - goto fail_clk_put; - } - v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); - - err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev, - platform_device_get); - if (err < 0) { - ret = err; - goto fail_dev_unregister; - } - - vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, - vpbe_dev->cfg->venc.module_name); - /* register venc sub device */ - if (!vpbe_dev->venc) { - v4l2_err(&vpbe_dev->v4l2_dev, - "vpbe unable to init venc sub device\n"); - ret = -ENODEV; - goto fail_dev_unregister; - } - /* initialize osd device */ - osd_device = vpbe_dev->osd_device; - if (osd_device->ops.initialize) { - err = osd_device->ops.initialize(osd_device); - if (err) { - v4l2_err(&vpbe_dev->v4l2_dev, - "unable to initialize the OSD device"); - ret = -ENOMEM; - goto fail_dev_unregister; - } - } - - /* - * Register any external encoders that are configured. At index 0 we - * store venc sd index. - */ - num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; - vpbe_dev->encoders = kmalloc_array(num_encoders, - sizeof(*vpbe_dev->encoders), - GFP_KERNEL); - if (!vpbe_dev->encoders) { - ret = -ENOMEM; - goto fail_dev_unregister; - } - - i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); - for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { - if (i == 0) { - /* venc is at index 0 */ - enc_subdev = &vpbe_dev->encoders[i]; - *enc_subdev = vpbe_dev->venc; - continue; - } - enc_info = &vpbe_dev->cfg->ext_encoders[i]; - if (enc_info->is_i2c) { - enc_subdev = &vpbe_dev->encoders[i]; - *enc_subdev = v4l2_i2c_new_subdev_board( - &vpbe_dev->v4l2_dev, i2c_adap, - &enc_info->board_info, NULL); - if (*enc_subdev) - v4l2_info(&vpbe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - enc_info->module_name); - else { - v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s failed to register", - enc_info->module_name); - ret = -ENODEV; - goto fail_kfree_encoders; - } - } else - v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders currently not supported"); - } - /* Add amplifier subdevice for dm365 */ - if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) && - vpbe_dev->cfg->amp) { - amp_info = vpbe_dev->cfg->amp; - if (amp_info->is_i2c) { - vpbe_dev->amp = v4l2_i2c_new_subdev_board( - &vpbe_dev->v4l2_dev, i2c_adap, - &_info->board_info, NULL); - if (!vpbe_dev->amp) { - v4l2_err(&vpbe_dev->v4l2_dev, - "amplifier %s failed to register", - amp_info->module_name); - ret = -ENODEV; - goto fail_kfree_encoders; - } - v4l2_info(&vpbe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - amp_info->module_name); - } else { - vpbe_dev->amp = NULL; - v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers currently not supported"); - } - } else { - vpbe_dev->amp = NULL; - } - - /* set the current encoder and output to that of venc by default */ - vpbe_dev->current_sd_index = 0; - vpbe_dev->current_out_index = 0; - - mutex_unlock(&vpbe_dev->lock); - - printk(KERN_NOTICE "Setting default output to %s\n", def_output); - ret = vpbe_set_default_output(vpbe_dev); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", - def_output); - goto fail_kfree_amp; - } - - printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); - ret = vpbe_set_default_mode(vpbe_dev); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", - def_mode); - goto fail_kfree_amp; - } - vpbe_dev->initialized = 1; - /* TBD handling of bootargs for default output and mode */ - return 0; - -fail_kfree_amp: - mutex_lock(&vpbe_dev->lock); - kfree(vpbe_dev->amp); -fail_kfree_encoders: - kfree(vpbe_dev->encoders); -fail_dev_unregister: - v4l2_device_unregister(&vpbe_dev->v4l2_dev); -fail_clk_put: - if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { - clk_disable_unprepare(vpbe_dev->dac_clk); - clk_put(vpbe_dev->dac_clk); - } -fail_mutex_unlock: - mutex_unlock(&vpbe_dev->lock); - return ret; -} - -/** - * vpbe_deinitialize() - de-initialize the vpbe display controller - * @dev: Master and slave device ptr - * @vpbe_dev: vpbe device ptr - * - * vpbe_master and slave frame buffer devices calls this to de-initialize - * the display controller. It is called when master and slave device - * driver modules are removed and no longer requires the display controller. - */ -static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) -{ - v4l2_device_unregister(&vpbe_dev->v4l2_dev); - if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { - clk_disable_unprepare(vpbe_dev->dac_clk); - clk_put(vpbe_dev->dac_clk); - } - - kfree(vpbe_dev->amp); - kfree(vpbe_dev->encoders); - vpbe_dev->initialized = 0; - /* disable vpss clocks */ - vpss_enable_clock(VPSS_VPBE_CLOCK, 0); -} - -static const struct vpbe_device_ops vpbe_dev_ops = { - .enum_outputs = vpbe_enum_outputs, - .set_output = vpbe_set_output, - .get_output = vpbe_get_output, - .s_dv_timings = vpbe_s_dv_timings, - .g_dv_timings = vpbe_g_dv_timings, - .enum_dv_timings = vpbe_enum_dv_timings, - .s_std = vpbe_s_std, - .g_std = vpbe_g_std, - .initialize = vpbe_initialize, - .deinitialize = vpbe_deinitialize, - .get_mode_info = vpbe_get_current_mode_info, - .set_mode = vpbe_set_mode, -}; - -static int vpbe_probe(struct platform_device *pdev) -{ - struct vpbe_device *vpbe_dev; - struct vpbe_config *cfg; - - if (!pdev->dev.platform_data) { - v4l2_err(pdev->dev.driver, "No platform data\n"); - return -ENODEV; - } - cfg = pdev->dev.platform_data; - - if (!cfg->module_name[0] || - !cfg->osd.module_name[0] || - !cfg->venc.module_name[0]) { - v4l2_err(pdev->dev.driver, "vpbe display module names not defined\n"); - return -EINVAL; - } - - vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); - if (!vpbe_dev) - return -ENOMEM; - - vpbe_dev->cfg = cfg; - vpbe_dev->ops = vpbe_dev_ops; - vpbe_dev->pdev = &pdev->dev; - - if (cfg->outputs->num_modes > 0) - vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; - else { - kfree(vpbe_dev); - return -ENODEV; - } - - /* set the driver data in platform device */ - platform_set_drvdata(pdev, vpbe_dev); - mutex_init(&vpbe_dev->lock); - - return 0; -} - -static int vpbe_remove(struct platform_device *device) -{ - struct vpbe_device *vpbe_dev = platform_get_drvdata(device); - - kfree(vpbe_dev); - - return 0; -} - -static struct platform_driver vpbe_driver = { - .driver = { - .name = "vpbe_controller", - }, - .probe = vpbe_probe, - .remove = vpbe_remove, -}; - -module_platform_driver(vpbe_driver); diff --git a/drivers/media/platform/ti/davinci/vpbe_display.c b/drivers/media/platform/ti/davinci/vpbe_display.c deleted file mode 100644 index 9ea70817538e..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_display.c +++ /dev/null @@ -1,1510 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "vpbe_venc_regs.h" - -#define VPBE_DISPLAY_DRIVER "vpbe-v4l2" - -static int debug; - -#define VPBE_DEFAULT_NUM_BUFS 3 - -module_param(debug, int, 0644); - -static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, - struct vpbe_layer *layer); - -static int venc_is_second_field(struct vpbe_display *disp_dev) -{ - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - int ret, val; - - ret = v4l2_subdev_call(vpbe_dev->venc, - core, - command, - VENC_GET_FLD, - &val); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in getting Field ID 0\n"); - return 1; - } - return val; -} - -static void vpbe_isr_even_field(struct vpbe_display *disp_obj, - struct vpbe_layer *layer) -{ - if (layer->cur_frm == layer->next_frm) - return; - - layer->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); - /* Make cur_frm pointing to next_frm */ - layer->cur_frm = layer->next_frm; -} - -static void vpbe_isr_odd_field(struct vpbe_display *disp_obj, - struct vpbe_layer *layer) -{ - struct osd_state *osd_device = disp_obj->osd_device; - unsigned long addr; - - spin_lock(&disp_obj->dma_queue_lock); - if (list_empty(&layer->dma_queue) || - (layer->cur_frm != layer->next_frm)) { - spin_unlock(&disp_obj->dma_queue_lock); - return; - } - /* - * one field is displayed configure - * the next frame if it is available - * otherwise hold on current frame - * Get next from the buffer queue - */ - layer->next_frm = list_entry(layer->dma_queue.next, - struct vpbe_disp_buffer, list); - /* Remove that from the buffer queue */ - list_del(&layer->next_frm->list); - spin_unlock(&disp_obj->dma_queue_lock); - /* Mark state of the frame to active */ - layer->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - addr = vb2_dma_contig_plane_dma_addr(&layer->next_frm->vb.vb2_buf, 0); - osd_device->ops.start_layer(osd_device, - layer->layer_info.id, - addr, - disp_obj->cbcr_ofst); -} - -/* interrupt service routine */ -static irqreturn_t venc_isr(int irq, void *arg) -{ - struct vpbe_display *disp_dev = (struct vpbe_display *)arg; - struct vpbe_layer *layer; - static unsigned last_event; - unsigned event = 0; - int fid; - int i; - - if (!arg || !disp_dev->dev[0]) - return IRQ_HANDLED; - - if (venc_is_second_field(disp_dev)) - event |= VENC_SECOND_FIELD; - else - event |= VENC_FIRST_FIELD; - - if (event == (last_event & ~VENC_END_OF_FRAME)) { - /* - * If the display is non-interlaced, then we need to flag the - * end-of-frame event at every interrupt regardless of the - * value of the FIDST bit. We can conclude that the display is - * non-interlaced if the value of the FIDST bit is unchanged - * from the previous interrupt. - */ - event |= VENC_END_OF_FRAME; - } else if (event == VENC_SECOND_FIELD) { - /* end-of-frame for interlaced display */ - event |= VENC_END_OF_FRAME; - } - last_event = event; - - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - layer = disp_dev->dev[i]; - - if (!vb2_start_streaming_called(&layer->buffer_queue)) - continue; - - if (layer->layer_first_int) { - layer->layer_first_int = 0; - continue; - } - /* Check the field format */ - if ((V4L2_FIELD_NONE == layer->pix_fmt.field) && - (event & VENC_END_OF_FRAME)) { - /* Progressive mode */ - - vpbe_isr_even_field(disp_dev, layer); - vpbe_isr_odd_field(disp_dev, layer); - } else { - /* Interlaced mode */ - - layer->field_id ^= 1; - if (event & VENC_FIRST_FIELD) - fid = 0; - else - fid = 1; - - /* - * If field id does not match with store - * field id - */ - if (fid != layer->field_id) { - /* Make them in sync */ - layer->field_id = fid; - continue; - } - /* - * device field id and local field id are - * in sync. If this is even field - */ - if (0 == fid) - vpbe_isr_even_field(disp_dev, layer); - else /* odd field */ - vpbe_isr_odd_field(disp_dev, layer); - } - } - - return IRQ_HANDLED; -} - -/* - * vpbe_buffer_prepare() - * This is the callback function called from vb2_qbuf() function - * the buffer is prepared and user space virtual address is converted into - * physical address - */ -static int vpbe_buffer_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *q = vb->vb2_queue; - struct vpbe_layer *layer = vb2_get_drv_priv(q); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - unsigned long addr; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "vpbe_buffer_prepare\n"); - - vb2_set_plane_payload(vb, 0, layer->pix_fmt.sizeimage); - if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) - return -EINVAL; - - addr = vb2_dma_contig_plane_dma_addr(vb, 0); - if (!IS_ALIGNED(addr, 8)) { - v4l2_err(&vpbe_dev->v4l2_dev, - "buffer_prepare:offset is not aligned to 32 bytes\n"); - return -EINVAL; - } - return 0; -} - -/* - * vpbe_buffer_setup() - * This function allocates memory for the buffers - */ -static int -vpbe_buffer_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) - -{ - /* Get the file handle object and layer object */ - struct vpbe_layer *layer = vb2_get_drv_priv(vq); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); - - /* Store number of buffers allocated in numbuffer member */ - if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS) - *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers; - - if (*nplanes) - return sizes[0] < layer->pix_fmt.sizeimage ? -EINVAL : 0; - - *nplanes = 1; - sizes[0] = layer->pix_fmt.sizeimage; - - return 0; -} - -/* - * vpbe_buffer_queue() - * This function adds the buffer to DMA queue - */ -static void vpbe_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - /* Get the file handle object and layer object */ - struct vpbe_disp_buffer *buf = container_of(vbuf, - struct vpbe_disp_buffer, vb); - struct vpbe_layer *layer = vb2_get_drv_priv(vb->vb2_queue); - struct vpbe_display *disp = layer->disp_dev; - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - unsigned long flags; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "vpbe_buffer_queue\n"); - - /* add the buffer to the DMA queue */ - spin_lock_irqsave(&disp->dma_queue_lock, flags); - list_add_tail(&buf->list, &layer->dma_queue); - spin_unlock_irqrestore(&disp->dma_queue_lock, flags); -} - -static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vpbe_layer *layer = vb2_get_drv_priv(vq); - struct osd_state *osd_device = layer->disp_dev->osd_device; - int ret; - - osd_device->ops.disable_layer(osd_device, layer->layer_info.id); - - /* Get the next frame from the buffer queue */ - layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, - struct vpbe_disp_buffer, list); - /* Remove buffer from the buffer queue */ - list_del(&layer->cur_frm->list); - /* Mark state of the current frame to active */ - layer->cur_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - /* Initialize field_id and started member */ - layer->field_id = 0; - - /* Set parameters in OSD and VENC */ - ret = vpbe_set_osd_display_params(layer->disp_dev, layer); - if (ret < 0) { - struct vpbe_disp_buffer *buf, *tmp; - - vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - list_for_each_entry_safe(buf, tmp, &layer->dma_queue, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - - return ret; - } - - /* - * if request format is yuv420 semiplanar, need to - * enable both video windows - */ - layer->layer_first_int = 1; - - return ret; -} - -static void vpbe_stop_streaming(struct vb2_queue *vq) -{ - struct vpbe_layer *layer = vb2_get_drv_priv(vq); - struct osd_state *osd_device = layer->disp_dev->osd_device; - struct vpbe_display *disp = layer->disp_dev; - unsigned long flags; - - if (!vb2_is_streaming(vq)) - return; - - osd_device->ops.disable_layer(osd_device, layer->layer_info.id); - - /* release all active buffers */ - spin_lock_irqsave(&disp->dma_queue_lock, flags); - if (layer->cur_frm == layer->next_frm) { - vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } else { - if (layer->cur_frm) - vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - if (layer->next_frm) - vb2_buffer_done(&layer->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } - - while (!list_empty(&layer->dma_queue)) { - layer->next_frm = list_entry(layer->dma_queue.next, - struct vpbe_disp_buffer, list); - list_del(&layer->next_frm->list); - vb2_buffer_done(&layer->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } - spin_unlock_irqrestore(&disp->dma_queue_lock, flags); -} - -static const struct vb2_ops video_qops = { - .queue_setup = vpbe_buffer_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_prepare = vpbe_buffer_prepare, - .start_streaming = vpbe_start_streaming, - .stop_streaming = vpbe_stop_streaming, - .buf_queue = vpbe_buffer_queue, -}; - -static -struct vpbe_layer* -_vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev, - struct vpbe_layer *layer) -{ - enum vpbe_display_device_id thiswin, otherwin; - thiswin = layer->device_id; - - otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ? - VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0; - return disp_dev->dev[otherwin]; -} - -static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, - struct vpbe_layer *layer) -{ - struct osd_layer_config *cfg = &layer->layer_info.config; - struct osd_state *osd_device = disp_dev->osd_device; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - unsigned long addr; - int ret; - - addr = vb2_dma_contig_plane_dma_addr(&layer->cur_frm->vb.vb2_buf, 0); - /* Set address in the display registers */ - osd_device->ops.start_layer(osd_device, - layer->layer_info.id, - addr, - disp_dev->cbcr_ofst); - - ret = osd_device->ops.enable_layer(osd_device, - layer->layer_info.id, 0); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in enabling osd window layer 0\n"); - return -1; - } - - /* Enable the window */ - layer->layer_info.enable = 1; - if (cfg->pixfmt == PIXFMT_NV12) { - struct vpbe_layer *otherlayer = - _vpbe_display_get_other_win_layer(disp_dev, layer); - - ret = osd_device->ops.enable_layer(osd_device, - otherlayer->layer_info.id, 1); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in enabling osd window layer 1\n"); - return -1; - } - otherlayer->layer_info.enable = 1; - } - return 0; -} - -static void -vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, - struct vpbe_layer *layer, - int expected_xsize, int expected_ysize) -{ - struct display_layer_info *layer_info = &layer->layer_info; - struct v4l2_pix_format *pixfmt = &layer->pix_fmt; - struct osd_layer_config *cfg = &layer->layer_info.config; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - int calculated_xsize; - int h_exp = 0; - int v_exp = 0; - int h_scale; - int v_scale; - - v4l2_std_id standard_id = vpbe_dev->current_timings.std_id; - - /* - * Application initially set the image format. Current display - * size is obtained from the vpbe display controller. expected_xsize - * and expected_ysize are set through S_SELECTION ioctl. Based on this, - * driver will calculate the scale factors for vertical and - * horizontal direction so that the image is displayed scaled - * and expanded. Application uses expansion to display the image - * in a square pixel. Otherwise it is displayed using displays - * pixel aspect ratio.It is expected that application chooses - * the crop coordinates for cropped or scaled display. if crop - * size is less than the image size, it is displayed cropped or - * it is displayed scaled and/or expanded. - * - * to begin with, set the crop window same as expected. Later we - * will override with scaled window size - */ - - cfg->xsize = pixfmt->width; - cfg->ysize = pixfmt->height; - layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */ - layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */ - layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */ - layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */ - - if (pixfmt->width < expected_xsize) { - h_scale = vpbe_dev->current_timings.xres / pixfmt->width; - if (h_scale < 2) - h_scale = 1; - else if (h_scale >= 4) - h_scale = 4; - else - h_scale = 2; - cfg->xsize *= h_scale; - if (cfg->xsize < expected_xsize) { - if ((standard_id & V4L2_STD_525_60) || - (standard_id & V4L2_STD_625_50)) { - calculated_xsize = (cfg->xsize * - VPBE_DISPLAY_H_EXP_RATIO_N) / - VPBE_DISPLAY_H_EXP_RATIO_D; - if (calculated_xsize <= expected_xsize) { - h_exp = 1; - cfg->xsize = calculated_xsize; - } - } - } - if (h_scale == 2) - layer_info->h_zoom = ZOOM_X2; - else if (h_scale == 4) - layer_info->h_zoom = ZOOM_X4; - if (h_exp) - layer_info->h_exp = H_EXP_9_OVER_8; - } else { - /* no scaling, only cropping. Set display area to crop area */ - cfg->xsize = expected_xsize; - } - - if (pixfmt->height < expected_ysize) { - v_scale = expected_ysize / pixfmt->height; - if (v_scale < 2) - v_scale = 1; - else if (v_scale >= 4) - v_scale = 4; - else - v_scale = 2; - cfg->ysize *= v_scale; - if (cfg->ysize < expected_ysize) { - if ((standard_id & V4L2_STD_625_50)) { - calculated_xsize = (cfg->ysize * - VPBE_DISPLAY_V_EXP_RATIO_N) / - VPBE_DISPLAY_V_EXP_RATIO_D; - if (calculated_xsize <= expected_ysize) { - v_exp = 1; - cfg->ysize = calculated_xsize; - } - } - } - if (v_scale == 2) - layer_info->v_zoom = ZOOM_X2; - else if (v_scale == 4) - layer_info->v_zoom = ZOOM_X4; - if (v_exp) - layer_info->v_exp = V_EXP_6_OVER_5; - } else { - /* no scaling, only cropping. Set display area to crop area */ - cfg->ysize = expected_ysize; - } - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "crop display xsize = %d, ysize = %d\n", - cfg->xsize, cfg->ysize); -} - -static void vpbe_disp_adj_position(struct vpbe_display *disp_dev, - struct vpbe_layer *layer, - int top, int left) -{ - struct osd_layer_config *cfg = &layer->layer_info.config; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - - cfg->xpos = min((unsigned int)left, - vpbe_dev->current_timings.xres - cfg->xsize); - cfg->ypos = min((unsigned int)top, - vpbe_dev->current_timings.yres - cfg->ysize); - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "new xpos = %d, ypos = %d\n", - cfg->xpos, cfg->ypos); -} - -static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev, - struct v4l2_rect *c) -{ - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - - if ((c->width == 0) || - ((c->width + c->left) > vpbe_dev->current_timings.xres)) - c->width = vpbe_dev->current_timings.xres - c->left; - - if ((c->height == 0) || ((c->height + c->top) > - vpbe_dev->current_timings.yres)) - c->height = vpbe_dev->current_timings.yres - c->top; - - /* window height must be even for interlaced display */ - if (vpbe_dev->current_timings.interlaced) - c->height &= (~0x01); - -} - -/* - * vpbe_try_format() - * If user application provides width and height, and have bytesperline set - * to zero, driver calculates bytesperline and sizeimage based on hardware - * limits. - */ -static int vpbe_try_format(struct vpbe_display *disp_dev, - struct v4l2_pix_format *pixfmt, int check) -{ - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - int min_height = 1; - int min_width = 32; - int max_height; - int max_width; - int bpp; - - if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) && - (pixfmt->pixelformat != V4L2_PIX_FMT_NV12)) - /* choose default as V4L2_PIX_FMT_UYVY */ - pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; - - /* Check the field format */ - if ((pixfmt->field != V4L2_FIELD_INTERLACED) && - (pixfmt->field != V4L2_FIELD_NONE)) { - if (vpbe_dev->current_timings.interlaced) - pixfmt->field = V4L2_FIELD_INTERLACED; - else - pixfmt->field = V4L2_FIELD_NONE; - } - - if (pixfmt->field == V4L2_FIELD_INTERLACED) - min_height = 2; - - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) - bpp = 1; - else - bpp = 2; - - max_width = vpbe_dev->current_timings.xres; - max_height = vpbe_dev->current_timings.yres; - - min_width /= bpp; - - if (!pixfmt->width || (pixfmt->width < min_width) || - (pixfmt->width > max_width)) { - pixfmt->width = vpbe_dev->current_timings.xres; - } - - if (!pixfmt->height || (pixfmt->height < min_height) || - (pixfmt->height > max_height)) { - pixfmt->height = vpbe_dev->current_timings.yres; - } - - if (pixfmt->bytesperline < (pixfmt->width * bpp)) - pixfmt->bytesperline = pixfmt->width * bpp; - - /* Make the bytesperline 32 byte aligned */ - pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31); - - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height + - (pixfmt->bytesperline * pixfmt->height >> 1); - else - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - - return 0; -} - -static int vpbe_display_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - snprintf(cap->driver, sizeof(cap->driver), "%s", - dev_name(vpbe_dev->pdev)); - strscpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card)); - - return 0; -} - -static int vpbe_display_s_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - struct osd_layer_config *cfg = &layer->layer_info.config; - struct osd_state *osd_device = disp_dev->osd_device; - struct v4l2_rect rect = sel->r; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_S_SELECTION, layer id = %d\n", layer->device_id); - - if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - if (rect.top < 0) - rect.top = 0; - if (rect.left < 0) - rect.left = 0; - - vpbe_disp_check_window_params(disp_dev, &rect); - - osd_device->ops.get_layer_config(osd_device, - layer->layer_info.id, cfg); - - vpbe_disp_calculate_scale_factor(disp_dev, layer, - rect.width, - rect.height); - vpbe_disp_adj_position(disp_dev, layer, rect.top, - rect.left); - ret = osd_device->ops.set_layer_config(osd_device, - layer->layer_info.id, cfg); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in set layer config:\n"); - return -EINVAL; - } - - /* apply zooming and h or v expansion */ - osd_device->ops.set_zoom(osd_device, - layer->layer_info.id, - layer->layer_info.h_zoom, - layer->layer_info.v_zoom); - ret = osd_device->ops.set_vid_expansion(osd_device, - layer->layer_info.h_exp, - layer->layer_info.v_exp); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in set vid expansion:\n"); - return -EINVAL; - } - - if ((layer->layer_info.h_zoom != ZOOM_X1) || - (layer->layer_info.v_zoom != ZOOM_X1) || - (layer->layer_info.h_exp != H_EXP_OFF) || - (layer->layer_info.v_exp != V_EXP_OFF)) - /* Enable expansion filter */ - osd_device->ops.set_interpolation_filter(osd_device, 1); - else - osd_device->ops.set_interpolation_filter(osd_device, 0); - - sel->r = rect; - return 0; -} - -static int vpbe_display_g_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct osd_layer_config *cfg = &layer->layer_info.config; - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - struct osd_state *osd_device = layer->disp_dev->osd_device; - struct v4l2_rect *rect = &sel->r; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_G_SELECTION, layer id = %d\n", - layer->device_id); - - if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - osd_device->ops.get_layer_config(osd_device, - layer->layer_info.id, cfg); - rect->top = cfg->ypos; - rect->left = cfg->xpos; - rect->width = cfg->xsize; - rect->height = cfg->ysize; - break; - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - rect->left = 0; - rect->top = 0; - rect->width = vpbe_dev->current_timings.xres; - rect->height = vpbe_dev->current_timings.yres; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vpbe_display_g_pixelaspect(struct file *file, void *priv, - int type, struct v4l2_fract *f) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); - - if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - *f = vpbe_dev->current_timings.aspect; - return 0; -} - -static int vpbe_display_g_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_G_FMT, layer id = %d\n", - layer->device_id); - - /* If buffer type is video output */ - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { - v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); - return -EINVAL; - } - /* Fill in the information about format */ - fmt->fmt.pix = layer->pix_fmt; - - return 0; -} - -static int vpbe_display_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_ENUM_FMT, layer id = %d\n", - layer->device_id); - if (fmt->index > 1) { - v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n"); - return -EINVAL; - } - - /* Fill in the information about format */ - if (fmt->index == 0) - fmt->pixelformat = V4L2_PIX_FMT_UYVY; - else - fmt->pixelformat = V4L2_PIX_FMT_NV12; - - return 0; -} - -static int vpbe_display_s_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - struct osd_layer_config *cfg = &layer->layer_info.config; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - struct osd_state *osd_device = disp_dev->osd_device; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "VIDIOC_S_FMT, layer id = %d\n", - layer->device_id); - - if (vb2_is_busy(&layer->buffer_queue)) - return -EBUSY; - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n"); - return -EINVAL; - } - /* Check for valid pixel format */ - ret = vpbe_try_format(disp_dev, pixfmt, 1); - if (ret) - return ret; - - /* YUV420 is requested, check availability of the - other video window */ - - layer->pix_fmt = *pixfmt; - if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) { - struct vpbe_layer *otherlayer; - - otherlayer = _vpbe_display_get_other_win_layer(disp_dev, layer); - /* if other layer is available, only - * claim it, do not configure it - */ - ret = osd_device->ops.request_layer(osd_device, - otherlayer->layer_info.id); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Display Manager failed to allocate layer\n"); - return -EBUSY; - } - } - - /* Get osd layer config */ - osd_device->ops.get_layer_config(osd_device, - layer->layer_info.id, cfg); - /* Store the pixel format in the layer object */ - cfg->xsize = pixfmt->width; - cfg->ysize = pixfmt->height; - cfg->line_length = pixfmt->bytesperline; - cfg->ypos = 0; - cfg->xpos = 0; - cfg->interlaced = vpbe_dev->current_timings.interlaced; - - if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat) - cfg->pixfmt = PIXFMT_YCBCRI; - - /* Change of the default pixel format for both video windows */ - if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) { - struct vpbe_layer *otherlayer; - cfg->pixfmt = PIXFMT_NV12; - otherlayer = _vpbe_display_get_other_win_layer(disp_dev, - layer); - otherlayer->layer_info.config.pixfmt = PIXFMT_NV12; - } - - /* Set the layer config in the osd window */ - ret = osd_device->ops.set_layer_config(osd_device, - layer->layer_info.id, cfg); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Error in S_FMT params:\n"); - return -EINVAL; - } - - /* Readback and fill the local copy of current pix format */ - osd_device->ops.get_layer_config(osd_device, - layer->layer_info.id, cfg); - - return 0; -} - -static int vpbe_display_try_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n"); - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { - v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); - return -EINVAL; - } - - /* Check for valid field format */ - return vpbe_try_format(disp_dev, pixfmt, 0); - -} - -/* - * vpbe_display_s_std - Set the given standard in the encoder - * - * Sets the standard if supported by the current encoder. Return the status. - * 0 - success & -EINVAL on error - */ -static int vpbe_display_s_std(struct file *file, void *priv, - v4l2_std_id std_id) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n"); - - if (vb2_is_busy(&layer->buffer_queue)) - return -EBUSY; - - if (vpbe_dev->ops.s_std) { - ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set standard for sub devices\n"); - return -EINVAL; - } - } else { - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_g_std - Get the standard in the current encoder - * - * Get the standard in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int vpbe_display_g_std(struct file *file, void *priv, - v4l2_std_id *std_id) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n"); - - /* Get the standard from the current encoder */ - if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { - *std_id = vpbe_dev->current_timings.std_id; - return 0; - } - - return -EINVAL; -} - -/* - * vpbe_display_enum_output - enumerate outputs - * - * Enumerates the outputs available at the vpbe display - * returns the status, -EINVAL if end of output list - */ -static int vpbe_display_enum_output(struct file *file, void *priv, - struct v4l2_output *output) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); - - /* Enumerate outputs */ - if (!vpbe_dev->ops.enum_outputs) - return -EINVAL; - - ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); - if (ret) { - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "Failed to enumerate outputs\n"); - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_s_output - Set output to - * the output specified by the index - */ -static int vpbe_display_s_output(struct file *file, void *priv, - unsigned int i) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n"); - - if (vb2_is_busy(&layer->buffer_queue)) - return -EBUSY; - - if (!vpbe_dev->ops.set_output) - return -EINVAL; - - ret = vpbe_dev->ops.set_output(vpbe_dev, i); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set output for sub devices\n"); - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_g_output - Get output from subdevice - * for a given by the index - */ -static int vpbe_display_g_output(struct file *file, void *priv, - unsigned int *i) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n"); - /* Get the standard from the current encoder */ - *i = vpbe_dev->current_out_index; - - return 0; -} - -/* - * vpbe_display_enum_dv_timings - Enumerate the dv timings - * - * enum the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int -vpbe_display_enum_dv_timings(struct file *file, void *priv, - struct v4l2_enum_dv_timings *timings) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_TIMINGS\n"); - - /* Enumerate outputs */ - if (!vpbe_dev->ops.enum_dv_timings) - return -EINVAL; - - ret = vpbe_dev->ops.enum_dv_timings(vpbe_dev, timings); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to enumerate dv timings info\n"); - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_s_dv_timings - Set the dv timings - * - * Set the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int -vpbe_display_s_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - int ret; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_TIMINGS\n"); - - if (vb2_is_busy(&layer->buffer_queue)) - return -EBUSY; - - /* Set the given standard in the encoder */ - if (!vpbe_dev->ops.s_dv_timings) - return -EINVAL; - - ret = vpbe_dev->ops.s_dv_timings(vpbe_dev, timings); - if (ret) { - v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set the dv timings info\n"); - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_g_dv_timings - Set the dv timings - * - * Get the timings in the current encoder. Return the status. 0 - success - * -EINVAL on error - */ -static int -vpbe_display_g_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *dv_timings) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_TIMINGS\n"); - - /* Get the given standard in the encoder */ - - if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_TIMINGS) { - *dv_timings = vpbe_dev->current_timings.dv_timings; - } else { - return -EINVAL; - } - - return 0; -} - -/* - * vpbe_display_open() - * It creates object of file handle structure and stores it in private_data - * member of filepointer - */ -static int vpbe_display_open(struct file *file) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - struct osd_state *osd_device = disp_dev->osd_device; - int err; - - /* creating context for file descriptor */ - err = v4l2_fh_open(file); - if (err) { - v4l2_err(&vpbe_dev->v4l2_dev, "v4l2_fh_open failed\n"); - return err; - } - - /* leaving if layer is already initialized */ - if (!v4l2_fh_is_singular_file(file)) - return err; - - if (!layer->usrs) { - if (mutex_lock_interruptible(&layer->opslock)) - return -ERESTARTSYS; - /* First claim the layer for this device */ - err = osd_device->ops.request_layer(osd_device, - layer->layer_info.id); - mutex_unlock(&layer->opslock); - if (err < 0) { - /* Couldn't get layer */ - v4l2_err(&vpbe_dev->v4l2_dev, - "Display Manager failed to allocate layer\n"); - v4l2_fh_release(file); - return -EINVAL; - } - } - /* Increment layer usrs counter */ - layer->usrs++; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "vpbe display device opened successfully\n"); - return 0; -} - -/* - * vpbe_display_release() - * This function deletes buffer queue, frees the buffers and the davinci - * display file * handle - */ -static int vpbe_display_release(struct file *file) -{ - struct vpbe_layer *layer = video_drvdata(file); - struct osd_layer_config *cfg = &layer->layer_info.config; - struct vpbe_display *disp_dev = layer->disp_dev; - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - struct osd_state *osd_device = disp_dev->osd_device; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n"); - - mutex_lock(&layer->opslock); - - osd_device->ops.disable_layer(osd_device, - layer->layer_info.id); - /* Decrement layer usrs counter */ - layer->usrs--; - /* If this file handle has initialize encoder device, reset it */ - if (!layer->usrs) { - if (cfg->pixfmt == PIXFMT_NV12) { - struct vpbe_layer *otherlayer; - otherlayer = - _vpbe_display_get_other_win_layer(disp_dev, layer); - osd_device->ops.disable_layer(osd_device, - otherlayer->layer_info.id); - osd_device->ops.release_layer(osd_device, - otherlayer->layer_info.id); - } - osd_device->ops.disable_layer(osd_device, - layer->layer_info.id); - osd_device->ops.release_layer(osd_device, - layer->layer_info.id); - } - - _vb2_fop_release(file, NULL); - mutex_unlock(&layer->opslock); - - disp_dev->cbcr_ofst = 0; - - return 0; -} - -/* vpbe capture ioctl operations */ -static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { - .vidioc_querycap = vpbe_display_querycap, - .vidioc_g_fmt_vid_out = vpbe_display_g_fmt, - .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt, - .vidioc_s_fmt_vid_out = vpbe_display_s_fmt, - .vidioc_try_fmt_vid_out = vpbe_display_try_fmt, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_expbuf = vb2_ioctl_expbuf, - - .vidioc_g_pixelaspect = vpbe_display_g_pixelaspect, - .vidioc_g_selection = vpbe_display_g_selection, - .vidioc_s_selection = vpbe_display_s_selection, - - .vidioc_s_std = vpbe_display_s_std, - .vidioc_g_std = vpbe_display_g_std, - - .vidioc_enum_output = vpbe_display_enum_output, - .vidioc_s_output = vpbe_display_s_output, - .vidioc_g_output = vpbe_display_g_output, - - .vidioc_s_dv_timings = vpbe_display_s_dv_timings, - .vidioc_g_dv_timings = vpbe_display_g_dv_timings, - .vidioc_enum_dv_timings = vpbe_display_enum_dv_timings, -}; - -static const struct v4l2_file_operations vpbe_fops = { - .owner = THIS_MODULE, - .open = vpbe_display_open, - .release = vpbe_display_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vb2_fop_mmap, - .poll = vb2_fop_poll, -}; - -static int vpbe_device_get(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct vpbe_display *vpbe_disp = data; - - if (strcmp("vpbe_controller", pdev->name) == 0) - vpbe_disp->vpbe_dev = platform_get_drvdata(pdev); - - if (strstr(pdev->name, "vpbe-osd")) - vpbe_disp->osd_device = platform_get_drvdata(pdev); - - return 0; -} - -static int init_vpbe_layer(int i, struct vpbe_display *disp_dev, - struct platform_device *pdev) -{ - struct vpbe_layer *vpbe_display_layer = NULL; - struct video_device *vbd = NULL; - - /* Allocate memory for four plane display objects */ - disp_dev->dev[i] = kzalloc(sizeof(*disp_dev->dev[i]), GFP_KERNEL); - if (!disp_dev->dev[i]) - return -ENOMEM; - - spin_lock_init(&disp_dev->dev[i]->irqlock); - mutex_init(&disp_dev->dev[i]->opslock); - - /* Get the pointer to the layer object */ - vpbe_display_layer = disp_dev->dev[i]; - vbd = &vpbe_display_layer->video_dev; - /* Initialize field of video device */ - vbd->release = video_device_release_empty; - vbd->fops = &vpbe_fops; - vbd->ioctl_ops = &vpbe_ioctl_ops; - vbd->minor = -1; - vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; - vbd->lock = &vpbe_display_layer->opslock; - vbd->vfl_dir = VFL_DIR_TX; - vbd->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - - if (disp_dev->vpbe_dev->current_timings.timings_type & - VPBE_ENC_STD) - vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); - - snprintf(vbd->name, sizeof(vbd->name), - "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", - (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff, - (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff, - (VPBE_DISPLAY_VERSION_CODE) & 0xff); - - vpbe_display_layer->device_id = i; - - vpbe_display_layer->layer_info.id = - ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1); - - - return 0; -} - -static int register_device(struct vpbe_layer *vpbe_display_layer, - struct vpbe_display *disp_dev, - struct platform_device *pdev) -{ - int err; - - v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, - "Trying to register VPBE display device.\n"); - v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, - "layer=%p,layer->video_dev=%p\n", - vpbe_display_layer, - &vpbe_display_layer->video_dev); - - vpbe_display_layer->video_dev.queue = &vpbe_display_layer->buffer_queue; - err = video_register_device(&vpbe_display_layer->video_dev, - VFL_TYPE_VIDEO, - -1); - if (err) - return -ENODEV; - - vpbe_display_layer->disp_dev = disp_dev; - /* set the driver data in platform device */ - platform_set_drvdata(pdev, disp_dev); - video_set_drvdata(&vpbe_display_layer->video_dev, - vpbe_display_layer); - - return 0; -} - - - -/* - * vpbe_display_probe() - * This function creates device entries by register itself to the V4L2 driver - * and initializes fields of each layer objects - */ -static int vpbe_display_probe(struct platform_device *pdev) -{ - struct vpbe_display *disp_dev; - struct v4l2_device *v4l2_dev; - struct resource *res = NULL; - struct vb2_queue *q; - int k; - int i; - int err; - int irq; - - printk(KERN_DEBUG "vpbe_display_probe\n"); - /* Allocate memory for vpbe_display */ - disp_dev = devm_kzalloc(&pdev->dev, sizeof(*disp_dev), GFP_KERNEL); - if (!disp_dev) - return -ENOMEM; - - spin_lock_init(&disp_dev->dma_queue_lock); - /* - * Scan all the platform devices to find the vpbe - * controller device and get the vpbe_dev object - */ - err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev, - vpbe_device_get); - if (err < 0) - return err; - - v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; - /* Initialize the vpbe display controller */ - if (disp_dev->vpbe_dev->ops.initialize) { - err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev, - disp_dev->vpbe_dev); - if (err) { - v4l2_err(v4l2_dev, "Error initing vpbe\n"); - err = -ENOMEM; - goto probe_out; - } - } - - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - if (init_vpbe_layer(i, disp_dev, pdev)) { - err = -ENODEV; - goto probe_out; - } - } - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - v4l2_err(v4l2_dev, "Unable to get VENC interrupt resource\n"); - err = -ENODEV; - goto probe_out; - } - - irq = res->start; - err = devm_request_irq(&pdev->dev, irq, venc_isr, 0, - VPBE_DISPLAY_DRIVER, disp_dev); - if (err) { - v4l2_err(v4l2_dev, "VPBE IRQ request failed\n"); - goto probe_out; - } - - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - /* initialize vb2 queue */ - q = &disp_dev->dev[i]->buffer_queue; - memset(q, 0, sizeof(*q)); - q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->drv_priv = disp_dev->dev[i]; - q->ops = &video_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct vpbe_disp_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 1; - q->lock = &disp_dev->dev[i]->opslock; - q->dev = disp_dev->vpbe_dev->pdev; - err = vb2_queue_init(q); - if (err) { - v4l2_err(v4l2_dev, "vb2_queue_init() failed\n"); - goto probe_out; - } - - INIT_LIST_HEAD(&disp_dev->dev[i]->dma_queue); - - if (register_device(disp_dev->dev[i], disp_dev, pdev)) { - err = -ENODEV; - goto probe_out; - } - } - - v4l2_dbg(1, debug, v4l2_dev, - "Successfully completed the probing of vpbe v4l2 device\n"); - - return 0; - -probe_out: - for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { - /* Unregister video device */ - if (disp_dev->dev[k]) { - video_unregister_device(&disp_dev->dev[k]->video_dev); - kfree(disp_dev->dev[k]); - } - } - return err; -} - -/* - * vpbe_display_remove() - * It un-register hardware layer from V4L2 driver - */ -static int vpbe_display_remove(struct platform_device *pdev) -{ - struct vpbe_layer *vpbe_display_layer; - struct vpbe_display *disp_dev = platform_get_drvdata(pdev); - struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; - int i; - - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); - - /* deinitialize the vpbe display controller */ - if (vpbe_dev->ops.deinitialize) - vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); - /* un-register device */ - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - /* Get the pointer to the layer object */ - vpbe_display_layer = disp_dev->dev[i]; - /* Unregister video device */ - video_unregister_device(&vpbe_display_layer->video_dev); - - } - for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { - kfree(disp_dev->dev[i]); - disp_dev->dev[i] = NULL; - } - - return 0; -} - -static struct platform_driver vpbe_display_driver = { - .driver = { - .name = VPBE_DISPLAY_DRIVER, - .bus = &platform_bus_type, - }, - .probe = vpbe_display_probe, - .remove = vpbe_display_remove, -}; - -module_platform_driver(vpbe_display_driver); - -MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/platform/ti/davinci/vpbe_osd.c b/drivers/media/platform/ti/davinci/vpbe_osd.c deleted file mode 100644 index 32f7ef547c82..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_osd.c +++ /dev/null @@ -1,1582 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2007-2010 Texas Instruments Inc - * Copyright (C) 2007 MontaVista Software, Inc. - * - * Andy Lowe (alowe@mvista.com), MontaVista Software - * - Initial version - * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd. - * - ported to sub device interface - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include "vpbe_osd_regs.h" - -#define MODULE_NAME "davinci-vpbe-osd" - -static const struct platform_device_id vpbe_osd_devtype[] = { - { - .name = DM644X_VPBE_OSD_SUBDEV_NAME, - .driver_data = VPBE_VERSION_1, - }, { - .name = DM365_VPBE_OSD_SUBDEV_NAME, - .driver_data = VPBE_VERSION_2, - }, { - .name = DM355_VPBE_OSD_SUBDEV_NAME, - .driver_data = VPBE_VERSION_3, - }, - { - /* sentinel */ - } -}; - -MODULE_DEVICE_TABLE(platform, vpbe_osd_devtype); - -/* register access routines */ -static inline u32 __always_unused osd_read(struct osd_state *sd, u32 offset) -{ - struct osd_state *osd = sd; - - return readl(osd->osd_base + offset); -} - -static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset) -{ - struct osd_state *osd = sd; - - writel(val, osd->osd_base + offset); - - return val; -} - -static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset) -{ - struct osd_state *osd = sd; - - void __iomem *addr = osd->osd_base + offset; - u32 val = readl(addr) | mask; - - writel(val, addr); - - return val; -} - -static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset) -{ - struct osd_state *osd = sd; - - void __iomem *addr = osd->osd_base + offset; - u32 val = readl(addr) & ~mask; - - writel(val, addr); - - return val; -} - -static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, - u32 offset) -{ - struct osd_state *osd = sd; - - void __iomem *addr = osd->osd_base + offset; - u32 new_val = (readl(addr) & ~mask) | (val & mask); - - writel(new_val, addr); - - return new_val; -} - -/* define some macros for layer and pixfmt classification */ -#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1)) -#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1)) -#define is_rgb_pixfmt(pixfmt) \ - (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888)) -#define is_yc_pixfmt(pixfmt) \ - (((pixfmt) == PIXFMT_YCBCRI) || ((pixfmt) == PIXFMT_YCRCBI) || \ - ((pixfmt) == PIXFMT_NV12)) -#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X -#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5) - -/** - * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446 - * @sd: ptr to struct osd_state - * @field_inversion: inversion flag - * @fb_base_phys: frame buffer address - * @lconfig: ptr to layer config - * - * This routine implements a workaround for the field signal inversion silicon - * erratum described in Advisory 1.3.8 for the DM6446. The fb_base_phys and - * lconfig parameters apply to the vid0 window. This routine should be called - * whenever the vid0 layer configuration or start address is modified, or when - * the OSD field inversion setting is modified. - * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or - * 0 otherwise - */ -static int _osd_dm6446_vid0_pingpong(struct osd_state *sd, - int field_inversion, - unsigned long fb_base_phys, - const struct osd_layer_config *lconfig) -{ - struct osd_platform_data *pdata; - - pdata = (struct osd_platform_data *)sd->dev->platform_data; - if (pdata != NULL && pdata->field_inv_wa_enable) { - - if (!field_inversion || !lconfig->interlaced) { - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); - osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR); - osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0, - OSD_MISCCTL); - return 0; - } else { - unsigned miscctl = OSD_MISCCTL_PPRV; - - osd_write(sd, - (fb_base_phys & ~0x1F) - lconfig->line_length, - OSD_VIDWIN0ADR); - osd_write(sd, - (fb_base_phys & ~0x1F) + lconfig->line_length, - OSD_PPVWIN0ADR); - osd_modify(sd, - OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl, - OSD_MISCCTL); - - return 1; - } - } - - return 0; -} - -static void _osd_set_field_inversion(struct osd_state *sd, int enable) -{ - unsigned fsinv = 0; - - if (enable) - fsinv = OSD_MODE_FSINV; - - osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE); -} - -static void _osd_set_blink_attribute(struct osd_state *sd, int enable, - enum osd_blink_interval blink) -{ - u32 osdatrmd = 0; - - if (enable) { - osdatrmd |= OSD_OSDATRMD_BLNK; - osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT; - } - /* caller must ensure that OSD1 is configured in attribute mode */ - osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd, - OSD_OSDATRMD); -} - -static void _osd_set_rom_clut(struct osd_state *sd, - enum osd_rom_clut rom_clut) -{ - if (rom_clut == ROM_CLUT0) - osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); - else - osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); -} - -static void _osd_set_palette_map(struct osd_state *sd, - enum osd_win_layer osdwin, - unsigned char pixel_value, - unsigned char clut_index, - enum osd_pix_format pixfmt) -{ - static const int map_2bpp[] = { 0, 5, 10, 15 }; - static const int map_1bpp[] = { 0, 15 }; - int bmp_offset; - int bmp_shift; - int bmp_mask; - int bmp_reg; - - switch (pixfmt) { - case PIXFMT_1BPP: - bmp_reg = map_1bpp[pixel_value & 0x1]; - break; - case PIXFMT_2BPP: - bmp_reg = map_2bpp[pixel_value & 0x3]; - break; - case PIXFMT_4BPP: - bmp_reg = pixel_value & 0xf; - break; - default: - return; - } - - switch (osdwin) { - case OSDWIN_OSD0: - bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32); - break; - case OSDWIN_OSD1: - bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32); - break; - default: - return; - } - - if (bmp_reg & 1) { - bmp_shift = 8; - bmp_mask = 0xff << 8; - } else { - bmp_shift = 0; - bmp_mask = 0xff; - } - - osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset); -} - -static void _osd_set_rec601_attenuation(struct osd_state *sd, - enum osd_win_layer osdwin, int enable) -{ - switch (osdwin) { - case OSDWIN_OSD0: - osd_modify(sd, OSD_OSDWIN0MD_ATN0E, - enable ? OSD_OSDWIN0MD_ATN0E : 0, - OSD_OSDWIN0MD); - if (sd->vpbe_type == VPBE_VERSION_1) - osd_modify(sd, OSD_OSDWIN0MD_ATN0E, - enable ? OSD_OSDWIN0MD_ATN0E : 0, - OSD_OSDWIN0MD); - else if ((sd->vpbe_type == VPBE_VERSION_3) || - (sd->vpbe_type == VPBE_VERSION_2)) - osd_modify(sd, OSD_EXTMODE_ATNOSD0EN, - enable ? OSD_EXTMODE_ATNOSD0EN : 0, - OSD_EXTMODE); - break; - case OSDWIN_OSD1: - osd_modify(sd, OSD_OSDWIN1MD_ATN1E, - enable ? OSD_OSDWIN1MD_ATN1E : 0, - OSD_OSDWIN1MD); - if (sd->vpbe_type == VPBE_VERSION_1) - osd_modify(sd, OSD_OSDWIN1MD_ATN1E, - enable ? OSD_OSDWIN1MD_ATN1E : 0, - OSD_OSDWIN1MD); - else if ((sd->vpbe_type == VPBE_VERSION_3) || - (sd->vpbe_type == VPBE_VERSION_2)) - osd_modify(sd, OSD_EXTMODE_ATNOSD1EN, - enable ? OSD_EXTMODE_ATNOSD1EN : 0, - OSD_EXTMODE); - break; - } -} - -static void _osd_set_blending_factor(struct osd_state *sd, - enum osd_win_layer osdwin, - enum osd_blending_factor blend) -{ - switch (osdwin) { - case OSDWIN_OSD0: - osd_modify(sd, OSD_OSDWIN0MD_BLND0, - blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD); - break; - case OSDWIN_OSD1: - osd_modify(sd, OSD_OSDWIN1MD_BLND1, - blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD); - break; - } -} - -static void _osd_enable_rgb888_pixblend(struct osd_state *sd, - enum osd_win_layer osdwin) -{ - - osd_modify(sd, OSD_MISCCTL_BLDSEL, 0, OSD_MISCCTL); - switch (osdwin) { - case OSDWIN_OSD0: - osd_modify(sd, OSD_EXTMODE_OSD0BLDCHR, - OSD_EXTMODE_OSD0BLDCHR, OSD_EXTMODE); - break; - case OSDWIN_OSD1: - osd_modify(sd, OSD_EXTMODE_OSD1BLDCHR, - OSD_EXTMODE_OSD1BLDCHR, OSD_EXTMODE); - break; - } -} - -static void _osd_enable_color_key(struct osd_state *sd, - enum osd_win_layer osdwin, - unsigned colorkey, - enum osd_pix_format pixfmt) -{ - switch (pixfmt) { - case PIXFMT_1BPP: - case PIXFMT_2BPP: - case PIXFMT_4BPP: - case PIXFMT_8BPP: - if (sd->vpbe_type == VPBE_VERSION_3) { - switch (osdwin) { - case OSDWIN_OSD0: - osd_modify(sd, OSD_TRANSPBMPIDX_BMP0, - colorkey << - OSD_TRANSPBMPIDX_BMP0_SHIFT, - OSD_TRANSPBMPIDX); - break; - case OSDWIN_OSD1: - osd_modify(sd, OSD_TRANSPBMPIDX_BMP1, - colorkey << - OSD_TRANSPBMPIDX_BMP1_SHIFT, - OSD_TRANSPBMPIDX); - break; - } - } - break; - case PIXFMT_RGB565: - if (sd->vpbe_type == VPBE_VERSION_1) - osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, - OSD_TRANSPVAL); - else if (sd->vpbe_type == VPBE_VERSION_3) - osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL, - OSD_TRANSPVALL); - break; - case PIXFMT_YCBCRI: - case PIXFMT_YCRCBI: - if (sd->vpbe_type == VPBE_VERSION_3) - osd_modify(sd, OSD_TRANSPVALU_Y, colorkey, - OSD_TRANSPVALU); - break; - case PIXFMT_RGB888: - if (sd->vpbe_type == VPBE_VERSION_3) { - osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL, - OSD_TRANSPVALL); - osd_modify(sd, OSD_TRANSPVALU_RGBU, colorkey >> 16, - OSD_TRANSPVALU); - } - break; - default: - break; - } - - switch (osdwin) { - case OSDWIN_OSD0: - osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); - break; - case OSDWIN_OSD1: - osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); - break; - } -} - -static void _osd_disable_color_key(struct osd_state *sd, - enum osd_win_layer osdwin) -{ - switch (osdwin) { - case OSDWIN_OSD0: - osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); - break; - case OSDWIN_OSD1: - osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); - break; - } -} - -static void _osd_set_osd_clut(struct osd_state *sd, - enum osd_win_layer osdwin, - enum osd_clut clut) -{ - u32 winmd = 0; - - switch (osdwin) { - case OSDWIN_OSD0: - if (clut == RAM_CLUT) - winmd |= OSD_OSDWIN0MD_CLUTS0; - osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD); - break; - case OSDWIN_OSD1: - if (clut == RAM_CLUT) - winmd |= OSD_OSDWIN1MD_CLUTS1; - osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD); - break; - } -} - -static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer, - enum osd_zoom_factor h_zoom, - enum osd_zoom_factor v_zoom) -{ - u32 winmd = 0; - - switch (layer) { - case WIN_OSD0: - winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT); - winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT); - osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd, - OSD_OSDWIN0MD); - break; - case WIN_VID0: - winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT); - winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT); - osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd, - OSD_VIDWINMD); - break; - case WIN_OSD1: - winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT); - winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT); - osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd, - OSD_OSDWIN1MD); - break; - case WIN_VID1: - winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT); - winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT); - osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd, - OSD_VIDWINMD); - break; - } -} - -static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer) -{ - switch (layer) { - case WIN_OSD0: - osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); - break; - case WIN_VID0: - osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); - break; - case WIN_OSD1: - /* disable attribute mode as well as disabling the window */ - osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, - OSD_OSDWIN1MD); - break; - case WIN_VID1: - osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); - break; - } -} - -static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - if (!win->is_enabled) { - spin_unlock_irqrestore(&osd->lock, flags); - return; - } - win->is_enabled = 0; - - _osd_disable_layer(sd, layer); - - spin_unlock_irqrestore(&osd->lock, flags); -} - -static void _osd_enable_attribute_mode(struct osd_state *sd) -{ - /* enable attribute mode for OSD1 */ - osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD); -} - -static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer) -{ - switch (layer) { - case WIN_OSD0: - osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); - break; - case WIN_VID0: - osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); - break; - case WIN_OSD1: - /* enable OSD1 and disable attribute mode */ - osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, - OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD); - break; - case WIN_VID1: - osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); - break; - } -} - -static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, - int otherwin) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - struct osd_layer_config *cfg = &win->lconfig; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - /* - * use otherwin flag to know this is the other vid window - * in YUV420 mode, if is, skip this check - */ - if (!otherwin && (!win->is_allocated || - !win->fb_base_phys || - !cfg->line_length || - !cfg->xsize || - !cfg->ysize)) { - spin_unlock_irqrestore(&osd->lock, flags); - return -1; - } - - if (win->is_enabled) { - spin_unlock_irqrestore(&osd->lock, flags); - return 0; - } - win->is_enabled = 1; - - if (cfg->pixfmt != PIXFMT_OSD_ATTR) - _osd_enable_layer(sd, layer); - else { - _osd_enable_attribute_mode(sd); - _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink); - } - - spin_unlock_irqrestore(&osd->lock, flags); - - return 0; -} - -#define OSD_SRC_ADDR_HIGH4 0x7800000 -#define OSD_SRC_ADDR_HIGH7 0x7F0000 -#define OSD_SRCADD_OFSET_SFT 23 -#define OSD_SRCADD_ADD_SFT 16 -#define OSD_WINADL_MASK 0xFFFF -#define OSD_WINOFST_MASK 0x1000 -#define VPBE_REG_BASE 0x80000000 - -static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, - unsigned long fb_base_phys, - unsigned long cbcr_ofst) -{ - - if (sd->vpbe_type == VPBE_VERSION_1) { - switch (layer) { - case WIN_OSD0: - osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); - break; - case WIN_VID0: - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); - break; - case WIN_OSD1: - osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); - break; - case WIN_VID1: - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); - break; - } - } else if (sd->vpbe_type == VPBE_VERSION_3) { - unsigned long fb_offset_32 = - (fb_base_phys - VPBE_REG_BASE) >> 5; - - switch (layer) { - case WIN_OSD0: - osd_modify(sd, OSD_OSDWINADH_O0AH, - fb_offset_32 >> (OSD_SRCADD_ADD_SFT - - OSD_OSDWINADH_O0AH_SHIFT), - OSD_OSDWINADH); - osd_write(sd, fb_offset_32 & OSD_OSDWIN0ADL_O0AL, - OSD_OSDWIN0ADL); - break; - case WIN_VID0: - osd_modify(sd, OSD_VIDWINADH_V0AH, - fb_offset_32 >> (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V0AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_VIDWIN0ADL_V0AL, - OSD_VIDWIN0ADL); - break; - case WIN_OSD1: - osd_modify(sd, OSD_OSDWINADH_O1AH, - fb_offset_32 >> (OSD_SRCADD_ADD_SFT - - OSD_OSDWINADH_O1AH_SHIFT), - OSD_OSDWINADH); - osd_write(sd, fb_offset_32 & OSD_OSDWIN1ADL_O1AL, - OSD_OSDWIN1ADL); - break; - case WIN_VID1: - osd_modify(sd, OSD_VIDWINADH_V1AH, - fb_offset_32 >> (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V1AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_VIDWIN1ADL_V1AL, - OSD_VIDWIN1ADL); - break; - } - } else if (sd->vpbe_type == VPBE_VERSION_2) { - struct osd_window_state *win = &sd->win[layer]; - unsigned long fb_offset_32, cbcr_offset_32; - - fb_offset_32 = fb_base_phys - VPBE_REG_BASE; - if (cbcr_ofst) - cbcr_offset_32 = cbcr_ofst; - else - cbcr_offset_32 = win->lconfig.line_length * - win->lconfig.ysize; - cbcr_offset_32 += fb_offset_32; - fb_offset_32 = fb_offset_32 >> 5; - cbcr_offset_32 = cbcr_offset_32 >> 5; - /* - * DM365: start address is 27-bit long address b26 - b23 are - * in offset register b12 - b9, and * bit 26 has to be '1' - */ - if (win->lconfig.pixfmt == PIXFMT_NV12) { - switch (layer) { - case WIN_VID0: - case WIN_VID1: - /* Y is in VID0 */ - osd_modify(sd, OSD_VIDWIN0OFST_V0AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | - OSD_WINOFST_MASK, OSD_VIDWIN0OFST); - osd_modify(sd, OSD_VIDWINADH_V0AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V0AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_VIDWIN0ADL); - /* CbCr is in VID1 */ - osd_modify(sd, OSD_VIDWIN1OFST_V1AH, - ((cbcr_offset_32 & - OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | - OSD_WINOFST_MASK, OSD_VIDWIN1OFST); - osd_modify(sd, OSD_VIDWINADH_V1AH, - (cbcr_offset_32 & - OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V1AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, cbcr_offset_32 & OSD_WINADL_MASK, - OSD_VIDWIN1ADL); - break; - default: - break; - } - } - - switch (layer) { - case WIN_OSD0: - osd_modify(sd, OSD_OSDWIN0OFST_O0AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK, - OSD_OSDWIN0OFST); - osd_modify(sd, OSD_OSDWINADH_O0AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_OSDWINADH_O0AH_SHIFT), OSD_OSDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_OSDWIN0ADL); - break; - case WIN_VID0: - if (win->lconfig.pixfmt != PIXFMT_NV12) { - osd_modify(sd, OSD_VIDWIN0OFST_V0AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | - OSD_WINOFST_MASK, OSD_VIDWIN0OFST); - osd_modify(sd, OSD_VIDWINADH_V0AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V0AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_VIDWIN0ADL); - } - break; - case WIN_OSD1: - osd_modify(sd, OSD_OSDWIN1OFST_O1AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK, - OSD_OSDWIN1OFST); - osd_modify(sd, OSD_OSDWINADH_O1AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_OSDWINADH_O1AH_SHIFT), - OSD_OSDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_OSDWIN1ADL); - break; - case WIN_VID1: - if (win->lconfig.pixfmt != PIXFMT_NV12) { - osd_modify(sd, OSD_VIDWIN1OFST_V1AH, - ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> - (OSD_SRCADD_OFSET_SFT - - OSD_WINOFST_AH_SHIFT)) | - OSD_WINOFST_MASK, OSD_VIDWIN1OFST); - osd_modify(sd, OSD_VIDWINADH_V1AH, - (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> - (OSD_SRCADD_ADD_SFT - - OSD_VIDWINADH_V1AH_SHIFT), - OSD_VIDWINADH); - osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, - OSD_VIDWIN1ADL); - } - break; - } - } -} - -static void osd_start_layer(struct osd_state *sd, enum osd_layer layer, - unsigned long fb_base_phys, - unsigned long cbcr_ofst) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - struct osd_layer_config *cfg = &win->lconfig; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - win->fb_base_phys = fb_base_phys & ~0x1F; - _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst); - - if (layer == WIN_VID0) { - osd->pingpong = - _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, - win->fb_base_phys, - cfg); - } - - spin_unlock_irqrestore(&osd->lock, flags); -} - -static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer, - struct osd_layer_config *lconfig) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - *lconfig = win->lconfig; - - spin_unlock_irqrestore(&osd->lock, flags); -} - -/** - * try_layer_config() - Try a specific configuration for the layer - * @sd: ptr to struct osd_state - * @layer: layer to configure - * @lconfig: layer configuration to try - * - * If the requested lconfig is completely rejected and the value of lconfig on - * exit is the current lconfig, then try_layer_config() returns 1. Otherwise, - * try_layer_config() returns 0. A return value of 0 does not necessarily mean - * that the value of lconfig on exit is identical to the value of lconfig on - * entry, but merely that it represents a change from the current lconfig. - */ -static int try_layer_config(struct osd_state *sd, enum osd_layer layer, - struct osd_layer_config *lconfig) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - int bad_config = 0; - - /* verify that the pixel format is compatible with the layer */ - switch (lconfig->pixfmt) { - case PIXFMT_1BPP: - case PIXFMT_2BPP: - case PIXFMT_4BPP: - case PIXFMT_8BPP: - case PIXFMT_RGB565: - if (osd->vpbe_type == VPBE_VERSION_1) - bad_config = !is_vid_win(layer); - break; - case PIXFMT_YCBCRI: - case PIXFMT_YCRCBI: - bad_config = !is_vid_win(layer); - break; - case PIXFMT_RGB888: - if (osd->vpbe_type == VPBE_VERSION_1) - bad_config = !is_vid_win(layer); - else if ((osd->vpbe_type == VPBE_VERSION_3) || - (osd->vpbe_type == VPBE_VERSION_2)) - bad_config = !is_osd_win(layer); - break; - case PIXFMT_NV12: - if (osd->vpbe_type != VPBE_VERSION_2) - bad_config = 1; - else - bad_config = is_osd_win(layer); - break; - case PIXFMT_OSD_ATTR: - bad_config = (layer != WIN_OSD1); - break; - default: - bad_config = 1; - break; - } - if (bad_config) { - /* - * The requested pixel format is incompatible with the layer, - * so keep the current layer configuration. - */ - *lconfig = win->lconfig; - return bad_config; - } - - /* DM6446: */ - /* only one OSD window at a time can use RGB pixel formats */ - if ((osd->vpbe_type == VPBE_VERSION_1) && - is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { - enum osd_pix_format pixfmt; - - if (layer == WIN_OSD0) - pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; - else - pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt; - - if (is_rgb_pixfmt(pixfmt)) { - /* - * The other OSD window is already configured for an - * RGB, so keep the current layer configuration. - */ - *lconfig = win->lconfig; - return 1; - } - } - - /* DM6446: only one video window at a time can use RGB888 */ - if ((osd->vpbe_type == VPBE_VERSION_1) && is_vid_win(layer) && - lconfig->pixfmt == PIXFMT_RGB888) { - enum osd_pix_format pixfmt; - - if (layer == WIN_VID0) - pixfmt = osd->win[WIN_VID1].lconfig.pixfmt; - else - pixfmt = osd->win[WIN_VID0].lconfig.pixfmt; - - if (pixfmt == PIXFMT_RGB888) { - /* - * The other video window is already configured for - * RGB888, so keep the current layer configuration. - */ - *lconfig = win->lconfig; - return 1; - } - } - - /* window dimensions must be non-zero */ - if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) { - *lconfig = win->lconfig; - return 1; - } - - /* round line_length up to a multiple of 32 */ - lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32; - lconfig->line_length = - min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH); - lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE); - lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE); - lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE); - lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE); - lconfig->interlaced = (lconfig->interlaced != 0); - if (lconfig->interlaced) { - /* ysize and ypos must be even for interlaced displays */ - lconfig->ysize &= ~1; - lconfig->ypos &= ~1; - } - - return 0; -} - -static void _osd_disable_vid_rgb888(struct osd_state *sd) -{ - /* - * The DM6446 supports RGB888 pixel format in a single video window. - * This routine disables RGB888 pixel format for both video windows. - * The caller must ensure that neither video window is currently - * configured for RGB888 pixel format. - */ - if (sd->vpbe_type == VPBE_VERSION_1) - osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); -} - -static void _osd_enable_vid_rgb888(struct osd_state *sd, - enum osd_layer layer) -{ - /* - * The DM6446 supports RGB888 pixel format in a single video window. - * This routine enables RGB888 pixel format for the specified video - * window. The caller must ensure that the other video window is not - * currently configured for RGB888 pixel format, as this routine will - * disable RGB888 pixel format for the other window. - */ - if (sd->vpbe_type == VPBE_VERSION_1) { - if (layer == WIN_VID0) - osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL_RGBEN, OSD_MISCCTL); - else if (layer == WIN_VID1) - osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL); - } -} - -static void _osd_set_cbcr_order(struct osd_state *sd, - enum osd_pix_format pixfmt) -{ - /* - * The caller must ensure that all windows using YC pixfmt use the same - * Cb/Cr order. - */ - if (pixfmt == PIXFMT_YCBCRI) - osd_clear(sd, OSD_MODE_CS, OSD_MODE); - else if (pixfmt == PIXFMT_YCRCBI) - osd_set(sd, OSD_MODE_CS, OSD_MODE); -} - -static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, - const struct osd_layer_config *lconfig) -{ - u32 winmd = 0, winmd_mask = 0, bmw = 0; - - _osd_set_cbcr_order(sd, lconfig->pixfmt); - - switch (layer) { - case WIN_OSD0: - if (sd->vpbe_type == VPBE_VERSION_1) { - winmd_mask |= OSD_OSDWIN0MD_RGB0E; - if (lconfig->pixfmt == PIXFMT_RGB565) - winmd |= OSD_OSDWIN0MD_RGB0E; - } else if ((sd->vpbe_type == VPBE_VERSION_3) || - (sd->vpbe_type == VPBE_VERSION_2)) { - winmd_mask |= OSD_OSDWIN0MD_BMP0MD; - switch (lconfig->pixfmt) { - case PIXFMT_RGB565: - winmd |= (1 << - OSD_OSDWIN0MD_BMP0MD_SHIFT); - break; - case PIXFMT_RGB888: - winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT); - _osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0); - break; - case PIXFMT_YCBCRI: - case PIXFMT_YCRCBI: - winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT); - break; - default: - break; - } - } - - winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; - - switch (lconfig->pixfmt) { - case PIXFMT_1BPP: - bmw = 0; - break; - case PIXFMT_2BPP: - bmw = 1; - break; - case PIXFMT_4BPP: - bmw = 2; - break; - case PIXFMT_8BPP: - bmw = 3; - break; - default: - break; - } - winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT); - - if (lconfig->interlaced) - winmd |= OSD_OSDWIN0MD_OFF0; - - osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD); - osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST); - osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP); - osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL); - if (lconfig->interlaced) { - osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP); - osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL); - } else { - osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP); - osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL); - } - break; - case WIN_VID0: - winmd_mask |= OSD_VIDWINMD_VFF0; - if (lconfig->interlaced) - winmd |= OSD_VIDWINMD_VFF0; - - osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); - osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST); - osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); - osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); - /* - * For YUV420P format the register contents are - * duplicated in both VID registers - */ - if ((sd->vpbe_type == VPBE_VERSION_2) && - (lconfig->pixfmt == PIXFMT_NV12)) { - /* other window also */ - if (lconfig->interlaced) { - winmd_mask |= OSD_VIDWINMD_VFF1; - winmd |= OSD_VIDWINMD_VFF1; - osd_modify(sd, winmd_mask, winmd, - OSD_VIDWINMD); - } - - osd_modify(sd, OSD_MISCCTL_S420D, - OSD_MISCCTL_S420D, OSD_MISCCTL); - osd_write(sd, lconfig->line_length >> 5, - OSD_VIDWIN1OFST); - osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); - osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); - /* - * if NV21 pixfmt and line length not 32B - * aligned (e.g. NTSC), Need to set window - * X pixel size to be 32B aligned as well - */ - if (lconfig->xsize % 32) { - osd_write(sd, - ((lconfig->xsize + 31) & ~31), - OSD_VIDWIN1XL); - osd_write(sd, - ((lconfig->xsize + 31) & ~31), - OSD_VIDWIN0XL); - } - } else if ((sd->vpbe_type == VPBE_VERSION_2) && - (lconfig->pixfmt != PIXFMT_NV12)) { - osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, - OSD_MISCCTL); - } - - if (lconfig->interlaced) { - osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); - osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); - if ((sd->vpbe_type == VPBE_VERSION_2) && - lconfig->pixfmt == PIXFMT_NV12) { - osd_write(sd, lconfig->ypos >> 1, - OSD_VIDWIN1YP); - osd_write(sd, lconfig->ysize >> 1, - OSD_VIDWIN1YL); - } - } else { - osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); - osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); - if ((sd->vpbe_type == VPBE_VERSION_2) && - lconfig->pixfmt == PIXFMT_NV12) { - osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); - osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); - } - } - break; - case WIN_OSD1: - /* - * The caller must ensure that OSD1 is disabled prior to - * switching from a normal mode to attribute mode or from - * attribute mode to a normal mode. - */ - if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { - if (sd->vpbe_type == VPBE_VERSION_1) { - winmd_mask |= OSD_OSDWIN1MD_ATN1E | - OSD_OSDWIN1MD_RGB1E | OSD_OSDWIN1MD_CLUTS1 | - OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; - } else { - winmd_mask |= OSD_OSDWIN1MD_BMP1MD | - OSD_OSDWIN1MD_CLUTS1 | OSD_OSDWIN1MD_BLND1 | - OSD_OSDWIN1MD_TE1; - } - } else { - if (sd->vpbe_type == VPBE_VERSION_1) { - winmd_mask |= OSD_OSDWIN1MD_RGB1E; - if (lconfig->pixfmt == PIXFMT_RGB565) - winmd |= OSD_OSDWIN1MD_RGB1E; - } else if ((sd->vpbe_type == VPBE_VERSION_3) - || (sd->vpbe_type == VPBE_VERSION_2)) { - winmd_mask |= OSD_OSDWIN1MD_BMP1MD; - switch (lconfig->pixfmt) { - case PIXFMT_RGB565: - winmd |= - (1 << OSD_OSDWIN1MD_BMP1MD_SHIFT); - break; - case PIXFMT_RGB888: - winmd |= - (2 << OSD_OSDWIN1MD_BMP1MD_SHIFT); - _osd_enable_rgb888_pixblend(sd, - OSDWIN_OSD1); - break; - case PIXFMT_YCBCRI: - case PIXFMT_YCRCBI: - winmd |= - (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT); - break; - default: - break; - } - } - - winmd_mask |= OSD_OSDWIN1MD_BMW1; - switch (lconfig->pixfmt) { - case PIXFMT_1BPP: - bmw = 0; - break; - case PIXFMT_2BPP: - bmw = 1; - break; - case PIXFMT_4BPP: - bmw = 2; - break; - case PIXFMT_8BPP: - bmw = 3; - break; - default: - break; - } - winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT); - } - - winmd_mask |= OSD_OSDWIN1MD_OFF1; - if (lconfig->interlaced) - winmd |= OSD_OSDWIN1MD_OFF1; - - osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD); - osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST); - osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP); - osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL); - if (lconfig->interlaced) { - osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP); - osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL); - } else { - osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP); - osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL); - } - break; - case WIN_VID1: - winmd_mask |= OSD_VIDWINMD_VFF1; - if (lconfig->interlaced) - winmd |= OSD_VIDWINMD_VFF1; - - osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); - osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST); - osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); - osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); - /* - * For YUV420P format the register contents are - * duplicated in both VID registers - */ - if (sd->vpbe_type == VPBE_VERSION_2) { - if (lconfig->pixfmt == PIXFMT_NV12) { - /* other window also */ - if (lconfig->interlaced) { - winmd_mask |= OSD_VIDWINMD_VFF0; - winmd |= OSD_VIDWINMD_VFF0; - osd_modify(sd, winmd_mask, winmd, - OSD_VIDWINMD); - } - osd_modify(sd, OSD_MISCCTL_S420D, - OSD_MISCCTL_S420D, OSD_MISCCTL); - osd_write(sd, lconfig->line_length >> 5, - OSD_VIDWIN0OFST); - osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); - osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); - } else { - osd_modify(sd, OSD_MISCCTL_S420D, - ~OSD_MISCCTL_S420D, OSD_MISCCTL); - } - } - - if (lconfig->interlaced) { - osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); - osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); - if ((sd->vpbe_type == VPBE_VERSION_2) && - lconfig->pixfmt == PIXFMT_NV12) { - osd_write(sd, lconfig->ypos >> 1, - OSD_VIDWIN0YP); - osd_write(sd, lconfig->ysize >> 1, - OSD_VIDWIN0YL); - } - } else { - osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); - osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); - if ((sd->vpbe_type == VPBE_VERSION_2) && - lconfig->pixfmt == PIXFMT_NV12) { - osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); - osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); - } - } - break; - } -} - -static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, - struct osd_layer_config *lconfig) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - struct osd_layer_config *cfg = &win->lconfig; - unsigned long flags; - int reject_config; - - spin_lock_irqsave(&osd->lock, flags); - - reject_config = try_layer_config(sd, layer, lconfig); - if (reject_config) { - spin_unlock_irqrestore(&osd->lock, flags); - return reject_config; - } - - /* update the current Cb/Cr order */ - if (is_yc_pixfmt(lconfig->pixfmt)) - osd->yc_pixfmt = lconfig->pixfmt; - - /* - * If we are switching OSD1 from normal mode to attribute mode or from - * attribute mode to normal mode, then we must disable the window. - */ - if (layer == WIN_OSD1) { - if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) && - (cfg->pixfmt != PIXFMT_OSD_ATTR)) || - ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && - (cfg->pixfmt == PIXFMT_OSD_ATTR))) { - win->is_enabled = 0; - _osd_disable_layer(sd, layer); - } - } - - _osd_set_layer_config(sd, layer, lconfig); - - if (layer == WIN_OSD1) { - struct osd_osdwin_state *osdwin_state = - &osd->osdwin[OSDWIN_OSD1]; - - if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && - (cfg->pixfmt == PIXFMT_OSD_ATTR)) { - /* - * We just switched OSD1 from attribute mode to normal - * mode, so we must initialize the CLUT select, the - * blend factor, transparency colorkey enable, and - * attenuation enable (DM6446 only) bits in the - * OSDWIN1MD register. - */ - _osd_set_osd_clut(sd, OSDWIN_OSD1, - osdwin_state->clut); - _osd_set_blending_factor(sd, OSDWIN_OSD1, - osdwin_state->blend); - if (osdwin_state->colorkey_blending) { - _osd_enable_color_key(sd, OSDWIN_OSD1, - osdwin_state-> - colorkey, - lconfig->pixfmt); - } else - _osd_disable_color_key(sd, OSDWIN_OSD1); - _osd_set_rec601_attenuation(sd, OSDWIN_OSD1, - osdwin_state-> - rec601_attenuation); - } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) && - (cfg->pixfmt != PIXFMT_OSD_ATTR)) { - /* - * We just switched OSD1 from normal mode to attribute - * mode, so we must initialize the blink enable and - * blink interval bits in the OSDATRMD register. - */ - _osd_set_blink_attribute(sd, osd->is_blinking, - osd->blink); - } - } - - /* - * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format - * then configure a default palette map. - */ - if ((lconfig->pixfmt != cfg->pixfmt) && - ((lconfig->pixfmt == PIXFMT_1BPP) || - (lconfig->pixfmt == PIXFMT_2BPP) || - (lconfig->pixfmt == PIXFMT_4BPP))) { - enum osd_win_layer osdwin = - ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1); - struct osd_osdwin_state *osdwin_state = - &osd->osdwin[osdwin]; - unsigned char clut_index; - unsigned char clut_entries = 0; - - switch (lconfig->pixfmt) { - case PIXFMT_1BPP: - clut_entries = 2; - break; - case PIXFMT_2BPP: - clut_entries = 4; - break; - case PIXFMT_4BPP: - clut_entries = 16; - break; - default: - break; - } - /* - * The default palette map maps the pixel value to the clut - * index, i.e. pixel value 0 maps to clut entry 0, pixel value - * 1 maps to clut entry 1, etc. - */ - for (clut_index = 0; clut_index < 16; clut_index++) { - osdwin_state->palette_map[clut_index] = clut_index; - if (clut_index < clut_entries) { - _osd_set_palette_map(sd, osdwin, clut_index, - clut_index, - lconfig->pixfmt); - } - } - } - - *cfg = *lconfig; - /* DM6446: configure the RGB888 enable and window selection */ - if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888) - _osd_enable_vid_rgb888(sd, WIN_VID0); - else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888) - _osd_enable_vid_rgb888(sd, WIN_VID1); - else - _osd_disable_vid_rgb888(sd); - - if (layer == WIN_VID0) { - osd->pingpong = - _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, - win->fb_base_phys, - cfg); - } - - spin_unlock_irqrestore(&osd->lock, flags); - - return 0; -} - -static void osd_init_layer(struct osd_state *sd, enum osd_layer layer) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - enum osd_win_layer osdwin; - struct osd_osdwin_state *osdwin_state; - struct osd_layer_config *cfg = &win->lconfig; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - win->is_enabled = 0; - _osd_disable_layer(sd, layer); - - win->h_zoom = ZOOM_X1; - win->v_zoom = ZOOM_X1; - _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom); - - win->fb_base_phys = 0; - _osd_start_layer(sd, layer, win->fb_base_phys, 0); - - cfg->line_length = 0; - cfg->xsize = 0; - cfg->ysize = 0; - cfg->xpos = 0; - cfg->ypos = 0; - cfg->interlaced = 0; - switch (layer) { - case WIN_OSD0: - case WIN_OSD1: - osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1; - osdwin_state = &osd->osdwin[osdwin]; - /* - * Other code relies on the fact that OSD windows default to a - * bitmap pixel format when they are deallocated, so don't - * change this default pixel format. - */ - cfg->pixfmt = PIXFMT_8BPP; - _osd_set_layer_config(sd, layer, cfg); - osdwin_state->clut = RAM_CLUT; - _osd_set_osd_clut(sd, osdwin, osdwin_state->clut); - osdwin_state->colorkey_blending = 0; - _osd_disable_color_key(sd, osdwin); - osdwin_state->blend = OSD_8_VID_0; - _osd_set_blending_factor(sd, osdwin, osdwin_state->blend); - osdwin_state->rec601_attenuation = 0; - _osd_set_rec601_attenuation(sd, osdwin, - osdwin_state-> - rec601_attenuation); - if (osdwin == OSDWIN_OSD1) { - osd->is_blinking = 0; - osd->blink = BLINK_X1; - } - break; - case WIN_VID0: - case WIN_VID1: - cfg->pixfmt = osd->yc_pixfmt; - _osd_set_layer_config(sd, layer, cfg); - break; - } - - spin_unlock_irqrestore(&osd->lock, flags); -} - -static void osd_release_layer(struct osd_state *sd, enum osd_layer layer) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - if (!win->is_allocated) { - spin_unlock_irqrestore(&osd->lock, flags); - return; - } - - spin_unlock_irqrestore(&osd->lock, flags); - osd_init_layer(sd, layer); - spin_lock_irqsave(&osd->lock, flags); - - win->is_allocated = 0; - - spin_unlock_irqrestore(&osd->lock, flags); -} - -static int osd_request_layer(struct osd_state *sd, enum osd_layer layer) -{ - struct osd_state *osd = sd; - struct osd_window_state *win = &osd->win[layer]; - unsigned long flags; - - spin_lock_irqsave(&osd->lock, flags); - - if (win->is_allocated) { - spin_unlock_irqrestore(&osd->lock, flags); - return -1; - } - win->is_allocated = 1; - - spin_unlock_irqrestore(&osd->lock, flags); - - return 0; -} - -static void _osd_init(struct osd_state *sd) -{ - osd_write(sd, 0, OSD_MODE); - osd_write(sd, 0, OSD_VIDWINMD); - osd_write(sd, 0, OSD_OSDWIN0MD); - osd_write(sd, 0, OSD_OSDWIN1MD); - osd_write(sd, 0, OSD_RECTCUR); - osd_write(sd, 0, OSD_MISCCTL); - if (sd->vpbe_type == VPBE_VERSION_3) { - osd_write(sd, 0, OSD_VBNDRY); - osd_write(sd, 0, OSD_EXTMODE); - osd_write(sd, OSD_MISCCTL_DMANG, OSD_MISCCTL); - } -} - -static void osd_set_left_margin(struct osd_state *sd, u32 val) -{ - osd_write(sd, val, OSD_BASEPX); -} - -static void osd_set_top_margin(struct osd_state *sd, u32 val) -{ - osd_write(sd, val, OSD_BASEPY); -} - -static int osd_initialize(struct osd_state *osd) -{ - if (osd == NULL) - return -ENODEV; - _osd_init(osd); - - /* set default Cb/Cr order */ - osd->yc_pixfmt = PIXFMT_YCBCRI; - - if (osd->vpbe_type == VPBE_VERSION_3) { - /* - * ROM CLUT1 on the DM355 is similar (identical?) to ROM CLUT0 - * on the DM6446, so make ROM_CLUT1 the default on the DM355. - */ - osd->rom_clut = ROM_CLUT1; - } - - _osd_set_field_inversion(osd, osd->field_inversion); - _osd_set_rom_clut(osd, osd->rom_clut); - - osd_init_layer(osd, WIN_OSD0); - osd_init_layer(osd, WIN_VID0); - osd_init_layer(osd, WIN_OSD1); - osd_init_layer(osd, WIN_VID1); - - return 0; -} - -static const struct vpbe_osd_ops osd_ops = { - .initialize = osd_initialize, - .request_layer = osd_request_layer, - .release_layer = osd_release_layer, - .enable_layer = osd_enable_layer, - .disable_layer = osd_disable_layer, - .set_layer_config = osd_set_layer_config, - .get_layer_config = osd_get_layer_config, - .start_layer = osd_start_layer, - .set_left_margin = osd_set_left_margin, - .set_top_margin = osd_set_top_margin, -}; - -static int osd_probe(struct platform_device *pdev) -{ - const struct platform_device_id *pdev_id; - struct osd_state *osd; - struct resource *res; - - pdev_id = platform_get_device_id(pdev); - if (!pdev_id) - return -EINVAL; - - osd = devm_kzalloc(&pdev->dev, sizeof(struct osd_state), GFP_KERNEL); - if (osd == NULL) - return -ENOMEM; - - - osd->dev = &pdev->dev; - osd->vpbe_type = pdev_id->driver_data; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - osd->osd_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(osd->osd_base)) - return PTR_ERR(osd->osd_base); - - osd->osd_base_phys = res->start; - osd->osd_size = resource_size(res); - spin_lock_init(&osd->lock); - osd->ops = osd_ops; - platform_set_drvdata(pdev, osd); - dev_notice(osd->dev, "OSD sub device probe success\n"); - - return 0; -} - -static int osd_remove(struct platform_device *pdev) -{ - return 0; -} - -static struct platform_driver osd_driver = { - .probe = osd_probe, - .remove = osd_remove, - .driver = { - .name = MODULE_NAME, - }, - .id_table = vpbe_osd_devtype -}; - -module_platform_driver(osd_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); -MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/platform/ti/davinci/vpbe_osd_regs.h b/drivers/media/platform/ti/davinci/vpbe_osd_regs.h deleted file mode 100644 index cecd5991d4c5..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_osd_regs.h +++ /dev/null @@ -1,352 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2006-2010 Texas Instruments Inc - */ -#ifndef _VPBE_OSD_REGS_H -#define _VPBE_OSD_REGS_H - -/* VPBE Global Registers */ -#define VPBE_PID 0x0 -#define VPBE_PCR 0x4 - -/* VPSS CLock Registers */ -#define VPSSCLK_PID 0x00 -#define VPSSCLK_CLKCTRL 0x04 - -/* VPSS Buffer Logic Registers */ -#define VPSSBL_PID 0x00 -#define VPSSBL_PCR 0x04 -#define VPSSBL_BCR 0x08 -#define VPSSBL_INTSTAT 0x0C -#define VPSSBL_INTSEL 0x10 -#define VPSSBL_EVTSEL 0x14 -#define VPSSBL_MEMCTRL 0x18 -#define VPSSBL_CCDCMUX 0x1C - -/* DM365 ISP5 system configuration */ -#define ISP5_PID 0x0 -#define ISP5_PCCR 0x4 -#define ISP5_BCR 0x8 -#define ISP5_INTSTAT 0xC -#define ISP5_INTSEL1 0x10 -#define ISP5_INTSEL2 0x14 -#define ISP5_INTSEL3 0x18 -#define ISP5_EVTSEL 0x1c -#define ISP5_CCDCMUX 0x20 - -/* VPBE On-Screen Display Subsystem Registers (OSD) */ -#define OSD_MODE 0x00 -#define OSD_VIDWINMD 0x04 -#define OSD_OSDWIN0MD 0x08 -#define OSD_OSDWIN1MD 0x0C -#define OSD_OSDATRMD 0x0C -#define OSD_RECTCUR 0x10 -#define OSD_VIDWIN0OFST 0x18 -#define OSD_VIDWIN1OFST 0x1C -#define OSD_OSDWIN0OFST 0x20 -#define OSD_OSDWIN1OFST 0x24 -#define OSD_VIDWINADH 0x28 -#define OSD_VIDWIN0ADL 0x2C -#define OSD_VIDWIN0ADR 0x2C -#define OSD_VIDWIN1ADL 0x30 -#define OSD_VIDWIN1ADR 0x30 -#define OSD_OSDWINADH 0x34 -#define OSD_OSDWIN0ADL 0x38 -#define OSD_OSDWIN0ADR 0x38 -#define OSD_OSDWIN1ADL 0x3C -#define OSD_OSDWIN1ADR 0x3C -#define OSD_BASEPX 0x40 -#define OSD_BASEPY 0x44 -#define OSD_VIDWIN0XP 0x48 -#define OSD_VIDWIN0YP 0x4C -#define OSD_VIDWIN0XL 0x50 -#define OSD_VIDWIN0YL 0x54 -#define OSD_VIDWIN1XP 0x58 -#define OSD_VIDWIN1YP 0x5C -#define OSD_VIDWIN1XL 0x60 -#define OSD_VIDWIN1YL 0x64 -#define OSD_OSDWIN0XP 0x68 -#define OSD_OSDWIN0YP 0x6C -#define OSD_OSDWIN0XL 0x70 -#define OSD_OSDWIN0YL 0x74 -#define OSD_OSDWIN1XP 0x78 -#define OSD_OSDWIN1YP 0x7C -#define OSD_OSDWIN1XL 0x80 -#define OSD_OSDWIN1YL 0x84 -#define OSD_CURXP 0x88 -#define OSD_CURYP 0x8C -#define OSD_CURXL 0x90 -#define OSD_CURYL 0x94 -#define OSD_W0BMP01 0xA0 -#define OSD_W0BMP23 0xA4 -#define OSD_W0BMP45 0xA8 -#define OSD_W0BMP67 0xAC -#define OSD_W0BMP89 0xB0 -#define OSD_W0BMPAB 0xB4 -#define OSD_W0BMPCD 0xB8 -#define OSD_W0BMPEF 0xBC -#define OSD_W1BMP01 0xC0 -#define OSD_W1BMP23 0xC4 -#define OSD_W1BMP45 0xC8 -#define OSD_W1BMP67 0xCC -#define OSD_W1BMP89 0xD0 -#define OSD_W1BMPAB 0xD4 -#define OSD_W1BMPCD 0xD8 -#define OSD_W1BMPEF 0xDC -#define OSD_VBNDRY 0xE0 -#define OSD_EXTMODE 0xE4 -#define OSD_MISCCTL 0xE8 -#define OSD_CLUTRAMYCB 0xEC -#define OSD_CLUTRAMCR 0xF0 -#define OSD_TRANSPVAL 0xF4 -#define OSD_TRANSPVALL 0xF4 -#define OSD_TRANSPVALU 0xF8 -#define OSD_TRANSPBMPIDX 0xFC -#define OSD_PPVWIN0ADR 0xFC - -/* bit definitions */ -#define VPBE_PCR_VENC_DIV (1 << 1) -#define VPBE_PCR_CLK_OFF (1 << 0) - -#define VPSSBL_INTSTAT_HSSIINT (1 << 14) -#define VPSSBL_INTSTAT_CFALDINT (1 << 13) -#define VPSSBL_INTSTAT_IPIPE_INT5 (1 << 12) -#define VPSSBL_INTSTAT_IPIPE_INT4 (1 << 11) -#define VPSSBL_INTSTAT_IPIPE_INT3 (1 << 10) -#define VPSSBL_INTSTAT_IPIPE_INT2 (1 << 9) -#define VPSSBL_INTSTAT_IPIPE_INT1 (1 << 8) -#define VPSSBL_INTSTAT_IPIPE_INT0 (1 << 7) -#define VPSSBL_INTSTAT_IPIPEIFINT (1 << 6) -#define VPSSBL_INTSTAT_OSDINT (1 << 5) -#define VPSSBL_INTSTAT_VENCINT (1 << 4) -#define VPSSBL_INTSTAT_H3AINT (1 << 3) -#define VPSSBL_INTSTAT_CCDC_VDINT2 (1 << 2) -#define VPSSBL_INTSTAT_CCDC_VDINT1 (1 << 1) -#define VPSSBL_INTSTAT_CCDC_VDINT0 (1 << 0) - -/* DM365 ISP5 bit definitions */ -#define ISP5_INTSTAT_VENCINT (1 << 21) -#define ISP5_INTSTAT_OSDINT (1 << 20) - -/* VMOD TVTYP options for HDMD=0 */ -#define SDTV_NTSC 0 -#define SDTV_PAL 1 -/* VMOD TVTYP options for HDMD=1 */ -#define HDTV_525P 0 -#define HDTV_625P 1 -#define HDTV_1080I 2 -#define HDTV_720P 3 - -#define OSD_MODE_CS (1 << 15) -#define OSD_MODE_OVRSZ (1 << 14) -#define OSD_MODE_OHRSZ (1 << 13) -#define OSD_MODE_EF (1 << 12) -#define OSD_MODE_VVRSZ (1 << 11) -#define OSD_MODE_VHRSZ (1 << 10) -#define OSD_MODE_FSINV (1 << 9) -#define OSD_MODE_BCLUT (1 << 8) -#define OSD_MODE_CABG_SHIFT 0 -#define OSD_MODE_CABG (0xff << 0) - -#define OSD_VIDWINMD_VFINV (1 << 15) -#define OSD_VIDWINMD_V1EFC (1 << 14) -#define OSD_VIDWINMD_VHZ1_SHIFT 12 -#define OSD_VIDWINMD_VHZ1 (3 << 12) -#define OSD_VIDWINMD_VVZ1_SHIFT 10 -#define OSD_VIDWINMD_VVZ1 (3 << 10) -#define OSD_VIDWINMD_VFF1 (1 << 9) -#define OSD_VIDWINMD_ACT1 (1 << 8) -#define OSD_VIDWINMD_V0EFC (1 << 6) -#define OSD_VIDWINMD_VHZ0_SHIFT 4 -#define OSD_VIDWINMD_VHZ0 (3 << 4) -#define OSD_VIDWINMD_VVZ0_SHIFT 2 -#define OSD_VIDWINMD_VVZ0 (3 << 2) -#define OSD_VIDWINMD_VFF0 (1 << 1) -#define OSD_VIDWINMD_ACT0 (1 << 0) - -#define OSD_OSDWIN0MD_ATN0E (1 << 14) -#define OSD_OSDWIN0MD_RGB0E (1 << 13) -#define OSD_OSDWIN0MD_BMP0MD_SHIFT 13 -#define OSD_OSDWIN0MD_BMP0MD (3 << 13) -#define OSD_OSDWIN0MD_CLUTS0 (1 << 12) -#define OSD_OSDWIN0MD_OHZ0_SHIFT 10 -#define OSD_OSDWIN0MD_OHZ0 (3 << 10) -#define OSD_OSDWIN0MD_OVZ0_SHIFT 8 -#define OSD_OSDWIN0MD_OVZ0 (3 << 8) -#define OSD_OSDWIN0MD_BMW0_SHIFT 6 -#define OSD_OSDWIN0MD_BMW0 (3 << 6) -#define OSD_OSDWIN0MD_BLND0_SHIFT 3 -#define OSD_OSDWIN0MD_BLND0 (7 << 3) -#define OSD_OSDWIN0MD_TE0 (1 << 2) -#define OSD_OSDWIN0MD_OFF0 (1 << 1) -#define OSD_OSDWIN0MD_OACT0 (1 << 0) - -#define OSD_OSDWIN1MD_OASW (1 << 15) -#define OSD_OSDWIN1MD_ATN1E (1 << 14) -#define OSD_OSDWIN1MD_RGB1E (1 << 13) -#define OSD_OSDWIN1MD_BMP1MD_SHIFT 13 -#define OSD_OSDWIN1MD_BMP1MD (3 << 13) -#define OSD_OSDWIN1MD_CLUTS1 (1 << 12) -#define OSD_OSDWIN1MD_OHZ1_SHIFT 10 -#define OSD_OSDWIN1MD_OHZ1 (3 << 10) -#define OSD_OSDWIN1MD_OVZ1_SHIFT 8 -#define OSD_OSDWIN1MD_OVZ1 (3 << 8) -#define OSD_OSDWIN1MD_BMW1_SHIFT 6 -#define OSD_OSDWIN1MD_BMW1 (3 << 6) -#define OSD_OSDWIN1MD_BLND1_SHIFT 3 -#define OSD_OSDWIN1MD_BLND1 (7 << 3) -#define OSD_OSDWIN1MD_TE1 (1 << 2) -#define OSD_OSDWIN1MD_OFF1 (1 << 1) -#define OSD_OSDWIN1MD_OACT1 (1 << 0) - -#define OSD_OSDATRMD_OASW (1 << 15) -#define OSD_OSDATRMD_OHZA_SHIFT 10 -#define OSD_OSDATRMD_OHZA (3 << 10) -#define OSD_OSDATRMD_OVZA_SHIFT 8 -#define OSD_OSDATRMD_OVZA (3 << 8) -#define OSD_OSDATRMD_BLNKINT_SHIFT 6 -#define OSD_OSDATRMD_BLNKINT (3 << 6) -#define OSD_OSDATRMD_OFFA (1 << 1) -#define OSD_OSDATRMD_BLNK (1 << 0) - -#define OSD_RECTCUR_RCAD_SHIFT 8 -#define OSD_RECTCUR_RCAD (0xff << 8) -#define OSD_RECTCUR_CLUTSR (1 << 7) -#define OSD_RECTCUR_RCHW_SHIFT 4 -#define OSD_RECTCUR_RCHW (7 << 4) -#define OSD_RECTCUR_RCVW_SHIFT 1 -#define OSD_RECTCUR_RCVW (7 << 1) -#define OSD_RECTCUR_RCACT (1 << 0) - -#define OSD_VIDWIN0OFST_V0LO (0x1ff << 0) - -#define OSD_VIDWIN1OFST_V1LO (0x1ff << 0) - -#define OSD_OSDWIN0OFST_O0LO (0x1ff << 0) - -#define OSD_OSDWIN1OFST_O1LO (0x1ff << 0) - -#define OSD_WINOFST_AH_SHIFT 9 - -#define OSD_VIDWIN0OFST_V0AH (0xf << 9) -#define OSD_VIDWIN1OFST_V1AH (0xf << 9) -#define OSD_OSDWIN0OFST_O0AH (0xf << 9) -#define OSD_OSDWIN1OFST_O1AH (0xf << 9) - -#define OSD_VIDWINADH_V1AH_SHIFT 8 -#define OSD_VIDWINADH_V1AH (0x7f << 8) -#define OSD_VIDWINADH_V0AH_SHIFT 0 -#define OSD_VIDWINADH_V0AH (0x7f << 0) - -#define OSD_VIDWIN0ADL_V0AL (0xffff << 0) - -#define OSD_VIDWIN1ADL_V1AL (0xffff << 0) - -#define OSD_OSDWINADH_O1AH_SHIFT 8 -#define OSD_OSDWINADH_O1AH (0x7f << 8) -#define OSD_OSDWINADH_O0AH_SHIFT 0 -#define OSD_OSDWINADH_O0AH (0x7f << 0) - -#define OSD_OSDWIN0ADL_O0AL (0xffff << 0) - -#define OSD_OSDWIN1ADL_O1AL (0xffff << 0) - -#define OSD_BASEPX_BPX (0x3ff << 0) - -#define OSD_BASEPY_BPY (0x1ff << 0) - -#define OSD_VIDWIN0XP_V0X (0x7ff << 0) - -#define OSD_VIDWIN0YP_V0Y (0x7ff << 0) - -#define OSD_VIDWIN0XL_V0W (0x7ff << 0) - -#define OSD_VIDWIN0YL_V0H (0x7ff << 0) - -#define OSD_VIDWIN1XP_V1X (0x7ff << 0) - -#define OSD_VIDWIN1YP_V1Y (0x7ff << 0) - -#define OSD_VIDWIN1XL_V1W (0x7ff << 0) - -#define OSD_VIDWIN1YL_V1H (0x7ff << 0) - -#define OSD_OSDWIN0XP_W0X (0x7ff << 0) - -#define OSD_OSDWIN0YP_W0Y (0x7ff << 0) - -#define OSD_OSDWIN0XL_W0W (0x7ff << 0) - -#define OSD_OSDWIN0YL_W0H (0x7ff << 0) - -#define OSD_OSDWIN1XP_W1X (0x7ff << 0) - -#define OSD_OSDWIN1YP_W1Y (0x7ff << 0) - -#define OSD_OSDWIN1XL_W1W (0x7ff << 0) - -#define OSD_OSDWIN1YL_W1H (0x7ff << 0) - -#define OSD_CURXP_RCSX (0x7ff << 0) - -#define OSD_CURYP_RCSY (0x7ff << 0) - -#define OSD_CURXL_RCSW (0x7ff << 0) - -#define OSD_CURYL_RCSH (0x7ff << 0) - -#define OSD_EXTMODE_EXPMDSEL (1 << 15) -#define OSD_EXTMODE_SCRNHEXP_SHIFT 13 -#define OSD_EXTMODE_SCRNHEXP (3 << 13) -#define OSD_EXTMODE_SCRNVEXP (1 << 12) -#define OSD_EXTMODE_OSD1BLDCHR (1 << 11) -#define OSD_EXTMODE_OSD0BLDCHR (1 << 10) -#define OSD_EXTMODE_ATNOSD1EN (1 << 9) -#define OSD_EXTMODE_ATNOSD0EN (1 << 8) -#define OSD_EXTMODE_OSDHRSZ15 (1 << 7) -#define OSD_EXTMODE_VIDHRSZ15 (1 << 6) -#define OSD_EXTMODE_ZMFILV1HEN (1 << 5) -#define OSD_EXTMODE_ZMFILV1VEN (1 << 4) -#define OSD_EXTMODE_ZMFILV0HEN (1 << 3) -#define OSD_EXTMODE_ZMFILV0VEN (1 << 2) -#define OSD_EXTMODE_EXPFILHEN (1 << 1) -#define OSD_EXTMODE_EXPFILVEN (1 << 0) - -#define OSD_MISCCTL_BLDSEL (1 << 15) -#define OSD_MISCCTL_S420D (1 << 14) -#define OSD_MISCCTL_BMAPT (1 << 13) -#define OSD_MISCCTL_DM365M (1 << 12) -#define OSD_MISCCTL_RGBEN (1 << 7) -#define OSD_MISCCTL_RGBWIN (1 << 6) -#define OSD_MISCCTL_DMANG (1 << 6) -#define OSD_MISCCTL_TMON (1 << 5) -#define OSD_MISCCTL_RSEL (1 << 4) -#define OSD_MISCCTL_CPBSY (1 << 3) -#define OSD_MISCCTL_PPSW (1 << 2) -#define OSD_MISCCTL_PPRV (1 << 1) - -#define OSD_CLUTRAMYCB_Y_SHIFT 8 -#define OSD_CLUTRAMYCB_Y (0xff << 8) -#define OSD_CLUTRAMYCB_CB_SHIFT 0 -#define OSD_CLUTRAMYCB_CB (0xff << 0) - -#define OSD_CLUTRAMCR_CR_SHIFT 8 -#define OSD_CLUTRAMCR_CR (0xff << 8) -#define OSD_CLUTRAMCR_CADDR_SHIFT 0 -#define OSD_CLUTRAMCR_CADDR (0xff << 0) - -#define OSD_TRANSPVAL_RGBTRANS (0xffff << 0) - -#define OSD_TRANSPVALL_RGBL (0xffff << 0) - -#define OSD_TRANSPVALU_Y_SHIFT 8 -#define OSD_TRANSPVALU_Y (0xff << 8) -#define OSD_TRANSPVALU_RGBU_SHIFT 0 -#define OSD_TRANSPVALU_RGBU (0xff << 0) - -#define OSD_TRANSPBMPIDX_BMP1_SHIFT 8 -#define OSD_TRANSPBMPIDX_BMP1 (0xff << 8) -#define OSD_TRANSPBMPIDX_BMP0_SHIFT 0 -#define OSD_TRANSPBMPIDX_BMP0 0xff - -#endif /* _DAVINCI_VPBE_H_ */ diff --git a/drivers/media/platform/ti/davinci/vpbe_venc.c b/drivers/media/platform/ti/davinci/vpbe_venc.c deleted file mode 100644 index 4c8e31de12b1..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_venc.c +++ /dev/null @@ -1,676 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2010 Texas Instruments Inc - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#include "vpbe_venc_regs.h" - -#define MODULE_NAME "davinci-vpbe-venc" - -static const struct platform_device_id vpbe_venc_devtype[] = { - { - .name = DM644X_VPBE_VENC_SUBDEV_NAME, - .driver_data = VPBE_VERSION_1, - }, { - .name = DM365_VPBE_VENC_SUBDEV_NAME, - .driver_data = VPBE_VERSION_2, - }, { - .name = DM355_VPBE_VENC_SUBDEV_NAME, - .driver_data = VPBE_VERSION_3, - }, - { - /* sentinel */ - } -}; - -MODULE_DEVICE_TABLE(platform, vpbe_venc_devtype); - -static int debug = 2; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level 0-2"); - -struct venc_state { - struct v4l2_subdev sd; - struct venc_callback *callback; - struct venc_platform_data *pdata; - struct device *pdev; - u32 output; - v4l2_std_id std; - spinlock_t lock; - void __iomem *venc_base; - void __iomem *vdaccfg_reg; - enum vpbe_version venc_type; -}; - -static inline struct venc_state *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct venc_state, sd); -} - -static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) -{ - struct venc_state *venc = to_state(sd); - - return readl(venc->venc_base + offset); -} - -static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) -{ - struct venc_state *venc = to_state(sd); - - writel(val, (venc->venc_base + offset)); - - return val; -} - -static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, - u32 val, u32 mask) -{ - u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); - - venc_write(sd, offset, new_val); - - return new_val; -} - -static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) -{ - struct venc_state *venc = to_state(sd); - - writel(val, venc->vdaccfg_reg); - - val = readl(venc->vdaccfg_reg); - - return val; -} - -#define VDAC_COMPONENT 0x543 -#define VDAC_S_VIDEO 0x210 -/* This function sets the dac of the VPBE for various outputs - */ -static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) -{ - switch (out_index) { - case 0: - v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); - venc_write(sd, VENC_DACSEL, 0); - break; - case 1: - v4l2_dbg(debug, 1, sd, "Setting output to Component\n"); - venc_write(sd, VENC_DACSEL, VDAC_COMPONENT); - break; - case 2: - v4l2_dbg(debug, 1, sd, "Setting output to S-video\n"); - venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO); - break; - default: - return -EINVAL; - } - - return 0; -} - -static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) -{ - struct venc_state *venc = to_state(sd); - - v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); - - if (benable) { - venc_write(sd, VENC_VMOD, 0); - venc_write(sd, VENC_CVBS, 0); - venc_write(sd, VENC_LCDOUT, 0); - venc_write(sd, VENC_HSPLS, 0); - venc_write(sd, VENC_HSTART, 0); - venc_write(sd, VENC_HVALID, 0); - venc_write(sd, VENC_HINT, 0); - venc_write(sd, VENC_VSPLS, 0); - venc_write(sd, VENC_VSTART, 0); - venc_write(sd, VENC_VVALID, 0); - venc_write(sd, VENC_VINT, 0); - venc_write(sd, VENC_YCCCTL, 0); - venc_write(sd, VENC_DACSEL, 0); - - } else { - venc_write(sd, VENC_VMOD, 0); - /* disable VCLK output pin enable */ - venc_write(sd, VENC_VIDCTL, 0x141); - - /* Disable output sync pins */ - venc_write(sd, VENC_SYNCCTL, 0); - - /* Disable DCLOCK */ - venc_write(sd, VENC_DCLKCTL, 0); - venc_write(sd, VENC_DRGBX1, 0x0000057C); - - /* Disable LCD output control (accepting default polarity) */ - venc_write(sd, VENC_LCDOUT, 0); - if (venc->venc_type != VPBE_VERSION_3) - venc_write(sd, VENC_CMPNT, 0x100); - venc_write(sd, VENC_HSPLS, 0); - venc_write(sd, VENC_HINT, 0); - venc_write(sd, VENC_HSTART, 0); - venc_write(sd, VENC_HVALID, 0); - - venc_write(sd, VENC_VSPLS, 0); - venc_write(sd, VENC_VINT, 0); - venc_write(sd, VENC_VSTART, 0); - venc_write(sd, VENC_VVALID, 0); - - venc_write(sd, VENC_HSDLY, 0); - venc_write(sd, VENC_VSDLY, 0); - - venc_write(sd, VENC_YCCCTL, 0); - venc_write(sd, VENC_VSTARTA, 0); - - /* Set OSD clock and OSD Sync Adavance registers */ - venc_write(sd, VENC_OSDCLK0, 1); - venc_write(sd, VENC_OSDCLK1, 2); - } -} - -static void -venc_enable_vpss_clock(int venc_type, - enum vpbe_enc_timings_type type, - unsigned int pclock) -{ - if (venc_type == VPBE_VERSION_1) - return; - - if (venc_type == VPBE_VERSION_2 && (type == VPBE_ENC_STD || (type == - VPBE_ENC_DV_TIMINGS && pclock <= 27000000))) { - vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); - vpss_enable_clock(VPSS_VPBE_CLOCK, 1); - return; - } - - if (venc_type == VPBE_VERSION_3 && type == VPBE_ENC_STD) - vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 0); -} - -#define VDAC_CONFIG_SD_V3 0x0E21A6B6 -#define VDAC_CONFIG_SD_V2 0x081141CF -/* - * setting NTSC mode - */ -static int venc_set_ntsc(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); - - /* Setup clock at VPSS & VENC for SD */ - vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); - if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_525_60); - venc_enabledigitaloutput(sd, 0); - - if (venc->venc_type == VPBE_VERSION_3) { - venc_write(sd, VENC_CLKCTL, 0x01); - venc_write(sd, VENC_VIDCTL, 0); - vdaccfg_write(sd, VDAC_CONFIG_SD_V3); - } else if (venc->venc_type == VPBE_VERSION_2) { - venc_write(sd, VENC_CLKCTL, 0x01); - venc_write(sd, VENC_VIDCTL, 0); - vdaccfg_write(sd, VDAC_CONFIG_SD_V2); - } else { - /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ - venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); - /* Set REC656 Mode */ - venc_write(sd, VENC_YCCCTL, 0x1); - venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); - } - - venc_write(sd, VENC_VMOD, 0); - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); - venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_write(sd, VENC_DACTST, 0x0); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - - return 0; -} - -/* - * setting PAL mode - */ -static int venc_set_pal(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - - v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); - - /* Setup clock at VPSS & VENC for SD */ - vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); - if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_625_50); - venc_enabledigitaloutput(sd, 0); - - if (venc->venc_type == VPBE_VERSION_3) { - venc_write(sd, VENC_CLKCTL, 0x1); - venc_write(sd, VENC_VIDCTL, 0); - vdaccfg_write(sd, VDAC_CONFIG_SD_V3); - } else if (venc->venc_type == VPBE_VERSION_2) { - venc_write(sd, VENC_CLKCTL, 0x1); - venc_write(sd, VENC_VIDCTL, 0); - vdaccfg_write(sd, VDAC_CONFIG_SD_V2); - } else { - /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ - venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); - /* Set REC656 Mode */ - venc_write(sd, VENC_YCCCTL, 0x1); - } - - venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, - VENC_SYNCCTL_OVD); - venc_write(sd, VENC_VMOD, 0); - venc_modify(sd, VENC_VMOD, - (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, - (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); - venc_modify(sd, VENC_VMOD, - (1 << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_write(sd, VENC_DACTST, 0x0); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - - return 0; -} - -#define VDAC_CONFIG_HD_V2 0x081141EF -/* - * venc_set_480p59_94 - * - * This function configures the video encoder to EDTV(525p) component setting. - */ -static int venc_set_480p59_94(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); - if (venc->venc_type != VPBE_VERSION_1 && - venc->venc_type != VPBE_VERSION_2) - return -EINVAL; - - /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000); - venc_enabledigitaloutput(sd, 0); - - if (venc->venc_type == VPBE_VERSION_2) - vdaccfg_write(sd, VDAC_CONFIG_HD_V2); - venc_write(sd, VENC_OSDCLK0, 0); - venc_write(sd, VENC_OSDCLK1, 1); - - if (venc->venc_type == VPBE_VERSION_1) { - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, - VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, - VENC_VDPRO_DAUPS); - } - - venc_write(sd, VENC_VMOD, 0); - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); - venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << - VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); - - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - - return 0; -} - -/* - * venc_set_625p - * - * This function configures the video encoder to HDTV(625p) component setting - */ -static int venc_set_576p50(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); - - if (venc->venc_type != VPBE_VERSION_1 && - venc->venc_type != VPBE_VERSION_2) - return -EINVAL; - /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000); - venc_enabledigitaloutput(sd, 0); - - if (venc->venc_type == VPBE_VERSION_2) - vdaccfg_write(sd, VDAC_CONFIG_HD_V2); - - venc_write(sd, VENC_OSDCLK0, 0); - venc_write(sd, VENC_OSDCLK1, 1); - - if (venc->venc_type == VPBE_VERSION_1) { - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, - VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, - VENC_VDPRO_DAUPS); - } - - venc_write(sd, VENC_VMOD, 0); - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); - venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - - venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << - VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - - return 0; -} - -/* - * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only - */ -static int venc_set_720p60_internal(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000); - venc_enabledigitaloutput(sd, 0); - - venc_write(sd, VENC_OSDCLK0, 0); - venc_write(sd, VENC_OSDCLK1, 1); - - venc_write(sd, VENC_VMOD, 0); - /* DM365 component HD mode */ - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); - venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - venc_write(sd, VENC_XHINTVL, 0); - return 0; -} - -/* - * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only - */ -static int venc_set_1080i30_internal(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - struct venc_platform_data *pdata = venc->pdata; - - if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) - return -EINVAL; - - venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000); - venc_enabledigitaloutput(sd, 0); - - venc_write(sd, VENC_OSDCLK0, 0); - venc_write(sd, VENC_OSDCLK1, 1); - - - venc_write(sd, VENC_VMOD, 0); - /* DM365 component HD mode */ - venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), - VENC_VMOD_VIE); - venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); - venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT), - VENC_VMOD_TVTYP); - venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); - venc_write(sd, VENC_XHINTVL, 0); - return 0; -} - -static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); - - if (norm & V4L2_STD_525_60) - return venc_set_ntsc(sd); - else if (norm & V4L2_STD_625_50) - return venc_set_pal(sd); - - return -EINVAL; -} - -static int venc_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *dv_timings) -{ - struct venc_state *venc = to_state(sd); - u32 height = dv_timings->bt.height; - int ret; - - v4l2_dbg(debug, 1, sd, "venc_s_dv_timings\n"); - - if (height == 576) - return venc_set_576p50(sd); - else if (height == 480) - return venc_set_480p59_94(sd); - else if ((height == 720) && - (venc->venc_type == VPBE_VERSION_2)) { - /* TBD setup internal 720p mode here */ - ret = venc_set_720p60_internal(sd); - /* for DM365 VPBE, there is DAC inside */ - vdaccfg_write(sd, VDAC_CONFIG_HD_V2); - return ret; - } else if ((height == 1080) && - (venc->venc_type == VPBE_VERSION_2)) { - /* TBD setup internal 1080i mode here */ - ret = venc_set_1080i30_internal(sd); - /* for DM365 VPBE, there is DAC inside */ - vdaccfg_write(sd, VDAC_CONFIG_HD_V2); - return ret; - } - return -EINVAL; -} - -static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, - u32 config) -{ - struct venc_state *venc = to_state(sd); - int ret; - - v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); - - ret = venc_set_dac(sd, output); - if (!ret) - venc->output = output; - - return ret; -} - -static long venc_command(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - u32 val; - - switch (cmd) { - case VENC_GET_FLD: - val = venc_read(sd, VENC_VSTAT); - *((int *)arg) = ((val & VENC_VSTAT_FIDST) == - VENC_VSTAT_FIDST); - break; - default: - v4l2_err(sd, "Wrong IOCTL cmd\n"); - break; - } - - return 0; -} - -static const struct v4l2_subdev_core_ops venc_core_ops = { - .command = venc_command, -}; - -static const struct v4l2_subdev_video_ops venc_video_ops = { - .s_routing = venc_s_routing, - .s_std_output = venc_s_std_output, - .s_dv_timings = venc_s_dv_timings, -}; - -static const struct v4l2_subdev_ops venc_ops = { - .core = &venc_core_ops, - .video = &venc_video_ops, -}; - -static int venc_initialize(struct v4l2_subdev *sd) -{ - struct venc_state *venc = to_state(sd); - int ret; - - /* Set default to output to composite and std to NTSC */ - venc->output = 0; - venc->std = V4L2_STD_525_60; - - ret = venc_s_routing(sd, 0, venc->output, 0); - if (ret < 0) { - v4l2_err(sd, "Error setting output during init\n"); - return -EINVAL; - } - - ret = venc_s_std_output(sd, venc->std); - if (ret < 0) { - v4l2_err(sd, "Error setting std during init\n"); - return -EINVAL; - } - - return ret; -} - -static int venc_device_get(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - struct venc_state **venc = data; - - if (strstr(pdev->name, "vpbe-venc") != NULL) - *venc = platform_get_drvdata(pdev); - - return 0; -} - -struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, - const char *venc_name) -{ - struct venc_state *venc = NULL; - - bus_for_each_dev(&platform_bus_type, NULL, &venc, - venc_device_get); - if (venc == NULL) - return NULL; - - v4l2_subdev_init(&venc->sd, &venc_ops); - - strscpy(venc->sd.name, venc_name, sizeof(venc->sd.name)); - if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { - v4l2_err(v4l2_dev, - "vpbe unable to register venc sub device\n"); - return NULL; - } - if (venc_initialize(&venc->sd)) { - v4l2_err(v4l2_dev, - "vpbe venc initialization failed\n"); - return NULL; - } - - return &venc->sd; -} -EXPORT_SYMBOL(venc_sub_dev_init); - -static int venc_probe(struct platform_device *pdev) -{ - const struct platform_device_id *pdev_id; - struct venc_state *venc; - - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "No platform data for VENC sub device"); - return -EINVAL; - } - - pdev_id = platform_get_device_id(pdev); - if (!pdev_id) - return -EINVAL; - - venc = devm_kzalloc(&pdev->dev, sizeof(struct venc_state), GFP_KERNEL); - if (venc == NULL) - return -ENOMEM; - - venc->venc_type = pdev_id->driver_data; - venc->pdev = &pdev->dev; - venc->pdata = pdev->dev.platform_data; - - venc->venc_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(venc->venc_base)) - return PTR_ERR(venc->venc_base); - - if (venc->venc_type != VPBE_VERSION_1) { - venc->vdaccfg_reg = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(venc->vdaccfg_reg)) - return PTR_ERR(venc->vdaccfg_reg); - } - spin_lock_init(&venc->lock); - platform_set_drvdata(pdev, venc); - dev_notice(venc->pdev, "VENC sub device probe success\n"); - - return 0; -} - -static int venc_remove(struct platform_device *pdev) -{ - return 0; -} - -static struct platform_driver venc_driver = { - .probe = venc_probe, - .remove = venc_remove, - .driver = { - .name = MODULE_NAME, - }, - .id_table = vpbe_venc_devtype -}; - -module_platform_driver(venc_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VPBE VENC Driver"); -MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/media/platform/ti/davinci/vpbe_venc_regs.h b/drivers/media/platform/ti/davinci/vpbe_venc_regs.h deleted file mode 100644 index 29d8fc3af662..000000000000 --- a/drivers/media/platform/ti/davinci/vpbe_venc_regs.h +++ /dev/null @@ -1,165 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2006-2010 Texas Instruments Inc - */ -#ifndef _VPBE_VENC_REGS_H -#define _VPBE_VENC_REGS_H - -/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */ -#define VENC_VMOD 0x00 -#define VENC_VIDCTL 0x04 -#define VENC_VDPRO 0x08 -#define VENC_SYNCCTL 0x0C -#define VENC_HSPLS 0x10 -#define VENC_VSPLS 0x14 -#define VENC_HINT 0x18 -#define VENC_HSTART 0x1C -#define VENC_HVALID 0x20 -#define VENC_VINT 0x24 -#define VENC_VSTART 0x28 -#define VENC_VVALID 0x2C -#define VENC_HSDLY 0x30 -#define VENC_VSDLY 0x34 -#define VENC_YCCCTL 0x38 -#define VENC_RGBCTL 0x3C -#define VENC_RGBCLP 0x40 -#define VENC_LINECTL 0x44 -#define VENC_CULLLINE 0x48 -#define VENC_LCDOUT 0x4C -#define VENC_BRTS 0x50 -#define VENC_BRTW 0x54 -#define VENC_ACCTL 0x58 -#define VENC_PWMP 0x5C -#define VENC_PWMW 0x60 -#define VENC_DCLKCTL 0x64 -#define VENC_DCLKPTN0 0x68 -#define VENC_DCLKPTN1 0x6C -#define VENC_DCLKPTN2 0x70 -#define VENC_DCLKPTN3 0x74 -#define VENC_DCLKPTN0A 0x78 -#define VENC_DCLKPTN1A 0x7C -#define VENC_DCLKPTN2A 0x80 -#define VENC_DCLKPTN3A 0x84 -#define VENC_DCLKHS 0x88 -#define VENC_DCLKHSA 0x8C -#define VENC_DCLKHR 0x90 -#define VENC_DCLKVS 0x94 -#define VENC_DCLKVR 0x98 -#define VENC_CAPCTL 0x9C -#define VENC_CAPDO 0xA0 -#define VENC_CAPDE 0xA4 -#define VENC_ATR0 0xA8 -#define VENC_ATR1 0xAC -#define VENC_ATR2 0xB0 -#define VENC_VSTAT 0xB8 -#define VENC_RAMADR 0xBC -#define VENC_RAMPORT 0xC0 -#define VENC_DACTST 0xC4 -#define VENC_YCOLVL 0xC8 -#define VENC_SCPROG 0xCC -#define VENC_CVBS 0xDC -#define VENC_CMPNT 0xE0 -#define VENC_ETMG0 0xE4 -#define VENC_ETMG1 0xE8 -#define VENC_ETMG2 0xEC -#define VENC_ETMG3 0xF0 -#define VENC_DACSEL 0xF4 -#define VENC_ARGBX0 0x100 -#define VENC_ARGBX1 0x104 -#define VENC_ARGBX2 0x108 -#define VENC_ARGBX3 0x10C -#define VENC_ARGBX4 0x110 -#define VENC_DRGBX0 0x114 -#define VENC_DRGBX1 0x118 -#define VENC_DRGBX2 0x11C -#define VENC_DRGBX3 0x120 -#define VENC_DRGBX4 0x124 -#define VENC_VSTARTA 0x128 -#define VENC_OSDCLK0 0x12C -#define VENC_OSDCLK1 0x130 -#define VENC_HVLDCL0 0x134 -#define VENC_HVLDCL1 0x138 -#define VENC_OSDHADV 0x13C -#define VENC_CLKCTL 0x140 -#define VENC_GAMCTL 0x144 -#define VENC_XHINTVL 0x174 - -/* bit definitions */ -#define VPBE_PCR_VENC_DIV (1 << 1) -#define VPBE_PCR_CLK_OFF (1 << 0) - -#define VENC_VMOD_VDMD_SHIFT 12 -#define VENC_VMOD_VDMD_YCBCR16 0 -#define VENC_VMOD_VDMD_YCBCR8 1 -#define VENC_VMOD_VDMD_RGB666 2 -#define VENC_VMOD_VDMD_RGB8 3 -#define VENC_VMOD_VDMD_EPSON 4 -#define VENC_VMOD_VDMD_CASIO 5 -#define VENC_VMOD_VDMD_UDISPQVGA 6 -#define VENC_VMOD_VDMD_STNLCD 7 -#define VENC_VMOD_VIE_SHIFT 1 -#define VENC_VMOD_VDMD (7 << 12) -#define VENC_VMOD_ITLCL (1 << 11) -#define VENC_VMOD_ITLC (1 << 10) -#define VENC_VMOD_NSIT (1 << 9) -#define VENC_VMOD_HDMD (1 << 8) -#define VENC_VMOD_TVTYP_SHIFT 6 -#define VENC_VMOD_TVTYP (3 << 6) -#define VENC_VMOD_SLAVE (1 << 5) -#define VENC_VMOD_VMD (1 << 4) -#define VENC_VMOD_BLNK (1 << 3) -#define VENC_VMOD_VIE (1 << 1) -#define VENC_VMOD_VENC (1 << 0) - -/* VMOD TVTYP options for HDMD=0 */ -#define SDTV_NTSC 0 -#define SDTV_PAL 1 -/* VMOD TVTYP options for HDMD=1 */ -#define HDTV_525P 0 -#define HDTV_625P 1 -#define HDTV_1080I 2 -#define HDTV_720P 3 - -#define VENC_VIDCTL_VCLKP (1 << 14) -#define VENC_VIDCTL_VCLKE_SHIFT 13 -#define VENC_VIDCTL_VCLKE (1 << 13) -#define VENC_VIDCTL_VCLKZ_SHIFT 12 -#define VENC_VIDCTL_VCLKZ (1 << 12) -#define VENC_VIDCTL_SYDIR_SHIFT 8 -#define VENC_VIDCTL_SYDIR (1 << 8) -#define VENC_VIDCTL_DOMD_SHIFT 4 -#define VENC_VIDCTL_DOMD (3 << 4) -#define VENC_VIDCTL_YCDIR_SHIFT 0 -#define VENC_VIDCTL_YCDIR (1 << 0) - -#define VENC_VDPRO_ATYCC_SHIFT 5 -#define VENC_VDPRO_ATYCC (1 << 5) -#define VENC_VDPRO_ATCOM_SHIFT 4 -#define VENC_VDPRO_ATCOM (1 << 4) -#define VENC_VDPRO_DAFRQ (1 << 3) -#define VENC_VDPRO_DAUPS (1 << 2) -#define VENC_VDPRO_CUPS (1 << 1) -#define VENC_VDPRO_YUPS (1 << 0) - -#define VENC_SYNCCTL_VPL_SHIFT 3 -#define VENC_SYNCCTL_VPL (1 << 3) -#define VENC_SYNCCTL_HPL_SHIFT 2 -#define VENC_SYNCCTL_HPL (1 << 2) -#define VENC_SYNCCTL_SYEV_SHIFT 1 -#define VENC_SYNCCTL_SYEV (1 << 1) -#define VENC_SYNCCTL_SYEH_SHIFT 0 -#define VENC_SYNCCTL_SYEH (1 << 0) -#define VENC_SYNCCTL_OVD_SHIFT 14 -#define VENC_SYNCCTL_OVD (1 << 14) - -#define VENC_DCLKCTL_DCKEC_SHIFT 11 -#define VENC_DCLKCTL_DCKEC (1 << 11) -#define VENC_DCLKCTL_DCKPW_SHIFT 0 -#define VENC_DCLKCTL_DCKPW (0x3f << 0) - -#define VENC_VSTAT_FIDST (1 << 4) - -#define VENC_CMPNT_MRGB_SHIFT 14 -#define VENC_CMPNT_MRGB (1 << 14) - -#endif /* _VPBE_VENC_REGS_H */ diff --git a/drivers/media/platform/ti/davinci/vpss.c b/drivers/media/platform/ti/davinci/vpss.c deleted file mode 100644 index d15b991ab17c..000000000000 --- a/drivers/media/platform/ti/davinci/vpss.c +++ /dev/null @@ -1,529 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2009 Texas Instruments. - * - * common vpss system module platform driver for all video drivers. - */ -#include -#include -#include -#include -#include - -#include - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VPSS Driver"); -MODULE_AUTHOR("Texas Instruments"); - -/* DM644x defines */ -#define DM644X_SBL_PCR_VPSS (4) - -#define DM355_VPSSBL_INTSEL 0x10 -#define DM355_VPSSBL_EVTSEL 0x14 -/* vpss BL register offsets */ -#define DM355_VPSSBL_CCDCMUX 0x1c -/* vpss CLK register offsets */ -#define DM355_VPSSCLK_CLKCTRL 0x04 -/* masks and shifts */ -#define VPSS_HSSISEL_SHIFT 4 -/* - * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, - * IPIPE_INT1_SDR - vpss_int5 - */ -#define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 -/* VENCINT - vpss_int8 */ -#define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 - -#define DM365_ISP5_PCCR 0x04 -#define DM365_ISP5_PCCR_BL_CLK_ENABLE BIT(0) -#define DM365_ISP5_PCCR_ISIF_CLK_ENABLE BIT(1) -#define DM365_ISP5_PCCR_H3A_CLK_ENABLE BIT(2) -#define DM365_ISP5_PCCR_RSZ_CLK_ENABLE BIT(3) -#define DM365_ISP5_PCCR_IPIPE_CLK_ENABLE BIT(4) -#define DM365_ISP5_PCCR_IPIPEIF_CLK_ENABLE BIT(5) -#define DM365_ISP5_PCCR_RSV BIT(6) - -#define DM365_ISP5_BCR 0x08 -#define DM365_ISP5_BCR_ISIF_OUT_ENABLE BIT(1) - -#define DM365_ISP5_INTSEL1 0x10 -#define DM365_ISP5_INTSEL2 0x14 -#define DM365_ISP5_INTSEL3 0x18 -#define DM365_ISP5_CCDCMUX 0x20 -#define DM365_ISP5_PG_FRAME_SIZE 0x28 -#define DM365_VPBE_CLK_CTRL 0x00 - -#define VPSS_CLK_CTRL 0x01c40044 -#define VPSS_CLK_CTRL_VENCCLKEN BIT(3) -#define VPSS_CLK_CTRL_DACCLKEN BIT(4) - -/* - * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, - * AF - vpss_int3 - */ -#define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 -/* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ -#define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f -/* VENC - vpss_int8 */ -#define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 - -/* masks and shifts for DM365*/ -#define DM365_CCDC_PG_VD_POL_SHIFT 0 -#define DM365_CCDC_PG_HD_POL_SHIFT 1 - -#define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) -#define CCD_SRC_SEL_SHIFT 4 - -/* Different SoC platforms supported by this driver */ -enum vpss_platform_type { - DM644X, - DM355, - DM365, -}; - -/* - * vpss operations. Depends on platform. Not all functions are available - * on all platforms. The api, first check if a function is available before - * invoking it. In the probe, the function ptrs are initialized based on - * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. - */ -struct vpss_hw_ops { - /* enable clock */ - int (*enable_clock)(enum vpss_clock_sel clock_sel, int en); - /* select input to ccdc */ - void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel); - /* clear wbl overflow bit */ - int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel); - /* set sync polarity */ - void (*set_sync_pol)(struct vpss_sync_pol); - /* set the PG_FRAME_SIZE register*/ - void (*set_pg_frame_size)(struct vpss_pg_frame_size); - /* check and clear interrupt if occurred */ - int (*dma_complete_interrupt)(void); -}; - -/* vpss configuration */ -struct vpss_oper_config { - __iomem void *vpss_regs_base0; - __iomem void *vpss_regs_base1; - __iomem void *vpss_regs_base2; - enum vpss_platform_type platform; - spinlock_t vpss_lock; - struct vpss_hw_ops hw_ops; -}; - -static struct vpss_oper_config oper_cfg; - -/* register access routines */ -static inline u32 bl_regr(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base0 + offset); -} - -static inline void bl_regw(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); -} - -static inline u32 vpss_regr(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base1 + offset); -} - -static inline void vpss_regw(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); -} - -/* For DM365 only */ -static inline u32 isp5_read(u32 offset) -{ - return __raw_readl(oper_cfg.vpss_regs_base0 + offset); -} - -/* For DM365 only */ -static inline void isp5_write(u32 val, u32 offset) -{ - __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); -} - -static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; - - /* if we are using pattern generator, enable it */ - if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) - temp |= 0x08; - - temp |= (src_sel << CCD_SRC_SEL_SHIFT); - isp5_write(temp, DM365_ISP5_CCDCMUX); -} - -static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX); -} - -int vpss_dma_complete_interrupt(void) -{ - if (!oper_cfg.hw_ops.dma_complete_interrupt) - return 2; - return oper_cfg.hw_ops.dma_complete_interrupt(); -} -EXPORT_SYMBOL(vpss_dma_complete_interrupt); - -int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) -{ - if (!oper_cfg.hw_ops.select_ccdc_source) - return -EINVAL; - - oper_cfg.hw_ops.select_ccdc_source(src_sel); - return 0; -} -EXPORT_SYMBOL(vpss_select_ccdc_source); - -static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) -{ - u32 mask = 1, val; - - if (wbl_sel < VPSS_PCR_AEW_WBL_0 || - wbl_sel > VPSS_PCR_CCDC_WBL_O) - return -EINVAL; - - /* writing a 0 clear the overflow */ - mask = ~(mask << wbl_sel); - val = bl_regr(DM644X_SBL_PCR_VPSS) & mask; - bl_regw(val, DM644X_SBL_PCR_VPSS); - return 0; -} - -void vpss_set_sync_pol(struct vpss_sync_pol sync) -{ - if (!oper_cfg.hw_ops.set_sync_pol) - return; - - oper_cfg.hw_ops.set_sync_pol(sync); -} -EXPORT_SYMBOL(vpss_set_sync_pol); - -int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) -{ - if (!oper_cfg.hw_ops.clear_wbl_overflow) - return -EINVAL; - - return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); -} -EXPORT_SYMBOL(vpss_clear_wbl_overflow); - -/* - * dm355_enable_clock - Enable VPSS Clock - * @clock_sel: Clock to be enabled/disabled - * @en: enable/disable flag - * - * This is called to enable or disable a vpss clock - */ -static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - unsigned long flags; - u32 utemp, mask = 0x1, shift = 0; - - switch (clock_sel) { - case VPSS_VPBE_CLOCK: - /* nothing since lsb */ - break; - case VPSS_VENC_CLOCK_SEL: - shift = 2; - break; - case VPSS_CFALD_CLOCK: - shift = 3; - break; - case VPSS_H3A_CLOCK: - shift = 4; - break; - case VPSS_IPIPE_CLOCK: - shift = 5; - break; - case VPSS_CCDC_CLOCK: - shift = 6; - break; - default: - printk(KERN_ERR "dm355_enable_clock: Invalid selector: %d\n", - clock_sel); - return -EINVAL; - } - - spin_lock_irqsave(&oper_cfg.vpss_lock, flags); - utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL); - if (!en) - utemp &= ~(mask << shift); - else - utemp |= (mask << shift); - - vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL); - spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); - return 0; -} - -static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - unsigned long flags; - u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; - u32 (*read)(u32 offset) = isp5_read; - void(*write)(u32 val, u32 offset) = isp5_write; - - switch (clock_sel) { - case VPSS_BL_CLOCK: - break; - case VPSS_CCDC_CLOCK: - shift = 1; - break; - case VPSS_H3A_CLOCK: - shift = 2; - break; - case VPSS_RSZ_CLOCK: - shift = 3; - break; - case VPSS_IPIPE_CLOCK: - shift = 4; - break; - case VPSS_IPIPEIF_CLOCK: - shift = 5; - break; - case VPSS_PCLK_INTERNAL: - shift = 6; - break; - case VPSS_PSYNC_CLOCK_SEL: - shift = 7; - break; - case VPSS_VPBE_CLOCK: - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_VENC_CLOCK_SEL: - shift = 2; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_LDC_CLOCK: - shift = 3; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_FDIF_CLOCK: - shift = 4; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_OSD_CLOCK_SEL: - shift = 6; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - case VPSS_LDC_CLOCK_SEL: - shift = 7; - read = vpss_regr; - write = vpss_regw; - offset = DM365_VPBE_CLK_CTRL; - break; - default: - printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", - clock_sel); - return -1; - } - - spin_lock_irqsave(&oper_cfg.vpss_lock, flags); - utemp = read(offset); - if (!en) { - mask = ~mask; - utemp &= (mask << shift); - } else - utemp |= (mask << shift); - - write(utemp, offset); - spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); - - return 0; -} - -int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) -{ - if (!oper_cfg.hw_ops.enable_clock) - return -EINVAL; - - return oper_cfg.hw_ops.enable_clock(clock_sel, en); -} -EXPORT_SYMBOL(vpss_enable_clock); - -void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) -{ - int val = 0; - val = isp5_read(DM365_ISP5_CCDCMUX); - - val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); - val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); - - isp5_write(val, DM365_ISP5_CCDCMUX); -} -EXPORT_SYMBOL(dm365_vpss_set_sync_pol); - -void vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) -{ - if (!oper_cfg.hw_ops.set_pg_frame_size) - return; - - oper_cfg.hw_ops.set_pg_frame_size(frame_size); -} -EXPORT_SYMBOL(vpss_set_pg_frame_size); - -void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) -{ - int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; - - current_reg |= (frame_size.pplen - 1); - isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); -} -EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); - -static int vpss_probe(struct platform_device *pdev) -{ - char *platform_name; - - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "no platform data\n"); - return -ENOENT; - } - - platform_name = pdev->dev.platform_data; - if (!strcmp(platform_name, "dm355_vpss")) - oper_cfg.platform = DM355; - else if (!strcmp(platform_name, "dm365_vpss")) - oper_cfg.platform = DM365; - else if (!strcmp(platform_name, "dm644x_vpss")) - oper_cfg.platform = DM644X; - else { - dev_err(&pdev->dev, "vpss driver not supported on this platform\n"); - return -ENODEV; - } - - dev_info(&pdev->dev, "%s vpss probed\n", platform_name); - oper_cfg.vpss_regs_base0 = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(oper_cfg.vpss_regs_base0)) - return PTR_ERR(oper_cfg.vpss_regs_base0); - - if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { - oper_cfg.vpss_regs_base1 = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(oper_cfg.vpss_regs_base1)) - return PTR_ERR(oper_cfg.vpss_regs_base1); - } - - if (oper_cfg.platform == DM355) { - oper_cfg.hw_ops.enable_clock = dm355_enable_clock; - oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; - /* Setup vpss interrupts */ - bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); - bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); - } else if (oper_cfg.platform == DM365) { - oper_cfg.hw_ops.enable_clock = dm365_enable_clock; - oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; - /* Setup vpss interrupts */ - isp5_write((isp5_read(DM365_ISP5_PCCR) | - DM365_ISP5_PCCR_BL_CLK_ENABLE | - DM365_ISP5_PCCR_ISIF_CLK_ENABLE | - DM365_ISP5_PCCR_H3A_CLK_ENABLE | - DM365_ISP5_PCCR_RSZ_CLK_ENABLE | - DM365_ISP5_PCCR_IPIPE_CLK_ENABLE | - DM365_ISP5_PCCR_IPIPEIF_CLK_ENABLE | - DM365_ISP5_PCCR_RSV), DM365_ISP5_PCCR); - isp5_write((isp5_read(DM365_ISP5_BCR) | - DM365_ISP5_BCR_ISIF_OUT_ENABLE), DM365_ISP5_BCR); - isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); - isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); - isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); - } else - oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; - - pm_runtime_enable(&pdev->dev); - - pm_runtime_get(&pdev->dev); - - spin_lock_init(&oper_cfg.vpss_lock); - dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); - - return 0; -} - -static int vpss_remove(struct platform_device *pdev) -{ - pm_runtime_disable(&pdev->dev); - return 0; -} - -static int vpss_suspend(struct device *dev) -{ - pm_runtime_put(dev); - return 0; -} - -static int vpss_resume(struct device *dev) -{ - pm_runtime_get(dev); - return 0; -} - -static const struct dev_pm_ops vpss_pm_ops = { - .suspend = vpss_suspend, - .resume = vpss_resume, -}; - -static struct platform_driver vpss_driver = { - .driver = { - .name = "vpss", - .pm = &vpss_pm_ops, - }, - .remove = vpss_remove, - .probe = vpss_probe, -}; - -static void vpss_exit(void) -{ - platform_driver_unregister(&vpss_driver); - iounmap(oper_cfg.vpss_regs_base2); - release_mem_region(VPSS_CLK_CTRL, 4); -} - -static int __init vpss_init(void) -{ - int ret; - - if (!request_mem_region(VPSS_CLK_CTRL, 4, "vpss_clock_control")) - return -EBUSY; - - oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4); - if (unlikely(!oper_cfg.vpss_regs_base2)) { - ret = -ENOMEM; - goto err_ioremap; - } - - writel(VPSS_CLK_CTRL_VENCCLKEN | - VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2); - - ret = platform_driver_register(&vpss_driver); - if (ret) - goto err_pd_register; - - return 0; - -err_pd_register: - iounmap(oper_cfg.vpss_regs_base2); -err_ioremap: - release_mem_region(VPSS_CLK_CTRL, 4); - return ret; -} -subsys_initcall(vpss_init); -module_exit(vpss_exit); diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h deleted file mode 100644 index 646c4b48b29d..000000000000 --- a/include/media/davinci/vpbe.h +++ /dev/null @@ -1,184 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2010 Texas Instruments Inc - */ -#ifndef _VPBE_H -#define _VPBE_H - -#include -#include - -#include -#include -#include -#include -#include -#include - -/* OSD configuration info */ -struct osd_config_info { - char module_name[32]; -}; - -struct vpbe_output { - struct v4l2_output output; - /* - * If output capabilities include dv_timings, list supported timings - * below - */ - char *subdev_name; - /* - * default_mode identifies the default timings set at the venc or - * external encoder. - */ - char *default_mode; - /* - * Fields below are used for supporting multiple modes. For example, - * LCD panel might support different modes and they are listed here. - * Similarly for supporting external encoders, lcd controller port - * requires a set of non-standard timing values to be listed here for - * each supported mode since venc is used in non-standard timing mode - * for interfacing with external encoder similar to configuring lcd - * panel timings - */ - unsigned int num_modes; - struct vpbe_enc_mode_info *modes; - /* - * Bus configuration goes here for external encoders. Some encoders - * may require multiple interface types for each of the output. For - * example, SD modes would use YCC8 where as HD mode would use YCC16. - * Not sure if this is needed on a per mode basis instead of per - * output basis. If per mode is needed, we may have to move this to - * mode_info structure - */ - u32 if_params; -}; - -/* encoder configuration info */ -struct encoder_config_info { - char module_name[32]; - /* Is this an i2c device ? */ - unsigned int is_i2c:1; - /* i2c subdevice board info */ - struct i2c_board_info board_info; -}; - -/*amplifier configuration info */ -struct amp_config_info { - char module_name[32]; - /* Is this an i2c device ? */ - unsigned int is_i2c:1; - /* i2c subdevice board info */ - struct i2c_board_info board_info; -}; - -/* structure for defining vpbe display subsystem components */ -struct vpbe_config { - char module_name[32]; - /* i2c bus adapter no */ - int i2c_adapter_id; - struct osd_config_info osd; - struct encoder_config_info venc; - /* external encoder information goes here */ - int num_ext_encoders; - struct encoder_config_info *ext_encoders; - /* amplifier information goes here */ - struct amp_config_info *amp; - unsigned int num_outputs; - /* Order is venc outputs followed by LCD and then external encoders */ - struct vpbe_output *outputs; -}; - -struct vpbe_device; - -struct vpbe_device_ops { - /* Enumerate the outputs */ - int (*enum_outputs)(struct vpbe_device *vpbe_dev, - struct v4l2_output *output); - - /* Set output to the given index */ - int (*set_output)(struct vpbe_device *vpbe_dev, - int index); - - /* Get current output */ - unsigned int (*get_output)(struct vpbe_device *vpbe_dev); - - /* Set DV preset at current output */ - int (*s_dv_timings)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_timings *dv_timings); - - /* Get DV presets supported at the output */ - int (*g_dv_timings)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_timings *dv_timings); - - /* Enumerate the DV Presets supported at the output */ - int (*enum_dv_timings)(struct vpbe_device *vpbe_dev, - struct v4l2_enum_dv_timings *timings_info); - - /* Set std at the output */ - int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id std_id); - - /* Get the current std at the output */ - int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); - - /* initialize the device */ - int (*initialize)(struct device *dev, struct vpbe_device *vpbe_dev); - - /* De-initialize the device */ - void (*deinitialize)(struct device *dev, struct vpbe_device *vpbe_dev); - - /* Get the current mode info */ - int (*get_mode_info)(struct vpbe_device *vpbe_dev, - struct vpbe_enc_mode_info*); - - /* - * Set the current mode in the encoder. Alternate way of setting - * standard or DV preset or custom timings in the encoder - */ - int (*set_mode)(struct vpbe_device *vpbe_dev, - struct vpbe_enc_mode_info*); - /* Power management operations */ - int (*suspend)(struct vpbe_device *vpbe_dev); - int (*resume)(struct vpbe_device *vpbe_dev); -}; - -/* struct for vpbe device */ -struct vpbe_device { - /* V4l2 device */ - struct v4l2_device v4l2_dev; - /* vpbe dispay controller cfg */ - struct vpbe_config *cfg; - /* parent device */ - struct device *pdev; - /* external encoder v4l2 sub devices */ - struct v4l2_subdev **encoders; - /* current encoder index */ - int current_sd_index; - /* external amplifier v4l2 subdevice */ - struct v4l2_subdev *amp; - struct mutex lock; - /* device initialized */ - int initialized; - /* vpbe dac clock */ - struct clk *dac_clk; - /* osd_device pointer */ - struct osd_state *osd_device; - /* venc device pointer */ - struct venc_platform_data *venc_device; - /* - * fields below are accessed by users of vpbe_device. Not the - * ones above - */ - - /* current output */ - int current_out_index; - /* lock used by caller to do atomic operation on vpbe device */ - /* current timings set in the controller */ - struct vpbe_enc_mode_info current_timings; - /* venc sub device */ - struct v4l2_subdev *venc; - /* device operations below */ - struct vpbe_device_ops ops; -}; - -#endif diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h deleted file mode 100644 index d8751ea926a2..000000000000 --- a/include/media/davinci/vpbe_display.h +++ /dev/null @@ -1,122 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ - */ -#ifndef VPBE_DISPLAY_H -#define VPBE_DISPLAY_H - -/* Header files */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define VPBE_DISPLAY_MAX_DEVICES 2 - -enum vpbe_display_device_id { - VPBE_DISPLAY_DEVICE_0, - VPBE_DISPLAY_DEVICE_1 -}; - -#define VPBE_DISPLAY_DRV_NAME "vpbe-display" - -#define VPBE_DISPLAY_MAJOR_RELEASE 1 -#define VPBE_DISPLAY_MINOR_RELEASE 0 -#define VPBE_DISPLAY_BUILD 1 -#define VPBE_DISPLAY_VERSION_CODE ((VPBE_DISPLAY_MAJOR_RELEASE << 16) | \ - (VPBE_DISPLAY_MINOR_RELEASE << 8) | \ - VPBE_DISPLAY_BUILD) - -#define VPBE_DISPLAY_VALID_FIELD(field) ((V4L2_FIELD_NONE == field) || \ - (V4L2_FIELD_ANY == field) || (V4L2_FIELD_INTERLACED == field)) - -/* Exp ratio numerator and denominator constants */ -#define VPBE_DISPLAY_H_EXP_RATIO_N 9 -#define VPBE_DISPLAY_H_EXP_RATIO_D 8 -#define VPBE_DISPLAY_V_EXP_RATIO_N 6 -#define VPBE_DISPLAY_V_EXP_RATIO_D 5 - -/* Zoom multiplication factor */ -#define VPBE_DISPLAY_ZOOM_4X 4 -#define VPBE_DISPLAY_ZOOM_2X 2 - -/* Structures */ -struct display_layer_info { - int enable; - /* Layer ID used by Display Manager */ - enum osd_layer id; - struct osd_layer_config config; - enum osd_zoom_factor h_zoom; - enum osd_zoom_factor v_zoom; - enum osd_h_exp_ratio h_exp; - enum osd_v_exp_ratio v_exp; -}; - -struct vpbe_disp_buffer { - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -/* vpbe display object structure */ -struct vpbe_layer { - /* Pointer to the vpbe_display */ - struct vpbe_display *disp_dev; - /* Pointer pointing to current v4l2_buffer */ - struct vpbe_disp_buffer *cur_frm; - /* Pointer pointing to next v4l2_buffer */ - struct vpbe_disp_buffer *next_frm; - /* vb2 specific parameters - * Buffer queue used in vb2 - */ - struct vb2_queue buffer_queue; - /* Queue of filled frames */ - struct list_head dma_queue; - /* Used for video buffer handling */ - spinlock_t irqlock; - /* V4l2 specific parameters */ - /* Identifies video device for this layer */ - struct video_device video_dev; - /* Used to store pixel format */ - struct v4l2_pix_format pix_fmt; - enum v4l2_field buf_field; - /* Video layer configuration params */ - struct display_layer_info layer_info; - /* vpbe specific parameters - * enable window for display - */ - unsigned char window_enable; - /* number of open instances of the layer */ - unsigned int usrs; - /* Indicates id of the field which is being displayed */ - unsigned int field_id; - /* Identifies device object */ - enum vpbe_display_device_id device_id; - /* facilitation of ioctl ops lock by v4l2*/ - struct mutex opslock; - u8 layer_first_int; -}; - -/* vpbe device structure */ -struct vpbe_display { - /* layer specific parameters */ - /* lock for isr updates to buf layers*/ - spinlock_t dma_queue_lock; - /* C-Plane offset from start of y-plane */ - unsigned int cbcr_ofst; - struct vpbe_layer *dev[VPBE_DISPLAY_MAX_DEVICES]; - struct vpbe_device *vpbe_dev; - struct osd_state *osd_device; -}; - -struct buf_config_params { - unsigned char min_numbuffers; - unsigned char numbuffers[VPBE_DISPLAY_MAX_DEVICES]; - unsigned int min_bufsize[VPBE_DISPLAY_MAX_DEVICES]; - unsigned int layer_bufsize[VPBE_DISPLAY_MAX_DEVICES]; -}; - -#endif /* VPBE_DISPLAY_H */ diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h deleted file mode 100644 index a4fc4f2a56fb..000000000000 --- a/include/media/davinci/vpbe_osd.h +++ /dev/null @@ -1,382 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2007-2009 Texas Instruments Inc - * Copyright (C) 2007 MontaVista Software, Inc. - * - * Andy Lowe (alowe@mvista.com), MontaVista Software - * - Initial version - * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd. - * - ported to sub device interface - */ -#ifndef _OSD_H -#define _OSD_H - -#include - -#define DM644X_VPBE_OSD_SUBDEV_NAME "dm644x,vpbe-osd" -#define DM365_VPBE_OSD_SUBDEV_NAME "dm365,vpbe-osd" -#define DM355_VPBE_OSD_SUBDEV_NAME "dm355,vpbe-osd" - -/** - * enum osd_layer - * @WIN_OSD0: On-Screen Display Window 0 - * @WIN_VID0: Video Window 0 - * @WIN_OSD1: On-Screen Display Window 1 - * @WIN_VID1: Video Window 1 - * - * Description: - * An enumeration of the osd display layers. - */ -enum osd_layer { - WIN_OSD0, - WIN_VID0, - WIN_OSD1, - WIN_VID1, -}; - -/** - * enum osd_win_layer - * @OSDWIN_OSD0: On-Screen Display Window 0 - * @OSDWIN_OSD1: On-Screen Display Window 1 - * - * Description: - * An enumeration of the OSD Window layers. - */ -enum osd_win_layer { - OSDWIN_OSD0, - OSDWIN_OSD1, -}; - -/** - * enum osd_pix_format - * @PIXFMT_1BPP: 1-bit-per-pixel bitmap - * @PIXFMT_2BPP: 2-bits-per-pixel bitmap - * @PIXFMT_4BPP: 4-bits-per-pixel bitmap - * @PIXFMT_8BPP: 8-bits-per-pixel bitmap - * @PIXFMT_RGB565: 16-bits-per-pixel RGB565 - * @PIXFMT_YCBCRI: YUV 4:2:2 - * @PIXFMT_RGB888: 24-bits-per-pixel RGB888 - * @PIXFMT_YCRCBI: YUV 4:2:2 with chroma swap - * @PIXFMT_NV12: YUV 4:2:0 planar - * @PIXFMT_OSD_ATTR: OSD Attribute Window pixel format (4bpp) - * - * Description: - * An enumeration of the DaVinci pixel formats. - */ -enum osd_pix_format { - PIXFMT_1BPP = 0, - PIXFMT_2BPP, - PIXFMT_4BPP, - PIXFMT_8BPP, - PIXFMT_RGB565, - PIXFMT_YCBCRI, - PIXFMT_RGB888, - PIXFMT_YCRCBI, - PIXFMT_NV12, - PIXFMT_OSD_ATTR, -}; - -/** - * enum osd_h_exp_ratio - * @H_EXP_OFF: no expansion (1/1) - * @H_EXP_9_OVER_8: 9/8 expansion ratio - * @H_EXP_3_OVER_2: 3/2 expansion ratio - * - * Description: - * An enumeration of the available horizontal expansion ratios. - */ -enum osd_h_exp_ratio { - H_EXP_OFF, - H_EXP_9_OVER_8, - H_EXP_3_OVER_2, -}; - -/** - * enum osd_v_exp_ratio - * @V_EXP_OFF: no expansion (1/1) - * @V_EXP_6_OVER_5: 6/5 expansion ratio - * - * Description: - * An enumeration of the available vertical expansion ratios. - */ -enum osd_v_exp_ratio { - V_EXP_OFF, - V_EXP_6_OVER_5, -}; - -/** - * enum osd_zoom_factor - * @ZOOM_X1: no zoom (x1) - * @ZOOM_X2: x2 zoom - * @ZOOM_X4: x4 zoom - * - * Description: - * An enumeration of the available zoom factors. - */ -enum osd_zoom_factor { - ZOOM_X1, - ZOOM_X2, - ZOOM_X4, -}; - -/** - * enum osd_clut - * @ROM_CLUT: ROM CLUT - * @RAM_CLUT: RAM CLUT - * - * Description: - * An enumeration of the available Color Lookup Tables (CLUTs). - */ -enum osd_clut { - ROM_CLUT, - RAM_CLUT, -}; - -/** - * enum osd_rom_clut - * @ROM_CLUT0: Macintosh CLUT - * @ROM_CLUT1: CLUT from DM270 and prior devices - * - * Description: - * An enumeration of the ROM Color Lookup Table (CLUT) options. - */ -enum osd_rom_clut { - ROM_CLUT0, - ROM_CLUT1, -}; - -/** - * enum osd_blending_factor - * @OSD_0_VID_8: OSD pixels are fully transparent - * @OSD_1_VID_7: OSD pixels contribute 1/8, video pixels contribute 7/8 - * @OSD_2_VID_6: OSD pixels contribute 2/8, video pixels contribute 6/8 - * @OSD_3_VID_5: OSD pixels contribute 3/8, video pixels contribute 5/8 - * @OSD_4_VID_4: OSD pixels contribute 4/8, video pixels contribute 4/8 - * @OSD_5_VID_3: OSD pixels contribute 5/8, video pixels contribute 3/8 - * @OSD_6_VID_2: OSD pixels contribute 6/8, video pixels contribute 2/8 - * @OSD_8_VID_0: OSD pixels are fully opaque - * - * Description: - * An enumeration of the DaVinci pixel blending factor options. - */ -enum osd_blending_factor { - OSD_0_VID_8, - OSD_1_VID_7, - OSD_2_VID_6, - OSD_3_VID_5, - OSD_4_VID_4, - OSD_5_VID_3, - OSD_6_VID_2, - OSD_8_VID_0, -}; - -/** - * enum osd_blink_interval - * @BLINK_X1: blink interval is 1 vertical refresh cycle - * @BLINK_X2: blink interval is 2 vertical refresh cycles - * @BLINK_X3: blink interval is 3 vertical refresh cycles - * @BLINK_X4: blink interval is 4 vertical refresh cycles - * - * Description: - * An enumeration of the DaVinci pixel blinking interval options. - */ -enum osd_blink_interval { - BLINK_X1, - BLINK_X2, - BLINK_X3, - BLINK_X4, -}; - -/** - * enum osd_cursor_h_width - * @H_WIDTH_1: horizontal line width is 1 pixel - * @H_WIDTH_4: horizontal line width is 4 pixels - * @H_WIDTH_8: horizontal line width is 8 pixels - * @H_WIDTH_12: horizontal line width is 12 pixels - * @H_WIDTH_16: horizontal line width is 16 pixels - * @H_WIDTH_20: horizontal line width is 20 pixels - * @H_WIDTH_24: horizontal line width is 24 pixels - * @H_WIDTH_28: horizontal line width is 28 pixels - */ -enum osd_cursor_h_width { - H_WIDTH_1, - H_WIDTH_4, - H_WIDTH_8, - H_WIDTH_12, - H_WIDTH_16, - H_WIDTH_20, - H_WIDTH_24, - H_WIDTH_28, -}; - -/** - * enum osd_cursor_v_width - * @V_WIDTH_1: vertical line width is 1 line - * @V_WIDTH_2: vertical line width is 2 lines - * @V_WIDTH_4: vertical line width is 4 lines - * @V_WIDTH_6: vertical line width is 6 lines - * @V_WIDTH_8: vertical line width is 8 lines - * @V_WIDTH_10: vertical line width is 10 lines - * @V_WIDTH_12: vertical line width is 12 lines - * @V_WIDTH_14: vertical line width is 14 lines - */ -enum osd_cursor_v_width { - V_WIDTH_1, - V_WIDTH_2, - V_WIDTH_4, - V_WIDTH_6, - V_WIDTH_8, - V_WIDTH_10, - V_WIDTH_12, - V_WIDTH_14, -}; - -/** - * struct osd_cursor_config - * @xsize: horizontal size in pixels - * @ysize: vertical size in lines - * @xpos: horizontal offset in pixels from the left edge of the display - * @ypos: vertical offset in lines from the top of the display - * @interlaced: Non-zero if the display is interlaced, or zero otherwise - * @h_width: horizontal line width - * @v_width: vertical line width - * @clut: the CLUT selector (ROM or RAM) for the cursor color - * @clut_index: an index into the CLUT for the cursor color - * - * Description: - * A structure describing the configuration parameters of the hardware - * rectangular cursor. - */ -struct osd_cursor_config { - unsigned xsize; - unsigned ysize; - unsigned xpos; - unsigned ypos; - int interlaced; - enum osd_cursor_h_width h_width; - enum osd_cursor_v_width v_width; - enum osd_clut clut; - unsigned char clut_index; -}; - -/** - * struct osd_layer_config - * @pixfmt: pixel format - * @line_length: offset in bytes between start of each line in memory - * @xsize: number of horizontal pixels displayed per line - * @ysize: number of lines displayed - * @xpos: horizontal offset in pixels from the left edge of the display - * @ypos: vertical offset in lines from the top of the display - * @interlaced: Non-zero if the display is interlaced, or zero otherwise - * - * Description: - * A structure describing the configuration parameters of an On-Screen Display - * (OSD) or video layer related to how the image is stored in memory. - * @line_length must be a multiple of the cache line size (32 bytes). - */ -struct osd_layer_config { - enum osd_pix_format pixfmt; - unsigned line_length; - unsigned xsize; - unsigned ysize; - unsigned xpos; - unsigned ypos; - int interlaced; -}; - -/* parameters that apply on a per-window (OSD or video) basis */ -struct osd_window_state { - int is_allocated; - int is_enabled; - unsigned long fb_base_phys; - enum osd_zoom_factor h_zoom; - enum osd_zoom_factor v_zoom; - struct osd_layer_config lconfig; -}; - -/* parameters that apply on a per-OSD-window basis */ -struct osd_osdwin_state { - enum osd_clut clut; - enum osd_blending_factor blend; - int colorkey_blending; - unsigned colorkey; - int rec601_attenuation; - /* index is pixel value */ - unsigned char palette_map[16]; -}; - -/* hardware rectangular cursor parameters */ -struct osd_cursor_state { - int is_enabled; - struct osd_cursor_config config; -}; - -struct osd_state; - -struct vpbe_osd_ops { - int (*initialize)(struct osd_state *sd); - int (*request_layer)(struct osd_state *sd, enum osd_layer layer); - void (*release_layer)(struct osd_state *sd, enum osd_layer layer); - int (*enable_layer)(struct osd_state *sd, enum osd_layer layer, - int otherwin); - void (*disable_layer)(struct osd_state *sd, enum osd_layer layer); - int (*set_layer_config)(struct osd_state *sd, enum osd_layer layer, - struct osd_layer_config *lconfig); - void (*get_layer_config)(struct osd_state *sd, enum osd_layer layer, - struct osd_layer_config *lconfig); - void (*start_layer)(struct osd_state *sd, enum osd_layer layer, - unsigned long fb_base_phys, - unsigned long cbcr_ofst); - void (*set_left_margin)(struct osd_state *sd, u32 val); - void (*set_top_margin)(struct osd_state *sd, u32 val); - void (*set_interpolation_filter)(struct osd_state *sd, int filter); - int (*set_vid_expansion)(struct osd_state *sd, - enum osd_h_exp_ratio h_exp, - enum osd_v_exp_ratio v_exp); - void (*get_vid_expansion)(struct osd_state *sd, - enum osd_h_exp_ratio *h_exp, - enum osd_v_exp_ratio *v_exp); - void (*set_zoom)(struct osd_state *sd, enum osd_layer layer, - enum osd_zoom_factor h_zoom, - enum osd_zoom_factor v_zoom); -}; - -struct osd_state { - enum vpbe_version vpbe_type; - spinlock_t lock; - struct device *dev; - dma_addr_t osd_base_phys; - void __iomem *osd_base; - unsigned long osd_size; - /* 1-->the isr will toggle the VID0 ping-pong buffer */ - int pingpong; - int interpolation_filter; - int field_inversion; - enum osd_h_exp_ratio osd_h_exp; - enum osd_v_exp_ratio osd_v_exp; - enum osd_h_exp_ratio vid_h_exp; - enum osd_v_exp_ratio vid_v_exp; - enum osd_clut backg_clut; - unsigned backg_clut_index; - enum osd_rom_clut rom_clut; - int is_blinking; - /* attribute window blinking enabled */ - enum osd_blink_interval blink; - /* YCbCrI or YCrCbI */ - enum osd_pix_format yc_pixfmt; - /* columns are Y, Cb, Cr */ - unsigned char clut_ram[256][3]; - struct osd_cursor_state cursor; - /* OSD0, VID0, OSD1, VID1 */ - struct osd_window_state win[4]; - /* OSD0, OSD1 */ - struct osd_osdwin_state osdwin[2]; - /* OSD device Operations */ - struct vpbe_osd_ops ops; -}; - -struct osd_platform_data { - int field_inv_wa_enable; -}; - -#endif diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h deleted file mode 100644 index 6015cda235cc..000000000000 --- a/include/media/davinci/vpbe_types.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2010 Texas Instruments Inc - */ -#ifndef _VPBE_TYPES_H -#define _VPBE_TYPES_H - -enum vpbe_version { - VPBE_VERSION_1 = 1, - VPBE_VERSION_2, - VPBE_VERSION_3, -}; - -/* vpbe_timing_type - Timing types used in vpbe device */ -enum vpbe_enc_timings_type { - VPBE_ENC_STD = 0x1, - VPBE_ENC_DV_TIMINGS = 0x4, - /* Used when set timings through FB device interface */ - VPBE_ENC_TIMINGS_INVALID = 0x8, -}; - -/* - * struct vpbe_enc_mode_info - * @name: ptr to name string of the standard, "NTSC", "PAL" etc - * @std: standard or non-standard mode. 1 - standard, 0 - nonstandard - * @interlaced: 1 - interlaced, 0 - non interlaced/progressive - * @xres: x or horizontal resolution of the display - * @yres: y or vertical resolution of the display - * @fps: frame per second - * @left_margin: left margin of the display - * @right_margin: right margin of the display - * @upper_margin: upper margin of the display - * @lower_margin: lower margin of the display - * @hsync_len: h-sync length - * @vsync_len: v-sync length - * @flags: bit field: bit usage is documented below - * - * Description: - * Structure holding timing and resolution information of a standard. - * Used by vpbe_device to set required non-standard timing in the - * venc when lcd controller output is connected to a external encoder. - * A table of timings is maintained in vpbe device to set this in - * venc when external encoder is connected to lcd controller output. - * Encoder may provide a g_dv_timings() API to override these values - * as needed. - * - * Notes - * ------ - * if_type should be used only by encoder manager and encoder. - * flags usage - * b0 (LSB) - hsync polarity, 0 - negative, 1 - positive - * b1 - vsync polarity, 0 - negative, 1 - positive - * b2 - field id polarity, 0 - negative, 1 - positive - */ -struct vpbe_enc_mode_info { - unsigned char *name; - enum vpbe_enc_timings_type timings_type; - v4l2_std_id std_id; - struct v4l2_dv_timings dv_timings; - unsigned int interlaced; - unsigned int xres; - unsigned int yres; - struct v4l2_fract aspect; - struct v4l2_fract fps; - unsigned int left_margin; - unsigned int right_margin; - unsigned int upper_margin; - unsigned int lower_margin; - unsigned int hsync_len; - unsigned int vsync_len; - unsigned int flags; -}; - -#endif diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h deleted file mode 100644 index 93cf6a5fb49d..000000000000 --- a/include/media/davinci/vpbe_venc.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2010 Texas Instruments Inc - */ -#ifndef _VPBE_VENC_H -#define _VPBE_VENC_H - -#include -#include - -#define DM644X_VPBE_VENC_SUBDEV_NAME "dm644x,vpbe-venc" -#define DM365_VPBE_VENC_SUBDEV_NAME "dm365,vpbe-venc" -#define DM355_VPBE_VENC_SUBDEV_NAME "dm355,vpbe-venc" - -/* venc events */ -#define VENC_END_OF_FRAME BIT(0) -#define VENC_FIRST_FIELD BIT(1) -#define VENC_SECOND_FIELD BIT(2) - -struct venc_platform_data { - int (*setup_pinmux)(u32 if_type, int field); - int (*setup_clock)(enum vpbe_enc_timings_type type, - unsigned int pixclock); - int (*setup_if_config)(u32 pixcode); - /* Number of LCD outputs supported */ - int num_lcd_outputs; - struct vpbe_if_params *lcd_if_params; -}; - -enum venc_ioctls { - VENC_GET_FLD = 1, -}; - -/* exported functions */ -struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, - const char *venc_name); -#endif diff --git a/include/media/davinci/vpss.h b/include/media/davinci/vpss.h deleted file mode 100644 index 315fa77e238c..000000000000 --- a/include/media/davinci/vpss.h +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2009 Texas Instruments Inc - * - * vpss - video processing subsystem module header file. - * - * Include this header file if a driver needs to configure vpss system - * module. It exports a set of library functions for video drivers to - * configure vpss system module functions such as clock enable/disable, - * vpss interrupt mux to arm, and other common vpss system module - * functions. - */ -#ifndef _VPSS_H -#define _VPSS_H - -/* selector for ccdc input selection on DM355 */ -enum vpss_ccdc_source_sel { - VPSS_CCDCIN, - VPSS_HSSIIN, - VPSS_PGLPBK, /* for DM365 only */ - VPSS_CCDCPG /* for DM365 only */ -}; - -struct vpss_sync_pol { - unsigned int ccdpg_hdpol:1; - unsigned int ccdpg_vdpol:1; -}; - -struct vpss_pg_frame_size { - short hlpfr; - short pplen; -}; - -/* Used for enable/disable VPSS Clock */ -enum vpss_clock_sel { - /* DM355/DM365 */ - VPSS_CCDC_CLOCK, - VPSS_IPIPE_CLOCK, - VPSS_H3A_CLOCK, - VPSS_CFALD_CLOCK, - /* - * When using VPSS_VENC_CLOCK_SEL in vpss_enable_clock() api - * following applies:- - * en = 0 selects ENC_CLK - * en = 1 selects ENC_CLK/2 - */ - VPSS_VENC_CLOCK_SEL, - VPSS_VPBE_CLOCK, - /* DM365 only clocks */ - VPSS_IPIPEIF_CLOCK, - VPSS_RSZ_CLOCK, - VPSS_BL_CLOCK, - /* - * When using VPSS_PCLK_INTERNAL in vpss_enable_clock() api - * following applies:- - * en = 0 disable internal PCLK - * en = 1 enables internal PCLK - */ - VPSS_PCLK_INTERNAL, - /* - * When using VPSS_PSYNC_CLOCK_SEL in vpss_enable_clock() api - * following applies:- - * en = 0 enables MMR clock - * en = 1 enables VPSS clock - */ - VPSS_PSYNC_CLOCK_SEL, - VPSS_LDC_CLOCK_SEL, - VPSS_OSD_CLOCK_SEL, - VPSS_FDIF_CLOCK, - VPSS_LDC_CLOCK -}; - -/* select input to ccdc on dm355 */ -int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel); -/* enable/disable a vpss clock, 0 - success, -1 - failure */ -int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en); -/* set sync polarity, only for DM365*/ -void dm365_vpss_set_sync_pol(struct vpss_sync_pol); -/* set the PG_FRAME_SIZE register, only for DM365 */ -void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size); - -/* wbl reset for dm644x */ -enum vpss_wbl_sel { - VPSS_PCR_AEW_WBL_0 = 16, - VPSS_PCR_AF_WBL_0, - VPSS_PCR_RSZ4_WBL_0, - VPSS_PCR_RSZ3_WBL_0, - VPSS_PCR_RSZ2_WBL_0, - VPSS_PCR_RSZ1_WBL_0, - VPSS_PCR_PREV_WBL_0, - VPSS_PCR_CCDC_WBL_O, -}; -/* clear wbl overflow flag for DM6446 */ -int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel); - -/* set sync polarity*/ -void vpss_set_sync_pol(struct vpss_sync_pol sync); -/* set the PG_FRAME_SIZE register */ -void vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size); -/* - * vpss_check_and_clear_interrupt - check and clear interrupt - * @irq - common enumerator for IRQ - * - * Following return values used:- - * 0 - interrupt occurred and cleared - * 1 - interrupt not occurred - * 2 - interrupt status not available - */ -int vpss_dma_complete_interrupt(void); - -#endif -- cgit v1.2.3 From 952f6c9daf509f7919887c26753884fa530f8622 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 26 Dec 2022 20:16:09 +0100 Subject: wifi: mac80211: Drop stations iterator where the iterator function may sleep This reverts commit acb99b9b2a08f ("mac80211: Add stations iterator where the iterator function may sleep"). A different approach was found for the rtw88 driver where most of the problematic locks were converted to a driver-local mutex. Drop ieee80211_iterate_stations() because there are no users of that function. Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20221226191609.2934234-1-martin.blumenstingl@googlemail.com Signed-off-by: Johannes Berg --- include/net/mac80211.h | 21 --------------------- net/mac80211/util.c | 13 ------------- 2 files changed, 34 deletions(-) (limited to 'include') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 689da327ce2e..b421a1bfc7c5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5888,9 +5888,6 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, * This function iterates over the interfaces associated with a given * hardware that are currently active and calls the callback for them. * This version can only be used while holding the wiphy mutex. - * The driver must not call this with a lock held that it can also take in - * response to callbacks from mac80211, and it must not call this within - * callbacks made by mac80211 - both would result in deadlocks. * * @hw: the hardware struct of which the interfaces should be iterated over * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags @@ -5904,24 +5901,6 @@ void ieee80211_iterate_active_interfaces_mtx(struct ieee80211_hw *hw, struct ieee80211_vif *vif), void *data); -/** - * ieee80211_iterate_stations - iterate stations - * - * This function iterates over all stations associated with a given - * hardware that are currently uploaded to the driver and calls the callback - * function for them. - * This function allows the iterator function to sleep, when the iterator - * function is atomic @ieee80211_iterate_stations_atomic can be used. - * - * @hw: the hardware struct of which the interfaces should be iterated over - * @iterator: the iterator function to call, cannot sleep - * @data: first argument of the iterator function - */ -void ieee80211_iterate_stations(struct ieee80211_hw *hw, - void (*iterator)(void *data, - struct ieee80211_sta *sta), - void *data); - /** * ieee80211_iterate_stations_atomic - iterate stations * diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6f5407038459..bc8c285355a1 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -868,19 +868,6 @@ static void __iterate_stations(struct ieee80211_local *local, } } -void ieee80211_iterate_stations(struct ieee80211_hw *hw, - void (*iterator)(void *data, - struct ieee80211_sta *sta), - void *data) -{ - struct ieee80211_local *local = hw_to_local(hw); - - mutex_lock(&local->sta_mtx); - __iterate_stations(local, iterator, data); - mutex_unlock(&local->sta_mtx); -} -EXPORT_SYMBOL_GPL(ieee80211_iterate_stations); - void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw, void (*iterator)(void *data, struct ieee80211_sta *sta), -- cgit v1.2.3 From 28c8e088427ad30b4260953f3b6f908972b77c2d Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 4 Jan 2023 14:20:54 -0500 Subject: rseq: Increase AT_VECTOR_SIZE_BASE to match rseq auxvec entries Two new auxiliary vector entries are introduced for rseq without matching increment of the AT_VECTOR_SIZE_BASE, which causes failures with CONFIG_HARDENED_USERCOPY=y. Fixes: 317c8194e6ae ("rseq: Introduce feature size and alignment ELF auxiliary vector entries") Reported-by: Nathan Chancellor Signed-off-by: Mathieu Desnoyers Signed-off-by: Peter Zijlstra (Intel) Tested-by: Nathan Chancellor Link: https://lore.kernel.org/r/20230104192054.34046-1-mathieu.desnoyers@efficios.com --- include/linux/auxvec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/auxvec.h b/include/linux/auxvec.h index f68d0ec2d740..407f7005e6d6 100644 --- a/include/linux/auxvec.h +++ b/include/linux/auxvec.h @@ -4,6 +4,6 @@ #include -#define AT_VECTOR_SIZE_BASE 20 /* NEW_AUX_ENT entries in auxiliary table */ +#define AT_VECTOR_SIZE_BASE 22 /* NEW_AUX_ENT entries in auxiliary table */ /* number of "#define AT_.*" above, minus {AT_NULL, AT_IGNORE, AT_NOTELF} */ #endif /* _LINUX_AUXVEC_H */ -- cgit v1.2.3 From c4bdf94f97c86bdee8bacc87f8f85dc67866c928 Mon Sep 17 00:00:00 2001 From: Jinank Jain Date: Mon, 2 Jan 2023 07:12:51 +0000 Subject: x86/hyperv: Add support for detecting nested hypervisor Detect if Linux is running as a nested hypervisor in the root partition for Microsoft Hypervisor, using flags provided by MSHV. Expose a new variable hv_nested that is used later for decisions specific to the nested use case. Signed-off-by: Jinank Jain Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/8e3e7112806e81d2292a66a56fe547162754ecea.1672639707.git.jinankjain@linux.microsoft.com Signed-off-by: Wei Liu --- arch/x86/include/asm/hyperv-tlfs.h | 3 +++ arch/x86/kernel/cpu/mshyperv.c | 7 +++++++ drivers/hv/hv_common.c | 9 ++++++--- include/asm-generic/mshyperv.h | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h index 08e822bd7aa6..724a2589c0e7 100644 --- a/arch/x86/include/asm/hyperv-tlfs.h +++ b/arch/x86/include/asm/hyperv-tlfs.h @@ -116,6 +116,9 @@ /* Recommend using the newer ExProcessorMasks interface */ #define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED BIT(11) +/* Indicates that the hypervisor is nested within a Hyper-V partition. */ +#define HV_X64_HYPERV_NESTED BIT(12) + /* Recommend using enlightened VMCS */ #define HV_X64_ENLIGHTENED_VMCS_RECOMMENDED BIT(14) diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 46668e255421..f9b78d4829e3 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -37,6 +37,8 @@ /* Is Linux running as the root partition? */ bool hv_root_partition; +/* Is Linux running on nested Microsoft Hypervisor */ +bool hv_nested; struct ms_hyperv_info ms_hyperv; #if IS_ENABLED(CONFIG_HYPERV) @@ -301,6 +303,11 @@ static void __init ms_hyperv_init_platform(void) pr_info("Hyper-V: running as root partition\n"); } + if (ms_hyperv.hints & HV_X64_HYPERV_NESTED) { + hv_nested = true; + pr_info("Hyper-V: running on a nested hypervisor\n"); + } + /* * Extract host information. */ diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index ae68298c0dca..52a6f89ccdbd 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -25,17 +25,20 @@ #include /* - * hv_root_partition and ms_hyperv are defined here with other Hyper-V - * specific globals so they are shared across all architectures and are + * hv_root_partition, ms_hyperv and hv_nested are defined here with other + * Hyper-V specific globals so they are shared across all architectures and are * built only when CONFIG_HYPERV is defined. But on x86, * ms_hyperv_init_platform() is built even when CONFIG_HYPERV is not - * defined, and it uses these two variables. So mark them as __weak + * defined, and it uses these three variables. So mark them as __weak * here, allowing for an overriding definition in the module containing * ms_hyperv_init_platform(). */ bool __weak hv_root_partition; EXPORT_SYMBOL_GPL(hv_root_partition); +bool __weak hv_nested; +EXPORT_SYMBOL_GPL(hv_nested); + struct ms_hyperv_info __weak ms_hyperv; EXPORT_SYMBOL_GPL(ms_hyperv); diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index d55d2833a37b..8845a2eca339 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -48,6 +48,7 @@ struct ms_hyperv_info { u64 shared_gpa_boundary; }; extern struct ms_hyperv_info ms_hyperv; +extern bool hv_nested; extern void * __percpu *hyperv_pcpu_input_arg; extern void * __percpu *hyperv_pcpu_output_arg; -- cgit v1.2.3 From 16d73129f1fd8e91eb565482245233809647c649 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 11 Jan 2023 13:57:25 +0800 Subject: platform/chrome: fix kernel-doc warnings for panic notifier Fix the following kernel-doc warnings: $ ./scripts/kernel-doc -none drivers/platform/chrome/* drivers/platform/chrome/cros_ec_debugfs.c:54: warning: Function parameter or member 'notifier_panic' not described in 'cros_ec_debugfs' $ ./scripts/kernel-doc -none include/linux/platform_data/cros_ec_proto.h include/linux/platform_data/cros_ec_proto.h:187: warning: Function parameter or member 'panic_notifier' not described in 'cros_ec_device' Cc: Rob Barnes Fixes: d90fa2c64d59 ("platform/chrome: cros_ec: Poll EC log on EC panic") Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230111055728.708990-2-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_debugfs.c | 2 ++ include/linux/platform_data/cros_ec_proto.h | 1 + 2 files changed, 3 insertions(+) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index 34f7b46f8761..a98c529d8c69 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -38,6 +38,8 @@ static DECLARE_WAIT_QUEUE_HEAD(cros_ec_debugfs_log_wq); * @log_mutex: mutex to protect circular buffer * @log_poll_work: recurring task to poll EC for new console log data * @panicinfo_blob: panicinfo debugfs blob + * @notifier_panic: notifier_block to let kernel to flush buffered log + * when EC panic */ struct cros_ec_debugfs { struct cros_ec_dev *ec; diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 017d502ed66e..a4a3fec15504 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -140,6 +140,7 @@ struct cros_ec_command { * main EC. * @pd: The platform_device used by the mfd driver to interface with the * PD behind an EC. + * @panic_notifier: EC panic notifier. */ struct cros_ec_device { /* These are used by other drivers that want to talk to the EC */ -- cgit v1.2.3 From 20eb556dac27427f951ca13e117d32bd1c041b79 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 11 Jan 2023 13:57:26 +0800 Subject: platform/chrome: fix kernel-doc warning for suspend_timeout_ms Fix the following kernel-doc warning: $ ./scripts/kernel-doc -none include/linux/platform_data/cros_ec_proto.h include/linux/platform_data/cros_ec_proto.h:187: warning: Function parameter or member 'suspend_timeout_ms' not described in 'cros_ec_device' Cc: Evan Green Fixes: e8bf17d58a4d ("platform/chrome: cros_ec: Expose suspend_timeout_ms in debugfs") Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230111055728.708990-3-tzungbi@kernel.org --- include/linux/platform_data/cros_ec_proto.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index a4a3fec15504..805dcb19a36d 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -131,6 +131,11 @@ struct cros_ec_command { * @event_data: Raw payload transferred with the MKBP event. * @event_size: Size in bytes of the event data. * @host_event_wake_mask: Mask of host events that cause wake from suspend. + * @suspend_timeout_ms: The timeout in milliseconds between when sleep event + * is received and when the EC will declare sleep + * transition failure if the sleep signal is not + * asserted. See also struct + * ec_params_host_sleep_event_v1 in cros_ec_commands.h. * @last_event_time: exact time from the hard irq when we got notified of * a new event. * @notifier_ready: The notifier_block to let the kernel re-query EC -- cgit v1.2.3 From 212c9b9c395f72fd83c10cf2692b9562c2110d0f Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 11 Jan 2023 13:57:27 +0800 Subject: platform/chrome: fix kernel-doc warning for last_resume_result Fix the following kernel-doc warning: $ ./scripts/kernel-doc -none include/linux/platform_data/cros_ec_proto.h include/linux/platform_data/cros_ec_proto.h:187: warning: Function parameter or member 'last_resume_result' not described in 'cros_ec_device' Cc: Evan Green Fixes: 8c3166e17cf1 ("mfd / platform: cros_ec_debugfs: Expose resume result via debugfs") Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230111055728.708990-4-tzungbi@kernel.org --- include/linux/platform_data/cros_ec_proto.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 805dcb19a36d..4865c54d4af1 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -136,6 +136,10 @@ struct cros_ec_command { * transition failure if the sleep signal is not * asserted. See also struct * ec_params_host_sleep_event_v1 in cros_ec_commands.h. + * @last_resume_result: The number of sleep power signal transitions that + * occurred since the suspend message. The high bit + * indicates a timeout occurred. See also struct + * ec_response_host_sleep_event_v1 in cros_ec_commands.h. * @last_event_time: exact time from the hard irq when we got notified of * a new event. * @notifier_ready: The notifier_block to let the kernel re-query EC -- cgit v1.2.3 From 5fa1dd818fb4b30cd2de42696de547e243d946d6 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 11 Jan 2023 13:57:28 +0800 Subject: platform/chrome: fix kernel-doc warnings for cros_ec_command Fix the following kernel-doc warnings: $ ./scripts/kernel-doc -none \ include/linux/platform_data/cros_ec_commands.h include/linux/platform_data/cros_ec_commands.h:1092: warning: expecting prototype for struct ec_response_get_cmd_version. Prototype was for struct ec_response_get_cmd_versions instead include/linux/platform_data/cros_ec_commands.h:5485: warning: This comment starts with '/**', but isn't a kernel-doc comment. include/linux/platform_data/cros_ec_commands.h:5496: warning: This comment starts with '/**', but isn't a kernel-doc comment. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230111055728.708990-5-tzungbi@kernel.org --- include/linux/platform_data/cros_ec_commands.h | 6 +++--- 1 file changed, 3 insertions(+), 3 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 6665e7da6ee2..b9c4a3964247 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -1082,7 +1082,7 @@ struct ec_params_get_cmd_versions_v1 { } __ec_align2; /** - * struct ec_response_get_cmd_version - Response to the get command versions. + * struct ec_response_get_cmd_versions - Response to the get command versions. * @version_mask: Mask of supported versions; use EC_VER_MASK() to compare with * a desired version. */ @@ -5480,7 +5480,7 @@ struct ec_response_rollback_info { /* Issue AP reset */ #define EC_CMD_AP_RESET 0x0125 -/** +/* * Get the number of peripheral charge ports */ #define EC_CMD_PCHG_COUNT 0x0134 @@ -5491,7 +5491,7 @@ struct ec_response_pchg_count { uint8_t port_count; } __ec_align1; -/** +/* * Get the status of a peripheral charge port */ #define EC_CMD_PCHG 0x0135 -- cgit v1.2.3 From 961a325becd9a142ae5c8b258e5c2f221f8bfac8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 11 Jan 2023 15:41:46 +0800 Subject: platform/chrome: cros_ec: Use per-device lockdep key Lockdep reports a bogus possible deadlock on MT8192 Chromebooks due to the following lock sequences: 1. lock(i2c_register_adapter) [1]; lock(&ec_dev->lock) 2. lock(&ec_dev->lock); lock(prepare_lock); The actual dependency chains are much longer. The shortened version looks somewhat like: 1. cros-ec-rpmsg on mtk-scp ec_dev->lock -> prepare_lock 2. In rt5682_i2c_probe() on native I2C bus: prepare_lock -> regmap->lock -> (possibly) i2c_adapter->bus_lock 3. In rt5682_i2c_probe() on native I2C bus: regmap->lock -> i2c_adapter->bus_lock 4. In sbs_probe() on i2c-cros-ec-tunnel I2C bus attached on cros-ec: i2c_adapter->bus_lock -> ec_dev->lock While lockdep is correct that the shared lockdep classes have a circular dependency, it is bogus because a) 2+3 happen on a native I2C bus b) 4 happens on the actual EC on ChromeOS devices c) 1 happens on the SCP coprocessor on MediaTek Chromebooks that just happens to expose a cros-ec interface, but does not have an i2c-cros-ec-tunnel I2C bus In short, the "dependencies" are actually on different devices. Setup a per-device lockdep key for cros_ec devices so lockdep can tell the two instances apart. This helps with getting rid of the bogus lockdep warning. For ChromeOS devices that only have one cros-ec instance this doesn't change anything. Also add a missing mutex_destroy, just to make the teardown complete. [1] This is likely the per I2C bus lock with shared lockdep class Signed-off-by: Chen-Yu Tsai Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20230111074146.2624496-1-wenst@chromium.org --- drivers/platform/chrome/cros_ec.c | 14 +++++++++++--- include/linux/platform_data/cros_ec_proto.h | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index c4345dafec57..b895c8130bba 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -199,12 +199,14 @@ int cros_ec_register(struct cros_ec_device *ec_dev) if (!ec_dev->dout) return -ENOMEM; + lockdep_register_key(&ec_dev->lockdep_key); mutex_init(&ec_dev->lock); + lockdep_set_class(&ec_dev->lock, &ec_dev->lockdep_key); err = cros_ec_query_all(ec_dev); if (err) { dev_err(dev, "Cannot identify the EC: error %d\n", err); - return err; + goto destroy_mutex; } if (ec_dev->irq > 0) { @@ -216,7 +218,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) if (err) { dev_err(dev, "Failed to request IRQ %d: %d\n", ec_dev->irq, err); - return err; + goto destroy_mutex; } } @@ -227,7 +229,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev) if (IS_ERR(ec_dev->ec)) { dev_err(ec_dev->dev, "Failed to create CrOS EC platform device\n"); - return PTR_ERR(ec_dev->ec); + err = PTR_ERR(ec_dev->ec); + goto destroy_mutex; } if (ec_dev->max_passthru) { @@ -293,6 +296,9 @@ int cros_ec_register(struct cros_ec_device *ec_dev) exit: platform_device_unregister(ec_dev->ec); platform_device_unregister(ec_dev->pd); +destroy_mutex: + mutex_destroy(&ec_dev->lock); + lockdep_unregister_key(&ec_dev->lockdep_key); return err; } EXPORT_SYMBOL(cros_ec_register); @@ -310,6 +316,8 @@ void cros_ec_unregister(struct cros_ec_device *ec_dev) if (ec_dev->pd) platform_device_unregister(ec_dev->pd); platform_device_unregister(ec_dev->ec); + mutex_destroy(&ec_dev->lock); + lockdep_unregister_key(&ec_dev->lockdep_key); } EXPORT_SYMBOL(cros_ec_unregister); diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 4865c54d4af1..4f9f756bc17c 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -9,6 +9,7 @@ #define __LINUX_CROS_EC_PROTO_H #include +#include #include #include @@ -122,6 +123,8 @@ struct cros_ec_command { * command. The caller should check msg.result for the EC's result * code. * @pkt_xfer: Send packet to EC and get response. + * @lockdep_key: Lockdep class for each instance. Unused if CONFIG_LOCKDEP is + * not enabled. * @lock: One transaction at a time. * @mkbp_event_supported: 0 if MKBP not supported. Otherwise its value is * the maximum supported version of the MKBP host event @@ -176,6 +179,7 @@ struct cros_ec_device { struct cros_ec_command *msg); int (*pkt_xfer)(struct cros_ec_device *ec, struct cros_ec_command *msg); + struct lock_class_key lockdep_key; struct mutex lock; u8 mkbp_event_supported; bool host_sleep_v1; -- cgit v1.2.3 From dec5efcffad4f28f5d1fe5dc45b64dffa6abbf04 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 10 Jan 2023 17:07:38 +0100 Subject: u64_stat: Remove the obsolete fetch_irq() variants. There are no more users of the obsolete interface u64_stats_fetch_begin_irq() and u64_stats_fetch_retry_irq(). Remove the obsolete API. [bigeasy: Split out the bits from a larger patch]. Signed-off-by: Thomas Gleixner Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20230110160738.974085-1-bigeasy@linutronix.de Signed-off-by: Jakub Kicinski --- include/linux/u64_stats_sync.h | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'include') diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h index 46040d66334a..ffe48e69b3f3 100644 --- a/include/linux/u64_stats_sync.h +++ b/include/linux/u64_stats_sync.h @@ -213,16 +213,4 @@ static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp, return __u64_stats_fetch_retry(syncp, start); } -/* Obsolete interfaces */ -static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp) -{ - return u64_stats_fetch_begin(syncp); -} - -static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp, - unsigned int start) -{ - return u64_stats_fetch_retry(syncp, start); -} - #endif /* _LINUX_U64_STATS_SYNC_H */ -- cgit v1.2.3 From c2977c61f32e0d54319d158a04cad5fd82c2afcf Mon Sep 17 00:00:00 2001 From: Arun Ramadoss Date: Tue, 10 Jan 2023 14:19:20 +0530 Subject: net: dsa: microchip: ptp: add 4 bytes in tail tag when ptp enabled When the PTP is enabled in hardware bit 6 of PTP_MSG_CONF1 register, the transmit frame needs additional 4 bytes before the tail tag. It is needed for all the transmission packets irrespective of PTP packets or not. The 4-byte timestamp field is 0 for frames other than Pdelay_Resp. For the one-step Pdelay_Resp, the switch needs the receive timestamp of the Pdelay_Req message so that it can put the turnaround time in the correction field. Since PTP has to be enabled for both Transmission and reception timestamping, driver needs to track of the tx and rx setting of the all the user ports in the switch. Two flags hw_tx_en and hw_rx_en are added in ksz_port to track the timestampping setting of each port. When any one of ports has tx or rx timestampping enabled, bit 6 of PTP_MSG_CONF1 is set and it is indicated to tag_ksz.c through tagger bytes. This flag adds 4 additional bytes to the tail tag. When tx and rx timestamping of all the ports are disabled, then 4 bytes are not added. Tested using hwstamp -i Signed-off-by: Arun Ramadoss Reviewed-by: Vladimir Oltean # mostly api Signed-off-by: David S. Miller --- MAINTAINERS | 1 + drivers/net/dsa/microchip/ksz_common.h | 2 + drivers/net/dsa/microchip/ksz_ptp.c | 34 +++++++++++- include/linux/dsa/ksz_common.h | 22 ++++++++ net/dsa/tag_ksz.c | 95 +++++++++++++++++++++++++++++++--- 5 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 include/linux/dsa/ksz_common.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index c3d796e12bb8..5d6a5d51fca0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13710,6 +13710,7 @@ S: Maintained F: Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml F: Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml F: drivers/net/dsa/microchip/* +F: include/linux/dsa/ksz_common.h F: include/linux/platform_data/microchip-ksz.h F: net/dsa/tag_ksz.c diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index a5ce7ec30ba2..641aca78ef05 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -104,6 +104,8 @@ struct ksz_port { u8 num; #if IS_ENABLED(CONFIG_NET_DSA_MICROCHIP_KSZ_PTP) struct hwtstamp_config tstamp_config; + bool hwts_tx_en; + bool hwts_rx_en; #endif }; diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 6f6747671610..5281aeb84db6 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -5,6 +5,7 @@ * Copyright (C) 2022 Microchip Technology Inc. */ +#include #include #include #include @@ -24,6 +25,27 @@ #define KSZ_PTP_INC_NS 40ULL /* HW clock is incremented every 40 ns (by 40) */ #define KSZ_PTP_SUBNS_BITS 32 +static int ksz_ptp_enable_mode(struct ksz_device *dev) +{ + struct ksz_tagger_data *tagger_data = ksz_tagger_data(dev->ds); + struct ksz_port *prt; + struct dsa_port *dp; + bool tag_en = false; + + dsa_switch_for_each_user_port(dp, dev->ds) { + prt = &dev->ports[dp->index]; + if (prt->hwts_tx_en || prt->hwts_rx_en) { + tag_en = true; + break; + } + } + + tagger_data->hwtstamp_set_state(dev->ds, tag_en); + + return ksz_rmw16(dev, REG_PTP_MSG_CONF1, PTP_ENABLE, + tag_en ? PTP_ENABLE : 0); +} + /* The function is return back the capability of timestamping feature when * requested through ethtool -T utility */ @@ -67,6 +89,7 @@ int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr) } static int ksz_set_hwtstamp_config(struct ksz_device *dev, + struct ksz_port *prt, struct hwtstamp_config *config) { if (config->flags) @@ -74,7 +97,10 @@ static int ksz_set_hwtstamp_config(struct ksz_device *dev, switch (config->tx_type) { case HWTSTAMP_TX_OFF: + prt->hwts_tx_en = false; + break; case HWTSTAMP_TX_ONESTEP_P2P: + prt->hwts_tx_en = true; break; default: return -ERANGE; @@ -82,25 +108,29 @@ static int ksz_set_hwtstamp_config(struct ksz_device *dev, switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: + prt->hwts_rx_en = false; break; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; + prt->hwts_rx_en = true; break; case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + prt->hwts_rx_en = true; break; case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + prt->hwts_rx_en = true; break; default: config->rx_filter = HWTSTAMP_FILTER_NONE; return -ERANGE; } - return 0; + return ksz_ptp_enable_mode(dev); } int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) @@ -116,7 +146,7 @@ int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) if (ret) return ret; - ret = ksz_set_hwtstamp_config(dev, &config); + ret = ksz_set_hwtstamp_config(dev, prt, &config); if (ret) return ret; diff --git a/include/linux/dsa/ksz_common.h b/include/linux/dsa/ksz_common.h new file mode 100644 index 000000000000..d2a54161be97 --- /dev/null +++ b/include/linux/dsa/ksz_common.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Microchip switch tag common header + * + * Copyright (C) 2022 Microchip Technology Inc. + */ + +#ifndef _NET_DSA_KSZ_COMMON_H_ +#define _NET_DSA_KSZ_COMMON_H_ + +#include + +struct ksz_tagger_data { + void (*hwtstamp_set_state)(struct dsa_switch *ds, bool on); +}; + +static inline struct ksz_tagger_data * +ksz_tagger_data(struct dsa_switch *ds) +{ + return ds->tagger_data; +} + +#endif /* _NET_DSA_KSZ_COMMON_H_ */ diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 080e5c369f5b..420a12853676 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -4,6 +4,7 @@ * Copyright (c) 2017 Microchip Technology */ +#include #include #include #include @@ -16,9 +17,58 @@ #define LAN937X_NAME "lan937x" /* Typically only one byte is used for tail tag. */ +#define KSZ_PTP_TAG_LEN 4 #define KSZ_EGRESS_TAG_LEN 1 #define KSZ_INGRESS_TAG_LEN 1 +#define KSZ_HWTS_EN 0 + +struct ksz_tagger_private { + struct ksz_tagger_data data; /* Must be first */ + unsigned long state; +}; + +static struct ksz_tagger_private * +ksz_tagger_private(struct dsa_switch *ds) +{ + return ds->tagger_data; +} + +static void ksz_hwtstamp_set_state(struct dsa_switch *ds, bool on) +{ + struct ksz_tagger_private *priv = ksz_tagger_private(ds); + + if (on) + set_bit(KSZ_HWTS_EN, &priv->state); + else + clear_bit(KSZ_HWTS_EN, &priv->state); +} + +static void ksz_disconnect(struct dsa_switch *ds) +{ + struct ksz_tagger_private *priv = ds->tagger_data; + + kfree(priv); + ds->tagger_data = NULL; +} + +static int ksz_connect(struct dsa_switch *ds) +{ + struct ksz_tagger_data *tagger_data; + struct ksz_tagger_private *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Export functions for switch driver use */ + tagger_data = &priv->data; + tagger_data->hwtstamp_set_state = ksz_hwtstamp_set_state; + ds->tagger_data = priv; + + return 0; +} + static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, struct net_device *dev, unsigned int port, unsigned int len) @@ -92,10 +142,12 @@ DSA_TAG_DRIVER(ksz8795_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME); /* - * For Ingress (Host -> KSZ9477), 2 bytes are added before FCS. + * For Ingress (Host -> KSZ9477), 2/6 bytes are added before FCS. * --------------------------------------------------------------------------- - * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|tag1(1byte)| + * FCS(4bytes) * --------------------------------------------------------------------------- + * ts : time stamp (Present only if PTP is enabled in the Hardware) * tag0 : Prioritization (not used now) * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5) * @@ -114,6 +166,21 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME); #define KSZ9477_TAIL_TAG_OVERRIDE BIT(9) #define KSZ9477_TAIL_TAG_LOOKUP BIT(10) +/* Time stamp tag *needs* to be inserted if PTP is enabled in hardware. + * Regardless of Whether it is a PTP frame or not. + */ +static void ksz_xmit_timestamp(struct dsa_port *dp, struct sk_buff *skb) +{ + struct ksz_tagger_private *priv; + + priv = ksz_tagger_private(dp->ds); + + if (!test_bit(KSZ_HWTS_EN, &priv->state)) + return; + + put_unaligned_be32(0, skb_put(skb, KSZ_PTP_TAG_LEN)); +} + static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -126,6 +193,8 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, return NULL; /* Tag encoding */ + ksz_xmit_timestamp(dp, skb); + tag = skb_put(skb, KSZ9477_INGRESS_TAG_LEN); addr = skb_mac_header(skb); @@ -158,7 +227,9 @@ static const struct dsa_device_ops ksz9477_netdev_ops = { .proto = DSA_TAG_PROTO_KSZ9477, .xmit = ksz9477_xmit, .rcv = ksz9477_rcv, - .needed_tailroom = KSZ9477_INGRESS_TAG_LEN, + .connect = ksz_connect, + .disconnect = ksz_disconnect, + .needed_tailroom = KSZ9477_INGRESS_TAG_LEN + KSZ_PTP_TAG_LEN, }; DSA_TAG_DRIVER(ksz9477_netdev_ops); @@ -178,6 +249,8 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, return NULL; /* Tag encoding */ + ksz_xmit_timestamp(dp, skb); + tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); addr = skb_mac_header(skb); @@ -194,16 +267,20 @@ static const struct dsa_device_ops ksz9893_netdev_ops = { .proto = DSA_TAG_PROTO_KSZ9893, .xmit = ksz9893_xmit, .rcv = ksz9477_rcv, - .needed_tailroom = KSZ_INGRESS_TAG_LEN, + .connect = ksz_connect, + .disconnect = ksz_disconnect, + .needed_tailroom = KSZ_INGRESS_TAG_LEN + KSZ_PTP_TAG_LEN, }; DSA_TAG_DRIVER(ksz9893_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893, KSZ9893_NAME); -/* For xmit, 2 bytes are added before FCS. +/* For xmit, 2/6 bytes are added before FCS. * --------------------------------------------------------------------------- - * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes) + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|tag1(1byte)| + * FCS(4bytes) * --------------------------------------------------------------------------- + * ts : time stamp (Present only if PTP is enabled in the Hardware) * tag0 : represents tag override, lookup and valid * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8) * @@ -232,6 +309,8 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb, if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) return NULL; + ksz_xmit_timestamp(dp, skb); + tag = skb_put(skb, LAN937X_EGRESS_TAG_LEN); val = BIT(dp->index); @@ -252,7 +331,9 @@ static const struct dsa_device_ops lan937x_netdev_ops = { .proto = DSA_TAG_PROTO_LAN937X, .xmit = lan937x_xmit, .rcv = ksz9477_rcv, - .needed_tailroom = LAN937X_EGRESS_TAG_LEN, + .connect = ksz_connect, + .disconnect = ksz_disconnect, + .needed_tailroom = LAN937X_EGRESS_TAG_LEN + KSZ_PTP_TAG_LEN, }; DSA_TAG_DRIVER(lan937x_netdev_ops); -- cgit v1.2.3 From 2955762b372b791a8f4cd862cf0b5fef9c456449 Mon Sep 17 00:00:00 2001 From: Christian Eggers Date: Tue, 10 Jan 2023 14:19:23 +0530 Subject: net: ptp: add helper for one-step P2P clocks For P2P delay measurement, the ingress time stamp of the PDelay_Req is required for the correction field of the PDelay_Resp. The application echoes back the correction field of the PDelay_Req when sending the PDelay_Resp. Some hardware (like the ZHAW InES PTP time stamping IP core) subtracts the ingress timestamp autonomously from the correction field, so that the hardware only needs to add the egress timestamp on tx. Other hardware (like the Microchip KSZ9563) reports the ingress time stamp via an interrupt and requires that the software provides this time stamp via tail-tag on tx. In order to avoid introducing a further application interface for this, the driver can simply emulate the behavior of the InES device and subtract the ingress time stamp in software from the correction field. On egress, the correction field can either be kept as it is (and the time stamp field in the tail-tag is set to zero) or move the value from the correction field back to the tail-tag. Changing the correction field requires updating the UDP checksum (if UDP is used as transport). Signed-off-by: Christian Eggers Co-developed-by: Arun Ramadoss Signed-off-by: Arun Ramadoss Signed-off-by: David S. Miller --- include/linux/ptp_classify.h | 73 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'include') diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h index 2b6ea36ad162..1b5a953c6bbc 100644 --- a/include/linux/ptp_classify.h +++ b/include/linux/ptp_classify.h @@ -10,8 +10,12 @@ #ifndef _PTP_CLASSIFY_H_ #define _PTP_CLASSIFY_H_ +#include #include +#include #include +#include +#include #define PTP_CLASS_NONE 0x00 /* not a PTP event message */ #define PTP_CLASS_V1 0x01 /* protocol version 1 */ @@ -129,6 +133,69 @@ static inline u8 ptp_get_msgtype(const struct ptp_header *hdr, return msgtype; } +/** + * ptp_check_diff8 - Computes new checksum (when altering a 64-bit field) + * @old: old field value + * @new: new field value + * @oldsum: previous checksum + * + * This function can be used to calculate a new checksum when only a single + * field is changed. Similar as ip_vs_check_diff*() in ip_vs.h. + * + * Return: Updated checksum + */ +static inline __wsum ptp_check_diff8(__be64 old, __be64 new, __wsum oldsum) +{ + __be64 diff[2] = { ~old, new }; + + return csum_partial(diff, sizeof(diff), oldsum); +} + +/** + * ptp_header_update_correction - Update PTP header's correction field + * @skb: packet buffer + * @type: type of the packet (see ptp_classify_raw()) + * @hdr: ptp header + * @correction: new correction value + * + * This updates the correction field of a PTP header and updates the UDP + * checksum (if UDP is used as transport). It is needed for hardware capable of + * one-step P2P that does not already modify the correction field of Pdelay_Req + * event messages on ingress. + */ +static inline +void ptp_header_update_correction(struct sk_buff *skb, unsigned int type, + struct ptp_header *hdr, s64 correction) +{ + __be64 correction_old; + struct udphdr *uhdr; + + /* previous correction value is required for checksum update. */ + memcpy(&correction_old, &hdr->correction, sizeof(correction_old)); + + /* write new correction value */ + put_unaligned_be64((u64)correction, &hdr->correction); + + switch (type & PTP_CLASS_PMASK) { + case PTP_CLASS_IPV4: + case PTP_CLASS_IPV6: + /* locate udp header */ + uhdr = (struct udphdr *)((char *)hdr - sizeof(struct udphdr)); + break; + default: + return; + } + + /* update checksum */ + uhdr->check = csum_fold(ptp_check_diff8(correction_old, + hdr->correction, + ~csum_unfold(uhdr->check))); + if (!uhdr->check) + uhdr->check = CSUM_MANGLED_0; + + skb->ip_summed = CHECKSUM_NONE; +} + /** * ptp_msg_is_sync - Evaluates whether the given skb is a PTP Sync message * @skb: packet buffer @@ -166,5 +233,11 @@ static inline bool ptp_msg_is_sync(struct sk_buff *skb, unsigned int type) { return false; } + +static inline +void ptp_header_update_correction(struct sk_buff *skb, unsigned int type, + struct ptp_header *hdr, s64 correction) +{ +} #endif #endif /* _PTP_CLASSIFY_H_ */ -- cgit v1.2.3 From 90188fff655d8efad79acdf60c3012ffcbbef716 Mon Sep 17 00:00:00 2001 From: Christian Eggers Date: Tue, 10 Jan 2023 14:19:24 +0530 Subject: net: dsa: microchip: ptp: add packet reception timestamping Rx Timestamping is done through 4 additional bytes in tail tag. Whenever the ptp packet is received, the 4 byte hardware time stamped value is added before 1 byte tail tag. Also, bit 7 in tail tag indicates it as PTP frame. This 4 byte value is extracted from the tail tag and reconstructed to absolute time and assigned to skb hwtstamp. If the packet received in PDelay_Resp, then partial ingress timestamp is subtracted from the correction field. Since user space tools expects to be done in hardware. Signed-off-by: Christian Eggers Co-developed-by: Arun Ramadoss Signed-off-by: Arun Ramadoss Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 1 + drivers/net/dsa/microchip/ksz_ptp.c | 63 ++++++++++++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz_ptp.h | 4 +++ include/linux/dsa/ksz_common.h | 21 ++++++++++++ net/dsa/tag_ksz.c | 25 ++++++++++---- 5 files changed, 108 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index bdd068322ca0..b4e7d579ac51 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2991,6 +2991,7 @@ static const struct dsa_switch_ops ksz_switch_ops = { .get_ts_info = ksz_get_ts_info, .port_hwtstamp_get = ksz_hwtstamp_get, .port_hwtstamp_set = ksz_hwtstamp_set, + .port_rxtstamp = ksz_port_rxtstamp, }; struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 6cf30bf50c7e..29413fb608ed 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -169,6 +169,69 @@ int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) return copy_to_user(ifr->ifr_data, &config, sizeof(config)); } +static ktime_t ksz_tstamp_reconstruct(struct ksz_device *dev, ktime_t tstamp) +{ + struct timespec64 ptp_clock_time; + struct ksz_ptp_data *ptp_data; + struct timespec64 diff; + struct timespec64 ts; + + ptp_data = &dev->ptp_data; + ts = ktime_to_timespec64(tstamp); + + spin_lock_bh(&ptp_data->clock_lock); + ptp_clock_time = ptp_data->clock_time; + spin_unlock_bh(&ptp_data->clock_lock); + + /* calculate full time from partial time stamp */ + ts.tv_sec = (ptp_clock_time.tv_sec & ~3) | ts.tv_sec; + + /* find nearest possible point in time */ + diff = timespec64_sub(ts, ptp_clock_time); + if (diff.tv_sec > 2) + ts.tv_sec -= 4; + else if (diff.tv_sec < -2) + ts.tv_sec += 4; + + return timespec64_to_ktime(ts); +} + +bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb, + unsigned int type) +{ + struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb); + struct ksz_device *dev = ds->priv; + struct ptp_header *ptp_hdr; + u8 ptp_msg_type; + ktime_t tstamp; + s64 correction; + + tstamp = KSZ_SKB_CB(skb)->tstamp; + memset(hwtstamps, 0, sizeof(*hwtstamps)); + hwtstamps->hwtstamp = ksz_tstamp_reconstruct(dev, tstamp); + + ptp_hdr = ptp_parse_header(skb, type); + if (!ptp_hdr) + goto out; + + ptp_msg_type = ptp_get_msgtype(ptp_hdr, type); + if (ptp_msg_type != PTP_MSGTYPE_PDELAY_REQ) + goto out; + + /* Only subtract the partial time stamp from the correction field. When + * the hardware adds the egress time stamp to the correction field of + * the PDelay_Resp message on tx, also only the partial time stamp will + * be added. + */ + correction = (s64)get_unaligned_be64(&ptp_hdr->correction); + correction -= ktime_to_ns(tstamp) << 16; + + ptp_header_update_correction(skb, type, ptp_hdr, correction); + +out: + return false; +} + static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts) { u32 nanoseconds; diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index 7c5679372705..9bb8fb059ac2 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -30,6 +30,8 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); +bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb, + unsigned int type); int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p); void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p); @@ -60,6 +62,8 @@ static inline void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p) {} #define ksz_hwtstamp_set NULL +#define ksz_port_rxtstamp NULL + #endif /* End of CONFIG_NET_DSA_MICROCHIP_KSZ_PTP */ #endif diff --git a/include/linux/dsa/ksz_common.h b/include/linux/dsa/ksz_common.h index d2a54161be97..a256b08d837d 100644 --- a/include/linux/dsa/ksz_common.h +++ b/include/linux/dsa/ksz_common.h @@ -9,10 +9,31 @@ #include +/* All time stamps from the KSZ consist of 2 bits for seconds and 30 bits for + * nanoseconds. This is NOT the same as 32 bits for nanoseconds. + */ +#define KSZ_TSTAMP_SEC_MASK GENMASK(31, 30) +#define KSZ_TSTAMP_NSEC_MASK GENMASK(29, 0) + +static inline ktime_t ksz_decode_tstamp(u32 tstamp) +{ + u64 ns = FIELD_GET(KSZ_TSTAMP_SEC_MASK, tstamp) * NSEC_PER_SEC + + FIELD_GET(KSZ_TSTAMP_NSEC_MASK, tstamp); + + return ns_to_ktime(ns); +} + struct ksz_tagger_data { void (*hwtstamp_set_state)(struct dsa_switch *ds, bool on); }; +struct ksz_skb_cb { + u32 tstamp; +}; + +#define KSZ_SKB_CB(skb) \ + ((struct ksz_skb_cb *)((skb)->cb)) + static inline struct ksz_tagger_data * ksz_tagger_data(struct dsa_switch *ds) { diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 420a12853676..6603eaa234d2 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -151,10 +151,11 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME); * tag0 : Prioritization (not used now) * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5) * - * For Egress (KSZ9477 -> Host), 1 byte is added before FCS. + * For Egress (KSZ9477 -> Host), 1/5 bytes is added before FCS. * --------------------------------------------------------------------------- - * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|FCS(4bytes) * --------------------------------------------------------------------------- + * ts : time stamp (Present only if bit 7 of tag0 is set) * tag0 : zero-based value represents port * (eg, 0x00=port1, 0x02=port3, 0x06=port7) */ @@ -166,6 +167,15 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME); #define KSZ9477_TAIL_TAG_OVERRIDE BIT(9) #define KSZ9477_TAIL_TAG_LOOKUP BIT(10) +static void ksz_rcv_timestamp(struct sk_buff *skb, u8 *tag) +{ + u8 *tstamp_raw = tag - KSZ_PTP_TAG_LEN; + ktime_t tstamp; + + tstamp = ksz_decode_tstamp(get_unaligned_be32(tstamp_raw)); + KSZ_SKB_CB(skb)->tstamp = tstamp; +} + /* Time stamp tag *needs* to be inserted if PTP is enabled in hardware. * Regardless of Whether it is a PTP frame or not. */ @@ -216,8 +226,10 @@ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev) unsigned int len = KSZ_EGRESS_TAG_LEN; /* Extra 4-bytes PTP timestamp */ - if (tag[0] & KSZ9477_PTP_TAG_INDICATION) - len += KSZ9477_PTP_TAG_LEN; + if (tag[0] & KSZ9477_PTP_TAG_INDICATION) { + ksz_rcv_timestamp(skb, tag); + len += KSZ_PTP_TAG_LEN; + } return ksz_common_rcv(skb, dev, port, len); } @@ -284,10 +296,11 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893, KSZ9893_NAME); * tag0 : represents tag override, lookup and valid * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8) * - * For rcv, 1 byte is added before FCS. + * For rcv, 1/5 bytes is added before FCS. * --------------------------------------------------------------------------- - * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes) + * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|FCS(4bytes) * --------------------------------------------------------------------------- + * ts : time stamp (Present only if bit 7 of tag0 is set) * tag0 : zero-based value represents port * (eg, 0x00=port1, 0x02=port3, 0x07=port8) */ -- cgit v1.2.3 From ab32f56a4100f879c5064b45c7657bb4be175ac3 Mon Sep 17 00:00:00 2001 From: Christian Eggers Date: Tue, 10 Jan 2023 14:19:25 +0530 Subject: net: dsa: microchip: ptp: add packet transmission timestamping This patch adds the routines for transmission of ptp packets. When the ptp pdelay_req packet to be transmitted, it uses the deferred xmit worker to schedule the packets. During irq_setup, interrupt for Sync, Pdelay_req and Pdelay_rsp are enabled. So interrupt is triggered for all three packets. But for p2p1step, we require only time stamp of Pdelay_req packet. Hence to avoid posting of the completion from ISR routine for Sync and Pdelay_resp packets, ts_en flag is introduced. This controls which packets need to processed for timestamp. After the packet is transmitted, ISR is triggered. The time at which packet transmitted is recorded to separate register. This value is reconstructed to absolute time and posted to the user application through socket error queue. Signed-off-by: Christian Eggers Co-developed-by: Arun Ramadoss Signed-off-by: Arun Ramadoss Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 14 ++++ drivers/net/dsa/microchip/ksz_common.h | 3 + drivers/net/dsa/microchip/ksz_ptp.c | 115 ++++++++++++++++++++++++++++++++- drivers/net/dsa/microchip/ksz_ptp.h | 6 ++ include/linux/dsa/ksz_common.h | 8 +++ net/dsa/tag_ksz.c | 54 +++++++++++++++- 6 files changed, 196 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index b4e7d579ac51..5e1e5bd555d2 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -2539,6 +2540,17 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, return proto; } +static int ksz_connect_tag_protocol(struct dsa_switch *ds, + enum dsa_tag_protocol proto) +{ + struct ksz_tagger_data *tagger_data; + + tagger_data = ksz_tagger_data(ds); + tagger_data->xmit_work_fn = ksz_port_deferred_xmit; + + return 0; +} + static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag, struct netlink_ext_ack *extack) { @@ -2954,6 +2966,7 @@ static int ksz_switch_detect(struct ksz_device *dev) static const struct dsa_switch_ops ksz_switch_ops = { .get_tag_protocol = ksz_get_tag_protocol, + .connect_tag_protocol = ksz_connect_tag_protocol, .get_phy_flags = ksz_get_phy_flags, .setup = ksz_setup, .teardown = ksz_teardown, @@ -2991,6 +3004,7 @@ static const struct dsa_switch_ops ksz_switch_ops = { .get_ts_info = ksz_get_ts_info, .port_hwtstamp_get = ksz_hwtstamp_get, .port_hwtstamp_set = ksz_hwtstamp_set, + .port_txtstamp = ksz_port_txtstamp, .port_rxtstamp = ksz_port_rxtstamp, }; diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index ec1bceb4efcc..c8b49c86dfe1 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -87,6 +87,7 @@ struct ksz_irq { struct ksz_ptp_irq { struct ksz_port *port; u16 ts_reg; + bool ts_en; char name[16]; int num; }; @@ -116,6 +117,8 @@ struct ksz_port { bool hwts_rx_en; struct ksz_irq ptpirq; struct ksz_ptp_irq ptpmsg_irq[3]; + ktime_t tstamp_msg; + struct completion tstamp_msg_comp; #endif }; diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 29413fb608ed..6edce141cbd7 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -18,6 +18,8 @@ #define ptp_caps_to_data(d) container_of((d), struct ksz_ptp_data, caps) #define ptp_data_to_ksz_dev(d) container_of((d), struct ksz_device, ptp_data) +#define work_to_xmit_work(w) \ + container_of((w), struct ksz_deferred_xmit_work, work) /* Sub-nanoseconds-adj,max * sub-nanoseconds / 40ns * 1ns * = (2^30-1) * (2 ^ 32) / 40 ns * 1 ns = 6249999 @@ -111,9 +113,15 @@ static int ksz_set_hwtstamp_config(struct ksz_device *dev, switch (config->tx_type) { case HWTSTAMP_TX_OFF: + prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en = false; + prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = false; + prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = false; prt->hwts_tx_en = false; break; case HWTSTAMP_TX_ONESTEP_P2P: + prt->ptpmsg_irq[KSZ_SYNC_MSG].ts_en = false; + prt->ptpmsg_irq[KSZ_XDREQ_MSG].ts_en = true; + prt->ptpmsg_irq[KSZ_PDRES_MSG].ts_en = false; prt->hwts_tx_en = true; break; default: @@ -232,6 +240,87 @@ out: return false; } +void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb) +{ + struct ksz_device *dev = ds->priv; + struct ptp_header *hdr; + struct sk_buff *clone; + struct ksz_port *prt; + unsigned int type; + u8 ptp_msg_type; + + prt = &dev->ports[port]; + + if (!prt->hwts_tx_en) + return; + + type = ptp_classify_raw(skb); + if (type == PTP_CLASS_NONE) + return; + + hdr = ptp_parse_header(skb, type); + if (!hdr) + return; + + ptp_msg_type = ptp_get_msgtype(hdr, type); + + switch (ptp_msg_type) { + case PTP_MSGTYPE_PDELAY_REQ: + break; + + default: + return; + } + + clone = skb_clone_sk(skb); + if (!clone) + return; + + /* caching the value to be used in tag_ksz.c */ + KSZ_SKB_CB(skb)->clone = clone; +} + +static void ksz_ptp_txtstamp_skb(struct ksz_device *dev, + struct ksz_port *prt, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps hwtstamps = {}; + int ret; + + /* timeout must include DSA master to transmit data, tstamp latency, + * IRQ latency and time for reading the time stamp. + */ + ret = wait_for_completion_timeout(&prt->tstamp_msg_comp, + msecs_to_jiffies(100)); + if (!ret) + return; + + hwtstamps.hwtstamp = prt->tstamp_msg; + skb_complete_tx_timestamp(skb, &hwtstamps); +} + +void ksz_port_deferred_xmit(struct kthread_work *work) +{ + struct ksz_deferred_xmit_work *xmit_work = work_to_xmit_work(work); + struct sk_buff *clone, *skb = xmit_work->skb; + struct dsa_switch *ds = xmit_work->dp->ds; + struct ksz_device *dev = ds->priv; + struct ksz_port *prt; + + prt = &dev->ports[xmit_work->dp->index]; + + clone = KSZ_SKB_CB(skb)->clone; + + skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS; + + reinit_completion(&prt->tstamp_msg_comp); + + dsa_enqueue_skb(skb, skb->dev); + + ksz_ptp_txtstamp_skb(dev, prt, clone); + + kfree(xmit_work); +} + static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts) { u32 nanoseconds; @@ -488,7 +577,29 @@ void ksz_ptp_clock_unregister(struct dsa_switch *ds) static irqreturn_t ksz_ptp_msg_thread_fn(int irq, void *dev_id) { - return IRQ_NONE; + struct ksz_ptp_irq *ptpmsg_irq = dev_id; + struct ksz_device *dev; + struct ksz_port *port; + u32 tstamp_raw; + ktime_t tstamp; + int ret; + + port = ptpmsg_irq->port; + dev = port->ksz_dev; + + if (ptpmsg_irq->ts_en) { + ret = ksz_read32(dev, ptpmsg_irq->ts_reg, &tstamp_raw); + if (ret) + return IRQ_NONE; + + tstamp = ksz_decode_tstamp(tstamp_raw); + + port->tstamp_msg = ksz_tstamp_reconstruct(dev, tstamp); + + complete(&port->tstamp_msg_comp); + } + + return IRQ_HANDLED; } static irqreturn_t ksz_ptp_irq_thread_fn(int irq, void *dev_id) @@ -633,6 +744,8 @@ int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p) REG_PTP_PORT_TX_INT_STATUS__2); snprintf(ptpirq->name, sizeof(ptpirq->name), "ptp-irq-%d", p); + init_completion(&port->tstamp_msg_comp); + ptpirq->domain = irq_domain_add_linear(dev->dev->of_node, ptpirq->nirqs, &ksz_ptp_irq_domain_ops, ptpirq); if (!ptpirq->domain) diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index 9bb8fb059ac2..0b14aed71ec2 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -30,6 +30,8 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); +void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb); +void ksz_port_deferred_xmit(struct kthread_work *work); bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb, unsigned int type); int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p); @@ -64,6 +66,10 @@ static inline void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p) {} #define ksz_port_rxtstamp NULL +#define ksz_port_txtstamp NULL + +#define ksz_port_deferred_xmit NULL + #endif /* End of CONFIG_NET_DSA_MICROCHIP_KSZ_PTP */ #endif diff --git a/include/linux/dsa/ksz_common.h b/include/linux/dsa/ksz_common.h index a256b08d837d..b91beab5e138 100644 --- a/include/linux/dsa/ksz_common.h +++ b/include/linux/dsa/ksz_common.h @@ -23,11 +23,19 @@ static inline ktime_t ksz_decode_tstamp(u32 tstamp) return ns_to_ktime(ns); } +struct ksz_deferred_xmit_work { + struct dsa_port *dp; + struct sk_buff *skb; + struct kthread_work work; +}; + struct ksz_tagger_data { + void (*xmit_work_fn)(struct kthread_work *work); void (*hwtstamp_set_state)(struct dsa_switch *ds, bool on); }; struct ksz_skb_cb { + struct sk_buff *clone; u32 tstamp; }; diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 6603eaa234d2..e14ee26bf6a0 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -26,6 +26,7 @@ struct ksz_tagger_private { struct ksz_tagger_data data; /* Must be first */ unsigned long state; + struct kthread_worker *xmit_worker; }; static struct ksz_tagger_private * @@ -48,6 +49,7 @@ static void ksz_disconnect(struct dsa_switch *ds) { struct ksz_tagger_private *priv = ds->tagger_data; + kthread_destroy_worker(priv->xmit_worker); kfree(priv); ds->tagger_data = NULL; } @@ -55,12 +57,23 @@ static void ksz_disconnect(struct dsa_switch *ds) static int ksz_connect(struct dsa_switch *ds) { struct ksz_tagger_data *tagger_data; + struct kthread_worker *xmit_worker; struct ksz_tagger_private *priv; + int ret; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + xmit_worker = kthread_create_worker(0, "dsa%d:%d_xmit", + ds->dst->index, ds->index); + if (IS_ERR(xmit_worker)) { + ret = PTR_ERR(xmit_worker); + kfree(priv); + return ret; + } + + priv->xmit_worker = xmit_worker; /* Export functions for switch driver use */ tagger_data = &priv->data; tagger_data->hwtstamp_set_state = ksz_hwtstamp_set_state; @@ -191,6 +204,41 @@ static void ksz_xmit_timestamp(struct dsa_port *dp, struct sk_buff *skb) put_unaligned_be32(0, skb_put(skb, KSZ_PTP_TAG_LEN)); } +/* Defer transmit if waiting for egress time stamp is required. */ +static struct sk_buff *ksz_defer_xmit(struct dsa_port *dp, struct sk_buff *skb) +{ + struct ksz_tagger_data *tagger_data = ksz_tagger_data(dp->ds); + struct ksz_tagger_private *priv = ksz_tagger_private(dp->ds); + void (*xmit_work_fn)(struct kthread_work *work); + struct sk_buff *clone = KSZ_SKB_CB(skb)->clone; + struct ksz_deferred_xmit_work *xmit_work; + struct kthread_worker *xmit_worker; + + if (!clone) + return skb; /* no deferred xmit for this packet */ + + xmit_work_fn = tagger_data->xmit_work_fn; + xmit_worker = priv->xmit_worker; + + if (!xmit_work_fn || !xmit_worker) + return NULL; + + xmit_work = kzalloc(sizeof(*xmit_work), GFP_ATOMIC); + if (!xmit_work) + return NULL; + + kthread_init_work(&xmit_work->work, xmit_work_fn); + /* Increase refcount so the kfree_skb in dsa_slave_xmit + * won't really free the packet. + */ + xmit_work->dp = dp; + xmit_work->skb = skb_get(skb); + + kthread_queue_work(xmit_worker, &xmit_work->work); + + return NULL; +} + static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -215,7 +263,7 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, *tag = cpu_to_be16(val); - return skb; + return ksz_defer_xmit(dp, skb); } static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev) @@ -271,7 +319,7 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, if (is_link_local_ether_addr(addr)) *tag |= KSZ9893_TAIL_TAG_OVERRIDE; - return skb; + return ksz_defer_xmit(dp, skb); } static const struct dsa_device_ops ksz9893_netdev_ops = { @@ -336,7 +384,7 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb, put_unaligned_be16(val, tag); - return skb; + return ksz_defer_xmit(dp, skb); } static const struct dsa_device_ops lan937x_netdev_ops = { -- cgit v1.2.3 From a32190b154bde4a3bf2fddb9367aec49be09b15d Mon Sep 17 00:00:00 2001 From: Christian Eggers Date: Tue, 10 Jan 2023 14:19:26 +0530 Subject: net: dsa: microchip: ptp: move pdelay_rsp correction field to tail tag For PDelay_Resp messages we will likely have a negative value in the correction field. The switch hardware cannot correctly update such values (produces an off by one error in the UDP checksum), so it must be moved to the time stamp field in the tail tag. Format of the correction field is 48 bit ns + 16 bit fractional ns. After updating the correction field, clone is no longer required hence it is freed. Signed-off-by: Christian Eggers Co-developed-by: Arun Ramadoss Signed-off-by: Arun Ramadoss Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_ptp.c | 4 ++++ include/linux/dsa/ksz_common.h | 2 ++ net/dsa/tag_ksz.c | 29 ++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 6edce141cbd7..2a68649943d5 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -267,6 +267,10 @@ void ksz_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb) switch (ptp_msg_type) { case PTP_MSGTYPE_PDELAY_REQ: break; + case PTP_MSGTYPE_PDELAY_RESP: + KSZ_SKB_CB(skb)->ptp_type = type; + KSZ_SKB_CB(skb)->update_correction = true; + return; default: return; diff --git a/include/linux/dsa/ksz_common.h b/include/linux/dsa/ksz_common.h index b91beab5e138..576a99ca698d 100644 --- a/include/linux/dsa/ksz_common.h +++ b/include/linux/dsa/ksz_common.h @@ -36,6 +36,8 @@ struct ksz_tagger_data { struct ksz_skb_cb { struct sk_buff *clone; + unsigned int ptp_type; + bool update_correction; u32 tstamp; }; diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index e14ee26bf6a0..694478fe07d6 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "tag.h" @@ -195,13 +196,39 @@ static void ksz_rcv_timestamp(struct sk_buff *skb, u8 *tag) static void ksz_xmit_timestamp(struct dsa_port *dp, struct sk_buff *skb) { struct ksz_tagger_private *priv; + struct ptp_header *ptp_hdr; + unsigned int ptp_type; + u32 tstamp_raw = 0; + s64 correction; priv = ksz_tagger_private(dp->ds); if (!test_bit(KSZ_HWTS_EN, &priv->state)) return; - put_unaligned_be32(0, skb_put(skb, KSZ_PTP_TAG_LEN)); + if (!KSZ_SKB_CB(skb)->update_correction) + goto output_tag; + + ptp_type = KSZ_SKB_CB(skb)->ptp_type; + + ptp_hdr = ptp_parse_header(skb, ptp_type); + if (!ptp_hdr) + goto output_tag; + + correction = (s64)get_unaligned_be64(&ptp_hdr->correction); + + if (correction < 0) { + struct timespec64 ts; + + ts = ns_to_timespec64(-correction >> 16); + tstamp_raw = ((ts.tv_sec & 3) << 30) | ts.tv_nsec; + + /* Set correction field to 0 and update UDP checksum */ + ptp_header_update_correction(skb, ptp_type, ptp_hdr, 0); + } + +output_tag: + put_unaligned_be32(tstamp_raw, skb_put(skb, KSZ_PTP_TAG_LEN)); } /* Defer transmit if waiting for egress time stamp is required. */ -- cgit v1.2.3 From ab811cfffa949946ebcfd6e280d4dc37c7f0f602 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 12 Jan 2023 21:09:52 +0900 Subject: ALSA: fireface: update UAPI for data of knob control This commit adds a new event of knob control specific to RME Fireface 400. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20230112120954.500692-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- include/uapi/sound/firewire.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h index 3532ac7046d7..50917581dd2b 100644 --- a/include/uapi/sound/firewire.h +++ b/include/uapi/sound/firewire.h @@ -14,6 +14,7 @@ #define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479 #define SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL 0x7473636d #define SNDRV_FIREWIRE_EVENT_MOTU_REGISTER_DSP_CHANGE 0x4d545244 +#define SNDRV_FIREWIRE_EVENT_FF400_MESSAGE 0x4f6c6761 struct snd_firewire_event_common { unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */ @@ -72,6 +73,28 @@ struct snd_firewire_event_motu_register_dsp_change { __u32 changes[]; /* Encoded event for change of register DSP. */ }; +/** + * struct snd_firewire_event_ff400_message - the container for message from Fireface 400 when + * operating hardware knob. + * + * @type: Fixed to SNDRV_FIREWIRE_EVENT_FF400_MESSAGE. + * @messages.message: The messages expressing hardware knob operation. + * @messages.tstamp: The isochronous cycle at which the request subaction of asynchronous + * transaction was sent to deliver the message. It has 16 bit unsigned integer + * value. The higher 3 bits of value expresses the lower three bits of second + * field in the format of CYCLE_TIME, up to 7. The rest 13 bits expresses cycle + * field up to 7999. + * + * The structure expresses message transmitted by Fireface 400 when operating hardware knob. + */ +struct snd_firewire_event_ff400_message { + unsigned int type; + struct { + __u32 message; + __u32 tstamp; + } messages[]; +}; + union snd_firewire_event { struct snd_firewire_event_common common; struct snd_firewire_event_lock_status lock_status; @@ -81,6 +104,7 @@ union snd_firewire_event { struct snd_firewire_event_tascam_control tascam_control; struct snd_firewire_event_motu_notification motu_notification; struct snd_firewire_event_motu_register_dsp_change motu_register_dsp_change; + struct snd_firewire_event_ff400_message ff400_message; }; -- cgit v1.2.3 From 31de2842399ae68c4b2887ffeaedebb7934f343e Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Wed, 11 Jan 2023 14:05:18 +0100 Subject: ethtool: add tx aggregation parameters Add the following ethtool tx aggregation parameters: ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES Maximum size in bytes of a tx aggregated block of frames. ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES Maximum number of frames that can be aggregated into a block. ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS Time in usecs after the first packet arrival in an aggregated block for the block to be sent. Signed-off-by: Daniele Palmas Signed-off-by: David S. Miller --- Documentation/networking/ethtool-netlink.rst | 17 +++++++++++++++++ include/linux/ethtool.h | 12 +++++++++++- include/uapi/linux/ethtool_netlink.h | 3 +++ net/ethtool/coalesce.c | 22 ++++++++++++++++++++-- 4 files changed, 51 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index c59b542eb693..d345f5df248e 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -1004,6 +1004,9 @@ Kernel response contents: ``ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL`` u32 rate sampling interval ``ETHTOOL_A_COALESCE_USE_CQE_TX`` bool timer reset mode, Tx ``ETHTOOL_A_COALESCE_USE_CQE_RX`` bool timer reset mode, Rx + ``ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES`` u32 max aggr size, Tx + ``ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES`` u32 max aggr packets, Tx + ``ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS`` u32 time (us), aggr, Tx =========================================== ====== ======================= Attributes are only included in reply if their value is not zero or the @@ -1022,6 +1025,17 @@ each packet event resets the timer. In this mode timer is used to force the interrupt if queue goes idle, while busy queues depend on the packet limit to trigger interrupts. +Tx aggregation consists of copying frames into a contiguous buffer so that they +can be submitted as a single IO operation. ``ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES`` +describes the maximum size in bytes for the submitted buffer. +``ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES`` describes the maximum number of frames +that can be aggregated into a single buffer. +``ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS`` describes the amount of time in usecs, +counted since the first packet arrival in an aggregated block, after which the +block should be sent. +This feature is mainly of interest for specific USB devices which does not cope +well with frequent small-sized URBs transmissions. + COALESCE_SET ============ @@ -1055,6 +1069,9 @@ Request contents: ``ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL`` u32 rate sampling interval ``ETHTOOL_A_COALESCE_USE_CQE_TX`` bool timer reset mode, Tx ``ETHTOOL_A_COALESCE_USE_CQE_RX`` bool timer reset mode, Rx + ``ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES`` u32 max aggr size, Tx + ``ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES`` u32 max aggr packets, Tx + ``ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS`` u32 time (us), aggr, Tx =========================================== ====== ======================= Request is rejected if it attributes declared as unsupported by driver (i.e. diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index d0da303f6634..20d197693d34 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -217,6 +217,9 @@ __ethtool_get_link_ksettings(struct net_device *dev, struct kernel_ethtool_coalesce { u8 use_cqe_mode_tx; u8 use_cqe_mode_rx; + u32 tx_aggr_max_bytes; + u32 tx_aggr_max_frames; + u32 tx_aggr_time_usecs; }; /** @@ -260,7 +263,10 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, #define ETHTOOL_COALESCE_RATE_SAMPLE_INTERVAL BIT(21) #define ETHTOOL_COALESCE_USE_CQE_RX BIT(22) #define ETHTOOL_COALESCE_USE_CQE_TX BIT(23) -#define ETHTOOL_COALESCE_ALL_PARAMS GENMASK(23, 0) +#define ETHTOOL_COALESCE_TX_AGGR_MAX_BYTES BIT(24) +#define ETHTOOL_COALESCE_TX_AGGR_MAX_FRAMES BIT(25) +#define ETHTOOL_COALESCE_TX_AGGR_TIME_USECS BIT(26) +#define ETHTOOL_COALESCE_ALL_PARAMS GENMASK(26, 0) #define ETHTOOL_COALESCE_USECS \ (ETHTOOL_COALESCE_RX_USECS | ETHTOOL_COALESCE_TX_USECS) @@ -288,6 +294,10 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, ETHTOOL_COALESCE_RATE_SAMPLE_INTERVAL) #define ETHTOOL_COALESCE_USE_CQE \ (ETHTOOL_COALESCE_USE_CQE_RX | ETHTOOL_COALESCE_USE_CQE_TX) +#define ETHTOOL_COALESCE_TX_AGGR \ + (ETHTOOL_COALESCE_TX_AGGR_MAX_BYTES | \ + ETHTOOL_COALESCE_TX_AGGR_MAX_FRAMES | \ + ETHTOOL_COALESCE_TX_AGGR_TIME_USECS) #define ETHTOOL_STAT_NOT_SET (~0ULL) diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h index 75b3d6d476ff..83557cae0b87 100644 --- a/include/uapi/linux/ethtool_netlink.h +++ b/include/uapi/linux/ethtool_netlink.h @@ -406,6 +406,9 @@ enum { ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, /* u32 */ ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, /* u8 */ ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, /* u8 */ + ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES, /* u32 */ + ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES, /* u32 */ + ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, /* u32 */ /* add new constants above here */ __ETHTOOL_A_COALESCE_CNT, diff --git a/net/ethtool/coalesce.c b/net/ethtool/coalesce.c index 487bdf345541..e405b47f7eed 100644 --- a/net/ethtool/coalesce.c +++ b/net/ethtool/coalesce.c @@ -105,7 +105,10 @@ static int coalesce_reply_size(const struct ethnl_req_info *req_base, nla_total_size(sizeof(u32)) + /* _TX_MAX_FRAMES_HIGH */ nla_total_size(sizeof(u32)) + /* _RATE_SAMPLE_INTERVAL */ nla_total_size(sizeof(u8)) + /* _USE_CQE_MODE_TX */ - nla_total_size(sizeof(u8)); /* _USE_CQE_MODE_RX */ + nla_total_size(sizeof(u8)) + /* _USE_CQE_MODE_RX */ + nla_total_size(sizeof(u32)) + /* _TX_AGGR_MAX_BYTES */ + nla_total_size(sizeof(u32)) + /* _TX_AGGR_MAX_FRAMES */ + nla_total_size(sizeof(u32)); /* _TX_AGGR_TIME_USECS */ } static bool coalesce_put_u32(struct sk_buff *skb, u16 attr_type, u32 val, @@ -180,7 +183,13 @@ static int coalesce_fill_reply(struct sk_buff *skb, coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, kcoal->use_cqe_mode_tx, supported) || coalesce_put_bool(skb, ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, - kcoal->use_cqe_mode_rx, supported)) + kcoal->use_cqe_mode_rx, supported) || + coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES, + kcoal->tx_aggr_max_bytes, supported) || + coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES, + kcoal->tx_aggr_max_frames, supported) || + coalesce_put_u32(skb, ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, + kcoal->tx_aggr_time_usecs, supported)) return -EMSGSIZE; return 0; @@ -227,6 +236,9 @@ const struct nla_policy ethnl_coalesce_set_policy[] = { [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .type = NLA_U32 }, [ETHTOOL_A_COALESCE_USE_CQE_MODE_TX] = NLA_POLICY_MAX(NLA_U8, 1), [ETHTOOL_A_COALESCE_USE_CQE_MODE_RX] = NLA_POLICY_MAX(NLA_U8, 1), + [ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES] = { .type = NLA_U32 }, + [ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES] = { .type = NLA_U32 }, + [ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS] = { .type = NLA_U32 }, }; int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info) @@ -321,6 +333,12 @@ int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info) tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_TX], &mod); ethnl_update_u8(&kernel_coalesce.use_cqe_mode_rx, tb[ETHTOOL_A_COALESCE_USE_CQE_MODE_RX], &mod); + ethnl_update_u32(&kernel_coalesce.tx_aggr_max_bytes, + tb[ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES], &mod); + ethnl_update_u32(&kernel_coalesce.tx_aggr_max_frames, + tb[ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES], &mod); + ethnl_update_u32(&kernel_coalesce.tx_aggr_time_usecs, + tb[ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS], &mod); ret = 0; if (!mod) goto out_ops; -- cgit v1.2.3 From 6e6eda44b939c0931533d6681d9f2ed41b44cde9 Mon Sep 17 00:00:00 2001 From: Yunhui Cui Date: Wed, 11 Jan 2023 14:59:30 +0800 Subject: sock: add tracepoint for send recv length Add 2 tracepoints to monitor the tcp/udp traffic of per process and per cgroup. Regarding monitoring the tcp/udp traffic of each process, there are two existing solutions, the first one is https://www.atoptool.nl/netatop.php. The second is via kprobe/kretprobe. Netatop solution is implemented by registering the hook function at the hook point provided by the netfilter framework. These hook functions may be in the soft interrupt context and cannot directly obtain the pid. Some data structures are added to bind packets and processes. For example, struct taskinfobucket, struct taskinfo ... Every time the process sends and receives packets it needs multiple hashmaps,resulting in low performance and it has the problem fo inaccurate tcp/udp traffic statistics(for example: multiple threads share sockets). We can obtain the information with kretprobe, but as we know, kprobe gets the result by trappig in an exception, which loses performance compared to tracepoint. We compared the performance of tracepoints with the above two methods, and the results are as follows: ab -n 1000000 -c 1000 -r http://127.0.0.1/index.html without trace: Time per request: 39.660 [ms] (mean) Time per request: 0.040 [ms] (mean, across all concurrent requests) netatop: Time per request: 50.717 [ms] (mean) Time per request: 0.051 [ms] (mean, across all concurrent requests) kr: Time per request: 43.168 [ms] (mean) Time per request: 0.043 [ms] (mean, across all concurrent requests) tracepoint: Time per request: 41.004 [ms] (mean) Time per request: 0.041 [ms] (mean, across all concurrent requests It can be seen that tracepoint has better performance. Signed-off-by: Yunhui Cui Signed-off-by: Xiongchun Duan Reviewed-by: Steven Rostedt (Google) Signed-off-by: David S. Miller --- include/trace/events/sock.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ net/socket.c | 33 +++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/trace/events/sock.h b/include/trace/events/sock.h index 777ee6cbe933..71492e8276da 100644 --- a/include/trace/events/sock.h +++ b/include/trace/events/sock.h @@ -263,6 +263,51 @@ TRACE_EVENT(inet_sk_error_report, __entry->error) ); +/* + * sock send/recv msg length + */ +DECLARE_EVENT_CLASS(sock_msg_length, + + TP_PROTO(struct sock *sk, int ret, int flags), + + TP_ARGS(sk, ret, flags), + + TP_STRUCT__entry( + __field(void *, sk) + __field(__u16, family) + __field(__u16, protocol) + __field(int, ret) + __field(int, flags) + ), + + TP_fast_assign( + __entry->sk = sk; + __entry->family = sk->sk_family; + __entry->protocol = sk->sk_protocol; + __entry->ret = ret; + __entry->flags = flags; + ), + + TP_printk("sk address = %p, family = %s protocol = %s, length = %d, error = %d, flags = 0x%x", + __entry->sk, show_family_name(__entry->family), + show_inet_protocol_name(__entry->protocol), + !(__entry->flags & MSG_PEEK) ? + (__entry->ret > 0 ? __entry->ret : 0) : 0, + __entry->ret < 0 ? __entry->ret : 0, + __entry->flags) +); + +DEFINE_EVENT(sock_msg_length, sock_send_length, + TP_PROTO(struct sock *sk, int ret, int flags), + + TP_ARGS(sk, ret, flags) +); + +DEFINE_EVENT(sock_msg_length, sock_recv_length, + TP_PROTO(struct sock *sk, int ret, int flags), + + TP_ARGS(sk, ret, flags) +); #endif /* _TRACE_SOCK_H */ /* This part must be outside protection */ diff --git a/net/socket.c b/net/socket.c index 888cd618a968..77626e4d9690 100644 --- a/net/socket.c +++ b/net/socket.c @@ -106,6 +106,7 @@ #include #include #include +#include #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sysctl_net_busy_read __read_mostly; @@ -709,12 +710,22 @@ INDIRECT_CALLABLE_DECLARE(int inet_sendmsg(struct socket *, struct msghdr *, size_t)); INDIRECT_CALLABLE_DECLARE(int inet6_sendmsg(struct socket *, struct msghdr *, size_t)); + +static noinline void call_trace_sock_send_length(struct sock *sk, int ret, + int flags) +{ + trace_sock_send_length(sk, ret, 0); +} + static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) { int ret = INDIRECT_CALL_INET(sock->ops->sendmsg, inet6_sendmsg, inet_sendmsg, sock, msg, msg_data_left(msg)); BUG_ON(ret == -EIOCBQUEUED); + + if (trace_sock_send_length_enabled()) + call_trace_sock_send_length(sock->sk, ret, 0); return ret; } @@ -989,12 +1000,21 @@ INDIRECT_CALLABLE_DECLARE(int inet_recvmsg(struct socket *, struct msghdr *, size_t, int)); INDIRECT_CALLABLE_DECLARE(int inet6_recvmsg(struct socket *, struct msghdr *, size_t, int)); + +static noinline void call_trace_sock_recv_length(struct sock *sk, int ret, int flags) +{ + trace_sock_recv_length(sk, ret, flags); +} + static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, int flags) { - return INDIRECT_CALL_INET(sock->ops->recvmsg, inet6_recvmsg, - inet_recvmsg, sock, msg, msg_data_left(msg), - flags); + int ret = INDIRECT_CALL_INET(sock->ops->recvmsg, inet6_recvmsg, + inet_recvmsg, sock, msg, + msg_data_left(msg), flags); + if (trace_sock_recv_length_enabled()) + call_trace_sock_recv_length(sock->sk, ret, flags); + return ret; } /** @@ -1044,6 +1064,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, { struct socket *sock; int flags; + int ret; sock = file->private_data; @@ -1051,7 +1072,11 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, /* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */ flags |= more; - return kernel_sendpage(sock, page, offset, size, flags); + ret = kernel_sendpage(sock, page, offset, size, flags); + + if (trace_sock_send_length_enabled()) + call_trace_sock_send_length(sock->sk, ret, 0); + return ret; } static ssize_t sock_splice_read(struct file *file, loff_t *ppos, -- cgit v1.2.3 From 0c5ffc3d7b15978c6b184938cd6b8af06e436424 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 Jan 2023 20:43:26 +0100 Subject: cpuidle, dt: Push RCU-idle into driver Doing RCU-idle outside the driver, only to then temporarily enable it again before going idle is suboptimal. Notably: this converts all dt_init_idle_driver() and __CPU_PM_CPU_IDLE_ENTER() users for they are inextrably intertwined. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Tested-by: Tony Lindgren Tested-by: Ulf Hansson Acked-by: Rafael J. Wysocki Acked-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20230112195540.068981667@infradead.org --- drivers/acpi/processor_idle.c | 2 ++ drivers/cpuidle/cpuidle-big_little.c | 8 ++++++-- drivers/cpuidle/dt_idle_states.c | 2 +- include/linux/cpuidle.h | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 7bf882fcd64b..566f7dbf7ab3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1219,6 +1219,8 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) state->target_residency = lpi->min_residency; if (lpi->arch_flags) state->flags |= CPUIDLE_FLAG_TIMER_STOP; + if (i != 0 && lpi->entry_method == ACPI_CSTATE_FFH) + state->flags |= CPUIDLE_FLAG_RCU_IDLE; state->enter = acpi_idle_lpi_enter; drv->safe_state_index = i; } diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c index abe51185f243..fffd4ed0c4d1 100644 --- a/drivers/cpuidle/cpuidle-big_little.c +++ b/drivers/cpuidle/cpuidle-big_little.c @@ -64,7 +64,8 @@ static struct cpuidle_driver bl_idle_little_driver = { .enter = bl_enter_powerdown, .exit_latency = 700, .target_residency = 2500, - .flags = CPUIDLE_FLAG_TIMER_STOP, + .flags = CPUIDLE_FLAG_TIMER_STOP | + CPUIDLE_FLAG_RCU_IDLE, .name = "C1", .desc = "ARM little-cluster power down", }, @@ -85,7 +86,8 @@ static struct cpuidle_driver bl_idle_big_driver = { .enter = bl_enter_powerdown, .exit_latency = 500, .target_residency = 2000, - .flags = CPUIDLE_FLAG_TIMER_STOP, + .flags = CPUIDLE_FLAG_TIMER_STOP | + CPUIDLE_FLAG_RCU_IDLE, .name = "C1", .desc = "ARM big-cluster power down", }, @@ -124,11 +126,13 @@ static int bl_enter_powerdown(struct cpuidle_device *dev, struct cpuidle_driver *drv, int idx) { cpu_pm_enter(); + ct_idle_enter(); cpu_suspend(0, bl_powerdown_finisher); /* signals the MCPM core that CPU is out of low power state */ mcpm_cpu_powered_up(); + ct_idle_exit(); cpu_pm_exit(); diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index 7ca3d7d9b5ea..02aa0b39af9d 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -77,7 +77,7 @@ static int init_state_node(struct cpuidle_state *idle_state, if (err) desc = state_node->name; - idle_state->flags = 0; + idle_state->flags = CPUIDLE_FLAG_RCU_IDLE; if (of_property_read_bool(state_node, "local-timer-stop")) idle_state->flags |= CPUIDLE_FLAG_TIMER_STOP; /* diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index fce476275e16..0ddc11e44302 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -289,7 +289,9 @@ extern s64 cpuidle_governor_latency_req(unsigned int cpu); if (!is_retention) \ __ret = cpu_pm_enter(); \ if (!__ret) { \ + ct_idle_enter(); \ __ret = low_level_idle_enter(state); \ + ct_idle_exit(); \ if (!is_retention) \ cpu_pm_exit(); \ } \ -- cgit v1.2.3 From a01353cf1896ea5b8a7bbc5e2b2d38feed8b7aaa Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 Jan 2023 20:43:27 +0100 Subject: cpuidle: Fix ct_idle_*() usage The whole disable-RCU, enable-IRQS dance is very intricate since changing IRQ state is traced, which depends on RCU. Add two helpers for the cpuidle case that mirror the entry code: ct_cpuidle_enter() ct_cpuidle_exit() And fix all the cases where the enter/exit dance was buggy. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Tested-by: Tony Lindgren Tested-by: Ulf Hansson Acked-by: Rafael J. Wysocki Acked-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20230112195540.130014793@infradead.org --- arch/arm/mach-imx/cpuidle-imx6q.c | 4 ++-- arch/arm/mach-imx/cpuidle-imx6sx.c | 4 ++-- arch/arm/mach-omap2/cpuidle34xx.c | 4 ++-- arch/arm/mach-omap2/cpuidle44xx.c | 8 +++---- drivers/acpi/processor_idle.c | 8 +++++-- drivers/cpuidle/cpuidle-big_little.c | 4 ++-- drivers/cpuidle/cpuidle-mvebu-v7.c | 4 ++-- drivers/cpuidle/cpuidle-psci.c | 4 ++-- drivers/cpuidle/cpuidle-riscv-sbi.c | 4 ++-- drivers/cpuidle/cpuidle-tegra.c | 8 +++---- drivers/cpuidle/cpuidle.c | 11 +++++---- include/linux/clockchips.h | 4 ++-- include/linux/cpuidle.h | 34 +++++++++++++++++++++++++-- kernel/sched/idle.c | 45 +++++++++++------------------------- kernel/time/tick-broadcast.c | 6 ++++- 15 files changed, 86 insertions(+), 66 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c index d086cbae09c3..c24c78a67cc1 100644 --- a/arch/arm/mach-imx/cpuidle-imx6q.c +++ b/arch/arm/mach-imx/cpuidle-imx6q.c @@ -25,9 +25,9 @@ static int imx6q_enter_wait(struct cpuidle_device *dev, imx6_set_lpm(WAIT_UNCLOCKED); raw_spin_unlock(&cpuidle_lock); - ct_idle_enter(); + ct_cpuidle_enter(); cpu_do_idle(); - ct_idle_exit(); + ct_cpuidle_exit(); raw_spin_lock(&cpuidle_lock); if (num_idle_cpus-- == num_online_cpus()) diff --git a/arch/arm/mach-imx/cpuidle-imx6sx.c b/arch/arm/mach-imx/cpuidle-imx6sx.c index 1dc01f6b0f36..479f06286b50 100644 --- a/arch/arm/mach-imx/cpuidle-imx6sx.c +++ b/arch/arm/mach-imx/cpuidle-imx6sx.c @@ -47,9 +47,9 @@ static int imx6sx_enter_wait(struct cpuidle_device *dev, cpu_pm_enter(); cpu_cluster_pm_enter(); - ct_idle_enter(); + ct_cpuidle_enter(); cpu_suspend(0, imx6sx_idle_finish); - ct_idle_exit(); + ct_cpuidle_exit(); cpu_cluster_pm_exit(); cpu_pm_exit(); diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index cedf5cbe451f..6d63769cef0f 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c @@ -133,9 +133,9 @@ static int omap3_enter_idle(struct cpuidle_device *dev, } /* Execute ARM wfi */ - ct_idle_enter(); + ct_cpuidle_enter(); omap_sram_idle(); - ct_idle_exit(); + ct_cpuidle_exit(); /* * Call idle CPU PM enter notifier chain to restore diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index 953ad888737c..3c97d5676e81 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -105,9 +105,9 @@ static int omap_enter_idle_smp(struct cpuidle_device *dev, } raw_spin_unlock_irqrestore(&mpu_lock, flag); - ct_idle_enter(); + ct_cpuidle_enter(); omap4_enter_lowpower(dev->cpu, cx->cpu_state); - ct_idle_exit(); + ct_cpuidle_exit(); raw_spin_lock_irqsave(&mpu_lock, flag); if (cx->mpu_state_vote == num_online_cpus()) @@ -186,10 +186,10 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, } } - ct_idle_enter(); + ct_cpuidle_enter(); omap4_enter_lowpower(dev->cpu, cx->cpu_state); cpu_done[dev->cpu] = true; - ct_idle_exit(); + ct_cpuidle_exit(); /* Wakeup CPU1 only if it is not offlined */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 566f7dbf7ab3..a589cfac8c0f 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -642,6 +642,8 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, */ bool dis_bm = pr->flags.bm_control; + instrumentation_begin(); + /* If we can skip BM, demote to a safe state. */ if (!cx->bm_sts_skip && acpi_idle_bm_check()) { dis_bm = false; @@ -663,11 +665,11 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, raw_spin_unlock(&c3_lock); } - ct_idle_enter(); + ct_cpuidle_enter(); acpi_idle_do_entry(cx); - ct_idle_exit(); + ct_cpuidle_exit(); /* Re-enable bus master arbitration */ if (dis_bm) { @@ -677,6 +679,8 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, raw_spin_unlock(&c3_lock); } + instrumentation_end(); + return index; } diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c index fffd4ed0c4d1..5858db21e08c 100644 --- a/drivers/cpuidle/cpuidle-big_little.c +++ b/drivers/cpuidle/cpuidle-big_little.c @@ -126,13 +126,13 @@ static int bl_enter_powerdown(struct cpuidle_device *dev, struct cpuidle_driver *drv, int idx) { cpu_pm_enter(); - ct_idle_enter(); + ct_cpuidle_enter(); cpu_suspend(0, bl_powerdown_finisher); /* signals the MCPM core that CPU is out of low power state */ mcpm_cpu_powered_up(); - ct_idle_exit(); + ct_cpuidle_exit(); cpu_pm_exit(); diff --git a/drivers/cpuidle/cpuidle-mvebu-v7.c b/drivers/cpuidle/cpuidle-mvebu-v7.c index c9568aa9410c..20bfb26d5a88 100644 --- a/drivers/cpuidle/cpuidle-mvebu-v7.c +++ b/drivers/cpuidle/cpuidle-mvebu-v7.c @@ -36,9 +36,9 @@ static int mvebu_v7_enter_idle(struct cpuidle_device *dev, if (drv->states[index].flags & MVEBU_V7_FLAG_DEEP_IDLE) deepidle = true; - ct_idle_enter(); + ct_cpuidle_enter(); ret = mvebu_v7_cpu_suspend(deepidle); - ct_idle_exit(); + ct_cpuidle_exit(); cpu_pm_exit(); diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c index 969808cef520..58b2cbba98c8 100644 --- a/drivers/cpuidle/cpuidle-psci.c +++ b/drivers/cpuidle/cpuidle-psci.c @@ -74,7 +74,7 @@ static int __psci_enter_domain_idle_state(struct cpuidle_device *dev, else pm_runtime_put_sync_suspend(pd_dev); - ct_idle_enter(); + ct_cpuidle_enter(); state = psci_get_domain_state(); if (!state) @@ -82,7 +82,7 @@ static int __psci_enter_domain_idle_state(struct cpuidle_device *dev, ret = psci_cpu_suspend_enter(state) ? -1 : idx; - ct_idle_exit(); + ct_cpuidle_exit(); if (s2idle) dev_pm_genpd_resume(pd_dev); diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c index cbdbb11b972b..0a480f5799a7 100644 --- a/drivers/cpuidle/cpuidle-riscv-sbi.c +++ b/drivers/cpuidle/cpuidle-riscv-sbi.c @@ -126,7 +126,7 @@ static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, else pm_runtime_put_sync_suspend(pd_dev); - ct_idle_enter(); + ct_cpuidle_enter(); if (sbi_is_domain_state_available()) state = sbi_get_domain_state(); @@ -135,7 +135,7 @@ static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, ret = sbi_suspend(state) ? -1 : idx; - ct_idle_exit(); + ct_cpuidle_exit(); if (s2idle) dev_pm_genpd_resume(pd_dev); diff --git a/drivers/cpuidle/cpuidle-tegra.c b/drivers/cpuidle/cpuidle-tegra.c index 3ca5cfb9d322..9c2903c1b1c0 100644 --- a/drivers/cpuidle/cpuidle-tegra.c +++ b/drivers/cpuidle/cpuidle-tegra.c @@ -183,7 +183,7 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, tegra_pm_set_cpu_in_lp2(); cpu_pm_enter(); - ct_idle_enter(); + ct_cpuidle_enter(); switch (index) { case TEGRA_C7: @@ -199,7 +199,7 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, break; } - ct_idle_exit(); + ct_cpuidle_exit(); cpu_pm_exit(); tegra_pm_clear_cpu_in_lp2(); @@ -240,10 +240,10 @@ static int tegra_cpuidle_enter(struct cpuidle_device *dev, if (index == TEGRA_C1) { if (do_rcu) - ct_idle_enter(); + ct_cpuidle_enter(); ret = arm_cpuidle_simple_enter(dev, drv, index); if (do_rcu) - ct_idle_exit(); + ct_cpuidle_exit(); } else ret = tegra_cpuidle_state_enter(dev, index, cpu); diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 95c801f0b9a8..08374c7935ce 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -152,12 +153,12 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv, */ stop_critical_timings(); if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) - ct_idle_enter(); + ct_cpuidle_enter(); target_state->enter_s2idle(dev, drv, index); if (WARN_ON_ONCE(!irqs_disabled())) - local_irq_disable(); + raw_local_irq_disable(); if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) - ct_idle_exit(); + ct_cpuidle_exit(); tick_unfreeze(); start_critical_timings(); @@ -235,14 +236,14 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, stop_critical_timings(); if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) - ct_idle_enter(); + ct_cpuidle_enter(); entered_state = target_state->enter(dev, drv, index); if (WARN_ONCE(!irqs_disabled(), "%ps leaked IRQ state", target_state->enter)) raw_local_irq_disable(); if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE)) - ct_idle_exit(); + ct_cpuidle_exit(); start_critical_timings(); sched_clock_idle_wakeup_event(); diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 8ae9a95ebf5b..9aac31d856f3 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -211,7 +211,7 @@ extern int tick_receive_broadcast(void); extern void tick_setup_hrtimer_broadcast(void); extern int tick_check_broadcast_expired(void); # else -static inline int tick_check_broadcast_expired(void) { return 0; } +static __always_inline int tick_check_broadcast_expired(void) { return 0; } static inline void tick_setup_hrtimer_broadcast(void) { } # endif @@ -219,7 +219,7 @@ static inline void tick_setup_hrtimer_broadcast(void) { } static inline void clockevents_suspend(void) { } static inline void clockevents_resume(void) { } -static inline int tick_check_broadcast_expired(void) { return 0; } +static __always_inline int tick_check_broadcast_expired(void) { return 0; } static inline void tick_setup_hrtimer_broadcast(void) { } #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 0ddc11e44302..630c879143c7 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -14,6 +14,7 @@ #include #include #include +#include #define CPUIDLE_STATE_MAX 10 #define CPUIDLE_NAME_LEN 16 @@ -115,6 +116,35 @@ struct cpuidle_device { DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); DECLARE_PER_CPU(struct cpuidle_device, cpuidle_dev); +static __always_inline void ct_cpuidle_enter(void) +{ + lockdep_assert_irqs_disabled(); + /* + * Idle is allowed to (temporary) enable IRQs. It + * will return with IRQs disabled. + * + * Trace IRQs enable here, then switch off RCU, and have + * arch_cpu_idle() use raw_local_irq_enable(). Note that + * ct_idle_enter() relies on lockdep IRQ state, so switch that + * last -- this is very similar to the entry code. + */ + trace_hardirqs_on_prepare(); + lockdep_hardirqs_on_prepare(); + instrumentation_end(); + ct_idle_enter(); + lockdep_hardirqs_on(_RET_IP_); +} + +static __always_inline void ct_cpuidle_exit(void) +{ + /* + * Carefully undo the above. + */ + lockdep_hardirqs_off(_RET_IP_); + ct_idle_exit(); + instrumentation_begin(); +} + /**************************** * CPUIDLE DRIVER INTERFACE * ****************************/ @@ -289,9 +319,9 @@ extern s64 cpuidle_governor_latency_req(unsigned int cpu); if (!is_retention) \ __ret = cpu_pm_enter(); \ if (!__ret) { \ - ct_idle_enter(); \ + ct_cpuidle_enter(); \ __ret = low_level_idle_enter(state); \ - ct_idle_exit(); \ + ct_cpuidle_exit(); \ if (!is_retention) \ cpu_pm_exit(); \ } \ diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index f26ab2675f7d..e924602ec43b 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -51,18 +51,22 @@ __setup("hlt", cpu_idle_nopoll_setup); static noinline int __cpuidle cpu_idle_poll(void) { + instrumentation_begin(); trace_cpu_idle(0, smp_processor_id()); stop_critical_timings(); - ct_idle_enter(); - local_irq_enable(); + ct_cpuidle_enter(); + raw_local_irq_enable(); while (!tif_need_resched() && (cpu_idle_force_poll || tick_check_broadcast_expired())) cpu_relax(); + raw_local_irq_disable(); - ct_idle_exit(); + ct_cpuidle_exit(); start_critical_timings(); trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id()); + local_irq_enable(); + instrumentation_end(); return 1; } @@ -85,44 +89,21 @@ void __weak arch_cpu_idle(void) */ void __cpuidle default_idle_call(void) { - if (current_clr_polling_and_test()) { - local_irq_enable(); - } else { - + instrumentation_begin(); + if (!current_clr_polling_and_test()) { trace_cpu_idle(1, smp_processor_id()); stop_critical_timings(); - /* - * arch_cpu_idle() is supposed to enable IRQs, however - * we can't do that because of RCU and tracing. - * - * Trace IRQs enable here, then switch off RCU, and have - * arch_cpu_idle() use raw_local_irq_enable(). Note that - * ct_idle_enter() relies on lockdep IRQ state, so switch that - * last -- this is very similar to the entry code. - */ - trace_hardirqs_on_prepare(); - lockdep_hardirqs_on_prepare(); - ct_idle_enter(); - lockdep_hardirqs_on(_THIS_IP_); - + ct_cpuidle_enter(); arch_cpu_idle(); - - /* - * OK, so IRQs are enabled here, but RCU needs them disabled to - * turn itself back on.. funny thing is that disabling IRQs - * will cause tracing, which needs RCU. Jump through hoops to - * make it 'work'. - */ raw_local_irq_disable(); - lockdep_hardirqs_off(_THIS_IP_); - ct_idle_exit(); - lockdep_hardirqs_on(_THIS_IP_); - raw_local_irq_enable(); + ct_cpuidle_exit(); start_critical_timings(); trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id()); } + local_irq_enable(); + instrumentation_end(); } static int call_cpuidle_s2idle(struct cpuidle_driver *drv, diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index f7fe6fe36173..93bf2b4e47e5 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -622,9 +622,13 @@ struct cpumask *tick_get_broadcast_oneshot_mask(void) * to avoid a deep idle transition as we are about to get the * broadcast IPI right away. */ -int tick_check_broadcast_expired(void) +noinstr int tick_check_broadcast_expired(void) { +#ifdef _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H + return arch_test_bit(smp_processor_id(), cpumask_bits(tick_broadcast_force_mask)); +#else return cpumask_test_cpu(smp_processor_id(), tick_broadcast_force_mask); +#endif } /* -- cgit v1.2.3 From 2b5a0e425e6e319b1978db1e9564f6af4228a567 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 Jan 2023 20:43:31 +0100 Subject: objtool/idle: Validate __cpuidle code as noinstr Idle code is very like entry code in that RCU isn't available. As such, add a little validation. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Tested-by: Tony Lindgren Tested-by: Ulf Hansson Acked-by: Geert Uytterhoeven Acked-by: Rafael J. Wysocki Acked-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20230112195540.373461409@infradead.org --- arch/alpha/kernel/vmlinux.lds.S | 1 - arch/arc/kernel/vmlinux.lds.S | 1 - arch/arm/include/asm/vmlinux.lds.h | 1 - arch/arm64/kernel/vmlinux.lds.S | 1 - arch/csky/kernel/vmlinux.lds.S | 1 - arch/hexagon/kernel/vmlinux.lds.S | 1 - arch/ia64/kernel/vmlinux.lds.S | 1 - arch/loongarch/kernel/vmlinux.lds.S | 1 - arch/m68k/kernel/vmlinux-nommu.lds | 1 - arch/m68k/kernel/vmlinux-std.lds | 1 - arch/m68k/kernel/vmlinux-sun3.lds | 1 - arch/microblaze/kernel/vmlinux.lds.S | 1 - arch/mips/kernel/vmlinux.lds.S | 1 - arch/nios2/kernel/vmlinux.lds.S | 1 - arch/openrisc/kernel/vmlinux.lds.S | 1 - arch/parisc/kernel/vmlinux.lds.S | 1 - arch/powerpc/kernel/vmlinux.lds.S | 1 - arch/riscv/kernel/vmlinux-xip.lds.S | 1 - arch/riscv/kernel/vmlinux.lds.S | 1 - arch/s390/kernel/vmlinux.lds.S | 1 - arch/sh/kernel/vmlinux.lds.S | 1 - arch/sparc/kernel/vmlinux.lds.S | 1 - arch/um/kernel/dyn.lds.S | 1 - arch/um/kernel/uml.lds.S | 1 - arch/x86/include/asm/irqflags.h | 11 ++++------- arch/x86/include/asm/mwait.h | 2 +- arch/x86/kernel/vmlinux.lds.S | 1 - arch/xtensa/kernel/vmlinux.lds.S | 1 - include/asm-generic/vmlinux.lds.h | 9 +++------ include/linux/compiler_types.h | 8 ++++++-- include/linux/cpu.h | 3 --- tools/objtool/check.c | 13 +++++++++++++ 32 files changed, 27 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S index 5b78d640725d..2efa7dfc798a 100644 --- a/arch/alpha/kernel/vmlinux.lds.S +++ b/arch/alpha/kernel/vmlinux.lds.S @@ -27,7 +27,6 @@ SECTIONS HEAD_TEXT TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT *(.fixup) *(.gnu.warning) diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S index 529ae50f9fe2..549c3f407918 100644 --- a/arch/arc/kernel/vmlinux.lds.S +++ b/arch/arc/kernel/vmlinux.lds.S @@ -85,7 +85,6 @@ SECTIONS _stext = .; TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h index fad45c884e98..4c8632d5c432 100644 --- a/arch/arm/include/asm/vmlinux.lds.h +++ b/arch/arm/include/asm/vmlinux.lds.h @@ -96,7 +96,6 @@ SOFTIRQENTRY_TEXT \ TEXT_TEXT \ SCHED_TEXT \ - CPUIDLE_TEXT \ LOCK_TEXT \ KPROBES_TEXT \ ARM_STUBS_TEXT \ diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 4c13dafc98b8..2777214cbf1a 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -175,7 +175,6 @@ SECTIONS ENTRY_TEXT TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT HYPERVISOR_TEXT diff --git a/arch/csky/kernel/vmlinux.lds.S b/arch/csky/kernel/vmlinux.lds.S index 68c980d08482..d718961786d2 100644 --- a/arch/csky/kernel/vmlinux.lds.S +++ b/arch/csky/kernel/vmlinux.lds.S @@ -34,7 +34,6 @@ SECTIONS SOFTIRQENTRY_TEXT TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT *(.fixup) diff --git a/arch/hexagon/kernel/vmlinux.lds.S b/arch/hexagon/kernel/vmlinux.lds.S index 57465bff1fe4..1140051a0c45 100644 --- a/arch/hexagon/kernel/vmlinux.lds.S +++ b/arch/hexagon/kernel/vmlinux.lds.S @@ -41,7 +41,6 @@ SECTIONS IRQENTRY_TEXT SOFTIRQENTRY_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT *(.fixup) diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 9b265783be6a..53dfde161c8a 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -51,7 +51,6 @@ SECTIONS { __end_ivt_text = .; TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S index 733b16e8d55d..78506b31ba61 100644 --- a/arch/loongarch/kernel/vmlinux.lds.S +++ b/arch/loongarch/kernel/vmlinux.lds.S @@ -43,7 +43,6 @@ SECTIONS .text : { TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds index 387f334e87d3..2624fc18c131 100644 --- a/arch/m68k/kernel/vmlinux-nommu.lds +++ b/arch/m68k/kernel/vmlinux-nommu.lds @@ -48,7 +48,6 @@ SECTIONS { IRQENTRY_TEXT SOFTIRQENTRY_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT *(.fixup) . = ALIGN(16); diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index ed1d9eda3190..1ccdd04ae462 100644 --- a/arch/m68k/kernel/vmlinux-std.lds +++ b/arch/m68k/kernel/vmlinux-std.lds @@ -19,7 +19,6 @@ SECTIONS IRQENTRY_TEXT SOFTIRQENTRY_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT *(.fixup) *(.gnu.warning) diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds index 4a52f44f2ef0..f13ddcc2af5c 100644 --- a/arch/m68k/kernel/vmlinux-sun3.lds +++ b/arch/m68k/kernel/vmlinux-sun3.lds @@ -19,7 +19,6 @@ SECTIONS IRQENTRY_TEXT SOFTIRQENTRY_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT *(.fixup) *(.gnu.warning) diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index fb31747ec092..ae50d3d04a7d 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -36,7 +36,6 @@ SECTIONS { EXIT_TEXT EXIT_CALL SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 1f98947fe715..52cbde60edf5 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -61,7 +61,6 @@ SECTIONS .text : { TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/nios2/kernel/vmlinux.lds.S b/arch/nios2/kernel/vmlinux.lds.S index 126e114744cb..37b958055064 100644 --- a/arch/nios2/kernel/vmlinux.lds.S +++ b/arch/nios2/kernel/vmlinux.lds.S @@ -24,7 +24,6 @@ SECTIONS .text : { TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT IRQENTRY_TEXT SOFTIRQENTRY_TEXT diff --git a/arch/openrisc/kernel/vmlinux.lds.S b/arch/openrisc/kernel/vmlinux.lds.S index d5c7bb0fae57..bc1306047837 100644 --- a/arch/openrisc/kernel/vmlinux.lds.S +++ b/arch/openrisc/kernel/vmlinux.lds.S @@ -52,7 +52,6 @@ SECTIONS _stext = .; TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 2769eb991f58..1aaa2ca09800 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -86,7 +86,6 @@ SECTIONS TEXT_TEXT LOCK_TEXT SCHED_TEXT - CPUIDLE_TEXT KPROBES_TEXT IRQENTRY_TEXT SOFTIRQENTRY_TEXT diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 8c3862b4c259..86d5ca19a540 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -111,7 +111,6 @@ SECTIONS #endif NOINSTR_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/riscv/kernel/vmlinux-xip.lds.S b/arch/riscv/kernel/vmlinux-xip.lds.S index 75e0fa8a700a..eab9edc3b631 100644 --- a/arch/riscv/kernel/vmlinux-xip.lds.S +++ b/arch/riscv/kernel/vmlinux-xip.lds.S @@ -39,7 +39,6 @@ SECTIONS _stext = .; TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT ENTRY_TEXT diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S index 4e6c88aa4d87..643ab60e9efb 100644 --- a/arch/riscv/kernel/vmlinux.lds.S +++ b/arch/riscv/kernel/vmlinux.lds.S @@ -42,7 +42,6 @@ SECTIONS _stext = .; TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT ENTRY_TEXT diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 5ea3830af0cc..d1f1ab297995 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -42,7 +42,6 @@ SECTIONS HEAD_TEXT TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index 3161b9ccd2a5..947e2e213ff9 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S @@ -29,7 +29,6 @@ SECTIONS HEAD_TEXT TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index d55ae65a07ad..d317a843f7ea 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -50,7 +50,6 @@ SECTIONS HEAD_TEXT TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT IRQENTRY_TEXT diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 2b7fc5b54164..3385d653ebd0 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -74,7 +74,6 @@ SECTIONS _stext = .; TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT IRQENTRY_TEXT SOFTIRQENTRY_TEXT diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index 71a59b8adbdc..5c92d58a78e8 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -35,7 +35,6 @@ SECTIONS _stext = .; TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT IRQENTRY_TEXT SOFTIRQENTRY_TEXT diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index 7793e52d6237..8c5ae649d2df 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -8,9 +8,6 @@ #include -/* Provide __cpuidle; we can't safely include */ -#define __cpuidle __section(".cpuidle.text") - /* * Interrupt control: */ @@ -45,13 +42,13 @@ static __always_inline void native_irq_enable(void) asm volatile("sti": : :"memory"); } -static inline __cpuidle void native_safe_halt(void) +static __always_inline void native_safe_halt(void) { mds_idle_clear_cpu_buffers(); asm volatile("sti; hlt": : :"memory"); } -static inline __cpuidle void native_halt(void) +static __always_inline void native_halt(void) { mds_idle_clear_cpu_buffers(); asm volatile("hlt": : :"memory"); @@ -84,7 +81,7 @@ static __always_inline void arch_local_irq_enable(void) * Used in the idle loop; sti takes one instruction cycle * to complete: */ -static inline __cpuidle void arch_safe_halt(void) +static __always_inline void arch_safe_halt(void) { native_safe_halt(); } @@ -93,7 +90,7 @@ static inline __cpuidle void arch_safe_halt(void) * Used when interrupts are already enabled or to * shutdown the processor: */ -static inline __cpuidle void halt(void) +static __always_inline void halt(void) { native_halt(); } diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h index 3a8fdf881313..f2242167efe3 100644 --- a/arch/x86/include/asm/mwait.h +++ b/arch/x86/include/asm/mwait.h @@ -105,7 +105,7 @@ static inline void __sti_mwait(unsigned long eax, unsigned long ecx) * New with Core Duo processors, MWAIT can take some hints based on CPU * capability. */ -static inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) +static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) { if (static_cpu_has_bug(X86_BUG_MONITOR) || !current_set_polling_and_test()) { if (static_cpu_has_bug(X86_BUG_CLFLUSH_MONITOR)) { diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 2e0ee14229bf..25f155205770 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -129,7 +129,6 @@ SECTIONS HEAD_TEXT TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT KPROBES_TEXT SOFTIRQENTRY_TEXT diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index 965a3952c47b..c14fd96f459d 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S @@ -125,7 +125,6 @@ SECTIONS ENTRY_TEXT TEXT_TEXT SCHED_TEXT - CPUIDLE_TEXT LOCK_TEXT *(.fixup) } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index a94219e9916f..ad0d39403cf2 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -558,6 +558,9 @@ ALIGN_FUNCTION(); \ __noinstr_text_start = .; \ *(.noinstr.text) \ + __cpuidle_text_start = .; \ + *(.cpuidle.text) \ + __cpuidle_text_end = .; \ __noinstr_text_end = .; /* @@ -598,12 +601,6 @@ *(.spinlock.text) \ __lock_text_end = .; -#define CPUIDLE_TEXT \ - ALIGN_FUNCTION(); \ - __cpuidle_text_start = .; \ - *(.cpuidle.text) \ - __cpuidle_text_end = .; - #define KPROBES_TEXT \ ALIGN_FUNCTION(); \ __kprobes_text_start = .; \ diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 7c1afe0f4129..d7858901f035 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -232,11 +232,15 @@ struct ftrace_likely_data { #endif /* Section for code which can't be instrumented at all */ -#define noinstr \ - noinline notrace __attribute((__section__(".noinstr.text"))) \ +#define __noinstr_section(section) \ + noinline notrace __attribute((__section__(section))) \ __no_kcsan __no_sanitize_address __no_profile __no_sanitize_coverage \ __no_sanitize_memory +#define noinstr __noinstr_section(".noinstr.text") + +#define __cpuidle __noinstr_section(".cpuidle.text") + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 314802f98b9d..f83e4519c5f0 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -176,9 +176,6 @@ void __noreturn cpu_startup_entry(enum cpuhp_state state); void cpu_idle_poll_ctrl(bool enable); -/* Attach to any functions which should be considered cpuidle. */ -#define __cpuidle __section(".cpuidle.text") - bool cpu_in_idle(unsigned long pc); void arch_cpu_idle(void); diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 4350be739f4f..64954aa83522 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -376,6 +376,7 @@ static int decode_instructions(struct objtool_file *file) if (!strcmp(sec->name, ".noinstr.text") || !strcmp(sec->name, ".entry.text") || + !strcmp(sec->name, ".cpuidle.text") || !strncmp(sec->name, ".text.__x86.", 12)) sec->noinstr = true; @@ -3365,6 +3366,12 @@ static inline bool noinstr_call_dest(struct objtool_file *file, if (func->sec->noinstr) return true; + /* + * If the symbol is a static_call trampoline, we can't tell. + */ + if (func->static_call_tramp) + return true; + /* * The __ubsan_handle_*() calls are like WARN(), they only happen when * something 'BAD' happened. At the risk of taking the machine down, @@ -4162,6 +4169,12 @@ static int validate_noinstr_sections(struct objtool_file *file) warnings += validate_unwind_hints(file, sec); } + sec = find_section_by_name(file->elf, ".cpuidle.text"); + if (sec) { + warnings += validate_section(file, sec); + warnings += validate_unwind_hints(file, sec); + } + return warnings; } -- cgit v1.2.3 From e4df1511e1f4bcaa0d590aa7bbffe8bbbd6dfb49 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 Jan 2023 20:43:41 +0100 Subject: cpuidle, sched: Remove instrumentation from TIF_{POLLING_NRFLAG,NEED_RESCHED} objtool pointed out that various idle-TIF management methods have instrumentation: vmlinux.o: warning: objtool: mwait_idle+0x5: call to current_set_polling_and_test() leaves .noinstr.text section vmlinux.o: warning: objtool: acpi_processor_ffh_cstate_enter+0xc5: call to current_set_polling_and_test() leaves .noinstr.text section vmlinux.o: warning: objtool: cpu_idle_poll.isra.0+0x73: call to test_ti_thread_flag() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle+0xbc: call to current_set_polling_and_test() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle_irq+0xea: call to current_set_polling_and_test() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle_s2idle+0xb4: call to current_set_polling_and_test() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle+0xa6: call to current_clr_polling() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle_irq+0xbf: call to current_clr_polling() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle_s2idle+0xa1: call to current_clr_polling() leaves .noinstr.text section vmlinux.o: warning: objtool: mwait_idle+0xe: call to __current_set_polling() leaves .noinstr.text section vmlinux.o: warning: objtool: acpi_processor_ffh_cstate_enter+0xc5: call to __current_set_polling() leaves .noinstr.text section vmlinux.o: warning: objtool: cpu_idle_poll.isra.0+0x73: call to test_ti_thread_flag() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle+0xbc: call to __current_set_polling() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle_irq+0xea: call to __current_set_polling() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle_s2idle+0xb4: call to __current_set_polling() leaves .noinstr.text section vmlinux.o: warning: objtool: cpu_idle_poll.isra.0+0x73: call to test_ti_thread_flag() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle_s2idle+0x73: call to test_ti_thread_flag.constprop.0() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle_irq+0x91: call to test_ti_thread_flag.constprop.0() leaves .noinstr.text section vmlinux.o: warning: objtool: intel_idle+0x78: call to test_ti_thread_flag.constprop.0() leaves .noinstr.text section vmlinux.o: warning: objtool: acpi_safe_halt+0xf: call to test_ti_thread_flag.constprop.0() leaves .noinstr.text section Remove the instrumentation, because these methods are used in low-level cpuidle code moving between states, that should not be instrumented. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Tested-by: Tony Lindgren Tested-by: Ulf Hansson Acked-by: Rafael J. Wysocki Acked-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20230112195540.988741683@infradead.org --- include/linux/sched/idle.h | 40 ++++++++++++++++++++++++++++++---------- include/linux/thread_info.h | 18 +++++++++++++++++- 2 files changed, 47 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/linux/sched/idle.h b/include/linux/sched/idle.h index d73d314d59c6..478084f9105e 100644 --- a/include/linux/sched/idle.h +++ b/include/linux/sched/idle.h @@ -23,12 +23,37 @@ static inline void wake_up_if_idle(int cpu) { } */ #ifdef TIF_POLLING_NRFLAG -static inline void __current_set_polling(void) +#ifdef _ASM_GENERIC_BITOPS_INSTRUMENTED_ATOMIC_H + +static __always_inline void __current_set_polling(void) { - set_thread_flag(TIF_POLLING_NRFLAG); + arch_set_bit(TIF_POLLING_NRFLAG, + (unsigned long *)(¤t_thread_info()->flags)); } -static inline bool __must_check current_set_polling_and_test(void) +static __always_inline void __current_clr_polling(void) +{ + arch_clear_bit(TIF_POLLING_NRFLAG, + (unsigned long *)(¤t_thread_info()->flags)); +} + +#else + +static __always_inline void __current_set_polling(void) +{ + set_bit(TIF_POLLING_NRFLAG, + (unsigned long *)(¤t_thread_info()->flags)); +} + +static __always_inline void __current_clr_polling(void) +{ + clear_bit(TIF_POLLING_NRFLAG, + (unsigned long *)(¤t_thread_info()->flags)); +} + +#endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_ATOMIC_H */ + +static __always_inline bool __must_check current_set_polling_and_test(void) { __current_set_polling(); @@ -41,12 +66,7 @@ static inline bool __must_check current_set_polling_and_test(void) return unlikely(tif_need_resched()); } -static inline void __current_clr_polling(void) -{ - clear_thread_flag(TIF_POLLING_NRFLAG); -} - -static inline bool __must_check current_clr_polling_and_test(void) +static __always_inline bool __must_check current_clr_polling_and_test(void) { __current_clr_polling(); @@ -73,7 +93,7 @@ static inline bool __must_check current_clr_polling_and_test(void) } #endif -static inline void current_clr_polling(void) +static __always_inline void current_clr_polling(void) { __current_clr_polling(); diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h index 9f392ec76f2b..c02646884fa8 100644 --- a/include/linux/thread_info.h +++ b/include/linux/thread_info.h @@ -177,7 +177,23 @@ static __always_inline unsigned long read_ti_thread_flags(struct thread_info *ti clear_ti_thread_flag(task_thread_info(t), TIF_##fl) #endif /* !CONFIG_GENERIC_ENTRY */ -#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) +#ifdef _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H + +static __always_inline bool tif_need_resched(void) +{ + return arch_test_bit(TIF_NEED_RESCHED, + (unsigned long *)(¤t_thread_info()->flags)); +} + +#else + +static __always_inline bool tif_need_resched(void) +{ + return test_bit(TIF_NEED_RESCHED, + (unsigned long *)(¤t_thread_info()->flags)); +} + +#endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */ #ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES static inline int arch_within_stack_frames(const void * const stack, -- cgit v1.2.3 From 6a123d6ae6ea930b9bb3c595ceac2b2f93039f67 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 Jan 2023 20:43:46 +0100 Subject: cpuidle, ACPI: Make noinstr clean objtool found cases where ACPI methods called out into instrumentation code: vmlinux.o: warning: objtool: io_idle+0xc: call to __inb.isra.0() leaves .noinstr.text section vmlinux.o: warning: objtool: acpi_idle_enter+0xfe: call to num_online_cpus() leaves .noinstr.text section vmlinux.o: warning: objtool: acpi_idle_enter+0x115: call to acpi_idle_fallback_to_c1.isra.0() leaves .noinstr.text section Fix this by: marking the IO in/out, acpi_idle_fallback_to_c1() and num_online_cpus() methods as __always_inline. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Tested-by: Tony Lindgren Tested-by: Ulf Hansson Acked-by: Rafael J. Wysocki Acked-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20230112195541.294846301@infradead.org --- arch/x86/include/asm/shared/io.h | 4 ++-- drivers/acpi/processor_idle.c | 2 +- include/linux/cpumask.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/arch/x86/include/asm/shared/io.h b/arch/x86/include/asm/shared/io.h index c0ef921c0586..8009d781c2f9 100644 --- a/arch/x86/include/asm/shared/io.h +++ b/arch/x86/include/asm/shared/io.h @@ -5,13 +5,13 @@ #include #define BUILDIO(bwl, bw, type) \ -static inline void __out##bwl(type value, u16 port) \ +static __always_inline void __out##bwl(type value, u16 port) \ { \ asm volatile("out" #bwl " %" #bw "0, %w1" \ : : "a"(value), "Nd"(port)); \ } \ \ -static inline type __in##bwl(u16 port) \ +static __always_inline type __in##bwl(u16 port) \ { \ type value; \ asm volatile("in" #bwl " %w1, %" #bw "0" \ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 48fcd28eb907..7f77710c86fc 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -607,7 +607,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) return 0; } -static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) +static __always_inline bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) { return IS_ENABLED(CONFIG_HOTPLUG_CPU) && !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED); diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index c2aa0aa26b45..d45e5de13721 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -1017,9 +1017,9 @@ static inline const struct cpumask *get_cpu_mask(unsigned int cpu) * concurrent CPU hotplug operations unless invoked from a cpuhp_lock held * region. */ -static inline unsigned int num_online_cpus(void) +static __always_inline unsigned int num_online_cpus(void) { - return atomic_read(&__num_online_cpus); + return arch_atomic_read(&__num_online_cpus); } #define num_possible_cpus() cpumask_weight(cpu_possible_mask) #define num_present_cpus() cpumask_weight(cpu_present_mask) -- cgit v1.2.3 From 408b961146be4c1a776ce285c3c289afab15298a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 Jan 2023 20:43:48 +0100 Subject: tracing: WARN on rcuidle ARCH_WANTS_NO_INSTR (a superset of CONFIG_GENERIC_ENTRY) disallows any and all tracing when RCU isn't enabled. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Tested-by: Tony Lindgren Tested-by: Ulf Hansson Acked-by: Rafael J. Wysocki Acked-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20230112195541.416110581@infradead.org --- include/linux/tracepoint.h | 15 +++++++++++++-- kernel/trace/trace.c | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 4b33b95eb8be..552f80b8362f 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -177,6 +177,17 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) #define __DO_TRACE_CALL(name, args) __traceiter_##name(NULL, args) #endif /* CONFIG_HAVE_STATIC_CALL */ +/* + * ARCH_WANTS_NO_INSTR archs are expected to have sanitized entry and idle + * code that disallow any/all tracing/instrumentation when RCU isn't watching. + */ +#ifdef CONFIG_ARCH_WANTS_NO_INSTR +#define RCUIDLE_COND(rcuidle) (rcuidle) +#else +/* srcu can't be used from NMI */ +#define RCUIDLE_COND(rcuidle) (rcuidle && in_nmi()) +#endif + /* * it_func[0] is never NULL because there is at least one element in the array * when the array itself is non NULL. @@ -188,8 +199,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) if (!(cond)) \ return; \ \ - /* srcu can't be used from NMI */ \ - WARN_ON_ONCE(rcuidle && in_nmi()); \ + if (WARN_ON_ONCE(RCUIDLE_COND(rcuidle))) \ + return; \ \ /* keep srcu and sched-rcu usage consistent */ \ preempt_disable_notrace(); \ diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a555a861b978..54ec1592ac79 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3128,6 +3128,9 @@ void __trace_stack(struct trace_array *tr, unsigned int trace_ctx, return; } + if (WARN_ON_ONCE(IS_ENABLED(CONFIG_GENERIC_ENTRY))) + return; + /* * When an NMI triggers, RCU is enabled via ct_nmi_enter(), * but if the above rcu_is_watching() failed, then the NMI -- cgit v1.2.3 From f176d4ccb30747231831f66779697afa6d738b3c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 Jan 2023 20:43:59 +0100 Subject: sched/core: Always inline __this_cpu_preempt_check() Quite a few unnecessary instrumentation calls are generated via the no-op __this_cpu_preempt_check() call, if it gets uninlined by the compiler: vmlinux.o: warning: objtool: in_entry_stack+0x9: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: default_do_nmi+0x10: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: fpu_idle_fpregs+0x41: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: kvm_read_and_reset_apf_flags+0x1: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: lockdep_hardirqs_on+0xb0: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: lockdep_hardirqs_off+0xae: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: irqentry_nmi_enter+0x69: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: irqentry_nmi_exit+0x32: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: acpi_processor_ffh_cstate_enter+0x9: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: acpi_idle_enter+0x43: call to __this_cpu_preempt_check() leaves .noinstr.text section vmlinux.o: warning: objtool: acpi_idle_enter_s2idle+0x45: call to __this_cpu_preempt_check() leaves .noinstr.text section Mark it __always_inline. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Tested-by: Tony Lindgren Tested-by: Ulf Hansson Acked-by: Rafael J. Wysocki Acked-by: Frederic Weisbecker Link: https://lore.kernel.org/r/20230112195542.089981974@infradead.org --- include/linux/percpu-defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index af1071535de8..e60727be79c4 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -310,7 +310,7 @@ extern void __bad_size_call_parameter(void); #ifdef CONFIG_DEBUG_PREEMPT extern void __this_cpu_preempt_check(const char *op); #else -static inline void __this_cpu_preempt_check(const char *op) { } +static __always_inline void __this_cpu_preempt_check(const char *op) { } #endif #define __pcpu_size_call_return(stem, variable) \ -- cgit v1.2.3 From 0e985e9d22864e29d5d2b3d909ad15134d7f6d46 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 12 Jan 2023 20:44:04 +0100 Subject: cpuidle: Add comments about noinstr/__cpuidle usage Add a few words on noinstr / __cpuidle usage. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20230112195542.397238052@infradead.org --- drivers/cpuidle/cpuidle.c | 12 ++++++++++++ include/linux/compiler_types.h | 10 ++++++++++ 2 files changed, 22 insertions(+) (limited to 'include') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 73f7d8b763c6..500d1720421e 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -252,6 +252,18 @@ noinstr int cpuidle_enter_state(struct cpuidle_device *dev, instrumentation_begin(); } + /* + * NOTE!! + * + * For cpuidle_state::enter() methods that do *NOT* set + * CPUIDLE_FLAG_RCU_IDLE RCU will be disabled here and these functions + * must be marked either noinstr or __cpuidle. + * + * For cpuidle_state::enter() methods that *DO* set + * CPUIDLE_FLAG_RCU_IDLE this isn't required, but they must mark the + * function calling ct_cpuidle_enter() as noinstr/__cpuidle and all + * functions called within the RCU-idle region. + */ entered_state = target_state->enter(dev, drv, index); if (WARN_ONCE(!irqs_disabled(), "%ps leaked IRQ state", target_state->enter)) diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index d7858901f035..dea5bf5bd09c 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -239,6 +239,16 @@ struct ftrace_likely_data { #define noinstr __noinstr_section(".noinstr.text") +/* + * The __cpuidle section is used twofold: + * + * 1) the original use -- identifying if a CPU is 'stuck' in idle state based + * on it's instruction pointer. See cpu_in_idle(). + * + * 2) supressing instrumentation around where cpuidle disables RCU; where the + * function isn't strictly required for #1, this is interchangeable with + * noinstr. + */ #define __cpuidle __noinstr_section(".cpuidle.text") #endif /* __KERNEL__ */ -- cgit v1.2.3 From 6caeb33fa986151f745fc62190bc28a593b8a0d2 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Tue, 10 Jan 2023 10:54:05 +0800 Subject: iommu: Add set_platform_dma_ops iommu ops When VFIO finishes assigning a device to user space and calls iommu_group_release_dma_owner() to return the device to kernel, the IOMMU core will attach the default domain to the device. Unfortunately, some IOMMU drivers don't support default domain, hence in the end, the core calls .detach_dev instead. This adds set_platform_dma_ops iommu ops to make it clear that what it does is returning control back to the platform DMA ops. Suggested-by: Jason Gunthorpe Reviewed-by: Jason Gunthorpe Signed-off-by: Lu Baolu Link: https://lore.kernel.org/r/20230110025408.667767-3-baolu.lu@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 28 ++++++++++++++++++++++++---- include/linux/iommu.h | 4 ++++ 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index de91dd88705b..1c8b2c7678f7 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2163,6 +2163,16 @@ static int iommu_group_do_detach_device(struct device *dev, void *data) return 0; } +static int iommu_group_do_set_platform_dma(struct device *dev, void *data) +{ + const struct iommu_ops *ops = dev_iommu_ops(dev); + + if (!WARN_ON(!ops->set_platform_dma_ops)) + ops->set_platform_dma_ops(dev); + + return 0; +} + static int __iommu_group_set_domain(struct iommu_group *group, struct iommu_domain *new_domain) { @@ -2177,10 +2187,20 @@ static int __iommu_group_set_domain(struct iommu_group *group, * platform specific behavior. */ if (!new_domain) { - if (WARN_ON(!group->domain->ops->detach_dev)) - return -EINVAL; - __iommu_group_for_each_dev(group, group->domain, - iommu_group_do_detach_device); + struct group_device *grp_dev; + + grp_dev = list_first_entry(&group->devices, + struct group_device, list); + + if (dev_iommu_ops(grp_dev->dev)->set_platform_dma_ops) + __iommu_group_for_each_dev(group, NULL, + iommu_group_do_set_platform_dma); + else if (group->domain->ops->detach_dev) + __iommu_group_for_each_dev(group, group->domain, + iommu_group_do_detach_device); + else + WARN_ON_ONCE(1); + group->domain = NULL; return 0; } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 46e1347bfa22..7b3e3775b069 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -228,6 +228,9 @@ struct iommu_iotlb_gather { * @release_device: Remove device from iommu driver handling * @probe_finalize: Do final setup work after the device is added to an IOMMU * group and attached to the groups domain + * @set_platform_dma_ops: Returning control back to the platform DMA ops. This op + * is to support old IOMMU drivers, new drivers should use + * default domains, and the common IOMMU DMA ops. * @device_group: find iommu group for a particular device * @get_resv_regions: Request list of reserved regions for a device * @of_xlate: add OF master IDs to iommu grouping @@ -256,6 +259,7 @@ struct iommu_ops { struct iommu_device *(*probe_device)(struct device *dev); void (*release_device)(struct device *dev); void (*probe_finalize)(struct device *dev); + void (*set_platform_dma_ops)(struct device *dev); struct iommu_group *(*device_group)(struct device *dev); /* Request/Free a list of reserved regions for a device */ -- cgit v1.2.3 From dd8a25c557e109f868430bd2e3e8f394cb40eaa7 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 10 Jan 2023 10:54:07 +0800 Subject: iommu: Remove deferred attach check from __iommu_detach_device() At the current moment, __iommu_detach_device() is only called via call chains that are after the device driver is attached - eg via explicit attach APIs called by the device driver. Commit bd421264ed30 ("iommu: Fix deferred domain attachment") has removed deferred domain attachment check from __iommu_attach_device() path, so it should just unconditionally work in the __iommu_detach_device() path. It actually looks like a bug that we were blocking detach on these paths since the attach was unconditional and the caller is going to free the (probably) UNAMANGED domain once this returns. The only place we should be testing for deferred attach is during the initial point the dma device is linked to the group, and then again during the dma api calls. Signed-off-by: Jason Gunthorpe Signed-off-by: Lu Baolu Link: https://lore.kernel.org/r/20230110025408.667767-5-baolu.lu@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 70 ++++++++++++++++++++++++++------------------------- include/linux/iommu.h | 2 ++ 2 files changed, 38 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 1c8b2c7678f7..85ae20c8ff5e 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -371,6 +371,30 @@ err_unlock: return ret; } +static bool iommu_is_attach_deferred(struct device *dev) +{ + const struct iommu_ops *ops = dev_iommu_ops(dev); + + if (ops->is_attach_deferred) + return ops->is_attach_deferred(dev); + + return false; +} + +static int iommu_group_do_dma_first_attach(struct device *dev, void *data) +{ + struct iommu_domain *domain = data; + + lockdep_assert_held(&dev->iommu_group->mutex); + + if (iommu_is_attach_deferred(dev)) { + dev->iommu->attach_deferred = 1; + return 0; + } + + return __iommu_attach_device(domain, dev); +} + int iommu_probe_device(struct device *dev) { const struct iommu_ops *ops; @@ -401,7 +425,7 @@ int iommu_probe_device(struct device *dev) * attach the default domain. */ if (group->default_domain && !group->owner) { - ret = __iommu_attach_device(group->default_domain, dev); + ret = iommu_group_do_dma_first_attach(dev, group->default_domain); if (ret) { mutex_unlock(&group->mutex); iommu_group_put(group); @@ -947,16 +971,6 @@ out: return ret; } -static bool iommu_is_attach_deferred(struct device *dev) -{ - const struct iommu_ops *ops = dev_iommu_ops(dev); - - if (ops->is_attach_deferred) - return ops->is_attach_deferred(dev); - - return false; -} - /** * iommu_group_add_device - add a device to an iommu group * @group: the group into which to add the device (reference should be held) @@ -1009,8 +1023,8 @@ rename: mutex_lock(&group->mutex); list_add_tail(&device->list, &group->devices); - if (group->domain && !iommu_is_attach_deferred(dev)) - ret = __iommu_attach_device(group->domain, dev); + if (group->domain) + ret = iommu_group_do_dma_first_attach(dev, group->domain); mutex_unlock(&group->mutex); if (ret) goto err_put_group; @@ -1776,21 +1790,10 @@ static void probe_alloc_default_domain(struct bus_type *bus, } -static int iommu_group_do_dma_attach(struct device *dev, void *data) -{ - struct iommu_domain *domain = data; - int ret = 0; - - if (!iommu_is_attach_deferred(dev)) - ret = __iommu_attach_device(domain, dev); - - return ret; -} - -static int __iommu_group_dma_attach(struct iommu_group *group) +static int __iommu_group_dma_first_attach(struct iommu_group *group) { return __iommu_group_for_each_dev(group, group->default_domain, - iommu_group_do_dma_attach); + iommu_group_do_dma_first_attach); } static int iommu_group_do_probe_finalize(struct device *dev, void *data) @@ -1855,7 +1858,7 @@ int bus_iommu_probe(struct bus_type *bus) iommu_group_create_direct_mappings(group); - ret = __iommu_group_dma_attach(group); + ret = __iommu_group_dma_first_attach(group); mutex_unlock(&group->mutex); @@ -1987,9 +1990,11 @@ static int __iommu_attach_device(struct iommu_domain *domain, return -ENODEV; ret = domain->ops->attach_dev(domain, dev); - if (!ret) - trace_attach_device_to_domain(dev); - return ret; + if (ret) + return ret; + dev->iommu->attach_deferred = 0; + trace_attach_device_to_domain(dev); + return 0; } /** @@ -2034,7 +2039,7 @@ EXPORT_SYMBOL_GPL(iommu_attach_device); int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain) { - if (iommu_is_attach_deferred(dev)) + if (dev->iommu && dev->iommu->attach_deferred) return __iommu_attach_device(domain, dev); return 0; @@ -2043,9 +2048,6 @@ int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain) static void __iommu_detach_device(struct iommu_domain *domain, struct device *dev) { - if (iommu_is_attach_deferred(dev)) - return; - domain->ops->detach_dev(domain, dev); trace_detach_device_from_domain(dev); } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 7b3e3775b069..0d10566b3cb2 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -405,6 +405,7 @@ struct iommu_fault_param { * @iommu_dev: IOMMU device this device is linked to * @priv: IOMMU Driver private data * @max_pasids: number of PASIDs this device can consume + * @attach_deferred: the dma domain attachment is deferred * * TODO: migrate other per device data pointers under iommu_dev_data, e.g. * struct iommu_group *iommu_group; @@ -417,6 +418,7 @@ struct dev_iommu { struct iommu_device *iommu_dev; void *priv; u32 max_pasids; + u32 attach_deferred:1; }; int iommu_device_register(struct iommu_device *iommu, -- cgit v1.2.3 From 8f9930fa016134ea07db4775ec596b16c3d03f05 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Tue, 10 Jan 2023 10:54:08 +0800 Subject: iommu: Remove detach_dev callback The detach_dev callback of domain ops is not called in the IOMMU core. Remove this callback to avoid dead code. The trace event for detaching domain from device is removed accordingly. Reviewed-by: Jason Gunthorpe Signed-off-by: Lu Baolu Link: https://lore.kernel.org/r/20230110025408.667767-6-baolu.lu@linux.intel.com Signed-off-by: Joerg Roedel --- drivers/iommu/iommu-traces.c | 1 - drivers/iommu/iommu.c | 36 ++++-------------------------------- include/linux/iommu.h | 2 -- include/trace/events/iommu.h | 7 ------- 4 files changed, 4 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/drivers/iommu/iommu-traces.c b/drivers/iommu/iommu-traces.c index 1e9ca7789de1..23416bf76df9 100644 --- a/drivers/iommu/iommu-traces.c +++ b/drivers/iommu/iommu-traces.c @@ -18,7 +18,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(remove_device_from_group); /* iommu_device_event */ EXPORT_TRACEPOINT_SYMBOL_GPL(attach_device_to_domain); -EXPORT_TRACEPOINT_SYMBOL_GPL(detach_device_from_domain); /* iommu_map_unmap */ EXPORT_TRACEPOINT_SYMBOL_GPL(map); diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 85ae20c8ff5e..9135540d7d59 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2045,13 +2045,6 @@ int iommu_deferred_attach(struct device *dev, struct iommu_domain *domain) return 0; } -static void __iommu_detach_device(struct iommu_domain *domain, - struct device *dev) -{ - domain->ops->detach_dev(domain, dev); - trace_detach_device_from_domain(dev); -} - void iommu_detach_device(struct iommu_domain *domain, struct device *dev) { struct iommu_group *group; @@ -2156,15 +2149,6 @@ int iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group) } EXPORT_SYMBOL_GPL(iommu_attach_group); -static int iommu_group_do_detach_device(struct device *dev, void *data) -{ - struct iommu_domain *domain = data; - - __iommu_detach_device(domain, dev); - - return 0; -} - static int iommu_group_do_set_platform_dma(struct device *dev, void *data) { const struct iommu_ops *ops = dev_iommu_ops(dev); @@ -2184,25 +2168,13 @@ static int __iommu_group_set_domain(struct iommu_group *group, return 0; /* - * New drivers should support default domains and so the detach_dev() op - * will never be called. Otherwise the NULL domain represents some + * New drivers should support default domains, so set_platform_dma() + * op will never be called. Otherwise the NULL domain represents some * platform specific behavior. */ if (!new_domain) { - struct group_device *grp_dev; - - grp_dev = list_first_entry(&group->devices, - struct group_device, list); - - if (dev_iommu_ops(grp_dev->dev)->set_platform_dma_ops) - __iommu_group_for_each_dev(group, NULL, - iommu_group_do_set_platform_dma); - else if (group->domain->ops->detach_dev) - __iommu_group_for_each_dev(group, group->domain, - iommu_group_do_detach_device); - else - WARN_ON_ONCE(1); - + __iommu_group_for_each_dev(group, NULL, + iommu_group_do_set_platform_dma); group->domain = NULL; return 0; } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 0d10566b3cb2..a8063f26ff69 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -299,7 +299,6 @@ struct iommu_ops { * * EBUSY - device is attached to a domain and cannot be changed * * ENODEV - device specific errors, not able to be attached * * - treated as ENODEV by the caller. Use is discouraged - * @detach_dev: detach an iommu domain from a device * @set_dev_pasid: set an iommu domain to a pasid of device * @map: map a physically contiguous memory region to an iommu domain * @map_pages: map a physically contiguous set of pages of the same size to @@ -320,7 +319,6 @@ struct iommu_ops { */ struct iommu_domain_ops { int (*attach_dev)(struct iommu_domain *domain, struct device *dev); - void (*detach_dev)(struct iommu_domain *domain, struct device *dev); int (*set_dev_pasid)(struct iommu_domain *domain, struct device *dev, ioasid_t pasid); diff --git a/include/trace/events/iommu.h b/include/trace/events/iommu.h index 29096fe12623..70743db1fb75 100644 --- a/include/trace/events/iommu.h +++ b/include/trace/events/iommu.h @@ -76,13 +76,6 @@ DEFINE_EVENT(iommu_device_event, attach_device_to_domain, TP_ARGS(dev) ); -DEFINE_EVENT(iommu_device_event, detach_device_from_domain, - - TP_PROTO(struct device *dev), - - TP_ARGS(dev) -); - TRACE_EVENT(map, TP_PROTO(unsigned long iova, phys_addr_t paddr, size_t size), -- cgit v1.2.3 From 9f820fc0651c32f8dde26b8e3ad93e1b9fdb62c4 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 12 Jan 2023 10:36:35 +0100 Subject: mtd: rawnand: Check the data only read pattern only once Instead of checking if a pattern is supported each time we need it, let's create a bitfield that only the core would be allowed to fill at startup time. The core and the individual drivers may then use it in order to check what operation they should use. This bitfield is supposed to grow over time. Signed-off-by: Miquel Raynal Tested-by: Liao Jaime Link: https://lore.kernel.org/linux-mtd/20230112093637.987838-2-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 20 ++++++++++++++++++++ drivers/mtd/nand/raw/nand_jedec.c | 3 +-- drivers/mtd/nand/raw/nand_onfi.c | 3 +-- include/linux/mtd/rawnand.h | 8 ++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index c3cc66039925..7b87e2e70484 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4991,6 +4991,24 @@ nand_manufacturer_name(const struct nand_manufacturer_desc *manufacturer_desc) return manufacturer_desc ? manufacturer_desc->name : "Unknown"; } +static void rawnand_check_data_only_read_support(struct nand_chip *chip) +{ + /* Use an arbitrary size for the check */ + if (!nand_read_data_op(chip, NULL, SZ_512, true, true)) + chip->controller->supported_op.data_only_read = 1; +} + +static void rawnand_early_check_supported_ops(struct nand_chip *chip) +{ + /* The supported_op fields should not be set by individual drivers */ + WARN_ON_ONCE(chip->controller->supported_op.data_only_read); + + if (!nand_has_exec_op(chip)) + return; + + rawnand_check_data_only_read_support(chip); +} + /* * Get the flash and manufacturer id and lookup if the type is supported. */ @@ -5023,6 +5041,8 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) /* Select the device */ nand_select_target(chip, 0); + rawnand_early_check_supported_ops(chip); + /* Send the command for reading device ID */ ret = nand_readid_op(chip, 0, id_data, 2); if (ret) diff --git a/drivers/mtd/nand/raw/nand_jedec.c b/drivers/mtd/nand/raw/nand_jedec.c index 85b6d9372d80..836757717660 100644 --- a/drivers/mtd/nand/raw/nand_jedec.c +++ b/drivers/mtd/nand/raw/nand_jedec.c @@ -46,8 +46,7 @@ int nand_jedec_detect(struct nand_chip *chip) if (!p) return -ENOMEM; - if (!nand_has_exec_op(chip) || - !nand_read_data_op(chip, p, sizeof(*p), true, true)) + if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read) use_datain = true; for (i = 0; i < JEDEC_PARAM_PAGES; i++) { diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index 7586befce7f9..f15ef90aec8c 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -166,8 +166,7 @@ int nand_onfi_detect(struct nand_chip *chip) if (!pbuf) return -ENOMEM; - if (!nand_has_exec_op(chip) || - !nand_read_data_op(chip, &pbuf[0], sizeof(*pbuf), true, true)) + if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read) use_datain = true; for (i = 0; i < ONFI_PARAM_PAGES; i++) { diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index dcf90144d70b..28c5dce782dd 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1094,10 +1094,18 @@ struct nand_controller_ops { * * @lock: lock used to serialize accesses to the NAND controller * @ops: NAND controller operations. + * @supported_op: NAND controller known-to-be-supported operations, + * only writable by the core after initial checking. + * @supported_op.data_only_read: The controller supports reading more data from + * the bus without restarting an entire read operation nor + * changing the column. */ struct nand_controller { struct mutex lock; const struct nand_controller_ops *ops; + struct { + unsigned int data_only_read: 1; + } supported_op; }; static inline void nand_controller_init(struct nand_controller *nfc) -- cgit v1.2.3 From 003fe4b9545b83cca4f7a7633695d1f69a0b0011 Mon Sep 17 00:00:00 2001 From: JaimeLiao Date: Thu, 12 Jan 2023 10:36:37 +0100 Subject: mtd: rawnand: Support for sequential cache reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for sequential cache reads for controllers using the generic core helpers for their fast read/write helpers. Sequential reads may reduce the overhead when accessing physically continuous data by loading in cache the next page while the previous page gets sent out on the NAND bus. The ONFI specification provides the following additional commands to handle sequential cached reads: * 0x31 - READ CACHE SEQUENTIAL: Requires the NAND chip to load the next page into cache while keeping the current cache available for host reads. * 0x3F - READ CACHE END: Tells the NAND chip this is the end of the sequential cache read, the current cache shall remain accessible for the host but no more internal cache loading operation is required. On the bus, a multi page read operation is currently handled like this: 00 -- ADDR1 -- 30 -- WAIT_RDY (tR+tRR) -- DATA1_IN 00 -- ADDR2 -- 30 -- WAIT_RDY (tR+tRR) -- DATA2_IN 00 -- ADDR3 -- 30 -- WAIT_RDY (tR+tRR) -- DATA3_IN Sequential cached reads may instead be achieved with: 00 -- ADDR1 -- 30 -- WAIT_RDY (tR) -- \ 31 -- WAIT_RDY (tRCBSY+tRR) -- DATA1_IN \ 31 -- WAIT_RDY (tRCBSY+tRR) -- DATA2_IN \ 3F -- WAIT_RDY (tRCBSY+tRR) -- DATA3_IN Below are the read speed test results with regular reads and sequential cached reads, on NXP i.MX6 VAR-SOM-SOLO in mapping mode with a NAND chip characterized with the following timings: * tR: 20 µs * tRCBSY: 5 µs * tRR: 20 ns and the following geometry: * device size: 2 MiB * eraseblock size: 128 kiB * page size: 2 kiB ============= Normal read @ 33MHz ================= mtd_speedtest: eraseblock read speed is 15633 KiB/s mtd_speedtest: page read speed is 15515 KiB/s mtd_speedtest: 2 page read speed is 15398 KiB/s =================================================== ========= Sequential cache read @ 33MHz =========== mtd_speedtest: eraseblock read speed is 18285 KiB/s mtd_speedtest: page read speed is 15875 KiB/s mtd_speedtest: 2 page read speed is 16253 KiB/s =================================================== We observe an overall speed improvement of about 5% when reading 2 pages, up to 15% when reading an entire block. This is due to the ~14us gain on each additional page read (tR - (tRCBSY + tRR)). Co-developed-by: Miquel Raynal Signed-off-by: Miquel Raynal Signed-off-by: JaimeLiao Tested-by: Liao Jaime Link: https://lore.kernel.org/linux-mtd/20230112093637.987838-4-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/nand_base.c | 119 +++++++++++++++++++++++++++++++++++++-- include/linux/mtd/rawnand.h | 9 +++ 2 files changed, 124 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index e1f74e2fa415..a6af521832aa 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -1208,6 +1208,73 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page, return nand_exec_op(chip, &op); } +static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int page, + unsigned int offset_in_page, void *buf, + unsigned int len, bool check_only) +{ + const struct nand_interface_config *conf = + nand_get_interface_config(chip); + u8 addrs[5]; + struct nand_op_instr start_instrs[] = { + NAND_OP_CMD(NAND_CMD_READ0, 0), + NAND_OP_ADDR(4, addrs, 0), + NAND_OP_CMD(NAND_CMD_READSTART, NAND_COMMON_TIMING_NS(conf, tWB_max)), + NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max), 0), + NAND_OP_CMD(NAND_CMD_READCACHESEQ, NAND_COMMON_TIMING_NS(conf, tWB_max)), + NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max), + NAND_COMMON_TIMING_NS(conf, tRR_min)), + NAND_OP_DATA_IN(len, buf, 0), + }; + struct nand_op_instr cont_instrs[] = { + NAND_OP_CMD(page == chip->cont_read.last_page ? + NAND_CMD_READCACHEEND : NAND_CMD_READCACHESEQ, + NAND_COMMON_TIMING_NS(conf, tWB_max)), + NAND_OP_WAIT_RDY(NAND_COMMON_TIMING_MS(conf, tR_max), + NAND_COMMON_TIMING_NS(conf, tRR_min)), + NAND_OP_DATA_IN(len, buf, 0), + }; + struct nand_operation start_op = NAND_OPERATION(chip->cur_cs, start_instrs); + struct nand_operation cont_op = NAND_OPERATION(chip->cur_cs, cont_instrs); + int ret; + + if (!len) { + start_op.ninstrs--; + cont_op.ninstrs--; + } + + ret = nand_fill_column_cycles(chip, addrs, offset_in_page); + if (ret < 0) + return ret; + + addrs[2] = page; + addrs[3] = page >> 8; + + if (chip->options & NAND_ROW_ADDR_3) { + addrs[4] = page >> 16; + start_instrs[1].ctx.addr.naddrs++; + } + + /* Check if cache reads are supported */ + if (check_only) { + if (nand_check_op(chip, &start_op) || nand_check_op(chip, &cont_op)) + return -EOPNOTSUPP; + + return 0; + } + + if (page == chip->cont_read.first_page) + return nand_exec_op(chip, &start_op); + else + return nand_exec_op(chip, &cont_op); +} + +static bool rawnand_cont_read_ongoing(struct nand_chip *chip, unsigned int page) +{ + return chip->cont_read.ongoing && + page >= chip->cont_read.first_page && + page <= chip->cont_read.last_page; +} + /** * nand_read_page_op - Do a READ PAGE operation * @chip: The NAND chip @@ -1233,10 +1300,16 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page, return -EINVAL; if (nand_has_exec_op(chip)) { - if (mtd->writesize > 512) - return nand_lp_exec_read_page_op(chip, page, - offset_in_page, buf, - len); + if (mtd->writesize > 512) { + if (rawnand_cont_read_ongoing(chip, page)) + return nand_lp_exec_cont_read_page_op(chip, page, + offset_in_page, + buf, len, false); + else + return nand_lp_exec_read_page_op(chip, page, + offset_in_page, buf, + len); + } return nand_sp_exec_read_page_op(chip, page, offset_in_page, buf, len); @@ -3353,6 +3426,27 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, return NULL; } +static void rawnand_enable_cont_reads(struct nand_chip *chip, unsigned int page, + u32 readlen, int col) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (!chip->controller->supported_op.cont_read) + return; + + if ((col && col + readlen < (3 * mtd->writesize)) || + (!col && readlen < (2 * mtd->writesize))) { + chip->cont_read.ongoing = false; + return; + } + + chip->cont_read.ongoing = true; + chip->cont_read.first_page = page; + if (col) + chip->cont_read.first_page++; + chip->cont_read.last_page = page + ((readlen >> chip->page_shift) & chip->pagemask); +} + /** * nand_setup_read_retry - [INTERN] Set the READ RETRY mode * @chip: NAND chip object @@ -3426,6 +3520,8 @@ static int nand_do_read_ops(struct nand_chip *chip, loff_t from, oob = ops->oobbuf; oob_required = oob ? 1 : 0; + rawnand_enable_cont_reads(chip, page, readlen, col); + while (1) { struct mtd_ecc_stats ecc_stats = mtd->ecc_stats; @@ -5009,12 +5105,27 @@ static void rawnand_early_check_supported_ops(struct nand_chip *chip) rawnand_check_data_only_read_support(chip); } +static void rawnand_check_cont_read_support(struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (chip->read_retries) + return; + + if (!nand_lp_exec_cont_read_page_op(chip, 0, 0, NULL, + mtd->writesize, true)) + chip->controller->supported_op.cont_read = 1; +} + static void rawnand_late_check_supported_ops(struct nand_chip *chip) { /* The supported_op fields should not be set by individual drivers */ + WARN_ON_ONCE(chip->controller->supported_op.cont_read); if (!nand_has_exec_op(chip)) return; + + rawnand_check_cont_read_support(chip); } /* diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 28c5dce782dd..1b0936fe3c6e 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -67,6 +67,8 @@ struct gpio_desc; /* Extended commands for large page devices */ #define NAND_CMD_READSTART 0x30 +#define NAND_CMD_READCACHESEQ 0x31 +#define NAND_CMD_READCACHEEND 0x3f #define NAND_CMD_RNDOUTSTART 0xE0 #define NAND_CMD_CACHEDPROG 0x15 @@ -1099,12 +1101,14 @@ struct nand_controller_ops { * @supported_op.data_only_read: The controller supports reading more data from * the bus without restarting an entire read operation nor * changing the column. + * @supported_op.cont_read: The controller supports sequential cache reads. */ struct nand_controller { struct mutex lock; const struct nand_controller_ops *ops; struct { unsigned int data_only_read: 1; + unsigned int cont_read: 1; } supported_op; }; @@ -1308,6 +1312,11 @@ struct nand_chip { int read_retries; struct nand_secure_region *secure_regions; u8 nr_secure_regions; + struct { + bool ongoing; + unsigned int first_page; + unsigned int last_page; + } cont_read; /* Externals */ struct nand_controller *controller; -- cgit v1.2.3 From 8133844a8f2434be9576850c6978179d7cca5c81 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 12 Jan 2023 21:51:24 +0100 Subject: PCI/ACPI: Account for _S0W of the target bridge in acpi_pci_bridge_d3() It is questionable to allow a PCI bridge to go into D3 if it has _S0W returning D2 or a shallower power state, so modify acpi_pci_bridge_d3(() to always take the return value of _S0W for the target bridge into account. That is, make it return 'false' if _S0W returns D2 or a shallower power state for the target bridge regardless of its ancestor Root Port properties. Of course, this also causes 'false' to be returned if the Root Port itself is the target and its _S0W returns D2 or a shallower power state. However, still allow bridges without _S0W that are power-manageable via ACPI to enter D3 to retain the current code behavior in that case. This fixes problems where a hotplug notification is missed because a bridge is in D3. That means hot-added devices such as USB4 docks (and the devices they contain) and Thunderbolt 3 devices may not work. Link: https://lore.kernel.org/linux-pci/20221031223356.32570-1-mario.limonciello@amd.com/ Link: https://lore.kernel.org/r/12155458.O9o76ZdvQC@kreacher Reported-by: Mario Limonciello Signed-off-by: Rafael J. Wysocki Signed-off-by: Bjorn Helgaas --- drivers/acpi/device_pm.c | 19 +++++++++++++++++++ drivers/pci/pci-acpi.c | 45 +++++++++++++++++++++++++++++++-------------- include/acpi/acpi_bus.h | 1 + 3 files changed, 51 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 97450f4003cc..f007116a8427 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -484,6 +484,25 @@ void acpi_dev_power_up_children_with_adr(struct acpi_device *adev) acpi_dev_for_each_child(adev, acpi_power_up_if_adr_present, NULL); } +/** + * acpi_dev_power_state_for_wake - Deepest power state for wakeup signaling + * @adev: ACPI companion of the target device. + * + * Evaluate _S0W for @adev and return the value produced by it or return + * ACPI_STATE_UNKNOWN on errors (including _S0W not present). + */ +u8 acpi_dev_power_state_for_wake(struct acpi_device *adev) +{ + unsigned long long state; + acpi_status status; + + status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state); + if (ACPI_FAILURE(status)) + return ACPI_STATE_UNKNOWN; + + return state; +} + #ifdef CONFIG_PM static DEFINE_MUTEX(acpi_pm_notifier_lock); static DEFINE_MUTEX(acpi_pm_notifier_install_lock); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 068d6745bf98..052a611081ec 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -976,24 +976,41 @@ bool acpi_pci_power_manageable(struct pci_dev *dev) bool acpi_pci_bridge_d3(struct pci_dev *dev) { struct pci_dev *rpdev; - struct acpi_device *adev; - acpi_status status; - unsigned long long state; + struct acpi_device *adev, *rpadev; const union acpi_object *obj; if (acpi_pci_disabled || !dev->is_hotplug_bridge) return false; - /* Assume D3 support if the bridge is power-manageable by ACPI. */ - if (acpi_pci_power_manageable(dev)) - return true; + adev = ACPI_COMPANION(&dev->dev); + if (adev) { + /* + * If the bridge has _S0W, whether or not it can go into D3 + * depends on what is returned by that object. In particular, + * if the power state returned by _S0W is D2 or shallower, + * entering D3 should not be allowed. + */ + if (acpi_dev_power_state_for_wake(adev) <= ACPI_STATE_D2) + return false; + + /* + * Otherwise, assume that the bridge can enter D3 so long as it + * is power-manageable via ACPI. + */ + if (acpi_device_power_manageable(adev)) + return true; + } rpdev = pcie_find_root_port(dev); if (!rpdev) return false; - adev = ACPI_COMPANION(&rpdev->dev); - if (!adev) + if (rpdev == dev) + rpadev = adev; + else + rpadev = ACPI_COMPANION(&rpdev->dev); + + if (!rpadev) return false; /* @@ -1001,15 +1018,15 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev) * doesn't supply a wakeup GPE via _PRW, it cannot signal hotplug * events from low-power states including D3hot and D3cold. */ - if (!adev->wakeup.flags.valid) + if (!rpadev->wakeup.flags.valid) return false; /* - * If the Root Port cannot wake itself from D3hot or D3cold, we - * can't use D3. + * In the bridge-below-a-Root-Port case, evaluate _S0W for the Root Port + * to verify whether or not it can signal wakeup from D3. */ - status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state); - if (ACPI_SUCCESS(status) && state < ACPI_STATE_D3_HOT) + if (rpadev != adev && + acpi_dev_power_state_for_wake(rpadev) <= ACPI_STATE_D2) return false; /* @@ -1018,7 +1035,7 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev) * bridges *below* that Root Port can also signal hotplug events * while in D3. */ - if (!acpi_dev_get_property(adev, "HotPlugSupportInD3", + if (!acpi_dev_get_property(rpadev, "HotPlugSupportInD3", ACPI_TYPE_INTEGER, &obj) && obj->integer.value == 1) return true; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index cd3b75e08ec3..3412297a6b8b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -533,6 +533,7 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p); int acpi_device_update_power(struct acpi_device *device, int *state_p); bool acpi_bus_power_manageable(acpi_handle handle); void acpi_dev_power_up_children_with_adr(struct acpi_device *adev); +u8 acpi_dev_power_state_for_wake(struct acpi_device *adev); int acpi_device_power_add_dependent(struct acpi_device *adev, struct device *dev); void acpi_device_power_remove_dependent(struct acpi_device *adev, -- cgit v1.2.3 From fa5bde139ee43ab91087c01e690c61aec957c339 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 27 Oct 2022 13:07:55 +0900 Subject: ata: libata: Introduce ata_ncq_supported() Introduce the inline helper function ata_ncq_supported() to test if a device supports NCQ commands. The function ata_ncq_enabled() is also rewritten using this new helper function. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Reviewed-by: Chaitanya Kulkarni Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Niklas Cassel --- include/linux/libata.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/libata.h b/include/linux/libata.h index 3b7f5d9e2f87..059ca7f2b69c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1691,21 +1691,35 @@ extern struct ata_device *ata_dev_next(struct ata_device *dev, (dev) = ata_dev_next((dev), (link), ATA_DITER_##mode)) /** - * ata_ncq_enabled - Test whether NCQ is enabled - * @dev: ATA device to test for + * ata_ncq_supported - Test whether NCQ is supported + * @dev: ATA device to test * * LOCKING: * spin_lock_irqsave(host lock) * * RETURNS: - * 1 if NCQ is enabled for @dev, 0 otherwise. + * true if @dev supports NCQ, false otherwise. */ -static inline int ata_ncq_enabled(struct ata_device *dev) +static inline bool ata_ncq_supported(struct ata_device *dev) { if (!IS_ENABLED(CONFIG_SATA_HOST)) - return 0; - return (dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | - ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ; + return false; + return (dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ; +} + +/** + * ata_ncq_enabled - Test whether NCQ is enabled + * @dev: ATA device to test + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * true if NCQ is enabled for @dev, false otherwise. + */ +static inline bool ata_ncq_enabled(struct ata_device *dev) +{ + return ata_ncq_supported(dev) && !(dev->flags & ATA_DFLAG_NCQ_OFF); } static inline bool ata_fpdma_dsm_supported(struct ata_device *dev) -- cgit v1.2.3 From 4d2e4980a5289ae31a1cff40d258b68573182a37 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Fri, 14 Oct 2022 18:05:38 +0900 Subject: ata: libata: cleanup fua support detection Move the detection of a device FUA support from ata_scsiop_mode_sense()/ata_dev_supports_fua() to device scan time in ata_dev_configure(). The function ata_dev_config_fua() is introduced to detect if a device supports FUA and this support is indicated using the new device flag ATA_DFLAG_FUA. In order to blacklist known buggy devices, the horkage flag ATA_HORKAGE_NO_FUA is introduced. Similarly to other horkage flags, the libata.force= arguments "fua" and "nofua" are also introduced to allow a user to control this horkage flag through the "force" libata module parameter. The ATA_DFLAG_FUA device flag is set only and only if all the following conditions are met: * libata.fua module parameter is set to 1 * The device supports the WRITE DMA FUA EXT command, * The device is not marked with the ATA_HORKAGE_NO_FUA flag, either from the blacklist or set by the user with libata.force=nofua * The device supports NCQ (while this is not mandated by the standards, this restriction is introduced to avoid problems with older non-NCQ devices). Enabling or diabling libata FUA support for all devices can now also be done using the "force=[no]fua" module parameter when libata.fua is set to 1. Signed-off-by: Damien Le Moal Reviewed-by: Hannes Reinecke Reviewed-by: Chaitanya Kulkarni Reviewed-by: Christoph Hellwig Reviewed-by: Johannes Thumshirn Reviewed-by: Niklas Cassel --- Documentation/admin-guide/kernel-parameters.txt | 3 +++ drivers/ata/libata-core.c | 30 ++++++++++++++++++++++++- drivers/ata/libata-scsi.c | 30 ++----------------------- include/linux/libata.h | 8 ++++--- 4 files changed, 39 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 6cfa6e3996cf..3d0f2de7dc03 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2816,6 +2816,9 @@ * [no]setxfer: Indicate if transfer speed mode setting should be skipped. + * [no]fua: Disable or enable FUA (Force Unit Access) + support for devices supporting this feature. + * dump_id: Dump IDENTIFY data. * disable: Disable this device. diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1c16342dda08..d25a53a873dc 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2422,6 +2422,28 @@ static void ata_dev_config_chs(struct ata_device *dev) dev->heads, dev->sectors); } +static void ata_dev_config_fua(struct ata_device *dev) +{ + /* Ignore FUA support if its use is disabled globally */ + if (!libata_fua) + goto nofua; + + /* Ignore devices without support for WRITE DMA FUA EXT */ + if (!(dev->flags & ATA_DFLAG_LBA48) || !ata_id_has_fua(dev->id)) + goto nofua; + + /* Ignore known bad devices and devices that lack NCQ support */ + if (!ata_ncq_supported(dev) || (dev->horkage & ATA_HORKAGE_NO_FUA)) + goto nofua; + + dev->flags |= ATA_DFLAG_FUA; + + return; + +nofua: + dev->flags &= ~ATA_DFLAG_FUA; +} + static void ata_dev_config_devslp(struct ata_device *dev) { u8 *sata_setting = dev->link->ap->sector_buf; @@ -2510,7 +2532,8 @@ static void ata_dev_print_features(struct ata_device *dev) return; ata_dev_info(dev, - "Features:%s%s%s%s%s%s\n", + "Features:%s%s%s%s%s%s%s\n", + dev->flags & ATA_DFLAG_FUA ? " FUA" : "", dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "", dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "", dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "", @@ -2671,6 +2694,7 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_config_chs(dev); } + ata_dev_config_fua(dev); ata_dev_config_devslp(dev); ata_dev_config_sense_reporting(dev); ata_dev_config_zac(dev); @@ -4105,6 +4129,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { */ { "SATADOM-ML 3ME", NULL, ATA_HORKAGE_NO_LOG_DIR }, + /* Buggy FUA */ + { "Maxtor", "BANC1G10", ATA_HORKAGE_NO_FUA }, + /* End Marker */ { } }; @@ -6216,6 +6243,7 @@ static const struct ata_force_param force_tbl[] __initconst = { force_horkage_onoff(lpm, ATA_HORKAGE_NOLPM), force_horkage_onoff(setxfer, ATA_HORKAGE_NOSETXFER), force_horkage_on(dump_id, ATA_HORKAGE_DUMP_ID), + force_horkage_onoff(fua, ATA_HORKAGE_NO_FUA), force_horkage_on(disable, ATA_HORKAGE_DISABLE), }; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 46109bde8a04..aa338f10cef2 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2240,30 +2240,6 @@ static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable) return sizeof(def_rw_recovery_mpage); } -/* - * We can turn this into a real blacklist if it's needed, for now just - * blacklist any Maxtor BANC1G10 revision firmware - */ -static int ata_dev_supports_fua(u16 *id) -{ - unsigned char model[ATA_ID_PROD_LEN + 1], fw[ATA_ID_FW_REV_LEN + 1]; - - if (!libata_fua) - return 0; - if (!ata_id_has_fua(id)) - return 0; - - ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); - ata_id_c_string(id, fw, ATA_ID_FW_REV, sizeof(fw)); - - if (strcmp(model, "Maxtor")) - return 1; - if (strcmp(fw, "BANC1G10")) - return 1; - - return 0; /* blacklisted */ -} - /** * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands * @args: device IDENTIFY data / SCSI command of interest. @@ -2287,7 +2263,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) }; u8 pg, spg; unsigned int ebd, page_control, six_byte; - u8 dpofua, bp = 0xff; + u8 dpofua = 0, bp = 0xff; u16 fp; six_byte = (scsicmd[0] == MODE_SENSE); @@ -2350,9 +2326,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) goto invalid_fld; } - dpofua = 0; - if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) && - (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count)) + if (dev->flags & ATA_DFLAG_FUA) dpofua = 1 << 4; if (six_byte) { diff --git a/include/linux/libata.h b/include/linux/libata.h index 059ca7f2b69c..a759dfbdcc91 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -90,6 +90,7 @@ enum { ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ ATA_DFLAG_AN = (1 << 7), /* AN configured */ ATA_DFLAG_TRUSTED = (1 << 8), /* device supports trusted send/recv */ + ATA_DFLAG_FUA = (1 << 9), /* device supports FUA */ ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ ATA_DFLAG_NCQ_SEND_RECV = (1 << 11), /* device supports NCQ SEND and RECV */ ATA_DFLAG_NCQ_PRIO = (1 << 12), /* device supports NCQ priority */ @@ -112,9 +113,9 @@ enum { ATA_DFLAG_D_SENSE = (1 << 29), /* Descriptor sense requested */ ATA_DFLAG_ZAC = (1 << 30), /* ZAC device */ - ATA_DFLAG_FEATURES_MASK = ATA_DFLAG_TRUSTED | ATA_DFLAG_DA | \ - ATA_DFLAG_DEVSLP | ATA_DFLAG_NCQ_SEND_RECV | \ - ATA_DFLAG_NCQ_PRIO, + ATA_DFLAG_FEATURES_MASK = (ATA_DFLAG_TRUSTED | ATA_DFLAG_DA | \ + ATA_DFLAG_DEVSLP | ATA_DFLAG_NCQ_SEND_RECV | \ + ATA_DFLAG_NCQ_PRIO | ATA_DFLAG_FUA), ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -381,6 +382,7 @@ enum { ATA_HORKAGE_NO_NCQ_ON_ATI = (1 << 27), /* Disable NCQ on ATI chipset */ ATA_HORKAGE_NO_ID_DEV_LOG = (1 << 28), /* Identify device log missing */ ATA_HORKAGE_NO_LOG_DIR = (1 << 29), /* Do not read log directory */ + ATA_HORKAGE_NO_FUA = (1 << 30), /* Do not use FUA */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ -- cgit v1.2.3 From 64b6deadc938b37717aa1338715cb7ef5e7d444c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 5 Jan 2023 15:30:46 -0800 Subject: scsi: uapi: Replace 0-length array with flexible array Zero-length arrays are deprecated[1]. Replace struct fc_bsg_host_vendor_reply's "vendor_rsp" 0-length array with a flexible array. Detected with GCC 13, using -fstrict-flex-arrays=3: drivers/scsi/qla2xxx/qla_isr.c: In function 'qla25xx_process_bidir_status_iocb.isra': drivers/scsi/qla2xxx/qla_isr.c:3117:54: warning: array subscript 0 is outside array bounds of '__u32[0]' {aka 'unsigned int[]'} [-Warray-bounds=] 3117 | bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~ In file included from drivers/scsi/qla2xxx/qla_def.h:34, from drivers/scsi/qla2xxx/qla_isr.c:6: include/uapi/scsi/scsi_bsg_fc.h:219:15: note: while referencing 'vendor_rsp' 219 | __u32 vendor_rsp[0]; | ^~~~~~~~~~ [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays Cc: Martin K. Petersen Cc: Dan Williams Cc: "Gustavo A. R. Silva" Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20230105233042.never.913-kees@kernel.org Signed-off-by: Martin K. Petersen --- include/uapi/scsi/scsi_bsg_fc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/scsi/scsi_bsg_fc.h b/include/uapi/scsi/scsi_bsg_fc.h index 7f5930801f72..5e46cf1054af 100644 --- a/include/uapi/scsi/scsi_bsg_fc.h +++ b/include/uapi/scsi/scsi_bsg_fc.h @@ -216,7 +216,7 @@ struct fc_bsg_host_vendor { */ struct fc_bsg_host_vendor_reply { /* start of vendor response area */ - __u32 vendor_rsp[0]; + __DECLARE_FLEX_ARRAY(__u32, vendor_rsp); }; -- cgit v1.2.3 From 6e1d850acff9477ae4c18a73c19ef52841ac2010 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:38 -0800 Subject: scsi: ufs: core: Probe for EXT_IID support Task Tag is limited to 8 bits and this restricts the number of active I/Os to 255. In multi-circular queue mode, this may not be enough. The specification provides EXT_IID which can be used to increase the number of I/Os if the UFS device and UFSHC support it. This patch adds support to probe for EXT_IID support in UFS device and UFSHC. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Bart Van Assche Reviewed-by: Avri Altman Reviewed-by: Manivannan Sadhasivam Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 32 ++++++++++++++++++++++++++++++++ include/ufs/ufs.h | 5 +++++ include/ufs/ufshcd.h | 4 ++++ include/ufs/ufshci.h | 7 +++++++ 4 files changed, 48 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 0514669e03be..6ba05976c139 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2261,6 +2261,10 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) if (err) dev_err(hba->dev, "crypto setup failed\n"); + hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP); + hba->ext_iid_sup = FIELD_GET(MASK_EXT_IID_SUPPORT, + hba->mcq_capabilities); + return err; } @@ -7766,6 +7770,31 @@ static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf) } } +static void ufshcd_ext_iid_probe(struct ufs_hba *hba, u8 *desc_buf) +{ + struct ufs_dev_info *dev_info = &hba->dev_info; + u32 ext_ufs_feature; + u32 ext_iid_en = 0; + int err; + + /* Only UFS-4.0 and above may support EXT_IID */ + if (dev_info->wspecversion < 0x400) + goto out; + + ext_ufs_feature = get_unaligned_be32(desc_buf + + DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP); + if (!(ext_ufs_feature & UFS_DEV_EXT_IID_SUP)) + goto out; + + err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_EXT_IID_EN, 0, 0, &ext_iid_en); + if (err) + dev_err(hba->dev, "failed reading bEXTIIDEn. err = %d\n", err); + +out: + dev_info->b_ext_iid_en = ext_iid_en; +} + void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, const struct ufs_dev_quirk *fixups) { @@ -7864,6 +7893,9 @@ static int ufs_get_device_desc(struct ufs_hba *hba) ufshcd_temp_notif_probe(hba, desc_buf); + if (hba->ext_iid_sup) + ufshcd_ext_iid_probe(hba, desc_buf); + /* * ufshcd_read_string_desc returns size of the string * reset the error value diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index c146de52918d..bea7b2086a4a 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -169,6 +169,7 @@ enum attr_idn { QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E, QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F, + QUERY_ATTR_IDN_EXT_IID_EN = 0x2A, }; /* Descriptor idn for Query requests */ @@ -378,6 +379,7 @@ enum { UFS_DEV_EXT_TEMP_NOTIF = BIT(6), UFS_DEV_HPB_SUPPORT = BIT(7), UFS_DEV_WRITE_BOOSTER_SUP = BIT(8), + UFS_DEV_EXT_IID_SUP = BIT(16), }; #define UFS_DEV_HPB_SUPPORT_VERSION 0x310 @@ -629,6 +631,9 @@ struct ufs_dev_info { u8 b_presrv_uspc_en; bool b_advanced_rpmb_en; + + /* UFS EXT_IID Enable */ + bool b_ext_iid_en; }; /* diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index fc7373a1a15e..8f2080f9fdb5 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -757,6 +757,7 @@ struct ufs_hba_monitor { * @outstanding_lock: Protects @outstanding_reqs. * @outstanding_reqs: Bits representing outstanding transfer requests * @capabilities: UFS Controller Capabilities + * @mcq_capabilities: UFS Multi Circular Queue capabilities * @nutrs: Transfer Request Queue depth supported by controller * @nutmrs: Task Management Queue depth supported by controller * @reserved_slot: Used to submit device commands. Protected by @dev_cmd.lock. @@ -841,6 +842,7 @@ struct ufs_hba_monitor { * device * @complete_put: whether or not to call ufshcd_rpm_put() from inside * ufshcd_resume_complete() + * @ext_iid_sup: is EXT_IID is supported by UFSHC */ struct ufs_hba { void __iomem *mmio_base; @@ -882,6 +884,7 @@ struct ufs_hba { u32 capabilities; int nutrs; + u32 mcq_capabilities; int nutmrs; u32 reserved_slot; u32 ufs_version; @@ -991,6 +994,7 @@ struct ufs_hba { #endif u32 luns_avail; bool complete_put; + bool ext_iid_sup; }; #ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index 9346efea3eb3..f41bc7b03092 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -22,6 +22,7 @@ enum { /* UFSHCI Registers */ enum { REG_CONTROLLER_CAPABILITIES = 0x00, + REG_MCQCAP = 0x04, REG_UFS_VERSION = 0x08, REG_CONTROLLER_DEV_ID = 0x10, REG_CONTROLLER_PROD_ID = 0x14, @@ -69,6 +70,12 @@ enum { MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000, MASK_UIC_DME_TEST_MODE_SUPPORT = 0x04000000, MASK_CRYPTO_SUPPORT = 0x10000000, + MASK_MCQ_SUPPORT = 0x40000000, +}; + +/* MCQ capability mask */ +enum { + MASK_EXT_IID_SUPPORT = 0x00000400, }; #define UFS_MASK(mask, offset) ((mask) << (offset)) -- cgit v1.2.3 From 305a357d3595d39be7c001f72e135bc94cbd85da Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:39 -0800 Subject: scsi: ufs: core: Introduce multi-circular queue capability Add support to check for MCQ capability in the UFSHC. Add a module parameter to disable MCQ if needed. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Bart Van Assche Reviewed-by: Manivannan Sadhasivam Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 26 ++++++++++++++++++++++++++ include/ufs/ufshcd.h | 2 ++ 2 files changed, 28 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 6ba05976c139..64e04619326f 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -92,6 +92,28 @@ /* Polling time to wait for fDeviceInit */ #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */ +/* UFSHC 4.0 compliant HC support this mode, refer param_set_mcq_mode() */ +static bool use_mcq_mode = true; + +static int param_set_mcq_mode(const char *val, const struct kernel_param *kp) +{ + int ret; + + ret = param_set_bool(val, kp); + if (ret) + return ret; + + return 0; +} + +static const struct kernel_param_ops mcq_mode_ops = { + .set = param_set_mcq_mode, + .get = param_get_bool, +}; + +module_param_cb(use_mcq_mode, &mcq_mode_ops, &use_mcq_mode, 0644); +MODULE_PARM_DESC(use_mcq_mode, "Control MCQ mode for controllers starting from UFSHCI 4.0. 1 - enable MCQ, 0 - disable MCQ. MCQ is enabled by default"); + #define ufshcd_toggle_vreg(_dev, _vreg, _on) \ ({ \ int _ret; \ @@ -2261,6 +2283,10 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) if (err) dev_err(hba->dev, "crypto setup failed\n"); + hba->mcq_sup = FIELD_GET(MASK_MCQ_SUPPORT, hba->capabilities); + if (!hba->mcq_sup) + return err; + hba->mcq_capabilities = ufshcd_readl(hba, REG_MCQCAP); hba->ext_iid_sup = FIELD_GET(MASK_EXT_IID_SUPPORT, hba->mcq_capabilities); diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 8f2080f9fdb5..514687d2de54 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -843,6 +843,7 @@ struct ufs_hba_monitor { * @complete_put: whether or not to call ufshcd_rpm_put() from inside * ufshcd_resume_complete() * @ext_iid_sup: is EXT_IID is supported by UFSHC + * @mcq_sup: is mcq supported by UFSHC */ struct ufs_hba { void __iomem *mmio_base; @@ -995,6 +996,7 @@ struct ufs_hba { u32 luns_avail; bool complete_put; bool ext_iid_sup; + bool mcq_sup; }; #ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE -- cgit v1.2.3 From 0cab4023ec7b49b18145f74ab8389678d6d58878 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:40 -0800 Subject: scsi: ufs: core: Defer adding host to SCSI if MCQ is supported If MCQ support is present, enabling it after MCQ support has been configured would require reallocating tags and memory. It would also free up the already allocated memory in Single Doorbell Mode. So defer invoking scsi_add_host() until MCQ is configured. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Bart Van Assche Reviewed-by: Manivannan Sadhasivam Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 24 ++++++++++++++++++++---- include/ufs/ufshcd.h | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 64e04619326f..2cb05a6a0142 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -95,6 +95,11 @@ /* UFSHC 4.0 compliant HC support this mode, refer param_set_mcq_mode() */ static bool use_mcq_mode = true; +static bool is_mcq_supported(struct ufs_hba *hba) +{ + return hba->mcq_sup && use_mcq_mode; +} + static int param_set_mcq_mode(const char *val, const struct kernel_param *kp) { int ret; @@ -8292,6 +8297,7 @@ out: static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) { int ret; + struct Scsi_Host *host = hba->host; hba->ufshcd_state = UFSHCD_STATE_RESET; @@ -8326,6 +8332,14 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) ret = ufshcd_device_params_init(hba); if (ret) return ret; + if (is_mcq_supported(hba) && !hba->scsi_host_added) { + ret = scsi_add_host(host, hba->dev); + if (ret) { + dev_err(hba->dev, "scsi_add_host failed\n"); + return ret; + } + hba->scsi_host_added = true; + } } ufshcd_tune_unipro_params(hba); @@ -9964,10 +9978,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->is_irq_enabled = true; } - err = scsi_add_host(host, hba->dev); - if (err) { - dev_err(hba->dev, "scsi_add_host failed\n"); - goto out_disable; + if (!is_mcq_supported(hba)) { + err = scsi_add_host(host, hba->dev); + if (err) { + dev_err(hba->dev, "scsi_add_host failed\n"); + goto out_disable; + } } hba->tmf_tag_set = (struct blk_mq_tag_set) { diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 514687d2de54..a343bd4bc0eb 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -996,6 +996,7 @@ struct ufs_hba { u32 luns_avail; bool complete_put; bool ext_iid_sup; + bool scsi_host_added; bool mcq_sup; }; -- cgit v1.2.3 From 57b1c0ef89ac9d9e7475df7843aeb7672ebcd197 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:41 -0800 Subject: scsi: ufs: core: mcq: Add support to allocate multiple queues Multi-circular queue (MCQ) has been added in UFSHC v4.0 standard in addition to the Single Doorbell mode. The MCQ mode supports multiple submission and completion queues. Add support to allocate and configure the queues. Add module parameters support to configure the queues. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Bart Van Assche Reviewed-by: Manivannan Sadhasivam Signed-off-by: Martin K. Petersen --- drivers/ufs/core/Makefile | 2 +- drivers/ufs/core/ufs-mcq.c | 124 +++++++++++++++++++++++++++++++++++++++++ drivers/ufs/core/ufshcd-priv.h | 1 + drivers/ufs/core/ufshcd.c | 12 ++++ include/ufs/ufshcd.h | 4 ++ 5 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 drivers/ufs/core/ufs-mcq.c (limited to 'include') diff --git a/drivers/ufs/core/Makefile b/drivers/ufs/core/Makefile index 62f38c5bf857..4d02e0f2de10 100644 --- a/drivers/ufs/core/Makefile +++ b/drivers/ufs/core/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o -ufshcd-core-y += ufshcd.o ufs-sysfs.o +ufshcd-core-y += ufshcd.o ufs-sysfs.o ufs-mcq.o ufshcd-core-$(CONFIG_DEBUG_FS) += ufs-debugfs.o ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c new file mode 100644 index 000000000000..6ed362547806 --- /dev/null +++ b/drivers/ufs/core/ufs-mcq.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Qualcomm Innovation Center. All rights reserved. + * + * Authors: + * Asutosh Das + * Can Guo + */ + +#include +#include +#include +#include +#include "ufshcd-priv.h" + +#define MAX_QUEUE_SUP GENMASK(7, 0) +#define UFS_MCQ_MIN_RW_QUEUES 2 +#define UFS_MCQ_MIN_READ_QUEUES 0 +#define UFS_MCQ_NUM_DEV_CMD_QUEUES 1 +#define UFS_MCQ_MIN_POLL_QUEUES 0 + +static int rw_queue_count_set(const char *val, const struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_RW_QUEUES, + num_possible_cpus()); +} + +static const struct kernel_param_ops rw_queue_count_ops = { + .set = rw_queue_count_set, + .get = param_get_uint, +}; + +static unsigned int rw_queues; +module_param_cb(rw_queues, &rw_queue_count_ops, &rw_queues, 0644); +MODULE_PARM_DESC(rw_queues, + "Number of interrupt driven I/O queues used for rw. Default value is nr_cpus"); + +static int read_queue_count_set(const char *val, const struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_READ_QUEUES, + num_possible_cpus()); +} + +static const struct kernel_param_ops read_queue_count_ops = { + .set = read_queue_count_set, + .get = param_get_uint, +}; + +static unsigned int read_queues; +module_param_cb(read_queues, &read_queue_count_ops, &read_queues, 0644); +MODULE_PARM_DESC(read_queues, + "Number of interrupt driven read queues used for read. Default value is 0"); + +static int poll_queue_count_set(const char *val, const struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_POLL_QUEUES, + num_possible_cpus()); +} + +static const struct kernel_param_ops poll_queue_count_ops = { + .set = poll_queue_count_set, + .get = param_get_uint, +}; + +static unsigned int poll_queues = 1; +module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); +MODULE_PARM_DESC(poll_queues, + "Number of poll queues used for r/w. Default value is 1"); + +static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba) +{ + int i; + u32 hba_maxq, rem, tot_queues; + struct Scsi_Host *host = hba->host; + + hba_maxq = FIELD_GET(MAX_QUEUE_SUP, hba->mcq_capabilities); + + tot_queues = UFS_MCQ_NUM_DEV_CMD_QUEUES + read_queues + poll_queues + + rw_queues; + + if (hba_maxq < tot_queues) { + dev_err(hba->dev, "Total queues (%d) exceeds HC capacity (%d)\n", + tot_queues, hba_maxq); + return -EOPNOTSUPP; + } + + rem = hba_maxq - UFS_MCQ_NUM_DEV_CMD_QUEUES; + + if (rw_queues) { + hba->nr_queues[HCTX_TYPE_DEFAULT] = rw_queues; + rem -= hba->nr_queues[HCTX_TYPE_DEFAULT]; + } else { + rw_queues = num_possible_cpus(); + } + + if (poll_queues) { + hba->nr_queues[HCTX_TYPE_POLL] = poll_queues; + rem -= hba->nr_queues[HCTX_TYPE_POLL]; + } + + if (read_queues) { + hba->nr_queues[HCTX_TYPE_READ] = read_queues; + rem -= hba->nr_queues[HCTX_TYPE_READ]; + } + + if (!hba->nr_queues[HCTX_TYPE_DEFAULT]) + hba->nr_queues[HCTX_TYPE_DEFAULT] = min3(rem, rw_queues, + num_possible_cpus()); + + for (i = 0; i < HCTX_MAX_TYPES; i++) + host->nr_hw_queues += hba->nr_queues[i]; + + hba->nr_hw_queues = host->nr_hw_queues + UFS_MCQ_NUM_DEV_CMD_QUEUES; + return 0; +} + +int ufshcd_mcq_init(struct ufs_hba *hba) +{ + int ret; + + ret = ufshcd_mcq_config_nr_queues(hba); + + return ret; +} diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 8fff72e63e36..8d93ef675cea 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -61,6 +61,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, u8 index, bool *flag_res); void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit); +int ufshcd_mcq_init(struct ufs_hba *hba); #define SD_ASCII_STD true #define SD_RAW false diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 2cb05a6a0142..97120867a2a0 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8294,6 +8294,11 @@ out: return ret; } +static int ufshcd_alloc_mcq(struct ufs_hba *hba) +{ + return ufshcd_mcq_init(hba); +} + static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) { int ret; @@ -8333,6 +8338,13 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) if (ret) return ret; if (is_mcq_supported(hba) && !hba->scsi_host_added) { + ret = ufshcd_alloc_mcq(hba); + if (ret) { + /* Continue with SDB mode */ + use_mcq_mode = false; + dev_err(hba->dev, "MCQ mode is disabled, err=%d\n", + ret); + } ret = scsi_add_host(host, hba->dev); if (ret) { dev_err(hba->dev, "scsi_add_host failed\n"); diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index a343bd4bc0eb..91ca724c0294 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -840,6 +840,8 @@ struct ufs_hba_monitor { * ee_ctrl_mask * @luns_avail: number of regular and well known LUNs supported by the UFS * device + * @nr_hw_queues: number of hardware queues configured + * @nr_queues: number of Queues of different queue types * @complete_put: whether or not to call ufshcd_rpm_put() from inside * ufshcd_resume_complete() * @ext_iid_sup: is EXT_IID is supported by UFSHC @@ -994,6 +996,8 @@ struct ufs_hba { u32 debugfs_ee_rate_limit_ms; #endif u32 luns_avail; + unsigned int nr_hw_queues; + unsigned int nr_queues[HCTX_MAX_TYPES]; bool complete_put; bool ext_iid_sup; bool scsi_host_added; -- cgit v1.2.3 From c263b4ef737e622e2a908c58ca4bb68a89376387 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:42 -0800 Subject: scsi: ufs: core: mcq: Configure resource regions Define the MCQ resources and add support to ioremap the resource regions. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 3 ++ drivers/ufs/core/ufshcd-priv.h | 8 ++++ drivers/ufs/host/ufs-qcom.c | 101 +++++++++++++++++++++++++++++++++++++++++ include/ufs/ufshcd.h | 30 ++++++++++++ 4 files changed, 142 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 6ed362547806..65c00373af0e 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -119,6 +119,9 @@ int ufshcd_mcq_init(struct ufs_hba *hba) int ret; ret = ufshcd_mcq_config_nr_queues(hba); + if (ret) + return ret; + ret = ufshcd_vops_mcq_config_resource(hba); return ret; } diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 8d93ef675cea..e3bc4ce274e3 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -230,6 +230,14 @@ static inline void ufshcd_vops_reinit_notify(struct ufs_hba *hba) hba->vops->reinit_notify(hba); } +static inline int ufshcd_vops_mcq_config_resource(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->mcq_config_resource) + return hba->vops->mcq_config_resource(hba); + + return -EOPNOTSUPP; +} + extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[]; /** diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 5e7ba3b6a59d..2a1434ff0501 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -22,6 +22,12 @@ #include #include +#define MCQ_QCFGPTR_MASK GENMASK(7, 0) +#define MCQ_QCFGPTR_UNIT 0x200 +#define MCQ_SQATTR_OFFSET(c) \ + ((((c) >> 16) & MCQ_QCFGPTR_MASK) * MCQ_QCFGPTR_UNIT) +#define MCQ_QCFG_SIZE 0x40 + enum { TSTBUS_UAWM, TSTBUS_UARM, @@ -1396,6 +1402,100 @@ static void ufs_qcom_reinit_notify(struct ufs_hba *hba) phy_power_off(host->generic_phy); } +/* Resources */ +static const struct ufshcd_res_info ufs_res_info[RES_MAX] = { + {.name = "ufs_mem",}, + {.name = "mcq",}, + /* Submission Queue DAO */ + {.name = "mcq_sqd",}, + /* Submission Queue Interrupt Status */ + {.name = "mcq_sqis",}, + /* Completion Queue DAO */ + {.name = "mcq_cqd",}, + /* Completion Queue Interrupt Status */ + {.name = "mcq_cqis",}, + /* MCQ vendor specific */ + {.name = "mcq_vs",}, +}; + +static int ufs_qcom_mcq_config_resource(struct ufs_hba *hba) +{ + struct platform_device *pdev = to_platform_device(hba->dev); + struct ufshcd_res_info *res; + struct resource *res_mem, *res_mcq; + int i, ret = 0; + + memcpy(hba->res, ufs_res_info, sizeof(ufs_res_info)); + + for (i = 0; i < RES_MAX; i++) { + res = &hba->res[i]; + res->resource = platform_get_resource_byname(pdev, + IORESOURCE_MEM, + res->name); + if (!res->resource) { + dev_info(hba->dev, "Resource %s not provided\n", res->name); + if (i == RES_UFS) + return -ENOMEM; + continue; + } else if (i == RES_UFS) { + res_mem = res->resource; + res->base = hba->mmio_base; + continue; + } + + res->base = devm_ioremap_resource(hba->dev, res->resource); + if (IS_ERR(res->base)) { + dev_err(hba->dev, "Failed to map res %s, err=%d\n", + res->name, (int)PTR_ERR(res->base)); + res->base = NULL; + ret = PTR_ERR(res->base); + return ret; + } + } + + /* MCQ resource provided in DT */ + res = &hba->res[RES_MCQ]; + /* Bail if MCQ resource is provided */ + if (res->base) + goto out; + + /* Explicitly allocate MCQ resource from ufs_mem */ + res_mcq = devm_kzalloc(hba->dev, sizeof(*res_mcq), GFP_KERNEL); + if (!res_mcq) + return ret; + + res_mcq->start = res_mem->start + + MCQ_SQATTR_OFFSET(hba->mcq_capabilities); + res_mcq->end = res_mcq->start + hba->nr_hw_queues * MCQ_QCFG_SIZE - 1; + res_mcq->flags = res_mem->flags; + res_mcq->name = "mcq"; + + ret = insert_resource(&iomem_resource, res_mcq); + if (ret) { + dev_err(hba->dev, "Failed to insert MCQ resource, err=%d\n", + ret); + goto insert_res_err; + } + + res->base = devm_ioremap_resource(hba->dev, res_mcq); + if (IS_ERR(res->base)) { + dev_err(hba->dev, "MCQ registers mapping failed, err=%d\n", + (int)PTR_ERR(res->base)); + ret = PTR_ERR(res->base); + goto ioremap_err; + } + +out: + hba->mcq_base = res->base; + return 0; +ioremap_err: + res->base = NULL; + remove_resource(res_mcq); +insert_res_err: + devm_kfree(hba->dev, res_mcq); + return ret; +} + /* * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations * @@ -1420,6 +1520,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .config_scaling_param = ufs_qcom_config_scaling_param, .program_key = ufs_qcom_ice_program_key, .reinit_notify = ufs_qcom_reinit_notify, + .mcq_config_resource = ufs_qcom_mcq_config_resource, }; /** diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 91ca724c0294..81c7494cecad 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -300,6 +300,7 @@ struct ufs_pwr_mode_info { * @program_key: program or evict an inline encryption key * @event_notify: called to notify important events * @reinit_notify: called to notify reinit of UFSHCD during max gear switch + * @mcq_config_resource: called to configure MCQ platform resources */ struct ufs_hba_variant_ops { const char *name; @@ -339,6 +340,7 @@ struct ufs_hba_variant_ops { void (*event_notify)(struct ufs_hba *hba, enum ufs_event_type evt, void *data); void (*reinit_notify)(struct ufs_hba *); + int (*mcq_config_resource)(struct ufs_hba *hba); }; /* clock gating state */ @@ -733,6 +735,30 @@ struct ufs_hba_monitor { bool enabled; }; +/** + * struct ufshcd_res_info_t - MCQ related resource regions + * + * @name: resource name + * @resource: pointer to resource region + * @base: register base address + */ +struct ufshcd_res_info { + const char *name; + struct resource *resource; + void __iomem *base; +}; + +enum ufshcd_res { + RES_UFS, + RES_MCQ, + RES_MCQ_SQD, + RES_MCQ_SQIS, + RES_MCQ_CQD, + RES_MCQ_CQIS, + RES_MCQ_VS, + RES_MAX, +}; + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -846,6 +872,8 @@ struct ufs_hba_monitor { * ufshcd_resume_complete() * @ext_iid_sup: is EXT_IID is supported by UFSHC * @mcq_sup: is mcq supported by UFSHC + * @res: array of resource info of MCQ registers + * @mcq_base: Multi circular queue registers base address */ struct ufs_hba { void __iomem *mmio_base; @@ -1002,6 +1030,8 @@ struct ufs_hba { bool ext_iid_sup; bool scsi_host_added; bool mcq_sup; + struct ufshcd_res_info res[RES_MAX]; + void __iomem *mcq_base; }; #ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE -- cgit v1.2.3 From 7224c806876e46cfaf46b1c90da8d5c2e1f2108f Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:43 -0800 Subject: scsi: ufs: core: mcq: Calculate queue depth The UFS device defines the supported queuedepth by bqueuedepth which has a max value of 256. The HC defines MAC (Max Active Commands) that defines the max number of commands that in flight to the UFS device. Calculate and configure the nutrs based on both these values. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 35 +++++++++++++++++++++++++++++++++++ drivers/ufs/core/ufshcd-priv.h | 9 +++++++++ drivers/ufs/core/ufshcd.c | 17 ++++++++++++++++- drivers/ufs/host/ufs-qcom.c | 7 +++++++ drivers/ufs/host/ufs-qcom.h | 1 + include/ufs/ufs.h | 2 ++ include/ufs/ufshcd.h | 2 ++ include/ufs/ufshci.h | 1 + 8 files changed, 73 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 65c00373af0e..2f680ff5cafc 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -19,6 +19,9 @@ #define UFS_MCQ_NUM_DEV_CMD_QUEUES 1 #define UFS_MCQ_MIN_POLL_QUEUES 0 +#define MAX_DEV_CMD_ENTRIES 2 +#define MCQ_CFG_MAC_MASK GENMASK(16, 8) + static int rw_queue_count_set(const char *val, const struct kernel_param *kp) { return param_set_uint_minmax(val, kp, UFS_MCQ_MIN_RW_QUEUES, @@ -67,6 +70,38 @@ module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); MODULE_PARM_DESC(poll_queues, "Number of poll queues used for r/w. Default value is 1"); +/** + * ufshcd_mcq_decide_queue_depth - decide the queue depth + * @hba - per adapter instance + * + * Returns queue-depth on success, non-zero on error + * + * MAC - Max. Active Command of the Host Controller (HC) + * HC wouldn't send more than this commands to the device. + * It is mandatory to implement get_hba_mac() to enable MCQ mode. + * Calculates and adjusts the queue depth based on the depth + * supported by the HC and ufs device. + */ +int ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba) +{ + int mac; + + /* Mandatory to implement get_hba_mac() */ + mac = ufshcd_mcq_vops_get_hba_mac(hba); + if (mac < 0) { + dev_err(hba->dev, "Failed to get mac, err=%d\n", mac); + return mac; + } + + WARN_ON_ONCE(!hba->dev_info.bqueuedepth); + /* + * max. value of bqueuedepth = 256, mac is host dependent. + * It is mandatory for UFS device to define bQueueDepth if + * shared queuing architecture is enabled. + */ + return min_t(int, mac, hba->dev_info.bqueuedepth); +} + static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba) { int i; diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index e3bc4ce274e3..11076c3111c5 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -62,6 +62,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, u8 index, bool *flag_res); void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit); int ufshcd_mcq_init(struct ufs_hba *hba); +int ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba); #define SD_ASCII_STD true #define SD_RAW false @@ -238,6 +239,14 @@ static inline int ufshcd_vops_mcq_config_resource(struct ufs_hba *hba) return -EOPNOTSUPP; } +static inline int ufshcd_mcq_vops_get_hba_mac(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->get_hba_mac) + return hba->vops->get_hba_mac(hba); + + return -EOPNOTSUPP; +} + extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[]; /** diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 97120867a2a0..5c8570c8e100 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -7887,6 +7887,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba) /* getting Specification Version in big endian format */ dev_info->wspecversion = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 | desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1]; + dev_info->bqueuedepth = desc_buf[DEVICE_DESC_PARAM_Q_DPTH]; b_ufs_feature_sup = desc_buf[DEVICE_DESC_PARAM_UFS_FEAT]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; @@ -8296,7 +8297,21 @@ out: static int ufshcd_alloc_mcq(struct ufs_hba *hba) { - return ufshcd_mcq_init(hba); + int ret; + int old_nutrs = hba->nutrs; + + ret = ufshcd_mcq_decide_queue_depth(hba); + if (ret < 0) + return ret; + + hba->nutrs = ret; + ret = ufshcd_mcq_init(hba); + if (ret) { + hba->nutrs = old_nutrs; + return ret; + } + + return 0; } static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 2a1434ff0501..edd7225065df 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1496,6 +1496,12 @@ insert_res_err: return ret; } +static int ufs_qcom_get_hba_mac(struct ufs_hba *hba) +{ + /* Qualcomm HC supports up to 64 */ + return MAX_SUPP_MAC; +} + /* * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations * @@ -1521,6 +1527,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .program_key = ufs_qcom_ice_program_key, .reinit_notify = ufs_qcom_reinit_notify, .mcq_config_resource = ufs_qcom_mcq_config_resource, + .get_hba_mac = ufs_qcom_get_hba_mac, }; /** diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index f744a9e62002..164e18b6b1fb 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -16,6 +16,7 @@ #define HBRN8_POLL_TOUT_MS 100 #define DEFAULT_CLK_RATE_HZ 1000000 #define BUS_VECTOR_NAME_LEN 32 +#define MAX_SUPP_MAC 64 #define UFS_HW_VER_MAJOR_MASK GENMASK(31, 28) #define UFS_HW_VER_MINOR_MASK GENMASK(27, 16) diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index bea7b2086a4a..4e8d6240e589 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -617,6 +617,8 @@ struct ufs_dev_info { u8 *model; u16 wspecversion; u32 clk_gating_wait_us; + /* Stores the depth of queue in UFS device */ + u8 bqueuedepth; /* UFS HPB related flag */ bool hpb_enabled; diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 81c7494cecad..57854bb0395e 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -301,6 +301,7 @@ struct ufs_pwr_mode_info { * @event_notify: called to notify important events * @reinit_notify: called to notify reinit of UFSHCD during max gear switch * @mcq_config_resource: called to configure MCQ platform resources + * @get_hba_mac: called to get vendor specific mac value, mandatory for mcq mode */ struct ufs_hba_variant_ops { const char *name; @@ -341,6 +342,7 @@ struct ufs_hba_variant_ops { enum ufs_event_type evt, void *data); void (*reinit_notify)(struct ufs_hba *); int (*mcq_config_resource)(struct ufs_hba *hba); + int (*get_hba_mac)(struct ufs_hba *hba); }; /* clock gating state */ diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index f41bc7b03092..845a82a57f65 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -57,6 +57,7 @@ enum { REG_UFS_CCAP = 0x100, REG_UFS_CRYPTOCAP = 0x104, + REG_UFS_MCQ_CFG = 0x380, UFSHCI_CRYPTO_REG_SPACE_SIZE = 0x400, }; -- cgit v1.2.3 From 4682abfae2eb3a1c138130cfd6d71411d81aaa00 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:44 -0800 Subject: scsi: ufs: core: mcq: Allocate memory for MCQ mode To read the bqueuedepth, the device descriptor is fetched in Single Doorbell Mode. This allocated memory may not be enough for MCQ mode because the number of tags supported in MCQ mode may be larger than in SDB mode. Hence, release the memory allocated in SDB mode and allocate memory for MCQ mode operation. Define the UFS hardware queue and Completion Queue Entry. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 59 ++++++++++++++++++++++++++++++++++++++++-- drivers/ufs/core/ufshcd-priv.h | 1 + drivers/ufs/core/ufshcd.c | 48 +++++++++++++++++++++++++++++++--- include/ufs/ufshcd.h | 20 ++++++++++++++ include/ufs/ufshci.h | 22 ++++++++++++++++ 5 files changed, 145 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 2f680ff5cafc..c77bc54527b2 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -149,14 +149,69 @@ static int ufshcd_mcq_config_nr_queues(struct ufs_hba *hba) return 0; } +int ufshcd_mcq_memory_alloc(struct ufs_hba *hba) +{ + struct ufs_hw_queue *hwq; + size_t utrdl_size, cqe_size; + int i; + + for (i = 0; i < hba->nr_hw_queues; i++) { + hwq = &hba->uhq[i]; + + utrdl_size = sizeof(struct utp_transfer_req_desc) * + hwq->max_entries; + hwq->sqe_base_addr = dmam_alloc_coherent(hba->dev, utrdl_size, + &hwq->sqe_dma_addr, + GFP_KERNEL); + if (!hwq->sqe_dma_addr) { + dev_err(hba->dev, "SQE allocation failed\n"); + return -ENOMEM; + } + + cqe_size = sizeof(struct cq_entry) * hwq->max_entries; + hwq->cqe_base_addr = dmam_alloc_coherent(hba->dev, cqe_size, + &hwq->cqe_dma_addr, + GFP_KERNEL); + if (!hwq->cqe_dma_addr) { + dev_err(hba->dev, "CQE allocation failed\n"); + return -ENOMEM; + } + } + + return 0; +} + + int ufshcd_mcq_init(struct ufs_hba *hba) { - int ret; + struct ufs_hw_queue *hwq; + int ret, i; ret = ufshcd_mcq_config_nr_queues(hba); if (ret) return ret; ret = ufshcd_vops_mcq_config_resource(hba); - return ret; + if (ret) + return ret; + + hba->uhq = devm_kzalloc(hba->dev, + hba->nr_hw_queues * sizeof(struct ufs_hw_queue), + GFP_KERNEL); + if (!hba->uhq) { + dev_err(hba->dev, "ufs hw queue memory allocation failed\n"); + return -ENOMEM; + } + + for (i = 0; i < hba->nr_hw_queues; i++) { + hwq = &hba->uhq[i]; + hwq->max_entries = hba->nutrs; + } + + /* The very first HW queue serves device commands */ + hba->dev_cmd_queue = &hba->uhq[0]; + /* Give dev_cmd_queue the minimal number of entries */ + hba->dev_cmd_queue->max_entries = MAX_DEV_CMD_ENTRIES; + + return 0; } diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 11076c3111c5..667e601a480f 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -63,6 +63,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit); int ufshcd_mcq_init(struct ufs_hba *hba); int ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba); +int ufshcd_mcq_memory_alloc(struct ufs_hba *hba); #define SD_ASCII_STD true #define SD_RAW false diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 5c8570c8e100..9b4d7a9c81e6 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3719,6 +3719,14 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) goto out; } + /* + * Skip utmrdl allocation; it may have been + * allocated during first pass and not released during + * MCQ memory allocation. + * See ufshcd_release_sdb_queue() and ufshcd_config_mcq() + */ + if (hba->utmrdl_base_addr) + goto skip_utmrdl; /* * Allocate memory for UTP Task Management descriptors * UFSHCI requires 1024 byte alignment of UTMRD @@ -3735,6 +3743,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) goto out; } +skip_utmrdl: /* Allocate memory for local reference block */ hba->lrb = devm_kcalloc(hba->dev, hba->nutrs, sizeof(struct ufshcd_lrb), @@ -8295,6 +8304,22 @@ out: return ret; } +/* SDB - Single Doorbell */ +static void ufshcd_release_sdb_queue(struct ufs_hba *hba, int nutrs) +{ + size_t ucdl_size, utrdl_size; + + ucdl_size = sizeof(struct utp_transfer_cmd_desc) * nutrs; + dmam_free_coherent(hba->dev, ucdl_size, hba->ucdl_base_addr, + hba->ucdl_dma_addr); + + utrdl_size = sizeof(struct utp_transfer_req_desc) * nutrs; + dmam_free_coherent(hba->dev, utrdl_size, hba->utrdl_base_addr, + hba->utrdl_dma_addr); + + devm_kfree(hba->dev, hba->lrb); +} + static int ufshcd_alloc_mcq(struct ufs_hba *hba) { int ret; @@ -8306,12 +8331,29 @@ static int ufshcd_alloc_mcq(struct ufs_hba *hba) hba->nutrs = ret; ret = ufshcd_mcq_init(hba); - if (ret) { - hba->nutrs = old_nutrs; - return ret; + if (ret) + goto err; + + /* + * Previously allocated memory for nutrs may not be enough in MCQ mode. + * Number of supported tags in MCQ mode may be larger than SDB mode. + */ + if (hba->nutrs != old_nutrs) { + ufshcd_release_sdb_queue(hba, old_nutrs); + ret = ufshcd_memory_alloc(hba); + if (ret) + goto err; + ufshcd_host_memory_configure(hba); } + ret = ufshcd_mcq_memory_alloc(hba); + if (ret) + goto err; + return 0; +err: + hba->nutrs = old_nutrs; + return ret; } static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 57854bb0395e..311113c8e92d 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -876,6 +876,8 @@ enum ufshcd_res { * @mcq_sup: is mcq supported by UFSHC * @res: array of resource info of MCQ registers * @mcq_base: Multi circular queue registers base address + * @uhq: array of supported hardware queues + * @dev_cmd_queue: Queue for issuing device management commands */ struct ufs_hba { void __iomem *mmio_base; @@ -1034,6 +1036,24 @@ struct ufs_hba { bool mcq_sup; struct ufshcd_res_info res[RES_MAX]; void __iomem *mcq_base; + struct ufs_hw_queue *uhq; + struct ufs_hw_queue *dev_cmd_queue; +}; + +/** + * struct ufs_hw_queue - per hardware queue structure + * @sqe_base_addr: submission queue entry base address + * @sqe_dma_addr: submission queue dma address + * @cqe_base_addr: completion queue base address + * @cqe_dma_addr: completion queue dma address + * @max_entries: max number of slots in this hardware queue + */ +struct ufs_hw_queue { + void *sqe_base_addr; + dma_addr_t sqe_dma_addr; + struct cq_entry *cqe_base_addr; + dma_addr_t cqe_dma_addr; + u32 max_entries; }; #ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index 845a82a57f65..0d621e9e3146 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -492,6 +492,28 @@ struct utp_transfer_req_desc { __le16 prd_table_offset; }; +/* MCQ Completion Queue Entry */ +struct cq_entry { + /* DW 0-1 */ + __le64 command_desc_base_addr; + + /* DW 2 */ + __le16 response_upiu_length; + __le16 response_upiu_offset; + + /* DW 3 */ + __le16 prd_table_length; + __le16 prd_table_offset; + + /* DW 4 */ + __le32 status; + + /* DW 5-7 */ + __le32 reserved[3]; +}; + +static_assert(sizeof(struct cq_entry) == 32); + /* * UTMRD structure. */ -- cgit v1.2.3 From 2468da61ea095162067ed408824298ba9c3661c8 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:45 -0800 Subject: scsi: ufs: core: mcq: Configure operation and runtime interface Runtime and operation registers are defined per Submission and Completion queue. The location of these registers is not defined in the spec; meaning the offsets and stride may vary for different HC vendors. Establish the stride, base address, and doorbell address offsets from vendor host driver and program it. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 102 +++++++++++++++++++++++++++++++++++++++++ drivers/ufs/core/ufshcd-priv.h | 11 +++++ drivers/ufs/core/ufshcd.c | 27 +++++++++++ drivers/ufs/host/ufs-qcom.c | 24 ++++++++++ include/ufs/ufshcd.h | 52 +++++++++++++++++++++ include/ufs/ufshci.h | 31 +++++++++++++ 6 files changed, 247 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index c77bc54527b2..496e2b638c44 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -18,9 +18,13 @@ #define UFS_MCQ_MIN_READ_QUEUES 0 #define UFS_MCQ_NUM_DEV_CMD_QUEUES 1 #define UFS_MCQ_MIN_POLL_QUEUES 0 +#define QUEUE_EN_OFFSET 31 +#define QUEUE_ID_OFFSET 16 #define MAX_DEV_CMD_ENTRIES 2 #define MCQ_CFG_MAC_MASK GENMASK(16, 8) +#define MCQ_QCFG_SIZE 0x40 +#define MCQ_ENTRY_SIZE_IN_DWORD 8 static int rw_queue_count_set(const char *val, const struct kernel_param *kp) { @@ -70,6 +74,24 @@ module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644); MODULE_PARM_DESC(poll_queues, "Number of poll queues used for r/w. Default value is 1"); +/** + * ufshcd_mcq_config_mac - Set the #Max Activ Cmds. + * @hba - per adapter instance + * @max_active_cmds - maximum # of active commands to the device at any time. + * + * The controller won't send more than the max_active_cmds to the device at + * any time. + */ +void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds) +{ + u32 val; + + val = ufshcd_readl(hba, REG_UFS_MCQ_CFG); + val &= ~MCQ_CFG_MAC_MASK; + val |= FIELD_PREP(MCQ_CFG_MAC_MASK, max_active_cmds); + ufshcd_writel(hba, val, REG_UFS_MCQ_CFG); +} + /** * ufshcd_mcq_decide_queue_depth - decide the queue depth * @hba - per adapter instance @@ -182,6 +204,80 @@ int ufshcd_mcq_memory_alloc(struct ufs_hba *hba) } +/* Operation and runtime registers configuration */ +#define MCQ_CFG_n(r, i) ((r) + MCQ_QCFG_SIZE * (i)) +#define MCQ_OPR_OFFSET_n(p, i) \ + (hba->mcq_opr[(p)].offset + hba->mcq_opr[(p)].stride * (i)) + +static void __iomem *mcq_opr_base(struct ufs_hba *hba, + enum ufshcd_mcq_opr n, int i) +{ + struct ufshcd_mcq_opr_info_t *opr = &hba->mcq_opr[n]; + + return opr->base + opr->stride * i; +} + +void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) +{ + struct ufs_hw_queue *hwq; + u16 qsize; + int i; + + for (i = 0; i < hba->nr_hw_queues; i++) { + hwq = &hba->uhq[i]; + hwq->id = i; + qsize = hwq->max_entries * MCQ_ENTRY_SIZE_IN_DWORD - 1; + + /* Submission Queue Lower Base Address */ + ufsmcq_writelx(hba, lower_32_bits(hwq->sqe_dma_addr), + MCQ_CFG_n(REG_SQLBA, i)); + /* Submission Queue Upper Base Address */ + ufsmcq_writelx(hba, upper_32_bits(hwq->sqe_dma_addr), + MCQ_CFG_n(REG_SQUBA, i)); + /* Submission Queue Doorbell Address Offset */ + ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_SQD, i), + MCQ_CFG_n(REG_SQDAO, i)); + /* Submission Queue Interrupt Status Address Offset */ + ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_SQIS, i), + MCQ_CFG_n(REG_SQISAO, i)); + + /* Completion Queue Lower Base Address */ + ufsmcq_writelx(hba, lower_32_bits(hwq->cqe_dma_addr), + MCQ_CFG_n(REG_CQLBA, i)); + /* Completion Queue Upper Base Address */ + ufsmcq_writelx(hba, upper_32_bits(hwq->cqe_dma_addr), + MCQ_CFG_n(REG_CQUBA, i)); + /* Completion Queue Doorbell Address Offset */ + ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_CQD, i), + MCQ_CFG_n(REG_CQDAO, i)); + /* Completion Queue Interrupt Status Address Offset */ + ufsmcq_writelx(hba, MCQ_OPR_OFFSET_n(OPR_CQIS, i), + MCQ_CFG_n(REG_CQISAO, i)); + + /* Save the base addresses for quicker access */ + hwq->mcq_sq_head = mcq_opr_base(hba, OPR_SQD, i) + REG_SQHP; + hwq->mcq_sq_tail = mcq_opr_base(hba, OPR_SQD, i) + REG_SQTP; + hwq->mcq_cq_head = mcq_opr_base(hba, OPR_CQD, i) + REG_CQHP; + hwq->mcq_cq_tail = mcq_opr_base(hba, OPR_CQD, i) + REG_CQTP; + + /* Enable Tail Entry Push Status interrupt only for non-poll queues */ + if (i < hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL]) + writel(1, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIE); + + /* Completion Queue Enable|Size to Completion Queue Attribute */ + ufsmcq_writel(hba, (1 << QUEUE_EN_OFFSET) | qsize, + MCQ_CFG_n(REG_CQATTR, i)); + + /* + * Submission Qeueue Enable|Size|Completion Queue ID to + * Submission Queue Attribute + */ + ufsmcq_writel(hba, (1 << QUEUE_EN_OFFSET) | qsize | + (i << QUEUE_ID_OFFSET), + MCQ_CFG_n(REG_SQATTR, i)); + } +} + int ufshcd_mcq_init(struct ufs_hba *hba) { struct ufs_hw_queue *hwq; @@ -195,6 +291,12 @@ int ufshcd_mcq_init(struct ufs_hba *hba) if (ret) return ret; + ret = ufshcd_mcq_vops_op_runtime_config(hba); + if (ret) { + dev_err(hba->dev, "Operation runtime config failed, ret=%d\n", + ret); + return ret; + } hba->uhq = devm_kzalloc(hba->dev, hba->nr_hw_queues * sizeof(struct ufs_hw_queue), GFP_KERNEL); diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 667e601a480f..4cd9b7b63868 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -64,6 +64,9 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit); int ufshcd_mcq_init(struct ufs_hba *hba); int ufshcd_mcq_decide_queue_depth(struct ufs_hba *hba); int ufshcd_mcq_memory_alloc(struct ufs_hba *hba); +void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba); +void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds); +void ufshcd_mcq_select_mcq_mode(struct ufs_hba *hba); #define SD_ASCII_STD true #define SD_RAW false @@ -248,6 +251,14 @@ static inline int ufshcd_mcq_vops_get_hba_mac(struct ufs_hba *hba) return -EOPNOTSUPP; } +static inline int ufshcd_mcq_vops_op_runtime_config(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->op_runtime_config) + return hba->vops->op_runtime_config(hba); + + return -EOPNOTSUPP; +} + extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[]; /** diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 9b4d7a9c81e6..9d582786dabe 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -43,6 +43,12 @@ #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ UTP_TASK_REQ_COMPL |\ UFSHCD_ERROR_MASK) + +#define UFSHCD_ENABLE_MCQ_INTRS (UTP_TASK_REQ_COMPL |\ + UFSHCD_ERROR_MASK |\ + MCQ_CQ_EVENT_STATUS) + + /* UIC command timeout, unit: ms */ #define UIC_CMD_TIMEOUT 500 @@ -8356,6 +8362,20 @@ err: return ret; } +static void ufshcd_config_mcq(struct ufs_hba *hba) +{ + ufshcd_enable_intr(hba, UFSHCD_ENABLE_MCQ_INTRS); + ufshcd_mcq_make_queues_operational(hba); + ufshcd_mcq_config_mac(hba, hba->nutrs); + + hba->host->can_queue = hba->nutrs - UFSHCD_NUM_RESERVED; + hba->reserved_slot = hba->nutrs - UFSHCD_NUM_RESERVED; + dev_info(hba->dev, "MCQ configured, nr_queues=%d, io_queues=%d, read_queue=%d, poll_queues=%d, queue_depth=%d\n", + hba->nr_hw_queues, hba->nr_queues[HCTX_TYPE_DEFAULT], + hba->nr_queues[HCTX_TYPE_READ], hba->nr_queues[HCTX_TYPE_POLL], + hba->nutrs); +} + static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) { int ret; @@ -8376,6 +8396,10 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) /* UniPro link is active now */ ufshcd_set_link_active(hba); + /* Reconfigure MCQ upon reset */ + if (is_mcq_enabled(hba) && !init_dev_params) + ufshcd_config_mcq(hba); + /* Verify device initialization by sending NOP OUT UPIU */ ret = ufshcd_verify_dev_init(hba); if (ret) @@ -8409,6 +8433,9 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) } hba->scsi_host_added = true; } + /* MCQ may be disabled if ufshcd_alloc_mcq() fails */ + if (is_mcq_supported(hba) && use_mcq_mode) + ufshcd_config_mcq(hba); } ufshcd_tune_unipro_params(hba); diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index edd7225065df..e828b876e793 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1496,6 +1496,29 @@ insert_res_err: return ret; } +static int ufs_qcom_op_runtime_config(struct ufs_hba *hba) +{ + struct ufshcd_res_info *mem_res, *sqdao_res; + struct ufshcd_mcq_opr_info_t *opr; + int i; + + mem_res = &hba->res[RES_UFS]; + sqdao_res = &hba->res[RES_MCQ_SQD]; + + if (!mem_res->base || !sqdao_res->base) + return -EINVAL; + + for (i = 0; i < OPR_MAX; i++) { + opr = &hba->mcq_opr[i]; + opr->offset = sqdao_res->resource->start - + mem_res->resource->start + 0x40 * i; + opr->stride = 0x100; + opr->base = sqdao_res->base + 0x40 * i; + } + + return 0; +} + static int ufs_qcom_get_hba_mac(struct ufs_hba *hba) { /* Qualcomm HC supports up to 64 */ @@ -1528,6 +1551,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .reinit_notify = ufs_qcom_reinit_notify, .mcq_config_resource = ufs_qcom_mcq_config_resource, .get_hba_mac = ufs_qcom_get_hba_mac, + .op_runtime_config = ufs_qcom_op_runtime_config, }; /** diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 311113c8e92d..13a2f17daa8c 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -302,6 +302,7 @@ struct ufs_pwr_mode_info { * @reinit_notify: called to notify reinit of UFSHCD during max gear switch * @mcq_config_resource: called to configure MCQ platform resources * @get_hba_mac: called to get vendor specific mac value, mandatory for mcq mode + * @op_runtime_config: called to config Operation and runtime regs Pointers */ struct ufs_hba_variant_ops { const char *name; @@ -343,6 +344,7 @@ struct ufs_hba_variant_ops { void (*reinit_notify)(struct ufs_hba *); int (*mcq_config_resource)(struct ufs_hba *hba); int (*get_hba_mac)(struct ufs_hba *hba); + int (*op_runtime_config)(struct ufs_hba *hba); }; /* clock gating state */ @@ -761,6 +763,27 @@ enum ufshcd_res { RES_MAX, }; +/** + * struct ufshcd_mcq_opr_info_t - Operation and Runtime registers + * + * @offset: Doorbell Address Offset + * @stride: Steps proportional to queue [0...31] + * @base: base address + */ +struct ufshcd_mcq_opr_info_t { + unsigned long offset; + unsigned long stride; + void __iomem *base; +}; + +enum ufshcd_mcq_opr { + OPR_SQD, + OPR_SQIS, + OPR_CQD, + OPR_CQIS, + OPR_MAX, +}; + /** * struct ufs_hba - per adapter private structure * @mmio_base: UFSHCI base register address @@ -874,6 +897,7 @@ enum ufshcd_res { * ufshcd_resume_complete() * @ext_iid_sup: is EXT_IID is supported by UFSHC * @mcq_sup: is mcq supported by UFSHC + * @mcq_enabled: is mcq ready to accept requests * @res: array of resource info of MCQ registers * @mcq_base: Multi circular queue registers base address * @uhq: array of supported hardware queues @@ -1034,28 +1058,46 @@ struct ufs_hba { bool ext_iid_sup; bool scsi_host_added; bool mcq_sup; + bool mcq_enabled; struct ufshcd_res_info res[RES_MAX]; void __iomem *mcq_base; struct ufs_hw_queue *uhq; struct ufs_hw_queue *dev_cmd_queue; + struct ufshcd_mcq_opr_info_t mcq_opr[OPR_MAX]; }; /** * struct ufs_hw_queue - per hardware queue structure + * @mcq_sq_head: base address of submission queue head pointer + * @mcq_sq_tail: base address of submission queue tail pointer + * @mcq_cq_head: base address of completion queue head pointer + * @mcq_cq_tail: base address of completion queue tail pointer * @sqe_base_addr: submission queue entry base address * @sqe_dma_addr: submission queue dma address * @cqe_base_addr: completion queue base address * @cqe_dma_addr: completion queue dma address * @max_entries: max number of slots in this hardware queue + * @id: hardware queue ID */ struct ufs_hw_queue { + void __iomem *mcq_sq_head; + void __iomem *mcq_sq_tail; + void __iomem *mcq_cq_head; + void __iomem *mcq_cq_tail; + void *sqe_base_addr; dma_addr_t sqe_dma_addr; struct cq_entry *cqe_base_addr; dma_addr_t cqe_dma_addr; u32 max_entries; + u32 id; }; +static inline bool is_mcq_enabled(struct ufs_hba *hba) +{ + return hba->mcq_enabled; +} + #ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE static inline size_t ufshcd_sg_entry_size(const struct ufs_hba *hba) { @@ -1137,6 +1179,16 @@ static inline bool ufshcd_enable_wb_if_scaling_up(struct ufs_hba *hba) return hba->caps & UFSHCD_CAP_WB_WITH_CLK_SCALING; } +#define ufsmcq_writel(hba, val, reg) \ + writel((val), (hba)->mcq_base + (reg)) +#define ufsmcq_readl(hba, reg) \ + readl((hba)->mcq_base + (reg)) + +#define ufsmcq_writelx(hba, val, reg) \ + writel_relaxed((val), (hba)->mcq_base + (reg)) +#define ufsmcq_readlx(hba, reg) \ + readl_relaxed((hba)->mcq_base + (reg)) + #define ufshcd_writel(hba, val, reg) \ writel((val), (hba)->mmio_base + (reg)) #define ufshcd_readl(hba, reg) \ diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index 0d621e9e3146..b6ae5718387c 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -57,6 +57,7 @@ enum { REG_UFS_CCAP = 0x100, REG_UFS_CRYPTOCAP = 0x104, + REG_UFS_MEM_CFG = 0x300, REG_UFS_MCQ_CFG = 0x380, UFSHCI_CRYPTO_REG_SPACE_SIZE = 0x400, }; @@ -79,6 +80,35 @@ enum { MASK_EXT_IID_SUPPORT = 0x00000400, }; +enum { + REG_SQATTR = 0x0, + REG_SQLBA = 0x4, + REG_SQUBA = 0x8, + REG_SQDAO = 0xC, + REG_SQISAO = 0x10, + + REG_CQATTR = 0x20, + REG_CQLBA = 0x24, + REG_CQUBA = 0x28, + REG_CQDAO = 0x2C, + REG_CQISAO = 0x30, +}; + +enum { + REG_SQHP = 0x0, + REG_SQTP = 0x4, +}; + +enum { + REG_CQHP = 0x0, + REG_CQTP = 0x4, +}; + +enum { + REG_CQIS = 0x0, + REG_CQIE = 0x4, +}; + #define UFS_MASK(mask, offset) ((mask) << (offset)) /* UFS Version 08h */ @@ -135,6 +165,7 @@ static inline u32 ufshci_version(u32 major, u32 minor) #define CONTROLLER_FATAL_ERROR 0x10000 #define SYSTEM_BUS_FATAL_ERROR 0x20000 #define CRYPTO_ENGINE_FATAL_ERROR 0x40000 +#define MCQ_CQ_EVENT_STATUS 0x100000 #define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\ UIC_HIBERNATE_EXIT) -- cgit v1.2.3 From 22a2d563de1425ea294e9abfa104dbf20c83a28a Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:47 -0800 Subject: scsi: ufs: core: Prepare ufshcd_send_command() for MCQ Add support to send commands using multiple submission queues in MCQ mode. Modify the functions that use ufshcd_send_command(). Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Bart Van Assche Reviewed-by: Manivannan Sadhasivam Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 1 + drivers/ufs/core/ufshcd-priv.h | 10 ++++++++++ drivers/ufs/core/ufshcd.c | 38 +++++++++++++++++++++++++++----------- include/ufs/ufshcd.h | 5 +++++ 4 files changed, 43 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 8bf222fb4b06..68158259b223 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -309,6 +309,7 @@ int ufshcd_mcq_init(struct ufs_hba *hba) for (i = 0; i < hba->nr_hw_queues; i++) { hwq = &hba->uhq[i]; hwq->max_entries = hba->nutrs; + spin_lock_init(&hwq->sq_lock); } /* The very first HW queue serves device commands */ diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 4cd9b7b63868..013111fca0f7 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -335,4 +335,14 @@ static inline bool ufs_is_valid_unit_desc_lun(struct ufs_dev_info *dev_info, u8 return lun == UFS_UPIU_RPMB_WLUN || (lun < dev_info->max_lu_supported); } +static inline void ufshcd_inc_sq_tail(struct ufs_hw_queue *q) +{ + u32 mask = q->max_entries - 1; + u32 val; + + q->sq_tail_slot = (q->sq_tail_slot + 1) & mask; + val = q->sq_tail_slot * sizeof(struct utp_transfer_req_desc); + writel(val, q->mcq_sq_tail); +} + #endif /* _UFSHCD_PRIV_H_ */ diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index a492c88ccecb..655903b1d8f7 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2185,9 +2185,11 @@ static void ufshcd_update_monitor(struct ufs_hba *hba, const struct ufshcd_lrb * * ufshcd_send_command - Send SCSI or device management commands * @hba: per adapter instance * @task_tag: Task tag of the command + * @hwq: pointer to hardware queue instance */ static inline -void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) +void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag, + struct ufs_hw_queue *hwq) { struct ufshcd_lrb *lrbp = &hba->lrb[task_tag]; unsigned long flags; @@ -2201,12 +2203,24 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) if (unlikely(ufshcd_should_inform_monitor(hba, lrbp))) ufshcd_start_monitor(hba, lrbp); - spin_lock_irqsave(&hba->outstanding_lock, flags); - if (hba->vops && hba->vops->setup_xfer_req) - hba->vops->setup_xfer_req(hba, task_tag, !!lrbp->cmd); - __set_bit(task_tag, &hba->outstanding_reqs); - ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); - spin_unlock_irqrestore(&hba->outstanding_lock, flags); + if (is_mcq_enabled(hba)) { + int utrd_size = sizeof(struct utp_transfer_req_desc); + + spin_lock(&hwq->sq_lock); + memcpy(hwq->sqe_base_addr + (hwq->sq_tail_slot * utrd_size), + lrbp->utr_descriptor_ptr, utrd_size); + ufshcd_inc_sq_tail(hwq); + spin_unlock(&hwq->sq_lock); + } else { + spin_lock_irqsave(&hba->outstanding_lock, flags); + if (hba->vops && hba->vops->setup_xfer_req) + hba->vops->setup_xfer_req(hba, lrbp->task_tag, + !!lrbp->cmd); + __set_bit(lrbp->task_tag, &hba->outstanding_reqs); + ufshcd_writel(hba, 1 << lrbp->task_tag, + REG_UTP_TRANSFER_REQ_DOOR_BELL); + spin_unlock_irqrestore(&hba->outstanding_lock, flags); + } } /** @@ -2836,6 +2850,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) int tag = scsi_cmd_to_rq(cmd)->tag; struct ufshcd_lrb *lrbp; int err = 0; + struct ufs_hw_queue *hwq = NULL; WARN_ONCE(tag < 0 || tag >= hba->nutrs, "Invalid tag %d\n", tag); @@ -2920,7 +2935,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) goto out; } - ufshcd_send_command(hba, tag); + ufshcd_send_command(hba, tag, hwq); out: rcu_read_unlock(); @@ -3121,10 +3136,11 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, goto out; hba->dev_cmd.complete = &wait; + hba->dev_cmd.cqe = NULL; ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr); - ufshcd_send_command(hba, tag); + ufshcd_send_command(hba, tag, hba->dev_cmd_queue); err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout); ufshcd_add_query_upiu_trace(hba, err ? UFS_QUERY_ERR : UFS_QUERY_COMP, (struct utp_upiu_req *)lrbp->ucd_rsp_ptr); @@ -6938,7 +6954,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr); - ufshcd_send_command(hba, tag); + ufshcd_send_command(hba, tag, hba->dev_cmd_queue); /* * ignore the returning value here - ufshcd_check_query_response is * bound to fail since dev_cmd.query and dev_cmd.type were left empty. @@ -7104,7 +7120,7 @@ int ufshcd_advanced_rpmb_req_handler(struct ufs_hba *hba, struct utp_upiu_req *r hba->dev_cmd.complete = &wait; - ufshcd_send_command(hba, tag); + ufshcd_send_command(hba, tag, hba->dev_cmd_queue); err = ufshcd_wait_for_dev_cmd(hba, lrbp, ADVANCED_RPMB_REQ_TIMEOUT); diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 13a2f17daa8c..019b8cf23b29 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -224,6 +224,7 @@ struct ufs_dev_cmd { struct mutex lock; struct completion *complete; struct ufs_query query; + struct cq_entry *cqe; }; /** @@ -1078,6 +1079,8 @@ struct ufs_hba { * @cqe_dma_addr: completion queue dma address * @max_entries: max number of slots in this hardware queue * @id: hardware queue ID + * @sq_tp_slot: current slot to which SQ tail pointer is pointing + * @sq_lock: serialize submission queue access */ struct ufs_hw_queue { void __iomem *mcq_sq_head; @@ -1091,6 +1094,8 @@ struct ufs_hw_queue { dma_addr_t cqe_dma_addr; u32 max_entries; u32 id; + u32 sq_tail_slot; + spinlock_t sq_lock; }; static inline bool is_mcq_enabled(struct ufs_hba *hba) -- cgit v1.2.3 From f87b2c41822aad09aadac31b8ba22c0c0e639eee Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:50 -0800 Subject: scsi: ufs: mcq: Add completion support of a CQE Add support for completing requests from Completion Queue. Some host controllers support vendor specific registers that provide a bitmap of all CQs which have at least one completed CQE. Add this support. The MCQ specification doesn't provide the Task Tag or its equivalent in the Completion Queue Entry. So use an indirect method to find the Task Tag from the Completion Queue Entry. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Bart Van Assche Reviewed-by: Manivannan Sadhasivam Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 61 ++++++++++++++++++++++++++++++++++++++++++ drivers/ufs/core/ufshcd-priv.h | 43 +++++++++++++++++++++++++++++ drivers/ufs/core/ufshcd.c | 37 +++++++++++++++++++++++++ drivers/ufs/host/ufs-qcom.c | 14 ++++++++++ drivers/ufs/host/ufs-qcom.h | 4 +++ include/ufs/ufshcd.h | 7 +++++ include/ufs/ufshci.h | 3 +++ 7 files changed, 169 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index be84bcef2044..cd10d59c77e0 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -25,6 +25,7 @@ #define MCQ_CFG_MAC_MASK GENMASK(16, 8) #define MCQ_QCFG_SIZE 0x40 #define MCQ_ENTRY_SIZE_IN_DWORD 8 +#define CQE_UCD_BA GENMASK_ULL(63, 7) static int rw_queue_count_set(const char *val, const struct kernel_param *kp) { @@ -236,6 +237,63 @@ static void __iomem *mcq_opr_base(struct ufs_hba *hba, return opr->base + opr->stride * i; } +u32 ufshcd_mcq_read_cqis(struct ufs_hba *hba, int i) +{ + return readl(mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS); +} + +void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i) +{ + writel(val, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS); +} + +/* + * Current MCQ specification doesn't provide a Task Tag or its equivalent in + * the Completion Queue Entry. Find the Task Tag using an indirect method. + */ +static int ufshcd_mcq_get_tag(struct ufs_hba *hba, + struct ufs_hw_queue *hwq, + struct cq_entry *cqe) +{ + u64 addr; + + /* sizeof(struct utp_transfer_cmd_desc) must be a multiple of 128 */ + BUILD_BUG_ON(sizeof(struct utp_transfer_cmd_desc) & GENMASK(6, 0)); + + /* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */ + addr = (le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA) - + hba->ucdl_dma_addr; + + return div_u64(addr, sizeof(struct utp_transfer_cmd_desc)); +} + +static void ufshcd_mcq_process_cqe(struct ufs_hba *hba, + struct ufs_hw_queue *hwq) +{ + struct cq_entry *cqe = ufshcd_mcq_cur_cqe(hwq); + int tag = ufshcd_mcq_get_tag(hba, hwq, cqe); + + ufshcd_compl_one_cqe(hba, tag, cqe); +} + +unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba, + struct ufs_hw_queue *hwq) +{ + unsigned long completed_reqs = 0; + + ufshcd_mcq_update_cq_tail_slot(hwq); + while (!ufshcd_mcq_is_cq_empty(hwq)) { + ufshcd_mcq_process_cqe(hba, hwq); + ufshcd_mcq_inc_cq_head_slot(hwq); + completed_reqs++; + } + + if (completed_reqs) + ufshcd_mcq_update_cq_head(hwq); + + return completed_reqs; +} + void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) { struct ufs_hw_queue *hwq; @@ -279,6 +337,9 @@ void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) hwq->mcq_cq_head = mcq_opr_base(hba, OPR_CQD, i) + REG_CQHP; hwq->mcq_cq_tail = mcq_opr_base(hba, OPR_CQD, i) + REG_CQTP; + /* Reinitializing is needed upon HC reset */ + hwq->sq_tail_slot = hwq->cq_tail_slot = hwq->cq_head_slot = 0; + /* Enable Tail Entry Push Status interrupt only for non-poll queues */ if (i < hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL]) writel(1, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIE); diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index e87ce19ac896..583fb862013e 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -69,6 +69,10 @@ int ufshcd_mcq_memory_alloc(struct ufs_hba *hba); void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba); void ufshcd_mcq_config_mac(struct ufs_hba *hba, u32 max_active_cmds); void ufshcd_mcq_select_mcq_mode(struct ufs_hba *hba); +u32 ufshcd_mcq_read_cqis(struct ufs_hba *hba, int i); +void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i); +unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba, + struct ufs_hw_queue *hwq); struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba, struct request *req); @@ -264,6 +268,15 @@ static inline int ufshcd_mcq_vops_op_runtime_config(struct ufs_hba *hba) return -EOPNOTSUPP; } +static inline int ufshcd_vops_get_outstanding_cqs(struct ufs_hba *hba, + unsigned long *ocqs) +{ + if (hba->vops && hba->vops->get_outstanding_cqs) + return hba->vops->get_outstanding_cqs(hba, ocqs); + + return -EOPNOTSUPP; +} + extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[]; /** @@ -350,4 +363,34 @@ static inline void ufshcd_inc_sq_tail(struct ufs_hw_queue *q) writel(val, q->mcq_sq_tail); } +static inline void ufshcd_mcq_update_cq_tail_slot(struct ufs_hw_queue *q) +{ + u32 val = readl(q->mcq_cq_tail); + + q->cq_tail_slot = val / sizeof(struct cq_entry); +} + +static inline bool ufshcd_mcq_is_cq_empty(struct ufs_hw_queue *q) +{ + return q->cq_head_slot == q->cq_tail_slot; +} + +static inline void ufshcd_mcq_inc_cq_head_slot(struct ufs_hw_queue *q) +{ + q->cq_head_slot++; + if (q->cq_head_slot == q->max_entries) + q->cq_head_slot = 0; +} + +static inline void ufshcd_mcq_update_cq_head(struct ufs_hw_queue *q) +{ + writel(q->cq_head_slot * sizeof(struct cq_entry), q->mcq_cq_head); +} + +static inline struct cq_entry *ufshcd_mcq_cur_cqe(struct ufs_hw_queue *q) +{ + struct cq_entry *cqe = q->cqe_base_addr; + + return cqe + q->cq_head_slot; +} #endif /* _UFSHCD_PRIV_H_ */ diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 34947379320f..3afa07683ecf 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6683,6 +6683,40 @@ static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba) return ret; } +/** + * ufshcd_handle_mcq_cq_events - handle MCQ completion queue events + * @hba: per adapter instance + * + * Returns IRQ_HANDLED if interrupt is handled + */ +static irqreturn_t ufshcd_handle_mcq_cq_events(struct ufs_hba *hba) +{ + struct ufs_hw_queue *hwq; + unsigned long outstanding_cqs; + unsigned int nr_queues; + int i, ret; + u32 events; + + ret = ufshcd_vops_get_outstanding_cqs(hba, &outstanding_cqs); + if (ret) + outstanding_cqs = (1U << hba->nr_hw_queues) - 1; + + /* Exclude the poll queues */ + nr_queues = hba->nr_hw_queues - hba->nr_queues[HCTX_TYPE_POLL]; + for_each_set_bit(i, &outstanding_cqs, nr_queues) { + hwq = &hba->uhq[i]; + + events = ufshcd_mcq_read_cqis(hba, i); + if (events) + ufshcd_mcq_write_cqis(hba, events, i); + + if (events & UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS) + ufshcd_mcq_poll_cqe_nolock(hba, hwq); + } + + return IRQ_HANDLED; +} + /** * ufshcd_sl_intr - Interrupt service routine * @hba: per adapter instance @@ -6708,6 +6742,9 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) if (intr_status & UTP_TRANSFER_REQ_COMPL) retval |= ufshcd_transfer_req_compl(hba); + if (intr_status & MCQ_CQ_EVENT_STATUS) + retval |= ufshcd_handle_mcq_cq_events(hba); + return retval; } diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index e828b876e793..19b181447685 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1525,6 +1525,19 @@ static int ufs_qcom_get_hba_mac(struct ufs_hba *hba) return MAX_SUPP_MAC; } +static int ufs_qcom_get_outstanding_cqs(struct ufs_hba *hba, + unsigned long *ocqs) +{ + struct ufshcd_res_info *mcq_vs_res = &hba->res[RES_MCQ_VS]; + + if (!mcq_vs_res->base) + return -EINVAL; + + *ocqs = readl(mcq_vs_res->base + UFS_MEM_CQIS_VS); + + return 0; +} + /* * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations * @@ -1552,6 +1565,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .mcq_config_resource = ufs_qcom_mcq_config_resource, .get_hba_mac = ufs_qcom_get_hba_mac, .op_runtime_config = ufs_qcom_op_runtime_config, + .get_outstanding_cqs = ufs_qcom_get_outstanding_cqs, }; /** diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 164e18b6b1fb..8050e214f722 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -71,6 +71,10 @@ enum { UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, }; +enum { + UFS_MEM_CQIS_VS = 0x8, +}; + #define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x) #define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x) diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 019b8cf23b29..0dcb104a6713 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -304,6 +304,7 @@ struct ufs_pwr_mode_info { * @mcq_config_resource: called to configure MCQ platform resources * @get_hba_mac: called to get vendor specific mac value, mandatory for mcq mode * @op_runtime_config: called to config Operation and runtime regs Pointers + * @get_outstanding_cqs: called to get outstanding completion queues */ struct ufs_hba_variant_ops { const char *name; @@ -346,6 +347,8 @@ struct ufs_hba_variant_ops { int (*mcq_config_resource)(struct ufs_hba *hba); int (*get_hba_mac)(struct ufs_hba *hba); int (*op_runtime_config)(struct ufs_hba *hba); + int (*get_outstanding_cqs)(struct ufs_hba *hba, + unsigned long *ocqs); }; /* clock gating state */ @@ -1081,6 +1084,8 @@ struct ufs_hba { * @id: hardware queue ID * @sq_tp_slot: current slot to which SQ tail pointer is pointing * @sq_lock: serialize submission queue access + * @cq_tail_slot: current slot to which CQ tail pointer is pointing + * @cq_head_slot: current slot to which CQ head pointer is pointing */ struct ufs_hw_queue { void __iomem *mcq_sq_head; @@ -1096,6 +1101,8 @@ struct ufs_hw_queue { u32 id; u32 sq_tail_slot; spinlock_t sq_lock; + u32 cq_tail_slot; + u32 cq_head_slot; }; static inline bool is_mcq_enabled(struct ufs_hba *hba) diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index b6ae5718387c..eca89f9f6aac 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -263,6 +263,9 @@ enum { /* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */ #define UTP_TASK_REQ_LIST_RUN_STOP_BIT 0x1 +/* CQISy - CQ y Interrupt Status Register */ +#define UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS 0x1 + /* UICCMD - UIC Command */ #define COMMAND_OPCODE_MASK 0xFF #define GEN_SELECTOR_INDEX_MASK 0xFFFF -- cgit v1.2.3 From ed975065c31c2a0372e13c19e8140b69814a98ba Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 13 Jan 2023 12:48:51 -0800 Subject: scsi: ufs: core: mcq: Add completion support in poll Complete CQE requests in poll. Assumption is that several poll completion may happen in different CPUs for the same completion queue. Hence a spin lock protection is added. Co-developed-by: Can Guo Signed-off-by: Can Guo Signed-off-by: Asutosh Das Reviewed-by: Bart Van Assche Reviewed-by: Manivannan Sadhasivam Reviewed-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 13 +++++++++++++ drivers/ufs/core/ufshcd-priv.h | 2 ++ drivers/ufs/core/ufshcd.c | 7 +++++++ include/ufs/ufshcd.h | 2 ++ 4 files changed, 24 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index cd10d59c77e0..e710d19d4c55 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -294,6 +294,18 @@ unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba, return completed_reqs; } +unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba, + struct ufs_hw_queue *hwq) +{ + unsigned long completed_reqs; + + spin_lock(&hwq->cq_lock); + completed_reqs = ufshcd_mcq_poll_cqe_nolock(hba, hwq); + spin_unlock(&hwq->cq_lock); + + return completed_reqs; +} + void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) { struct ufs_hw_queue *hwq; @@ -390,6 +402,7 @@ int ufshcd_mcq_init(struct ufs_hba *hba) hwq = &hba->uhq[i]; hwq->max_entries = hba->nutrs; spin_lock_init(&hwq->sq_lock); + spin_lock_init(&hwq->cq_lock); } /* The very first HW queue serves device commands */ diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 583fb862013e..9b630907c4dc 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -75,6 +75,8 @@ unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba, struct ufs_hw_queue *hwq); struct ufs_hw_queue *ufshcd_mcq_req_to_hwq(struct ufs_hba *hba, struct request *req); +unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba, + struct ufs_hw_queue *hwq); #define UFSHCD_MCQ_IO_QUEUE_OFFSET 1 #define SD_ASCII_STD true diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 3afa07683ecf..cb1bca4d0c39 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5461,6 +5461,13 @@ static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num) struct ufs_hba *hba = shost_priv(shost); unsigned long completed_reqs, flags; u32 tr_doorbell; + struct ufs_hw_queue *hwq; + + if (is_mcq_enabled(hba)) { + hwq = &hba->uhq[queue_num + UFSHCD_MCQ_IO_QUEUE_OFFSET]; + + return ufshcd_mcq_poll_cqe_lock(hba, hwq); + } spin_lock_irqsave(&hba->outstanding_lock, flags); tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 0dcb104a6713..33973e9f6d6a 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1086,6 +1086,7 @@ struct ufs_hba { * @sq_lock: serialize submission queue access * @cq_tail_slot: current slot to which CQ tail pointer is pointing * @cq_head_slot: current slot to which CQ head pointer is pointing + * @cq_lock: Synchronize between multiple polling instances */ struct ufs_hw_queue { void __iomem *mcq_sq_head; @@ -1103,6 +1104,7 @@ struct ufs_hw_queue { spinlock_t sq_lock; u32 cq_tail_slot; u32 cq_head_slot; + spinlock_t cq_lock; }; static inline bool is_mcq_enabled(struct ufs_hba *hba) -- cgit v1.2.3 From edb0db05607ce05a5e0df00518b58a811e9f548e Mon Sep 17 00:00:00 2001 From: Can Guo Date: Wed, 14 Dec 2022 19:06:20 -0800 Subject: scsi: ufs: core: Add Event Specific Interrupt configuration vendor specific ops As Event Specific Interrupt message format is not defined in UFSHCI JEDEC specs, and the ESI handling highly depends on how the format is designed, hence add a vendor specific ops such that SoC vendors can configure their own ESI handlers. If ESI vops is not provided or returning error, go with the legacy (central) interrupt way. Signed-off-by: Can Guo Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd-priv.h | 8 ++++++++ drivers/ufs/core/ufshcd.c | 5 +++++ include/ufs/ufshcd.h | 2 ++ 3 files changed, 15 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 9b630907c4dc..529f8507a5e4 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -279,6 +279,14 @@ static inline int ufshcd_vops_get_outstanding_cqs(struct ufs_hba *hba, return -EOPNOTSUPP; } +static inline int ufshcd_mcq_vops_config_esi(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->config_esi) + return hba->vops->config_esi(hba); + + return -EOPNOTSUPP; +} + extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[]; /** diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 54717c497518..064a6d8605c1 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8449,6 +8449,11 @@ err: static void ufshcd_config_mcq(struct ufs_hba *hba) { + int ret; + + ret = ufshcd_mcq_vops_config_esi(hba); + dev_info(hba->dev, "ESI %sconfigured\n", ret ? "is not " : ""); + ufshcd_enable_intr(hba, UFSHCD_ENABLE_MCQ_INTRS); ufshcd_mcq_make_queues_operational(hba); ufshcd_mcq_config_mac(hba, hba->nutrs); diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 33973e9f6d6a..1285787e2628 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -305,6 +305,7 @@ struct ufs_pwr_mode_info { * @get_hba_mac: called to get vendor specific mac value, mandatory for mcq mode * @op_runtime_config: called to config Operation and runtime regs Pointers * @get_outstanding_cqs: called to get outstanding completion queues + * @config_esi: called to config Event Specific Interrupt */ struct ufs_hba_variant_ops { const char *name; @@ -349,6 +350,7 @@ struct ufs_hba_variant_ops { int (*op_runtime_config)(struct ufs_hba *hba); int (*get_outstanding_cqs)(struct ufs_hba *hba, unsigned long *ocqs); + int (*config_esi)(struct ufs_hba *hba); }; /* clock gating state */ -- cgit v1.2.3 From e02288e0265fe316a16d48ec6dd7b7fd54d66e3e Mon Sep 17 00:00:00 2001 From: Can Guo Date: Wed, 14 Dec 2022 19:06:21 -0800 Subject: scsi: ufs: core: mcq: Add Event Specific Interrupt enable and config functions Add and export two functions to enable ESI and config ESI base addresses. The calls to these exported functions will be added by the next patch in this series. Signed-off-by: Can Guo Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 16 ++++++++++++++++ include/ufs/ufshcd.h | 6 ++++++ include/ufs/ufshci.h | 2 ++ 3 files changed, 24 insertions(+) (limited to 'include') diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index e710d19d4c55..dd476f9e797c 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -246,6 +246,7 @@ void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i) { writel(val, mcq_opr_base(hba, OPR_CQIS, i) + REG_CQIS); } +EXPORT_SYMBOL_GPL(ufshcd_mcq_write_cqis); /* * Current MCQ specification doesn't provide a Task Tag or its equivalent in @@ -293,6 +294,7 @@ unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba, return completed_reqs; } +EXPORT_SYMBOL_GPL(ufshcd_mcq_poll_cqe_nolock); unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba, struct ufs_hw_queue *hwq) @@ -370,6 +372,20 @@ void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) } } +void ufshcd_mcq_enable_esi(struct ufs_hba *hba) +{ + ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, + REG_UFS_MEM_CFG); +} +EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); + +void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg) +{ + ufshcd_writel(hba, msg->address_lo, REG_UFS_ESILBA); + ufshcd_writel(hba, msg->address_hi, REG_UFS_ESIUBA); +} +EXPORT_SYMBOL_GPL(ufshcd_mcq_config_esi); + int ufshcd_mcq_init(struct ufs_hba *hba) { struct Scsi_Host *host = hba->host; diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 1285787e2628..1779238d8a56 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1241,6 +1242,11 @@ void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk); void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val); void ufshcd_hba_stop(struct ufs_hba *hba); void ufshcd_schedule_eh_work(struct ufs_hba *hba); +void ufshcd_mcq_write_cqis(struct ufs_hba *hba, u32 val, int i); +unsigned long ufshcd_mcq_poll_cqe_nolock(struct ufs_hba *hba, + struct ufs_hw_queue *hwq); +void ufshcd_mcq_enable_esi(struct ufs_hba *hba); +void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg); /** * ufshcd_set_variant - set variant specific data to the hba diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index eca89f9f6aac..11424bb03814 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -59,6 +59,8 @@ enum { REG_UFS_MEM_CFG = 0x300, REG_UFS_MCQ_CFG = 0x380, + REG_UFS_ESILBA = 0x384, + REG_UFS_ESIUBA = 0x388, UFSHCI_CRYPTO_REG_SPACE_SIZE = 0x400, }; -- cgit v1.2.3 From d0949565811f0896c1c7e781ab2ad99d34273fdf Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 29 Dec 2022 13:01:40 -0600 Subject: scsi: core: Add struct for args to execution functions Move the SCSI execution functions to use a struct for passing in optional args. This commit adds the new struct, temporarily converts scsi_execute() and scsi_execute_req() ands a new helper, scsi_execute_cmd(), which takes the scsi_exec_args struct. There should be no change in behavior. We no longer allow users to pass in any request->rq_flags value, but they were only passing in RQF_PM which we do support by allowing users to pass in the BLK_MQ_REQ flags used by blk_mq_alloc_request(). Subsequent commits will convert scsi_execute() and scsi_execute_req() users to the new helpers then remove scsi_execute() and scsi_execute_req(). Signed-off-by: Mike Christie Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Reviewed-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 52 ++++++++++++++++++++++------------------------ include/scsi/scsi_device.h | 51 ++++++++++++++++++++++++++++++++------------- 2 files changed, 62 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9ed1ebcb7443..7d324db6b2f7 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -185,39 +185,37 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason) __scsi_queue_insert(cmd, reason, true); } - /** - * __scsi_execute - insert request and wait for the result - * @sdev: scsi device + * scsi_execute_cmd - insert request and wait for the result + * @sdev: scsi_device * @cmd: scsi command - * @data_direction: data direction + * @opf: block layer request cmd_flags * @buffer: data buffer * @bufflen: len of buffer - * @sense: optional sense buffer - * @sshdr: optional decoded sense header * @timeout: request timeout in HZ * @retries: number of times to retry request - * @flags: flags for ->cmd_flags - * @rq_flags: flags for ->rq_flags - * @resid: optional residual length + * @args: Optional args. See struct definition for field descriptions * * Returns the scsi_cmnd result field if a command was executed, or a negative * Linux error code if we didn't get that far. */ -int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - unsigned char *sense, struct scsi_sense_hdr *sshdr, - int timeout, int retries, blk_opf_t flags, - req_flags_t rq_flags, int *resid) +int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, + blk_opf_t opf, void *buffer, unsigned int bufflen, + int timeout, int retries, + const struct scsi_exec_args *args) { + static const struct scsi_exec_args default_args; struct request *req; struct scsi_cmnd *scmd; int ret; - req = scsi_alloc_request(sdev->request_queue, - data_direction == DMA_TO_DEVICE ? - REQ_OP_DRV_OUT : REQ_OP_DRV_IN, - rq_flags & RQF_PM ? BLK_MQ_REQ_PM : 0); + if (!args) + args = &default_args; + else if (WARN_ON_ONCE(args->sense && + args->sense_len != SCSI_SENSE_BUFFERSIZE)) + return -EINVAL; + + req = scsi_alloc_request(sdev->request_queue, opf, args->req_flags); if (IS_ERR(req)) return PTR_ERR(req); @@ -232,8 +230,7 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, memcpy(scmd->cmnd, cmd, scmd->cmd_len); scmd->allowed = retries; req->timeout = timeout; - req->cmd_flags |= flags; - req->rq_flags |= rq_flags | RQF_QUIET; + req->rq_flags |= RQF_QUIET; /* * head injection *required* here otherwise quiesce won't work @@ -249,20 +246,21 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, if (unlikely(scmd->resid_len > 0 && scmd->resid_len <= bufflen)) memset(buffer + bufflen - scmd->resid_len, 0, scmd->resid_len); - if (resid) - *resid = scmd->resid_len; - if (sense && scmd->sense_len) - memcpy(sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); - if (sshdr) + if (args->resid) + *args->resid = scmd->resid_len; + if (args->sense) + memcpy(args->sense, scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); + if (args->sshdr) scsi_normalize_sense(scmd->sense_buffer, scmd->sense_len, - sshdr); + args->sshdr); + ret = scmd->result; out: blk_mq_free_request(req); return ret; } -EXPORT_SYMBOL(__scsi_execute); +EXPORT_SYMBOL(scsi_execute_cmd); /* * Wake up the error handler if necessary. Avoid as follows that the error diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 3642b8e3928b..f6b33c6c1064 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -455,28 +455,51 @@ extern const char *scsi_device_state_name(enum scsi_device_state); extern int scsi_is_sdev_device(const struct device *); extern int scsi_is_target_device(const struct device *); extern void scsi_sanitize_inquiry_string(unsigned char *s, int len); -extern int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - unsigned char *sense, struct scsi_sense_hdr *sshdr, - int timeout, int retries, blk_opf_t flags, - req_flags_t rq_flags, int *resid); + +/* Optional arguments to scsi_execute_cmd */ +struct scsi_exec_args { + unsigned char *sense; /* sense buffer */ + unsigned int sense_len; /* sense buffer len */ + struct scsi_sense_hdr *sshdr; /* decoded sense header */ + blk_mq_req_flags_t req_flags; /* BLK_MQ_REQ flags */ + int *resid; /* residual length */ +}; + +int scsi_execute_cmd(struct scsi_device *sdev, const unsigned char *cmd, + blk_opf_t opf, void *buffer, unsigned int bufflen, + int timeout, int retries, + const struct scsi_exec_args *args); + /* Make sure any sense buffer is the correct size. */ -#define scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense, \ - sshdr, timeout, retries, flags, rq_flags, resid) \ +#define scsi_execute(_sdev, _cmd, _data_dir, _buffer, _bufflen, _sense, \ + _sshdr, _timeout, _retries, _flags, _rq_flags, \ + _resid) \ ({ \ - BUILD_BUG_ON((sense) != NULL && \ - sizeof(sense) != SCSI_SENSE_BUFFERSIZE); \ - __scsi_execute(sdev, cmd, data_direction, buffer, bufflen, \ - sense, sshdr, timeout, retries, flags, rq_flags, \ - resid); \ + scsi_execute_cmd(_sdev, _cmd, (_data_dir == DMA_TO_DEVICE ? \ + REQ_OP_DRV_OUT : REQ_OP_DRV_IN) | _flags, \ + _buffer, _bufflen, _timeout, _retries, \ + &(struct scsi_exec_args) { \ + .sense = _sense, \ + .sshdr = _sshdr, \ + .req_flags = _rq_flags & RQF_PM ? \ + BLK_MQ_REQ_PM : 0, \ + .resid = _resid, \ + }); \ }) + static inline int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout, int retries, int *resid) { - return scsi_execute(sdev, cmd, data_direction, buffer, - bufflen, NULL, sshdr, timeout, retries, 0, 0, resid); + return scsi_execute_cmd(sdev, cmd, + data_direction == DMA_TO_DEVICE ? + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, buffer, + bufflen, timeout, retries, + &(struct scsi_exec_args) { + .sshdr = sshdr, + .resid = resid, + }); } extern void sdev_disable_disk_events(struct scsi_device *sdev); extern void sdev_enable_disk_events(struct scsi_device *sdev); -- cgit v1.2.3 From af6d10345ca76670c1b7c37799f0d5576ccef277 Mon Sep 17 00:00:00 2001 From: Jon Maxwell Date: Thu, 12 Jan 2023 12:25:32 +1100 Subject: ipv6: remove max_size check inline with ipv4 In ip6_dst_gc() replace: if (entries > gc_thresh) With: if (entries > ops->gc_thresh) Sending Ipv6 packets in a loop via a raw socket triggers an issue where a route is cloned by ip6_rt_cache_alloc() for each packet sent. This quickly consumes the Ipv6 max_size threshold which defaults to 4096 resulting in these warnings: [1] 99.187805] dst_alloc: 7728 callbacks suppressed [2] Route cache is full: consider increasing sysctl net.ipv6.route.max_size. . . [300] Route cache is full: consider increasing sysctl net.ipv6.route.max_size. When this happens the packet is dropped and sendto() gets a network is unreachable error: remaining pkt 200557 errno 101 remaining pkt 196462 errno 101 . . remaining pkt 126821 errno 101 Implement David Aherns suggestion to remove max_size check seeing that Ipv6 has a GC to manage memory usage. Ipv4 already does not check max_size. Here are some memory comparisons for Ipv4 vs Ipv6 with the patch: Test by running 5 instances of a program that sends UDP packets to a raw socket 5000000 times. Compare Ipv4 and Ipv6 performance with a similar program. Ipv4: Before test: MemFree: 29427108 kB Slab: 237612 kB ip6_dst_cache 1912 2528 256 32 2 : tunables 0 0 0 xfrm_dst_cache 0 0 320 25 2 : tunables 0 0 0 ip_dst_cache 2881 3990 192 42 2 : tunables 0 0 0 During test: MemFree: 29417608 kB Slab: 247712 kB ip6_dst_cache 1912 2528 256 32 2 : tunables 0 0 0 xfrm_dst_cache 0 0 320 25 2 : tunables 0 0 0 ip_dst_cache 44394 44394 192 42 2 : tunables 0 0 0 After test: MemFree: 29422308 kB Slab: 238104 kB ip6_dst_cache 1912 2528 256 32 2 : tunables 0 0 0 xfrm_dst_cache 0 0 320 25 2 : tunables 0 0 0 ip_dst_cache 3048 4116 192 42 2 : tunables 0 0 0 Ipv6 with patch: Errno 101 errors are not observed anymore with the patch. Before test: MemFree: 29422308 kB Slab: 238104 kB ip6_dst_cache 1912 2528 256 32 2 : tunables 0 0 0 xfrm_dst_cache 0 0 320 25 2 : tunables 0 0 0 ip_dst_cache 3048 4116 192 42 2 : tunables 0 0 0 During Test: MemFree: 29431516 kB Slab: 240940 kB ip6_dst_cache 11980 12064 256 32 2 : tunables 0 0 0 xfrm_dst_cache 0 0 320 25 2 : tunables 0 0 0 ip_dst_cache 3048 4116 192 42 2 : tunables 0 0 0 After Test: MemFree: 29441816 kB Slab: 238132 kB ip6_dst_cache 1902 2432 256 32 2 : tunables 0 0 0 xfrm_dst_cache 0 0 320 25 2 : tunables 0 0 0 ip_dst_cache 3048 4116 192 42 2 : tunables 0 0 0 Tested-by: Andrea Mayer Signed-off-by: Jon Maxwell Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230112012532.311021-1-jmaxwell37@gmail.com Signed-off-by: Jakub Kicinski --- include/net/dst_ops.h | 2 +- net/core/dst.c | 8 ++------ net/ipv6/route.c | 13 +++++-------- 3 files changed, 8 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h index 88ff7bb2bb9b..632086b2f644 100644 --- a/include/net/dst_ops.h +++ b/include/net/dst_ops.h @@ -16,7 +16,7 @@ struct dst_ops { unsigned short family; unsigned int gc_thresh; - int (*gc)(struct dst_ops *ops); + void (*gc)(struct dst_ops *ops); struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); unsigned int (*default_advmss)(const struct dst_entry *); unsigned int (*mtu)(const struct dst_entry *); diff --git a/net/core/dst.c b/net/core/dst.c index 6d2dd03dafa8..31c08a3386d3 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -82,12 +82,8 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, if (ops->gc && !(flags & DST_NOCOUNT) && - dst_entries_get_fast(ops) > ops->gc_thresh) { - if (ops->gc(ops)) { - pr_notice_ratelimited("Route cache is full: consider increasing sysctl net.ipv6.route.max_size.\n"); - return NULL; - } - } + dst_entries_get_fast(ops) > ops->gc_thresh) + ops->gc(ops); dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); if (!dst) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e74e0361fd92..b643dda68d31 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -91,7 +91,7 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *); static void ip6_dst_destroy(struct dst_entry *); static void ip6_dst_ifdown(struct dst_entry *, struct net_device *dev, int how); -static int ip6_dst_gc(struct dst_ops *ops); +static void ip6_dst_gc(struct dst_ops *ops); static int ip6_pkt_discard(struct sk_buff *skb); static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); @@ -3284,11 +3284,10 @@ out: return dst; } -static int ip6_dst_gc(struct dst_ops *ops) +static void ip6_dst_gc(struct dst_ops *ops) { struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; - int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; @@ -3296,11 +3295,10 @@ static int ip6_dst_gc(struct dst_ops *ops) int entries; entries = dst_entries_get_fast(ops); - if (entries > rt_max_size) + if (entries > ops->gc_thresh) entries = dst_entries_get_slow(ops); - if (time_after(rt_last_gc + rt_min_interval, jiffies) && - entries <= rt_max_size) + if (time_after(rt_last_gc + rt_min_interval, jiffies)) goto out; fib6_run_gc(atomic_inc_return(&net->ipv6.ip6_rt_gc_expire), net, true); @@ -3310,7 +3308,6 @@ static int ip6_dst_gc(struct dst_ops *ops) out: val = atomic_read(&net->ipv6.ip6_rt_gc_expire); atomic_set(&net->ipv6.ip6_rt_gc_expire, val - (val >> rt_elasticity)); - return entries > rt_max_size; } static int ip6_nh_lookup_table(struct net *net, struct fib6_config *cfg, @@ -6512,7 +6509,7 @@ static int __net_init ip6_route_net_init(struct net *net) #endif net->ipv6.sysctl.flush_delay = 0; - net->ipv6.sysctl.ip6_rt_max_size = 4096; + net->ipv6.sysctl.ip6_rt_max_size = INT_MAX; net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ; net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ; -- cgit v1.2.3 From 80e87442e69ba8589160c5d472c2d973d0731c86 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 12 Jan 2023 16:15:16 +0100 Subject: enetc: Separate C22 and C45 transactions The enetc MDIO bus driver can perform both C22 and C45 transfers. Create separate functions for each and register the C45 versions using the new API calls where appropriate. This driver is shared with the Felix DSA switch, so update that at the same time. Signed-off-by: Andrew Lunn Signed-off-by: Michael Walle Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix_vsc9959.c | 6 +- drivers/net/ethernet/freescale/enetc/enetc_mdio.c | 119 +++++++++++++++------ .../net/ethernet/freescale/enetc/enetc_pci_mdio.c | 6 +- drivers/net/ethernet/freescale/enetc/enetc_pf.c | 12 ++- include/linux/fsl/enetc_mdio.h | 21 +++- 5 files changed, 121 insertions(+), 43 deletions(-) (limited to 'include') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 01ac70fd7ddf..cbcc457499f3 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -954,8 +954,10 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) return -ENOMEM; bus->name = "VSC9959 internal MDIO bus"; - bus->read = enetc_mdio_read; - bus->write = enetc_mdio_write; + bus->read = enetc_mdio_read_c22; + bus->write = enetc_mdio_write_c22; + bus->read_c45 = enetc_mdio_read_c45; + bus->write_c45 = enetc_mdio_write_c45; bus->parent = dev; mdio_priv = bus->priv; mdio_priv->hw = hw; diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c index 1c8f5cc6dec4..998aaa394e9c 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c @@ -55,7 +55,8 @@ static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv) is_busy, !is_busy, 10, 10 * 1000); } -int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) +int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, + u16 value) { struct enetc_mdio_priv *mdio_priv = bus->priv; u32 mdio_ctl, mdio_cfg; @@ -63,14 +64,39 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) int ret; mdio_cfg = ENETC_EMDIO_CFG; - if (regnum & MII_ADDR_C45) { - dev_addr = (regnum >> 16) & 0x1f; - mdio_cfg |= MDIO_CFG_ENC45; - } else { - /* clause 22 (ie 1G) */ - dev_addr = regnum & 0x1f; - mdio_cfg &= ~MDIO_CFG_ENC45; - } + dev_addr = regnum & 0x1f; + mdio_cfg &= ~MDIO_CFG_ENC45; + + enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); + + ret = enetc_mdio_wait_complete(mdio_priv); + if (ret) + return ret; + + /* set port and dev addr */ + mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); + enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); + + /* write the value */ + enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); + + ret = enetc_mdio_wait_complete(mdio_priv); + if (ret) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(enetc_mdio_write_c22); + +int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr, + int regnum, u16 value) +{ + struct enetc_mdio_priv *mdio_priv = bus->priv; + u32 mdio_ctl, mdio_cfg; + int ret; + + mdio_cfg = ENETC_EMDIO_CFG; + mdio_cfg |= MDIO_CFG_ENC45; enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); @@ -83,13 +109,11 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); /* set the register address */ - if (regnum & MII_ADDR_C45) { - enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); + enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); - ret = enetc_mdio_wait_complete(mdio_priv); - if (ret) - return ret; - } + ret = enetc_mdio_wait_complete(mdio_priv); + if (ret) + return ret; /* write the value */ enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); @@ -100,9 +124,9 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) return 0; } -EXPORT_SYMBOL_GPL(enetc_mdio_write); +EXPORT_SYMBOL_GPL(enetc_mdio_write_c45); -int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) +int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) { struct enetc_mdio_priv *mdio_priv = bus->priv; u32 mdio_ctl, mdio_cfg; @@ -110,14 +134,51 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) int ret; mdio_cfg = ENETC_EMDIO_CFG; - if (regnum & MII_ADDR_C45) { - dev_addr = (regnum >> 16) & 0x1f; - mdio_cfg |= MDIO_CFG_ENC45; - } else { - dev_addr = regnum & 0x1f; - mdio_cfg &= ~MDIO_CFG_ENC45; + dev_addr = regnum & 0x1f; + mdio_cfg &= ~MDIO_CFG_ENC45; + + enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); + + ret = enetc_mdio_wait_complete(mdio_priv); + if (ret) + return ret; + + /* set port and device addr */ + mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); + enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); + + /* initiate the read */ + enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); + + ret = enetc_mdio_wait_complete(mdio_priv); + if (ret) + return ret; + + /* return all Fs if nothing was there */ + if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) { + dev_dbg(&bus->dev, + "Error while reading PHY%d reg at %d.%d\n", + phy_id, dev_addr, regnum); + return 0xffff; } + value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff; + + return value; +} +EXPORT_SYMBOL_GPL(enetc_mdio_read_c22); + +int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, + int regnum) +{ + struct enetc_mdio_priv *mdio_priv = bus->priv; + u32 mdio_ctl, mdio_cfg; + u16 value; + int ret; + + mdio_cfg = ENETC_EMDIO_CFG; + mdio_cfg |= MDIO_CFG_ENC45; + enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); ret = enetc_mdio_wait_complete(mdio_priv); @@ -129,13 +190,11 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); /* set the register address */ - if (regnum & MII_ADDR_C45) { - enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); + enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); - ret = enetc_mdio_wait_complete(mdio_priv); - if (ret) - return ret; - } + ret = enetc_mdio_wait_complete(mdio_priv); + if (ret) + return ret; /* initiate the read */ enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); @@ -156,7 +215,7 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) return value; } -EXPORT_SYMBOL_GPL(enetc_mdio_read); +EXPORT_SYMBOL_GPL(enetc_mdio_read_c45); struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) { diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c index dafb26f81f95..a1b595bd7993 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c @@ -39,8 +39,10 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev, } bus->name = ENETC_MDIO_BUS_NAME; - bus->read = enetc_mdio_read; - bus->write = enetc_mdio_write; + bus->read = enetc_mdio_read_c22; + bus->write = enetc_mdio_write_c22; + bus->read_c45 = enetc_mdio_read_c45; + bus->write_c45 = enetc_mdio_write_c45; bus->parent = dev; mdio_priv = bus->priv; mdio_priv->hw = hw; diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index 9f6c4f5c0a6c..bc012deedab4 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -848,8 +848,10 @@ static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np) return -ENOMEM; bus->name = "Freescale ENETC MDIO Bus"; - bus->read = enetc_mdio_read; - bus->write = enetc_mdio_write; + bus->read = enetc_mdio_read_c22; + bus->write = enetc_mdio_write_c22; + bus->read_c45 = enetc_mdio_read_c45; + bus->write_c45 = enetc_mdio_write_c45; bus->parent = dev; mdio_priv = bus->priv; mdio_priv->hw = &pf->si->hw; @@ -885,8 +887,10 @@ static int enetc_imdio_create(struct enetc_pf *pf) return -ENOMEM; bus->name = "Freescale ENETC internal MDIO Bus"; - bus->read = enetc_mdio_read; - bus->write = enetc_mdio_write; + bus->read = enetc_mdio_read_c22; + bus->write = enetc_mdio_write_c22; + bus->read_c45 = enetc_mdio_read_c45; + bus->write_c45 = enetc_mdio_write_c45; bus->parent = dev; bus->phy_mask = ~0; mdio_priv = bus->priv; diff --git a/include/linux/fsl/enetc_mdio.h b/include/linux/fsl/enetc_mdio.h index 2d9203314865..df25fffdc0ae 100644 --- a/include/linux/fsl/enetc_mdio.h +++ b/include/linux/fsl/enetc_mdio.h @@ -37,16 +37,27 @@ struct enetc_mdio_priv { #if IS_REACHABLE(CONFIG_FSL_ENETC_MDIO) -int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum); -int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value); +int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum); +int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, + u16 value); +int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, int devad, int regnum); +int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, int devad, int regnum, + u16 value); struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs); #else -static inline int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) +static inline int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, + int regnum) { return -EINVAL; } -static inline int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, - u16 value) +static inline int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, + int regnum, u16 value) +{ return -EINVAL; } +static inline int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, + int devad, int regnum) +{ return -EINVAL; } +static inline int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, + int devad, int regnum, u16 value) { return -EINVAL; } struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) { return ERR_PTR(-EINVAL); } -- cgit v1.2.3 From 9b2e3723728efe03433be5c13b31da451d88ee3d Mon Sep 17 00:00:00 2001 From: Patrisious Haddad Date: Wed, 4 Jan 2023 11:43:35 +0200 Subject: net/mlx5: Introduce CQE error syndrome Introduces CQE error syndrome bits which are inside qp_context_extension and are used to report the reason the QP was moved to error state. Useful for cases in which a CQE isn't generated, such as remote write rkey violation. Signed-off-by: Patrisious Haddad Link: https://lore.kernel.org/r/f8359315f8130f6d2abe4b94409ac7802f54bce3.1672821186.git.leonro@nvidia.com Reviewed-by: Saeed Mahameed Signed-off-by: Leon Romanovsky --- include/linux/mlx5/mlx5_ifc.h | 47 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index a9ee7bc59c90..2d17b6a6d82d 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1496,7 +1496,9 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 null_mkey[0x1]; u8 log_max_klm_list_size[0x6]; - u8 reserved_at_120[0xa]; + u8 reserved_at_120[0x2]; + u8 qpc_extension[0x1]; + u8 reserved_at_123[0x7]; u8 log_max_ra_req_dc[0x6]; u8 reserved_at_130[0x2]; u8 eth_wqe_too_small[0x1]; @@ -1662,7 +1664,9 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 log_bf_reg_size[0x5]; - u8 reserved_at_270[0x6]; + u8 reserved_at_270[0x3]; + u8 qp_error_syndrome[0x1]; + u8 reserved_at_274[0x2]; u8 lag_dct[0x2]; u8 lag_tx_port_affinity[0x1]; u8 lag_native_fdb_selection[0x1]; @@ -5342,6 +5346,37 @@ struct mlx5_ifc_query_rmp_in_bits { u8 reserved_at_60[0x20]; }; +struct mlx5_ifc_cqe_error_syndrome_bits { + u8 hw_error_syndrome[0x8]; + u8 hw_syndrome_type[0x4]; + u8 reserved_at_c[0x4]; + u8 vendor_error_syndrome[0x8]; + u8 syndrome[0x8]; +}; + +struct mlx5_ifc_qp_context_extension_bits { + u8 reserved_at_0[0x60]; + + struct mlx5_ifc_cqe_error_syndrome_bits error_syndrome; + + u8 reserved_at_80[0x580]; +}; + +struct mlx5_ifc_qpc_extension_and_pas_list_in_bits { + struct mlx5_ifc_qp_context_extension_bits qpc_data_extension; + + u8 pas[0][0x40]; +}; + +struct mlx5_ifc_qp_pas_list_in_bits { + struct mlx5_ifc_cmd_pas_bits pas[0]; +}; + +union mlx5_ifc_qp_pas_or_qpc_ext_and_pas_bits { + struct mlx5_ifc_qp_pas_list_in_bits qp_pas_list; + struct mlx5_ifc_qpc_extension_and_pas_list_in_bits qpc_ext_and_pas_list; +}; + struct mlx5_ifc_query_qp_out_bits { u8 status[0x8]; u8 reserved_at_8[0x18]; @@ -5358,7 +5393,7 @@ struct mlx5_ifc_query_qp_out_bits { u8 reserved_at_800[0x80]; - u8 pas[][0x40]; + union mlx5_ifc_qp_pas_or_qpc_ext_and_pas_bits qp_pas_or_qpc_ext_and_pas; }; struct mlx5_ifc_query_qp_in_bits { @@ -5368,7 +5403,8 @@ struct mlx5_ifc_query_qp_in_bits { u8 reserved_at_20[0x10]; u8 op_mod[0x10]; - u8 reserved_at_40[0x8]; + u8 qpc_ext[0x1]; + u8 reserved_at_41[0x7]; u8 qpn[0x18]; u8 reserved_at_60[0x20]; @@ -8571,7 +8607,8 @@ struct mlx5_ifc_create_qp_in_bits { u8 reserved_at_20[0x10]; u8 op_mod[0x10]; - u8 reserved_at_40[0x8]; + u8 qpc_ext[0x1]; + u8 reserved_at_41[0x7]; u8 input_qpn[0x18]; u8 reserved_at_60[0x20]; -- cgit v1.2.3 From 312b8f79eb05479628ee71357749815b2eeeeea8 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Wed, 4 Jan 2023 11:43:34 +0200 Subject: RDMA/mlx: Calling qp event handler in workqueue context Move the call of qp event handler from atomic to workqueue context, so that the handler is able to block. This is needed by following patches. Signed-off-by: Mark Zhang Reviewed-by: Patrisious Haddad Link: https://lore.kernel.org/r/0cd17b8331e445f03942f4bb28d447f24ac5669d.1672821186.git.leonro@nvidia.com Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx4/main.c | 8 +++ drivers/infiniband/hw/mlx4/mlx4_ib.h | 3 + drivers/infiniband/hw/mlx4/qp.c | 121 ++++++++++++++++++++++---------- drivers/infiniband/hw/mlx5/main.c | 7 ++ drivers/infiniband/hw/mlx5/qp.c | 119 ++++++++++++++++++++++--------- drivers/infiniband/hw/mlx5/qp.h | 2 + drivers/infiniband/hw/mlx5/qpc.c | 3 +- drivers/net/ethernet/mellanox/mlx4/qp.c | 14 ++-- include/linux/mlx4/qp.h | 1 + include/rdma/ib_verbs.h | 2 +- 10 files changed, 202 insertions(+), 78 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index dceebcd885bb..b18e9f2adc82 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -3303,6 +3303,10 @@ static int __init mlx4_ib_init(void) if (!wq) return -ENOMEM; + err = mlx4_ib_qp_event_init(); + if (err) + goto clean_qp_event; + err = mlx4_ib_cm_init(); if (err) goto clean_wq; @@ -3324,6 +3328,9 @@ clean_cm: mlx4_ib_cm_destroy(); clean_wq: + mlx4_ib_qp_event_cleanup(); + +clean_qp_event: destroy_workqueue(wq); return err; } @@ -3333,6 +3340,7 @@ static void __exit mlx4_ib_cleanup(void) mlx4_unregister_interface(&mlx4_ib_interface); mlx4_ib_mcg_destroy(); mlx4_ib_cm_destroy(); + mlx4_ib_qp_event_cleanup(); destroy_workqueue(wq); } diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 6a3b0f121045..17fee1e73a45 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -940,4 +940,7 @@ int mlx4_ib_umem_calc_optimal_mtt_size(struct ib_umem *umem, u64 start_va, int mlx4_ib_cm_init(void); void mlx4_ib_cm_destroy(void); +int mlx4_ib_qp_event_init(void); +void mlx4_ib_qp_event_cleanup(void); + #endif /* MLX4_IB_H */ diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index b17d6ebc5b70..884825b2e5f7 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -102,6 +102,14 @@ enum mlx4_ib_source_type { MLX4_IB_RWQ_SRC = 1, }; +struct mlx4_ib_qp_event_work { + struct work_struct work; + struct mlx4_qp *qp; + enum mlx4_event type; +}; + +static struct workqueue_struct *mlx4_ib_qp_event_wq; + static int is_tunnel_qp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) { if (!mlx4_is_master(dev->dev)) @@ -200,50 +208,77 @@ static void stamp_send_wqe(struct mlx4_ib_qp *qp, int n) } } +static void mlx4_ib_handle_qp_event(struct work_struct *_work) +{ + struct mlx4_ib_qp_event_work *qpe_work = + container_of(_work, struct mlx4_ib_qp_event_work, work); + struct ib_qp *ibqp = &to_mibqp(qpe_work->qp)->ibqp; + struct ib_event event = {}; + + event.device = ibqp->device; + event.element.qp = ibqp; + + switch (qpe_work->type) { + case MLX4_EVENT_TYPE_PATH_MIG: + event.event = IB_EVENT_PATH_MIG; + break; + case MLX4_EVENT_TYPE_COMM_EST: + event.event = IB_EVENT_COMM_EST; + break; + case MLX4_EVENT_TYPE_SQ_DRAINED: + event.event = IB_EVENT_SQ_DRAINED; + break; + case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: + event.event = IB_EVENT_QP_LAST_WQE_REACHED; + break; + case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: + event.event = IB_EVENT_QP_FATAL; + break; + case MLX4_EVENT_TYPE_PATH_MIG_FAILED: + event.event = IB_EVENT_PATH_MIG_ERR; + break; + case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: + event.event = IB_EVENT_QP_REQ_ERR; + break; + case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: + event.event = IB_EVENT_QP_ACCESS_ERR; + break; + default: + pr_warn("Unexpected event type %d on QP %06x\n", + qpe_work->type, qpe_work->qp->qpn); + goto out; + } + + ibqp->event_handler(&event, ibqp->qp_context); + +out: + mlx4_put_qp(qpe_work->qp); + kfree(qpe_work); +} + static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type) { - struct ib_event event; struct ib_qp *ibqp = &to_mibqp(qp)->ibqp; + struct mlx4_ib_qp_event_work *qpe_work; if (type == MLX4_EVENT_TYPE_PATH_MIG) to_mibqp(qp)->port = to_mibqp(qp)->alt_port; - if (ibqp->event_handler) { - event.device = ibqp->device; - event.element.qp = ibqp; - switch (type) { - case MLX4_EVENT_TYPE_PATH_MIG: - event.event = IB_EVENT_PATH_MIG; - break; - case MLX4_EVENT_TYPE_COMM_EST: - event.event = IB_EVENT_COMM_EST; - break; - case MLX4_EVENT_TYPE_SQ_DRAINED: - event.event = IB_EVENT_SQ_DRAINED; - break; - case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: - event.event = IB_EVENT_QP_LAST_WQE_REACHED; - break; - case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: - event.event = IB_EVENT_QP_FATAL; - break; - case MLX4_EVENT_TYPE_PATH_MIG_FAILED: - event.event = IB_EVENT_PATH_MIG_ERR; - break; - case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: - event.event = IB_EVENT_QP_REQ_ERR; - break; - case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: - event.event = IB_EVENT_QP_ACCESS_ERR; - break; - default: - pr_warn("Unexpected event type %d " - "on QP %06x\n", type, qp->qpn); - return; - } + if (!ibqp->event_handler) + goto out_no_handler; - ibqp->event_handler(&event, ibqp->qp_context); - } + qpe_work = kzalloc(sizeof(*qpe_work), GFP_ATOMIC); + if (!qpe_work) + goto out_no_handler; + + qpe_work->qp = qp; + qpe_work->type = type; + INIT_WORK(&qpe_work->work, mlx4_ib_handle_qp_event); + queue_work(mlx4_ib_qp_event_wq, &qpe_work->work); + return; + +out_no_handler: + mlx4_put_qp(qp); } static void mlx4_ib_wq_event(struct mlx4_qp *qp, enum mlx4_event type) @@ -4468,3 +4503,17 @@ void mlx4_ib_drain_rq(struct ib_qp *qp) handle_drain_completion(cq, &rdrain, dev); } + +int mlx4_ib_qp_event_init(void) +{ + mlx4_ib_qp_event_wq = alloc_ordered_workqueue("mlx4_ib_qp_event_wq", 0); + if (!mlx4_ib_qp_event_wq) + return -ENOMEM; + + return 0; +} + +void mlx4_ib_qp_event_cleanup(void) +{ + destroy_workqueue(mlx4_ib_qp_event_wq); +} diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index c669ef6e47e7..8588f2fc0cba 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -4403,6 +4403,10 @@ static int __init mlx5_ib_init(void) return -ENOMEM; } + ret = mlx5_ib_qp_event_init(); + if (ret) + goto qp_event_err; + mlx5_ib_odp_init(); ret = mlx5r_rep_init(); if (ret) @@ -4420,6 +4424,8 @@ drv_err: mp_err: mlx5r_rep_cleanup(); rep_err: + mlx5_ib_qp_event_cleanup(); +qp_event_err: destroy_workqueue(mlx5_ib_event_wq); free_page((unsigned long)xlt_emergency_page); return ret; @@ -4431,6 +4437,7 @@ static void __exit mlx5_ib_cleanup(void) auxiliary_driver_unregister(&mlx5r_mp_driver); mlx5r_rep_cleanup(); + mlx5_ib_qp_event_cleanup(); destroy_workqueue(mlx5_ib_event_wq); free_page((unsigned long)xlt_emergency_page); } diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index cf953d23d18d..9b85e1be0aed 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -71,6 +71,14 @@ struct mlx5_modify_raw_qp_param { u32 port; }; +struct mlx5_ib_qp_event_work { + struct work_struct work; + struct mlx5_core_qp *qp; + int type; +}; + +static struct workqueue_struct *mlx5_ib_qp_event_wq; + static void get_cqs(enum ib_qp_type qp_type, struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq, struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq); @@ -302,51 +310,78 @@ int mlx5_ib_read_wqe_srq(struct mlx5_ib_srq *srq, int wqe_index, void *buffer, return mlx5_ib_read_user_wqe_srq(srq, wqe_index, buffer, buflen, bc); } +static void mlx5_ib_handle_qp_event(struct work_struct *_work) +{ + struct mlx5_ib_qp_event_work *qpe_work = + container_of(_work, struct mlx5_ib_qp_event_work, work); + struct ib_qp *ibqp = &to_mibqp(qpe_work->qp)->ibqp; + struct ib_event event = {}; + + event.device = ibqp->device; + event.element.qp = ibqp; + switch (qpe_work->type) { + case MLX5_EVENT_TYPE_PATH_MIG: + event.event = IB_EVENT_PATH_MIG; + break; + case MLX5_EVENT_TYPE_COMM_EST: + event.event = IB_EVENT_COMM_EST; + break; + case MLX5_EVENT_TYPE_SQ_DRAINED: + event.event = IB_EVENT_SQ_DRAINED; + break; + case MLX5_EVENT_TYPE_SRQ_LAST_WQE: + event.event = IB_EVENT_QP_LAST_WQE_REACHED; + break; + case MLX5_EVENT_TYPE_WQ_CATAS_ERROR: + event.event = IB_EVENT_QP_FATAL; + break; + case MLX5_EVENT_TYPE_PATH_MIG_FAILED: + event.event = IB_EVENT_PATH_MIG_ERR; + break; + case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR: + event.event = IB_EVENT_QP_REQ_ERR; + break; + case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR: + event.event = IB_EVENT_QP_ACCESS_ERR; + break; + default: + pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", + qpe_work->type, qpe_work->qp->qpn); + goto out; + } + + ibqp->event_handler(&event, ibqp->qp_context); + +out: + mlx5_core_res_put(&qpe_work->qp->common); + kfree(qpe_work); +} + static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type) { struct ib_qp *ibqp = &to_mibqp(qp)->ibqp; - struct ib_event event; + struct mlx5_ib_qp_event_work *qpe_work; if (type == MLX5_EVENT_TYPE_PATH_MIG) { /* This event is only valid for trans_qps */ to_mibqp(qp)->port = to_mibqp(qp)->trans_qp.alt_port; } - if (ibqp->event_handler) { - event.device = ibqp->device; - event.element.qp = ibqp; - switch (type) { - case MLX5_EVENT_TYPE_PATH_MIG: - event.event = IB_EVENT_PATH_MIG; - break; - case MLX5_EVENT_TYPE_COMM_EST: - event.event = IB_EVENT_COMM_EST; - break; - case MLX5_EVENT_TYPE_SQ_DRAINED: - event.event = IB_EVENT_SQ_DRAINED; - break; - case MLX5_EVENT_TYPE_SRQ_LAST_WQE: - event.event = IB_EVENT_QP_LAST_WQE_REACHED; - break; - case MLX5_EVENT_TYPE_WQ_CATAS_ERROR: - event.event = IB_EVENT_QP_FATAL; - break; - case MLX5_EVENT_TYPE_PATH_MIG_FAILED: - event.event = IB_EVENT_PATH_MIG_ERR; - break; - case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR: - event.event = IB_EVENT_QP_REQ_ERR; - break; - case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR: - event.event = IB_EVENT_QP_ACCESS_ERR; - break; - default: - pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", type, qp->qpn); - return; - } + if (!ibqp->event_handler) + goto out_no_handler; - ibqp->event_handler(&event, ibqp->qp_context); - } + qpe_work = kzalloc(sizeof(*qpe_work), GFP_ATOMIC); + if (!qpe_work) + goto out_no_handler; + + qpe_work->qp = qp; + qpe_work->type = type; + INIT_WORK(&qpe_work->work, mlx5_ib_handle_qp_event); + queue_work(mlx5_ib_qp_event_wq, &qpe_work->work); + return; + +out_no_handler: + mlx5_core_res_put(&qp->common); } static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, @@ -5720,3 +5755,17 @@ out: mutex_unlock(&mqp->mutex); return err; } + +int mlx5_ib_qp_event_init(void) +{ + mlx5_ib_qp_event_wq = alloc_ordered_workqueue("mlx5_ib_qp_event_wq", 0); + if (!mlx5_ib_qp_event_wq) + return -ENOMEM; + + return 0; +} + +void mlx5_ib_qp_event_cleanup(void) +{ + destroy_workqueue(mlx5_ib_qp_event_wq); +} diff --git a/drivers/infiniband/hw/mlx5/qp.h b/drivers/infiniband/hw/mlx5/qp.h index 5d4e140db99c..fb2f4e030bb8 100644 --- a/drivers/infiniband/hw/mlx5/qp.h +++ b/drivers/infiniband/hw/mlx5/qp.h @@ -44,4 +44,6 @@ void mlx5_core_res_put(struct mlx5_core_rsc_common *res); int mlx5_core_xrcd_alloc(struct mlx5_ib_dev *dev, u32 *xrcdn); int mlx5_core_xrcd_dealloc(struct mlx5_ib_dev *dev, u32 xrcdn); int mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter); +int mlx5_ib_qp_event_init(void); +void mlx5_ib_qp_event_cleanup(void); #endif /* _MLX5_IB_QP_H */ diff --git a/drivers/infiniband/hw/mlx5/qpc.c b/drivers/infiniband/hw/mlx5/qpc.c index 542e4c63a8de..604af1fd6397 100644 --- a/drivers/infiniband/hw/mlx5/qpc.c +++ b/drivers/infiniband/hw/mlx5/qpc.c @@ -135,7 +135,8 @@ static int rsc_event_notifier(struct notifier_block *nb, case MLX5_RES_SQ: qp = (struct mlx5_core_qp *)common; qp->event(qp, event_type); - break; + /* Need to put resource in event handler */ + return NOTIFY_OK; case MLX5_RES_DCT: dct = (struct mlx5_core_dct *)common; if (event_type == MLX5_EVENT_TYPE_DCT_DRAINED) diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 48cfaa7eaf50..913ed255990f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -46,6 +46,13 @@ #define MLX4_BF_QP_SKIP_MASK 0xc0 #define MLX4_MAX_BF_QP_RANGE 0x40 +void mlx4_put_qp(struct mlx4_qp *qp) +{ + if (refcount_dec_and_test(&qp->refcount)) + complete(&qp->free); +} +EXPORT_SYMBOL_GPL(mlx4_put_qp); + void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type) { struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; @@ -64,10 +71,8 @@ void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type) return; } + /* Need to call mlx4_put_qp() in event handler */ qp->event(qp, event_type); - - if (refcount_dec_and_test(&qp->refcount)) - complete(&qp->free); } /* used for INIT/CLOSE port logic */ @@ -523,8 +528,7 @@ EXPORT_SYMBOL_GPL(mlx4_qp_remove); void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) { - if (refcount_dec_and_test(&qp->refcount)) - complete(&qp->free); + mlx4_put_qp(qp); wait_for_completion(&qp->free); mlx4_qp_free_icm(dev, qp->qpn); diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 9db93e487496..c78b90f2e9a1 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -503,4 +503,5 @@ static inline u16 folded_qp(u32 q) u16 mlx4_qp_roce_entropy(struct mlx4_dev *dev, u32 qpn); +void mlx4_put_qp(struct mlx4_qp *qp); #endif /* MLX4_QP_H */ diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index a9a429172c0a..949cf4ffc536 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1168,7 +1168,7 @@ enum ib_qp_create_flags { */ struct ib_qp_init_attr { - /* Consumer's event_handler callback must not block */ + /* This callback occurs in workqueue context */ void (*event_handler)(struct ib_event *, void *); void *qp_context; -- cgit v1.2.3 From a0c01bc565332cff9183bd8a17b4db94732d645d Mon Sep 17 00:00:00 2001 From: Apurva Nandan Date: Thu, 12 Jan 2023 19:57:23 +0530 Subject: dt-bindings: pinctrl: k3: Introduce pinmux definitions for J784s4 Add pinctrl macros for J784s4 SoC. These macro definitions are similar to that of J721s2, but adding new definitions to avoid any naming confusions in the soc dts files. checkpatch insists the following error exists: ERROR: Macros with complex values should be enclosed in parentheses However, we do not need parentheses enclosing the values for this macro as we do intend it to generate two separate values as has been done for other similar platforms. Signed-off-by: Hari Nagalla Signed-off-by: Apurva Nandan Acked-by: Rob Herring Acked-by: Linus Walleij Signed-off-by: Vignesh Raghavendra Link: https://lore.kernel.org/r/20230112142725.77785-3-a-nandan@ti.com --- include/dt-bindings/pinctrl/k3.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/dt-bindings/pinctrl/k3.h b/include/dt-bindings/pinctrl/k3.h index 54df633f9bfe..6bb9df1a264d 100644 --- a/include/dt-bindings/pinctrl/k3.h +++ b/include/dt-bindings/pinctrl/k3.h @@ -47,4 +47,7 @@ #define J721S2_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) #define J721S2_WKUP_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) +#define J784S4_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) +#define J784S4_WKUP_IOPAD(pa, val, muxmode) (((pa) & 0x1fff)) ((val) | (muxmode)) + #endif -- cgit v1.2.3 From d219df60a70ed0739aa5dd34b477763311fc5a7b Mon Sep 17 00:00:00 2001 From: Ziyang Xuan Date: Fri, 13 Jan 2023 17:24:51 +0800 Subject: bpf: Add ipip6 and ip6ip decap support for bpf_skb_adjust_room() Add ipip6 and ip6ip decap support for bpf_skb_adjust_room(). Main use case is for using cls_bpf on ingress hook to decapsulate IPv4 over IPv6 and IPv6 over IPv4 tunnel packets. Add two new flags BPF_F_ADJ_ROOM_DECAP_L3_IPV{4,6} to indicate the new IP header version after decapsulating the outer IP header. Suggested-by: Willem de Bruijn Signed-off-by: Ziyang Xuan Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/b268ec7f0ff9431f4f43b1b40ab856ebb28cb4e1.1673574419.git.william.xuanziyang@huawei.com Signed-off-by: Martin KaFai Lau --- include/uapi/linux/bpf.h | 7 +++++++ net/core/filter.c | 31 ++++++++++++++++++++++++++++++- tools/include/uapi/linux/bpf.h | 7 +++++++ 3 files changed, 44 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index bc1a3d232ae4..adae5b168f9d 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -2647,6 +2647,11 @@ union bpf_attr { * Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the * L2 type as Ethernet. * + * * **BPF_F_ADJ_ROOM_DECAP_L3_IPV4**, + * **BPF_F_ADJ_ROOM_DECAP_L3_IPV6**: + * Indicate the new IP header version after decapsulating the outer + * IP header. Used when the inner and outer IP versions are different. + * * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be @@ -5807,6 +5812,8 @@ enum { BPF_F_ADJ_ROOM_ENCAP_L4_UDP = (1ULL << 4), BPF_F_ADJ_ROOM_NO_CSUM_RESET = (1ULL << 5), BPF_F_ADJ_ROOM_ENCAP_L2_ETH = (1ULL << 6), + BPF_F_ADJ_ROOM_DECAP_L3_IPV4 = (1ULL << 7), + BPF_F_ADJ_ROOM_DECAP_L3_IPV6 = (1ULL << 8), }; enum { diff --git a/net/core/filter.c b/net/core/filter.c index d9befa6ba04e..b4547a2c02f4 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3381,13 +3381,17 @@ static u32 bpf_skb_net_base_len(const struct sk_buff *skb) #define BPF_F_ADJ_ROOM_ENCAP_L3_MASK (BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 | \ BPF_F_ADJ_ROOM_ENCAP_L3_IPV6) +#define BPF_F_ADJ_ROOM_DECAP_L3_MASK (BPF_F_ADJ_ROOM_DECAP_L3_IPV4 | \ + BPF_F_ADJ_ROOM_DECAP_L3_IPV6) + #define BPF_F_ADJ_ROOM_MASK (BPF_F_ADJ_ROOM_FIXED_GSO | \ BPF_F_ADJ_ROOM_ENCAP_L3_MASK | \ BPF_F_ADJ_ROOM_ENCAP_L4_GRE | \ BPF_F_ADJ_ROOM_ENCAP_L4_UDP | \ BPF_F_ADJ_ROOM_ENCAP_L2_ETH | \ BPF_F_ADJ_ROOM_ENCAP_L2( \ - BPF_ADJ_ROOM_ENCAP_L2_MASK)) + BPF_ADJ_ROOM_ENCAP_L2_MASK) | \ + BPF_F_ADJ_ROOM_DECAP_L3_MASK) static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff, u64 flags) @@ -3501,6 +3505,7 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff, int ret; if (unlikely(flags & ~(BPF_F_ADJ_ROOM_FIXED_GSO | + BPF_F_ADJ_ROOM_DECAP_L3_MASK | BPF_F_ADJ_ROOM_NO_CSUM_RESET))) return -EINVAL; @@ -3519,6 +3524,14 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff, if (unlikely(ret < 0)) return ret; + /* Match skb->protocol to new outer l3 protocol */ + if (skb->protocol == htons(ETH_P_IP) && + flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV6) + skb->protocol = htons(ETH_P_IPV6); + else if (skb->protocol == htons(ETH_P_IPV6) && + flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV4) + skb->protocol = htons(ETH_P_IP); + if (skb_is_gso(skb)) { struct skb_shared_info *shinfo = skb_shinfo(skb); @@ -3608,6 +3621,22 @@ BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff, return -ENOTSUPP; } + if (flags & BPF_F_ADJ_ROOM_DECAP_L3_MASK) { + if (!shrink) + return -EINVAL; + + switch (flags & BPF_F_ADJ_ROOM_DECAP_L3_MASK) { + case BPF_F_ADJ_ROOM_DECAP_L3_IPV4: + len_min = sizeof(struct iphdr); + break; + case BPF_F_ADJ_ROOM_DECAP_L3_IPV6: + len_min = sizeof(struct ipv6hdr); + break; + default: + return -EINVAL; + } + } + len_cur = skb->len - skb_network_offset(skb); if ((shrink && (len_diff_abs >= len_cur || len_cur - len_diff_abs < len_min)) || diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index bc1a3d232ae4..142b81bcbb2e 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -2647,6 +2647,11 @@ union bpf_attr { * Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the * L2 type as Ethernet. * + * * **BPF_F_ADJ_ROOM_DECAP_L3_IPV4**, + * **BPF_F_ADJ_ROOM_DECAP_L3_IPV6**: + * Indicate the new IP header version after decapsulating the outer + * IP header. Used when the inner and outer IP versions are different. + * * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be @@ -5807,6 +5812,8 @@ enum { BPF_F_ADJ_ROOM_ENCAP_L4_UDP = (1ULL << 4), BPF_F_ADJ_ROOM_NO_CSUM_RESET = (1ULL << 5), BPF_F_ADJ_ROOM_ENCAP_L2_ETH = (1ULL << 6), + BPF_F_ADJ_ROOM_DECAP_L3_IPV4 = (1ULL << 7), + BPF_F_ADJ_ROOM_DECAP_L3_IPV6 = (1ULL << 8), }; enum { -- cgit v1.2.3 From 716c330433e3ad6074d057092b98c09a989e17d8 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 5 Jan 2023 14:52:58 +0100 Subject: media: uvcvideo: Use standard names for menus Instead of duplicating the menu info, use the one from the core. Also, do not use extra memory for 1:1 mappings. Suggested-by: Laurent Pinchart Signed-off-by: Ricardo Ribalda Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- drivers/media/usb/uvc/uvc_ctrl.c | 129 ++++++++++++++++++++++++++++----------- drivers/media/usb/uvc/uvc_v4l2.c | 105 +++++++++++++++++++++++-------- drivers/media/usb/uvc/uvcvideo.h | 3 +- include/uapi/linux/uvcvideo.h | 4 +- 4 files changed, 176 insertions(+), 65 deletions(-) (limited to 'include') diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 6354efffe9b0..ee58f0db2763 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -364,19 +364,45 @@ static const u32 uvc_control_classes[] = { V4L2_CID_USER_CLASS, }; -static const struct uvc_menu_info power_line_frequency_controls[] = { - { 0, "Disabled" }, - { 1, "50 Hz" }, - { 2, "60 Hz" }, - { 3, "Auto" }, -}; +static const int exposure_auto_mapping[] = { 2, 1, 4, 8 }; -static const struct uvc_menu_info exposure_auto_controls[] = { - { 2, "Auto Mode" }, - { 1, "Manual Mode" }, - { 4, "Shutter Priority Mode" }, - { 8, "Aperture Priority Mode" }, -}; +/* + * This function translates the V4L2 menu index @idx, as exposed to userspace as + * the V4L2 control value, to the corresponding UVC control value used by the + * device. The custom menu_mapping in the control @mapping is used when + * available, otherwise the function assumes that the V4L2 and UVC values are + * identical. + * + * For controls of type UVC_CTRL_DATA_TYPE_BITMASK, the UVC control value is + * expressed as a bitmask and is thus guaranteed to have a single bit set. + * + * The function returns -EINVAL if the V4L2 menu index @idx isn't valid for the + * control, which includes all controls whose type isn't UVC_CTRL_DATA_TYPE_ENUM + * or UVC_CTRL_DATA_TYPE_BITMASK. + */ +static int uvc_mapping_get_menu_value(const struct uvc_control_mapping *mapping, + u32 idx) +{ + if (!test_bit(idx, &mapping->menu_mask)) + return -EINVAL; + + if (mapping->menu_mapping) + return mapping->menu_mapping[idx]; + + return idx; +} + +static const char * +uvc_mapping_get_menu_name(const struct uvc_control_mapping *mapping, u32 idx) +{ + if (!test_bit(idx, &mapping->menu_mask)) + return NULL; + + if (mapping->menu_names) + return mapping->menu_names[idx]; + + return v4l2_ctrl_get_menu(mapping->id)[idx]; +} static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query, const u8 *data) @@ -525,7 +551,7 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_MENU, .data_type = UVC_CTRL_DATA_TYPE_BITMASK, - .menu_info = exposure_auto_controls, + .menu_mapping = exposure_auto_mapping, .menu_mask = GENMASK(V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO), .slave_ids = { V4L2_CID_EXPOSURE_ABSOLUTE, }, @@ -731,7 +757,6 @@ const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = { .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_MENU, .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls, .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ, V4L2_CID_POWER_LINE_FREQUENCY_50HZ), }; @@ -744,7 +769,6 @@ const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11 = { .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_MENU, .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls, .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ, V4L2_CID_POWER_LINE_FREQUENCY_DISABLED), }; @@ -762,7 +786,6 @@ static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = { .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_MENU, .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls, .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO, V4L2_CID_POWER_LINE_FREQUENCY_DISABLED), }; @@ -995,13 +1018,17 @@ static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, s32 value = mapping->get(mapping, UVC_GET_CUR, data); if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { - const struct uvc_menu_info *menu = mapping->menu_info; unsigned int i; - for (i = 0; BIT(i) <= mapping->menu_mask; ++i, ++menu) { + for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { + u32 menu_value; + if (!test_bit(i, &mapping->menu_mask)) continue; - if (menu->value == value) { + + menu_value = uvc_mapping_get_menu_value(mapping, i); + + if (menu_value == value) { value = i; break; } @@ -1212,7 +1239,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, { struct uvc_control_mapping *master_map = NULL; struct uvc_control *master_ctrl = NULL; - const struct uvc_menu_info *menu; unsigned int i; memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); @@ -1257,11 +1283,15 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1; v4l2_ctrl->step = 1; - menu = mapping->menu_info; - for (i = 0; BIT(i) <= mapping->menu_mask; ++i, ++menu) { + for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { + u32 menu_value; + if (!test_bit(i, &mapping->menu_mask)) continue; - if (menu->value == v4l2_ctrl->default_value) { + + menu_value = uvc_mapping_get_menu_value(mapping, i); + + if (menu_value == v4l2_ctrl->default_value) { v4l2_ctrl->default_value = i; break; } @@ -1360,11 +1390,11 @@ done: int uvc_query_v4l2_menu(struct uvc_video_chain *chain, struct v4l2_querymenu *query_menu) { - const struct uvc_menu_info *menu_info; struct uvc_control_mapping *mapping; struct uvc_control *ctrl; u32 index = query_menu->index; u32 id = query_menu->id; + const char *name; int ret; memset(query_menu, 0, sizeof(*query_menu)); @@ -1386,22 +1416,34 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, goto done; } - menu_info = &mapping->menu_info[query_menu->index]; - if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) { + int mask; + if (!ctrl->cached) { ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) goto done; } - if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & menu_info->value)) { + mask = uvc_mapping_get_menu_value(mapping, query_menu->index); + if (mask < 0) { + ret = mask; + goto done; + } + + if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & mask)) { ret = -EINVAL; goto done; } } - strscpy(query_menu->name, menu_info->name, sizeof(query_menu->name)); + name = uvc_mapping_get_menu_name(mapping, query_menu->index); + if (!name) { + ret = -EINVAL; + goto done; + } + + strscpy(query_menu->name, name, sizeof(query_menu->name)); done: mutex_unlock(&chain->ctrl_mutex); @@ -1902,7 +1944,7 @@ int uvc_ctrl_set(struct uvc_fh *handle, if (!test_bit(xctrl->value, &mapping->menu_mask)) return -EINVAL; - value = mapping->menu_info[xctrl->value].value; + value = uvc_mapping_get_menu_value(mapping, xctrl->value); /* * Valid menu indices are reported by the GET_RES request for @@ -2327,7 +2369,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, return -ENOMEM; map->name = NULL; - map->menu_info = NULL; + map->menu_names = NULL; + map->menu_mapping = NULL; /* For UVCIOC_CTRL_MAP custom control */ if (mapping->name) { @@ -2338,10 +2381,22 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, INIT_LIST_HEAD(&map->ev_subs); - size = sizeof(*mapping->menu_info) * fls(mapping->menu_mask); - map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL); - if (!map->menu_info) - goto err_nomem; + if (mapping->menu_mapping && mapping->menu_mask) { + size = sizeof(mapping->menu_mapping[0]) + * fls(mapping->menu_mask); + map->menu_mapping = kmemdup(mapping->menu_mapping, size, + GFP_KERNEL); + if (!map->menu_mapping) + goto err_nomem; + } + if (mapping->menu_names && mapping->menu_mask) { + size = sizeof(mapping->menu_names[0]) + * fls(mapping->menu_mask); + map->menu_names = kmemdup(mapping->menu_names, size, + GFP_KERNEL); + if (!map->menu_names) + goto err_nomem; + } if (map->get == NULL) map->get = uvc_get_le_value; @@ -2364,7 +2419,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, return 0; err_nomem: - kfree(map->menu_info); + kfree(map->menu_names); + kfree(map->menu_mapping); kfree(map->name); kfree(map); return -ENOMEM; @@ -2689,7 +2745,8 @@ static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev, list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) { list_del(&mapping->list); - kfree(mapping->menu_info); + kfree(mapping->menu_names); + kfree(mapping->menu_mapping); kfree(mapping->name); kfree(mapping); } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 950b42d78a10..35453f81c1d9 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -26,14 +26,84 @@ #include "uvcvideo.h" +static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain, + struct uvc_control_mapping *map, + const struct uvc_xu_control_mapping *xmap) +{ + unsigned int i; + size_t size; + int ret; + + /* + * Prevent excessive memory consumption, as well as integer + * overflows. + */ + if (xmap->menu_count == 0 || + xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) + return -EINVAL; + + map->menu_names = NULL; + map->menu_mapping = NULL; + + map->menu_mask = BIT_MASK(xmap->menu_count); + + size = xmap->menu_count * sizeof(*map->menu_mapping); + map->menu_mapping = kzalloc(size, GFP_KERNEL); + if (!map->menu_mapping) { + ret = -ENOMEM; + goto done; + } + + for (i = 0; i < xmap->menu_count ; i++) { + if (copy_from_user((u32 *)&map->menu_mapping[i], + &xmap->menu_info[i].value, + sizeof(map->menu_mapping[i]))) { + ret = -EACCES; + goto done; + } + } + + /* + * Always use the standard naming if available, otherwise copy the + * names supplied by userspace. + */ + if (!v4l2_ctrl_get_menu(map->id)) { + size = xmap->menu_count * sizeof(map->menu_names[0]); + map->menu_names = kzalloc(size, GFP_KERNEL); + if (!map->menu_names) { + ret = -ENOMEM; + goto done; + } + + for (i = 0; i < xmap->menu_count ; i++) { + /* sizeof(names[i]) - 1: to take care of \0 */ + if (copy_from_user((char *)map->menu_names[i], + xmap->menu_info[i].name, + sizeof(map->menu_names[i]) - 1)) { + ret = -EACCES; + goto done; + } + } + } + + ret = uvc_ctrl_add_mapping(chain, map); + +done: + kfree(map->menu_names); + map->menu_names = NULL; + kfree(map->menu_mapping); + map->menu_mapping = NULL; + + return ret; +} + /* ------------------------------------------------------------------------ * UVC ioctls */ -static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, - struct uvc_xu_control_mapping *xmap) +static int uvc_ioctl_xu_ctrl_map(struct uvc_video_chain *chain, + struct uvc_xu_control_mapping *xmap) { struct uvc_control_mapping *map; - unsigned int size; int ret; map = kzalloc(sizeof(*map), GFP_KERNEL); @@ -61,39 +131,20 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, case V4L2_CTRL_TYPE_INTEGER: case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BUTTON: + ret = uvc_ctrl_add_mapping(chain, map); break; case V4L2_CTRL_TYPE_MENU: - /* - * Prevent excessive memory consumption, as well as integer - * overflows. - */ - if (xmap->menu_count == 0 || - xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) { - ret = -EINVAL; - goto free_map; - } - - size = xmap->menu_count * sizeof(*map->menu_info); - map->menu_info = memdup_user(xmap->menu_info, size); - if (IS_ERR(map->menu_info)) { - ret = PTR_ERR(map->menu_info); - goto free_map; - } - - map->menu_mask = GENMASK(xmap->menu_count - 1, 0); + ret = uvc_control_add_xu_mapping(chain, map, xmap); break; default: uvc_dbg(chain->dev, CONTROL, "Unsupported V4L2 control type %u\n", xmap->v4l2_type); ret = -ENOTTY; - goto free_map; + break; } - ret = uvc_ctrl_add_mapping(chain, map); - - kfree(map->menu_info); free_map: kfree(map); @@ -1314,7 +1365,7 @@ static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, switch (cmd) { /* Dynamic controls. */ case UVCIOC_CTRL_MAP: - return uvc_ioctl_ctrl_map(chain, arg); + return uvc_ioctl_xu_ctrl_map(chain, arg); case UVCIOC_CTRL_QUERY: return uvc_xu_ctrl_query(chain, arg); @@ -1427,7 +1478,7 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); if (ret) return ret; - ret = uvc_ioctl_ctrl_map(handle->chain, &karg.xmap); + ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap); if (ret) return ret; ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 178729467967..e85df8deb965 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -114,7 +114,8 @@ struct uvc_control_mapping { enum v4l2_ctrl_type v4l2_type; u32 data_type; - const struct uvc_menu_info *menu_info; + const u32 *menu_mapping; + const char (*menu_names)[UVC_MENU_NAME_LEN]; unsigned long menu_mask; u32 master_id; diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h index 8288137387c0..d45d0c2ea252 100644 --- a/include/uapi/linux/uvcvideo.h +++ b/include/uapi/linux/uvcvideo.h @@ -36,9 +36,11 @@ UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES | \ UVC_CTRL_FLAG_GET_DEF) +#define UVC_MENU_NAME_LEN 32 + struct uvc_menu_info { __u32 value; - __u8 name[32]; + __u8 name[UVC_MENU_NAME_LEN]; }; struct uvc_xu_control_mapping { -- cgit v1.2.3 From b839212988575c701aab4d3d9ca15e44c87e383c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 5 Jan 2023 22:17:04 -0800 Subject: media: uvcvideo: Silence memcpy() run-time false positive warnings The memcpy() in uvc_video_decode_meta() intentionally copies across the length and flags members and into the trailing buf flexible array. Split the copy so that the compiler can better reason about (the lack of) buffer overflows here. Avoid the run-time false positive warning: memcpy: detected field-spanning write (size 12) of single field "&meta->length" at drivers/media/usb/uvc/uvc_video.c:1355 (size 1) Additionally fix a typo in the documentation for struct uvc_meta_buf. Reported-by: ionut_n2001@yahoo.com Link: https://bugzilla.kernel.org/show_bug.cgi?id=216810 Signed-off-by: Kees Cook Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- drivers/media/usb/uvc/uvc_video.c | 4 +++- include/uapi/linux/uvcvideo.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 98d34d20afe3..d4b023d4de7c 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1356,7 +1356,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, if (has_scr) memcpy(stream->clock.last_scr, scr, 6); - memcpy(&meta->length, mem, length); + meta->length = mem[0]; + meta->flags = mem[1]; + memcpy(meta->buf, &mem[2], length - 2); meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof); uvc_dbg(stream->dev, FRAME, diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h index d45d0c2ea252..f86185456dc5 100644 --- a/include/uapi/linux/uvcvideo.h +++ b/include/uapi/linux/uvcvideo.h @@ -88,7 +88,7 @@ struct uvc_xu_control_query { * struct. The first two fields are added by the driver, they can be used for * clock synchronisation. The rest is an exact copy of a UVC payload header. * Only complete objects with complete buffers are included. Therefore it's - * always sizeof(meta->ts) + sizeof(meta->sof) + meta->length bytes large. + * always sizeof(meta->ns) + sizeof(meta->sof) + meta->length bytes large. */ struct uvc_meta_buf { __u64 ns; -- cgit v1.2.3 From 1ff45e6da54fc66ab2f9b4d3b202b29d1a706e01 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Sep 2022 15:16:38 +0200 Subject: ARM: sa1100: remove irda references IRDA support is long gone, so there is no need to declare the platform device data. See-also: d64c2a76123f ("staging: irda: remove the irda network stack and drivers") Signed-off-by: Arnd Bergmann fixup sa1100 irda Signed-off-by: Arnd Bergmann --- arch/arm/mach-sa1100/assabet.c | 34 --------------------------- arch/arm/mach-sa1100/collie.c | 33 --------------------------- arch/arm/mach-sa1100/generic.c | 19 ---------------- arch/arm/mach-sa1100/generic.h | 3 --- arch/arm/mach-sa1100/h3600.c | 38 ------------------------------- include/linux/platform_data/irda-sa11x0.h | 17 -------------- 6 files changed, 144 deletions(-) delete mode 100644 include/linux/platform_data/irda-sa11x0.h (limited to 'include') diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 9919e0f32c4b..2eba112f2ad8 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -38,7 +38,6 @@ #include #include -#include #include #include #include @@ -297,38 +296,6 @@ static struct resource assabet_flash_resources[] = { }; -/* - * Assabet IrDA support code. - */ - -static int assabet_irda_set_power(struct device *dev, unsigned int state) -{ - static unsigned int bcr_state[4] = { - ASSABET_BCR_IRDA_MD0, - ASSABET_BCR_IRDA_MD1|ASSABET_BCR_IRDA_MD0, - ASSABET_BCR_IRDA_MD1, - 0 - }; - - if (state < 4) - ASSABET_BCR_frob(ASSABET_BCR_IRDA_MD1 | ASSABET_BCR_IRDA_MD0, - bcr_state[state]); - return 0; -} - -static void assabet_irda_set_speed(struct device *dev, unsigned int speed) -{ - if (speed < 4000000) - ASSABET_BCR_clear(ASSABET_BCR_IRDA_FSEL); - else - ASSABET_BCR_set(ASSABET_BCR_IRDA_FSEL); -} - -static struct irda_platform_data assabet_irda_data = { - .set_power = assabet_irda_set_power, - .set_speed = assabet_irda_set_speed, -}; - static struct ucb1x00_plat_data assabet_ucb1x00_data = { .reset = assabet_ucb1x00_reset, .gpio_base = -1, @@ -618,7 +585,6 @@ static void __init assabet_init(void) #endif sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources, ARRAY_SIZE(assabet_flash_resources)); - sa11x0_register_irda(&assabet_irda_data); sa11x0_register_mcp(&assabet_mcp_data); if (!machine_has_neponset()) diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 14c33ed05318..466d755d5702 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -118,37 +117,6 @@ static struct gpiod_lookup_table collie_battery_gpiod_table = { }, }; -static int collie_ir_startup(struct device *dev) -{ - int rc = gpio_request(COLLIE_GPIO_IR_ON, "IrDA"); - if (rc) - return rc; - rc = gpio_direction_output(COLLIE_GPIO_IR_ON, 1); - - if (!rc) - return 0; - - gpio_free(COLLIE_GPIO_IR_ON); - return rc; -} - -static void collie_ir_shutdown(struct device *dev) -{ - gpio_free(COLLIE_GPIO_IR_ON); -} - -static int collie_ir_set_power(struct device *dev, unsigned int state) -{ - gpio_set_value(COLLIE_GPIO_IR_ON, !state); - return 0; -} - -static struct irda_platform_data collie_ir_data = { - .startup = collie_ir_startup, - .shutdown = collie_ir_shutdown, - .set_power = collie_ir_set_power, -}; - /* * Collie AC IN */ @@ -420,7 +388,6 @@ static void __init collie_init(void) sa11x0_register_mtd(&collie_flash_data, collie_flash_resources, ARRAY_SIZE(collie_flash_resources)); sa11x0_register_mcp(&collie_mcp_data); - sa11x0_register_irda(&collie_ir_data); sharpsl_save_param(); } diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 6c21f214cd60..0c586047d130 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -250,25 +250,6 @@ void sa11x0_register_mtd(struct flash_platform_data *flash, sa11x0_register_device(&sa11x0mtd_device, flash); } -static struct resource sa11x0ir_resources[] = { - DEFINE_RES_MEM(__PREG(Ser2UTCR0), 0x24), - DEFINE_RES_MEM(__PREG(Ser2HSCR0), 0x1c), - DEFINE_RES_MEM(__PREG(Ser2HSCR2), 0x04), - DEFINE_RES_IRQ(IRQ_Ser2ICP), -}; - -static struct platform_device sa11x0ir_device = { - .name = "sa11x0-ir", - .id = -1, - .num_resources = ARRAY_SIZE(sa11x0ir_resources), - .resource = sa11x0ir_resources, -}; - -void sa11x0_register_irda(struct irda_platform_data *irda) -{ - sa11x0_register_device(&sa11x0ir_device, irda); -} - static struct resource sa1100_rtc_resources[] = { DEFINE_RES_MEM(0x90010000, 0x40), DEFINE_RES_IRQ_NAMED(IRQ_RTC1Hz, "rtc 1Hz"), diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 158a4fd5ca24..5fe0d4fc0f8c 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -30,9 +30,6 @@ struct resource; void sa11x0_register_mtd(struct flash_platform_data *flash, struct resource *res, int nr); -struct irda_platform_data; -void sa11x0_register_irda(struct irda_platform_data *irda); - struct mcp_plat_data; void sa11x0_ppc_configure_mcp(void); void sa11x0_register_mcp(struct mcp_plat_data *data); diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index baf529117b26..5e25dfa752e9 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -14,7 +14,6 @@ #include #include -#include #include #include @@ -90,48 +89,11 @@ static void __init h3600_map_io(void) h3xxx_map_io(); } -/* - * This turns the IRDA power on or off on the Compaq H3600 - */ -static struct gpio h3600_irda_gpio[] = { - { H3600_EGPIO_IR_ON, GPIOF_OUT_INIT_LOW, "IrDA power" }, - { H3600_EGPIO_IR_FSEL, GPIOF_OUT_INIT_LOW, "IrDA fsel" }, -}; - -static int h3600_irda_set_power(struct device *dev, unsigned int state) -{ - gpio_set_value(H3600_EGPIO_IR_ON, state); - return 0; -} - -static void h3600_irda_set_speed(struct device *dev, unsigned int speed) -{ - gpio_set_value(H3600_EGPIO_IR_FSEL, !(speed < 4000000)); -} - -static int h3600_irda_startup(struct device *dev) -{ - return gpio_request_array(h3600_irda_gpio, sizeof(h3600_irda_gpio)); -} - -static void h3600_irda_shutdown(struct device *dev) -{ - return gpio_free_array(h3600_irda_gpio, sizeof(h3600_irda_gpio)); -} - -static struct irda_platform_data h3600_irda_data = { - .set_power = h3600_irda_set_power, - .set_speed = h3600_irda_set_speed, - .startup = h3600_irda_startup, - .shutdown = h3600_irda_shutdown, -}; - static void __init h3600_mach_init(void) { h3xxx_mach_init(); sa11x0_register_lcd(&h3600_lcd_info); - sa11x0_register_irda(&h3600_irda_data); } MACHINE_START(H3600, "Compaq iPAQ H3600") diff --git a/include/linux/platform_data/irda-sa11x0.h b/include/linux/platform_data/irda-sa11x0.h deleted file mode 100644 index 7db59c917575..000000000000 --- a/include/linux/platform_data/irda-sa11x0.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/include/asm/mach/irda.h - * - * Copyright (C) 2004 Russell King. - */ -#ifndef __ASM_ARM_MACH_IRDA_H -#define __ASM_ARM_MACH_IRDA_H - -struct irda_platform_data { - int (*startup)(struct device *); - void (*shutdown)(struct device *); - int (*set_power)(struct device *, unsigned int state); - void (*set_speed)(struct device *, unsigned int speed); -}; - -#endif -- cgit v1.2.3 From 028908f2ca6fc046a9932fb2d2f0409f4684ea41 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Sep 2022 09:25:25 +0200 Subject: ARM: mmp: remove custom sram code The MMP_SRAM code is no longer used by the tdma driver because the Kconfig symbol is not selected, so remove it along with its former callsite. Acked-By: Vinod Koul Signed-off-by: Arnd Bergmann --- arch/arm/mach-mmp/Makefile | 1 - arch/arm/mach-mmp/mmp2.h | 13 --- arch/arm/mach-mmp/sram.c | 167 ----------------------------- drivers/dma/mmp_tdma.c | 7 +- include/linux/platform_data/dma-mmp_tdma.h | 36 ------- 5 files changed, 2 insertions(+), 222 deletions(-) delete mode 100644 arch/arm/mach-mmp/sram.c delete mode 100644 include/linux/platform_data/dma-mmp_tdma.h (limited to 'include') diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile index 65cc9b691983..cd874c5a6cb8 100644 --- a/arch/arm/mach-mmp/Makefile +++ b/arch/arm/mach-mmp/Makefile @@ -8,7 +8,6 @@ obj-y += common.o devices.o time.o obj-$(CONFIG_CPU_PXA168) += pxa168.o obj-$(CONFIG_CPU_PXA910) += pxa910.o obj-$(CONFIG_CPU_MMP2) += mmp2.o -obj-$(CONFIG_MMP_SRAM) += sram.o ifeq ($(CONFIG_PM),y) obj-$(CONFIG_CPU_PXA910) += pm-pxa910.o diff --git a/arch/arm/mach-mmp/mmp2.h b/arch/arm/mach-mmp/mmp2.h index 7f80b90248fb..5c80836aea76 100644 --- a/arch/arm/mach-mmp/mmp2.h +++ b/arch/arm/mach-mmp/mmp2.h @@ -10,7 +10,6 @@ extern void mmp2_clear_pmic_int(void); #include #include -#include #include #include "devices.h" @@ -29,8 +28,6 @@ extern struct mmp_device_desc mmp2_device_sdh0; extern struct mmp_device_desc mmp2_device_sdh1; extern struct mmp_device_desc mmp2_device_sdh2; extern struct mmp_device_desc mmp2_device_sdh3; -extern struct mmp_device_desc mmp2_device_asram; -extern struct mmp_device_desc mmp2_device_isram; extern struct platform_device mmp2_device_gpio; @@ -90,15 +87,5 @@ static inline int mmp2_add_sdhost(int id, struct sdhci_pxa_platdata *data) return mmp_register_device(d, data, sizeof(*data)); } -static inline int mmp2_add_asram(struct sram_platdata *data) -{ - return mmp_register_device(&mmp2_device_asram, data, sizeof(*data)); -} - -static inline int mmp2_add_isram(struct sram_platdata *data) -{ - return mmp_register_device(&mmp2_device_isram, data, sizeof(*data)); -} - #endif /* __ASM_MACH_MMP2_H */ diff --git a/arch/arm/mach-mmp/sram.c b/arch/arm/mach-mmp/sram.c deleted file mode 100644 index ecc46c31004f..000000000000 --- a/arch/arm/mach-mmp/sram.c +++ /dev/null @@ -1,167 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-mmp/sram.c - * - * based on mach-davinci/sram.c - DaVinci simple SRAM allocator - * - * Copyright (c) 2011 Marvell Semiconductors Inc. - * All Rights Reserved - * - * Add for mmp sram support - Leo Yan - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -struct sram_bank_info { - char *pool_name; - struct gen_pool *gpool; - int granularity; - - phys_addr_t sram_phys; - void __iomem *sram_virt; - u32 sram_size; - - struct list_head node; -}; - -static DEFINE_MUTEX(sram_lock); -static LIST_HEAD(sram_bank_list); - -struct gen_pool *sram_get_gpool(char *pool_name) -{ - struct sram_bank_info *info = NULL; - - if (!pool_name) - return NULL; - - mutex_lock(&sram_lock); - - list_for_each_entry(info, &sram_bank_list, node) - if (!strcmp(pool_name, info->pool_name)) - break; - - mutex_unlock(&sram_lock); - - if (&info->node == &sram_bank_list) - return NULL; - - return info->gpool; -} -EXPORT_SYMBOL(sram_get_gpool); - -static int sram_probe(struct platform_device *pdev) -{ - struct sram_platdata *pdata = pdev->dev.platform_data; - struct sram_bank_info *info; - struct resource *res; - int ret = 0; - - if (!pdata || !pdata->pool_name) - return -ENODEV; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - platform_set_drvdata(pdev, info); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no memory resource defined\n"); - ret = -ENODEV; - goto out; - } - - if (!resource_size(res)) - return 0; - - info->sram_phys = (phys_addr_t)res->start; - info->sram_size = resource_size(res); - info->sram_virt = ioremap(info->sram_phys, info->sram_size); - info->pool_name = kstrdup(pdata->pool_name, GFP_KERNEL); - info->granularity = pdata->granularity; - - info->gpool = gen_pool_create(ilog2(info->granularity), -1); - if (!info->gpool) { - dev_err(&pdev->dev, "create pool failed\n"); - ret = -ENOMEM; - goto create_pool_err; - } - - ret = gen_pool_add_virt(info->gpool, (unsigned long)info->sram_virt, - info->sram_phys, info->sram_size, -1); - if (ret < 0) { - dev_err(&pdev->dev, "add new chunk failed\n"); - ret = -ENOMEM; - goto add_chunk_err; - } - - mutex_lock(&sram_lock); - list_add(&info->node, &sram_bank_list); - mutex_unlock(&sram_lock); - - dev_info(&pdev->dev, "initialized\n"); - return 0; - -add_chunk_err: - gen_pool_destroy(info->gpool); -create_pool_err: - iounmap(info->sram_virt); - kfree(info->pool_name); -out: - kfree(info); - return ret; -} - -static int sram_remove(struct platform_device *pdev) -{ - struct sram_bank_info *info; - - info = platform_get_drvdata(pdev); - - if (info->sram_size) { - mutex_lock(&sram_lock); - list_del(&info->node); - mutex_unlock(&sram_lock); - - gen_pool_destroy(info->gpool); - iounmap(info->sram_virt); - kfree(info->pool_name); - } - - kfree(info); - - return 0; -} - -static const struct platform_device_id sram_id_table[] = { - { "asram", MMP_ASRAM }, - { "isram", MMP_ISRAM }, - { } -}; - -static struct platform_driver sram_driver = { - .probe = sram_probe, - .remove = sram_remove, - .driver = { - .name = "mmp-sram", - }, - .id_table = sram_id_table, -}; - -static int __init sram_init(void) -{ - return platform_driver_register(&sram_driver); -} -core_initcall(sram_init); - -MODULE_LICENSE("GPL"); diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index a262e0eb4cc9..d83e608dca05 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -670,10 +670,7 @@ static int mmp_tdma_probe(struct platform_device *pdev) INIT_LIST_HEAD(&tdev->device.channels); - if (pdev->dev.of_node) - pool = of_gen_pool_get(pdev->dev.of_node, "asram", 0); - else - pool = sram_get_gpool("asram"); + pool = of_gen_pool_get(pdev->dev.of_node, "asram", 0); if (!pool) { dev_err(&pdev->dev, "asram pool not available\n"); return -ENOMEM; diff --git a/include/linux/platform_data/dma-mmp_tdma.h b/include/linux/platform_data/dma-mmp_tdma.h deleted file mode 100644 index 8bec5484dc86..000000000000 --- a/include/linux/platform_data/dma-mmp_tdma.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * SRAM Memory Management - * - * Copyright (c) 2011 Marvell Semiconductors Inc. - */ - -#ifndef __DMA_MMP_TDMA_H -#define __DMA_MMP_TDMA_H - -#include - -/* ARBITRARY: SRAM allocations are multiples of this 2^N size */ -#define SRAM_GRANULARITY 512 - -enum sram_type { - MMP_SRAM_UNDEFINED = 0, - MMP_ASRAM, - MMP_ISRAM, -}; - -struct sram_platdata { - char *pool_name; - int granularity; -}; - -#ifdef CONFIG_MMP_SRAM -extern struct gen_pool *sram_get_gpool(char *pool_name); -#else -static inline struct gen_pool *sram_get_gpool(char *pool_name) -{ - return NULL; -} -#endif - -#endif /* __DMA_MMP_TDMA_H */ -- cgit v1.2.3 From 1027b4df8354c55a5ed538e391d4cf9c509b74a7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Sep 2022 12:02:12 +0200 Subject: ARM: mmp: remove old PM support Assuming that we don't actually want the old-style pm-mmp2.c and pm-pxa910.c implementation, all these files can go away as well. Signed-off-by: Arnd Bergmann --- arch/arm/mach-mmp/Kconfig | 3 - arch/arm/mach-mmp/Makefile | 9 -- arch/arm/mach-mmp/irqs.h | 67 ------------- arch/arm/mach-mmp/mmp2.c | 106 -------------------- arch/arm/mach-mmp/mmp2.h | 8 -- arch/arm/mach-mmp/pm-mmp2.c | 214 ---------------------------------------- arch/arm/mach-mmp/pm-mmp2.h | 59 ----------- arch/arm/mach-mmp/pm-pxa910.c | 166 ------------------------------- arch/arm/mach-mmp/pm-pxa910.h | 75 -------------- arch/arm/mach-mmp/pxa168.c | 51 ---------- arch/arm/mach-mmp/pxa168.h | 16 --- arch/arm/mach-mmp/pxa910.c | 93 ----------------- arch/arm/mach-mmp/pxa910.h | 11 --- arch/arm/mach-mmp/regs-icu.h | 69 ------------- include/linux/soc/mmp/cputype.h | 24 +---- 15 files changed, 1 insertion(+), 970 deletions(-) delete mode 100644 arch/arm/mach-mmp/irqs.h delete mode 100644 arch/arm/mach-mmp/mmp2.c delete mode 100644 arch/arm/mach-mmp/mmp2.h delete mode 100644 arch/arm/mach-mmp/pm-mmp2.c delete mode 100644 arch/arm/mach-mmp/pm-mmp2.h delete mode 100644 arch/arm/mach-mmp/pm-pxa910.c delete mode 100644 arch/arm/mach-mmp/pm-pxa910.h delete mode 100644 arch/arm/mach-mmp/pxa168.c delete mode 100644 arch/arm/mach-mmp/pxa168.h delete mode 100644 arch/arm/mach-mmp/pxa910.c delete mode 100644 arch/arm/mach-mmp/pxa910.h delete mode 100644 arch/arm/mach-mmp/regs-icu.h (limited to 'include') diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig index a1396c495b85..85b0d9ddb7d8 100644 --- a/arch/arm/mach-mmp/Kconfig +++ b/arch/arm/mach-mmp/Kconfig @@ -20,8 +20,6 @@ config MACH_MMP_DT select PINCTRL_SINGLE select ARCH_HAS_RESET_CONTROLLER select CPU_MOHAWK - select CPU_PXA168 if ATAGS - select CPU_PXA910 if ATAGS help Include support for Marvell MMP2 based platforms using the device tree. Needn't select any other machine while @@ -34,7 +32,6 @@ config MACH_MMP2_DT select PINCTRL_SINGLE select ARCH_HAS_RESET_CONTROLLER select CPU_PJ4 - select CPU_MMP2 if ATAGS select PM_GENERIC_DOMAINS if PM select PM_GENERIC_DOMAINS_OF if PM && OF help diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile index 95d4217132eb..5d4a1a4a48cf 100644 --- a/arch/arm/mach-mmp/Makefile +++ b/arch/arm/mach-mmp/Makefile @@ -4,15 +4,6 @@ # obj-y += common.o time.o -# SoC support -obj-$(CONFIG_CPU_PXA168) += pxa168.o -obj-$(CONFIG_CPU_PXA910) += pxa910.o -obj-$(CONFIG_CPU_MMP2) += mmp2.o - -ifeq ($(CONFIG_PM),y) -obj-$(CONFIG_CPU_PXA910) += pm-pxa910.o -obj-$(CONFIG_CPU_MMP2) += pm-mmp2.o -endif ifeq ($(CONFIG_SMP),y) obj-$(CONFIG_MACH_MMP3_DT) += platsmp.o endif diff --git a/arch/arm/mach-mmp/irqs.h b/arch/arm/mach-mmp/irqs.h deleted file mode 100644 index b8446a17ea55..000000000000 --- a/arch/arm/mach-mmp/irqs.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_MACH_IRQS_H -#define __ASM_MACH_IRQS_H - -/* - * Interrupt numbers for PXA910 - */ -#define IRQ_PXA910_NONE (-1) -#define IRQ_PXA910_AIRQ 0 -#define IRQ_PXA910_SSP3 1 -#define IRQ_PXA910_SSP2 2 -#define IRQ_PXA910_SSP1 3 -#define IRQ_PXA910_PMIC_INT 4 -#define IRQ_PXA910_RTC_INT 5 -#define IRQ_PXA910_RTC_ALARM 6 -#define IRQ_PXA910_TWSI0 7 -#define IRQ_PXA910_GPU 8 -#define IRQ_PXA910_KEYPAD 9 -#define IRQ_PXA910_ROTARY 10 -#define IRQ_PXA910_TRACKBALL 11 -#define IRQ_PXA910_ONEWIRE 12 -#define IRQ_PXA910_AP1_TIMER1 13 -#define IRQ_PXA910_AP1_TIMER2 14 -#define IRQ_PXA910_AP1_TIMER3 15 -#define IRQ_PXA910_IPC_AP0 16 -#define IRQ_PXA910_IPC_AP1 17 -#define IRQ_PXA910_IPC_AP2 18 -#define IRQ_PXA910_IPC_AP3 19 -#define IRQ_PXA910_IPC_AP4 20 -#define IRQ_PXA910_IPC_CP0 21 -#define IRQ_PXA910_IPC_CP1 22 -#define IRQ_PXA910_IPC_CP2 23 -#define IRQ_PXA910_IPC_CP3 24 -#define IRQ_PXA910_IPC_CP4 25 -#define IRQ_PXA910_L2_DDR 26 -#define IRQ_PXA910_UART2 27 -#define IRQ_PXA910_UART3 28 -#define IRQ_PXA910_AP2_TIMER1 29 -#define IRQ_PXA910_AP2_TIMER2 30 -#define IRQ_PXA910_CP2_TIMER1 31 -#define IRQ_PXA910_CP2_TIMER2 32 -#define IRQ_PXA910_CP2_TIMER3 33 -#define IRQ_PXA910_GSSP 34 -#define IRQ_PXA910_CP2_WDT 35 -#define IRQ_PXA910_MAIN_PMU 36 -#define IRQ_PXA910_CP_FREQ_CHG 37 -#define IRQ_PXA910_AP_FREQ_CHG 38 -#define IRQ_PXA910_MMC 39 -#define IRQ_PXA910_AEU 40 -#define IRQ_PXA910_LCD 41 -#define IRQ_PXA910_CCIC 42 -#define IRQ_PXA910_IRE 43 -#define IRQ_PXA910_USB1 44 -#define IRQ_PXA910_NAND 45 -#define IRQ_PXA910_HIFI_DMA 46 -#define IRQ_PXA910_DMA_INT0 47 -#define IRQ_PXA910_DMA_INT1 48 -#define IRQ_PXA910_AP_GPIO 49 -#define IRQ_PXA910_AP2_TIMER3 50 -#define IRQ_PXA910_USB2 51 -#define IRQ_PXA910_TWSI1 54 -#define IRQ_PXA910_CP_GPIO 55 -#define IRQ_PXA910_UART1 59 /* Slow UART */ -#define IRQ_PXA910_AP_PMU 60 -#define IRQ_PXA910_SM_INT 63 /* from PinMux */ - -#endif /* __ASM_MACH_IRQS_H */ diff --git a/arch/arm/mach-mmp/mmp2.c b/arch/arm/mach-mmp/mmp2.c deleted file mode 100644 index 8ee6a4547731..000000000000 --- a/arch/arm/mach-mmp/mmp2.c +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-mmp/mmp2.c - * - * code name MMP2 - * - * Copyright (C) 2009 Marvell International Ltd. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include "addr-map.h" -#include -#include -#include "mmp2.h" -#include "pm-mmp2.h" - -#include "common.h" - -#define MFPR_VIRT_BASE (APB_VIRT_BASE + 0x1e000) - -static struct mfp_addr_map mmp2_addr_map[] __initdata = { - - MFP_ADDR_X(GPIO0, GPIO58, 0x54), - MFP_ADDR_X(GPIO59, GPIO73, 0x280), - MFP_ADDR_X(GPIO74, GPIO101, 0x170), - - MFP_ADDR(GPIO102, 0x0), - MFP_ADDR(GPIO103, 0x4), - MFP_ADDR(GPIO104, 0x1fc), - MFP_ADDR(GPIO105, 0x1f8), - MFP_ADDR(GPIO106, 0x1f4), - MFP_ADDR(GPIO107, 0x1f0), - MFP_ADDR(GPIO108, 0x21c), - MFP_ADDR(GPIO109, 0x218), - MFP_ADDR(GPIO110, 0x214), - MFP_ADDR(GPIO111, 0x200), - MFP_ADDR(GPIO112, 0x244), - MFP_ADDR(GPIO113, 0x25c), - MFP_ADDR(GPIO114, 0x164), - MFP_ADDR_X(GPIO115, GPIO122, 0x260), - - MFP_ADDR(GPIO123, 0x148), - MFP_ADDR_X(GPIO124, GPIO141, 0xc), - - MFP_ADDR(GPIO142, 0x8), - MFP_ADDR_X(GPIO143, GPIO151, 0x220), - MFP_ADDR_X(GPIO152, GPIO153, 0x248), - MFP_ADDR_X(GPIO154, GPIO155, 0x254), - MFP_ADDR_X(GPIO156, GPIO159, 0x14c), - - MFP_ADDR(GPIO160, 0x250), - MFP_ADDR(GPIO161, 0x210), - MFP_ADDR(GPIO162, 0x20c), - MFP_ADDR(GPIO163, 0x208), - MFP_ADDR(GPIO164, 0x204), - MFP_ADDR(GPIO165, 0x1ec), - MFP_ADDR(GPIO166, 0x1e8), - MFP_ADDR(GPIO167, 0x1e4), - MFP_ADDR(GPIO168, 0x1e0), - - MFP_ADDR_X(TWSI1_SCL, TWSI1_SDA, 0x140), - MFP_ADDR_X(TWSI4_SCL, TWSI4_SDA, 0x2bc), - - MFP_ADDR(PMIC_INT, 0x2c4), - MFP_ADDR(CLK_REQ, 0x160), - - MFP_ADDR_END, -}; - -void mmp2_clear_pmic_int(void) -{ - void __iomem *mfpr_pmic; - unsigned long data; - - mfpr_pmic = APB_VIRT_BASE + 0x1e000 + 0x2c4; - data = __raw_readl(mfpr_pmic); - __raw_writel(data | (1 << 6), mfpr_pmic); - __raw_writel(data, mfpr_pmic); -} - -static int __init mmp2_init(void) -{ - if (cpu_is_mmp2()) { -#ifdef CONFIG_CACHE_TAUROS2 - tauros2_init(0); -#endif - mfp_init_base(MFPR_VIRT_BASE); - mfp_init_addr(mmp2_addr_map); - mmp2_clk_init(APB_PHYS_BASE + 0x50000, - AXI_PHYS_BASE + 0x82800, - APB_PHYS_BASE + 0x15000); - } - - return 0; -} -postcore_initcall(mmp2_init); diff --git a/arch/arm/mach-mmp/mmp2.h b/arch/arm/mach-mmp/mmp2.h deleted file mode 100644 index 6616d3f7a0ac..000000000000 --- a/arch/arm/mach-mmp/mmp2.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_MACH_MMP2_H -#define __ASM_MACH_MMP2_H - -extern void mmp2_clear_pmic_int(void); - -#endif /* __ASM_MACH_MMP2_H */ - diff --git a/arch/arm/mach-mmp/pm-mmp2.c b/arch/arm/mach-mmp/pm-mmp2.c deleted file mode 100644 index bd6563962d77..000000000000 --- a/arch/arm/mach-mmp/pm-mmp2.c +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * MMP2 Power Management Routines - * - * (C) Copyright 2012 Marvell International Ltd. - * All Rights Reserved - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "addr-map.h" -#include "pm-mmp2.h" -#include "regs-icu.h" - -static void pm_scu_clk_disable(void) -{ - unsigned int val; - - /* close AXI fabric clock gate */ - __raw_writel(0x0, CIU_REG(0x64)); - __raw_writel(0x0, CIU_REG(0x68)); - - /* close MCB master clock gate */ - val = __raw_readl(CIU_REG(0x1c)); - val |= 0xf0; - __raw_writel(val, CIU_REG(0x1c)); - - return ; -} - -static void pm_scu_clk_enable(void) -{ - unsigned int val; - - /* open AXI fabric clock gate */ - __raw_writel(0x03003003, CIU_REG(0x64)); - __raw_writel(0x00303030, CIU_REG(0x68)); - - /* open MCB master clock gate */ - val = __raw_readl(CIU_REG(0x1c)); - val &= ~(0xf0); - __raw_writel(val, CIU_REG(0x1c)); - - return ; -} - -static void pm_mpmu_clk_disable(void) -{ - /* - * disable clocks in MPMU_CGR_PJ register - * except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M - */ - __raw_writel(0x0000a010, MPMU_CGR_PJ); -} - -static void pm_mpmu_clk_enable(void) -{ - unsigned int val; - - __raw_writel(0xdffefffe, MPMU_CGR_PJ); - val = __raw_readl(MPMU_PLL2_CTRL1); - val |= (1 << 29); - __raw_writel(val, MPMU_PLL2_CTRL1); - - return ; -} - -void mmp2_pm_enter_lowpower_mode(int state) -{ - uint32_t idle_cfg, apcr; - - idle_cfg = __raw_readl(APMU_PJ_IDLE_CFG); - apcr = __raw_readl(MPMU_PCR_PJ); - apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD | MPMU_PCR_PJ_APBSD - | MPMU_PCR_PJ_AXISD | MPMU_PCR_PJ_VCTCXOSD | (1 << 13)); - idle_cfg &= ~APMU_PJ_IDLE_CFG_PJ_IDLE; - - switch (state) { - case POWER_MODE_SYS_SLEEP: - apcr |= MPMU_PCR_PJ_SLPEN; /* set the SLPEN bit */ - apcr |= MPMU_PCR_PJ_VCTCXOSD; /* set VCTCXOSD */ - fallthrough; - case POWER_MODE_CHIP_SLEEP: - apcr |= MPMU_PCR_PJ_SLPEN; - fallthrough; - case POWER_MODE_APPS_SLEEP: - apcr |= MPMU_PCR_PJ_APBSD; /* set APBSD */ - fallthrough; - case POWER_MODE_APPS_IDLE: - apcr |= MPMU_PCR_PJ_AXISD; /* set AXISDD bit */ - apcr |= MPMU_PCR_PJ_DDRCORSD; /* set DDRCORSD bit */ - idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN; /* PJ power down */ - apcr |= MPMU_PCR_PJ_SPSD; - fallthrough; - case POWER_MODE_CORE_EXTIDLE: - idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE; /* set the IDLE bit */ - idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK; - idle_cfg |= APMU_PJ_IDLE_CFG_PWR_SW(3) - | APMU_PJ_IDLE_CFG_L2_PWR_SW; - break; - case POWER_MODE_CORE_INTIDLE: - apcr &= ~MPMU_PCR_PJ_SPSD; - break; - } - - /* set reserve bits */ - apcr |= (1 << 30) | (1 << 25); - - /* finally write the registers back */ - __raw_writel(idle_cfg, APMU_PJ_IDLE_CFG); - __raw_writel(apcr, MPMU_PCR_PJ); /* 0xfe086000 */ -} - -static int mmp2_pm_enter(suspend_state_t state) -{ - int temp; - - temp = __raw_readl(MMP2_ICU_INT4_MASK); - if (temp & (1 << 1)) { - printk(KERN_ERR "%s: PMIC interrupt is handling\n", __func__); - return -EAGAIN; - } - - temp = __raw_readl(APMU_SRAM_PWR_DWN); - temp |= ((1 << 19) | (1 << 18)); - __raw_writel(temp, APMU_SRAM_PWR_DWN); - pm_mpmu_clk_disable(); - pm_scu_clk_disable(); - - printk(KERN_INFO "%s: before suspend\n", __func__); - cpu_do_idle(); - printk(KERN_INFO "%s: after suspend\n", __func__); - - pm_mpmu_clk_enable(); /* enable clocks in MPMU */ - pm_scu_clk_enable(); /* enable clocks in SCU */ - - return 0; -} - -/* - * Called after processes are frozen, but before we shut down devices. - */ -static int mmp2_pm_prepare(void) -{ - mmp2_pm_enter_lowpower_mode(POWER_MODE_SYS_SLEEP); - - return 0; -} - -/* - * Called after devices are re-setup, but before processes are thawed. - */ -static void mmp2_pm_finish(void) -{ - mmp2_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE); -} - -static int mmp2_pm_valid(suspend_state_t state) -{ - return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM)); -} - -/* - * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. - */ -static const struct platform_suspend_ops mmp2_pm_ops = { - .valid = mmp2_pm_valid, - .prepare = mmp2_pm_prepare, - .enter = mmp2_pm_enter, - .finish = mmp2_pm_finish, -}; - -static int __init mmp2_pm_init(void) -{ - uint32_t apcr; - - if (!cpu_is_mmp2()) - return -EIO; - - suspend_set_ops(&mmp2_pm_ops); - - /* - * Set bit 0, Slow clock Select 32K clock input instead of VCXO - * VCXO is chosen by default, which would be disabled in suspend - */ - __raw_writel(0x5, MPMU_SCCR); - - /* - * Clear bit 23 of CIU_CPU_CONF - * direct PJ4 to DDR access through Memory Controller slow queue - * fast queue has issue and cause lcd will flick - */ - __raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8)); - - /* Clear default low power control bit */ - apcr = __raw_readl(MPMU_PCR_PJ); - apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD - | MPMU_PCR_PJ_APBSD | MPMU_PCR_PJ_AXISD | 1 << 13); - __raw_writel(apcr, MPMU_PCR_PJ); - - return 0; -} - -late_initcall(mmp2_pm_init); diff --git a/arch/arm/mach-mmp/pm-mmp2.h b/arch/arm/mach-mmp/pm-mmp2.h deleted file mode 100644 index 70cff8bf0cc8..000000000000 --- a/arch/arm/mach-mmp/pm-mmp2.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * MMP2 Power Management Routines - * - * (C) Copyright 2010 Marvell International Ltd. - * All Rights Reserved - */ - -#ifndef __MMP2_PM_H__ -#define __MMP2_PM_H__ - -#include "addr-map.h" - -#define APMU_PJ_IDLE_CFG APMU_REG(0x018) -#define APMU_PJ_IDLE_CFG_PJ_IDLE (1 << 1) -#define APMU_PJ_IDLE_CFG_PJ_PWRDWN (1 << 5) -#define APMU_PJ_IDLE_CFG_PWR_SW(x) ((x) << 16) -#define APMU_PJ_IDLE_CFG_L2_PWR_SW (1 << 19) -#define APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK (3 << 28) - -#define APMU_SRAM_PWR_DWN APMU_REG(0x08c) - -#define MPMU_SCCR MPMU_REG(0x038) -#define MPMU_PCR_PJ MPMU_REG(0x1000) -#define MPMU_PCR_PJ_AXISD (1 << 31) -#define MPMU_PCR_PJ_SLPEN (1 << 29) -#define MPMU_PCR_PJ_SPSD (1 << 28) -#define MPMU_PCR_PJ_DDRCORSD (1 << 27) -#define MPMU_PCR_PJ_APBSD (1 << 26) -#define MPMU_PCR_PJ_INTCLR (1 << 24) -#define MPMU_PCR_PJ_SLPWP0 (1 << 23) -#define MPMU_PCR_PJ_SLPWP1 (1 << 22) -#define MPMU_PCR_PJ_SLPWP2 (1 << 21) -#define MPMU_PCR_PJ_SLPWP3 (1 << 20) -#define MPMU_PCR_PJ_VCTCXOSD (1 << 19) -#define MPMU_PCR_PJ_SLPWP4 (1 << 18) -#define MPMU_PCR_PJ_SLPWP5 (1 << 17) -#define MPMU_PCR_PJ_SLPWP6 (1 << 16) -#define MPMU_PCR_PJ_SLPWP7 (1 << 15) - -#define MPMU_PLL2_CTRL1 MPMU_REG(0x0414) -#define MPMU_CGR_PJ MPMU_REG(0x1024) -#define MPMU_WUCRM_PJ MPMU_REG(0x104c) -#define MPMU_WUCRM_PJ_WAKEUP(x) (1 << (x)) -#define MPMU_WUCRM_PJ_RTC_ALARM (1 << 17) - -enum { - POWER_MODE_ACTIVE = 0, - POWER_MODE_CORE_INTIDLE, - POWER_MODE_CORE_EXTIDLE, - POWER_MODE_APPS_IDLE, - POWER_MODE_APPS_SLEEP, - POWER_MODE_CHIP_SLEEP, - POWER_MODE_SYS_SLEEP, -}; - -extern void mmp2_pm_enter_lowpower_mode(int state); - -#endif diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c deleted file mode 100644 index f6ba6db0aa36..000000000000 --- a/arch/arm/mach-mmp/pm-pxa910.c +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * PXA910 Power Management Routines - * - * (C) Copyright 2009 Marvell International Ltd. - * All Rights Reserved - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "addr-map.h" -#include "pm-pxa910.h" -#include "regs-icu.h" - -void pxa910_pm_enter_lowpower_mode(int state) -{ - uint32_t idle_cfg, apcr; - - idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG); - apcr = __raw_readl(MPMU_APCR); - - apcr &= ~(MPMU_APCR_DDRCORSD | MPMU_APCR_APBSD | MPMU_APCR_AXISD - | MPMU_APCR_VCTCXOSD | MPMU_APCR_STBYEN); - idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_IDLE - | APMU_MOH_IDLE_CFG_MOH_PWRDWN); - - switch (state) { - case POWER_MODE_UDR: - /* only shutdown APB in UDR */ - apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD; - fallthrough; - case POWER_MODE_SYS_SLEEP: - apcr |= MPMU_APCR_SLPEN; /* set the SLPEN bit */ - apcr |= MPMU_APCR_VCTCXOSD; /* set VCTCXOSD */ - fallthrough; - case POWER_MODE_APPS_SLEEP: - apcr |= MPMU_APCR_DDRCORSD; /* set DDRCORSD */ - fallthrough; - case POWER_MODE_APPS_IDLE: - apcr |= MPMU_APCR_AXISD; /* set AXISDD bit */ - fallthrough; - case POWER_MODE_CORE_EXTIDLE: - idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE; - idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN; - idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3) - | APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3); - fallthrough; - case POWER_MODE_CORE_INTIDLE: - break; - } - - /* program the memory controller hardware sleep type and auto wakeup */ - idle_cfg |= APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ; - idle_cfg |= APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN; - __raw_writel(0x0, APMU_MC_HW_SLP_TYPE); /* auto refresh */ - - /* set DSPSD, DTCMSD, BBSD, MSASLPEN */ - apcr |= MPMU_APCR_DSPSD | MPMU_APCR_DTCMSD | MPMU_APCR_BBSD - | MPMU_APCR_MSASLPEN; - - /*always set SLEPEN bit mainly for MSA*/ - apcr |= MPMU_APCR_SLPEN; - - /* finally write the registers back */ - __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG); - __raw_writel(apcr, MPMU_APCR); - -} - -static int pxa910_pm_enter(suspend_state_t state) -{ - unsigned int idle_cfg, reg = 0; - - /*pmic thread not completed,exit;otherwise system can't be waked up*/ - reg = __raw_readl(ICU_INT_CONF(IRQ_PXA910_PMIC_INT)); - if ((reg & 0x3) == 0) - return -EAGAIN; - - idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG); - idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN - | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN; - __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG); - - /* disable L2 */ - outer_disable(); - /* wait for l2 idle */ - while (!(readl(CIU_REG(0x8)) & (1 << 16))) - udelay(1); - - cpu_do_idle(); - - /* enable L2 */ - outer_resume(); - /* wait for l2 idle */ - while (!(readl(CIU_REG(0x8)) & (1 << 16))) - udelay(1); - - idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG); - idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_PWRDWN - | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN); - __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG); - - return 0; -} - -/* - * Called after processes are frozen, but before we shut down devices. - */ -static int pxa910_pm_prepare(void) -{ - pxa910_pm_enter_lowpower_mode(POWER_MODE_UDR); - return 0; -} - -/* - * Called after devices are re-setup, but before processes are thawed. - */ -static void pxa910_pm_finish(void) -{ - pxa910_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE); -} - -static int pxa910_pm_valid(suspend_state_t state) -{ - return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM)); -} - -static const struct platform_suspend_ops pxa910_pm_ops = { - .valid = pxa910_pm_valid, - .prepare = pxa910_pm_prepare, - .enter = pxa910_pm_enter, - .finish = pxa910_pm_finish, -}; - -static int __init pxa910_pm_init(void) -{ - uint32_t awucrm = 0; - - if (!cpu_is_pxa910()) - return -EIO; - - suspend_set_ops(&pxa910_pm_ops); - - /* Set the following bits for MMP3 playback with VCTXO on */ - __raw_writel(__raw_readl(APMU_SQU_CLK_GATE_CTRL) | (1 << 30), - APMU_SQU_CLK_GATE_CTRL); - __raw_writel(__raw_readl(MPMU_FCCR) | (1 << 28), MPMU_FCCR); - - awucrm |= MPMU_AWUCRM_AP_ASYNC_INT | MPMU_AWUCRM_AP_FULL_IDLE; - __raw_writel(awucrm, MPMU_AWUCRM); - - return 0; -} - -late_initcall(pxa910_pm_init); diff --git a/arch/arm/mach-mmp/pm-pxa910.h b/arch/arm/mach-mmp/pm-pxa910.h deleted file mode 100644 index 8e6344adaf51..000000000000 --- a/arch/arm/mach-mmp/pm-pxa910.h +++ /dev/null @@ -1,75 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * PXA910 Power Management Routines - * - * (C) Copyright 2009 Marvell International Ltd. - * All Rights Reserved - */ - -#ifndef __PXA910_PM_H__ -#define __PXA910_PM_H__ - -#define APMU_MOH_IDLE_CFG APMU_REG(0x0018) -#define APMU_MOH_IDLE_CFG_MOH_IDLE (1 << 1) -#define APMU_MOH_IDLE_CFG_MOH_PWRDWN (1 << 5) -#define APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN (1 << 6) -#define APMU_MOH_IDLE_CFG_MOH_PWR_SW(x) (((x) & 0x3) << 16) -#define APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(x) (((x) & 0x3) << 18) -#define APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ (1 << 21) -#define APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN (1 << 20) - -#define APMU_SQU_CLK_GATE_CTRL APMU_REG(0x001c) -#define APMU_MC_HW_SLP_TYPE APMU_REG(0x00b0) - -#define MPMU_FCCR MPMU_REG(0x0008) -#define MPMU_APCR MPMU_REG(0x1000) -#define MPMU_APCR_AXISD (1 << 31) -#define MPMU_APCR_DSPSD (1 << 30) -#define MPMU_APCR_SLPEN (1 << 29) -#define MPMU_APCR_DTCMSD (1 << 28) -#define MPMU_APCR_DDRCORSD (1 << 27) -#define MPMU_APCR_APBSD (1 << 26) -#define MPMU_APCR_BBSD (1 << 25) -#define MPMU_APCR_SLPWP0 (1 << 23) -#define MPMU_APCR_SLPWP1 (1 << 22) -#define MPMU_APCR_SLPWP2 (1 << 21) -#define MPMU_APCR_SLPWP3 (1 << 20) -#define MPMU_APCR_VCTCXOSD (1 << 19) -#define MPMU_APCR_SLPWP4 (1 << 18) -#define MPMU_APCR_SLPWP5 (1 << 17) -#define MPMU_APCR_SLPWP6 (1 << 16) -#define MPMU_APCR_SLPWP7 (1 << 15) -#define MPMU_APCR_MSASLPEN (1 << 14) -#define MPMU_APCR_STBYEN (1 << 13) - -#define MPMU_AWUCRM MPMU_REG(0x104c) -#define MPMU_AWUCRM_AP_ASYNC_INT (1 << 25) -#define MPMU_AWUCRM_AP_FULL_IDLE (1 << 24) -#define MPMU_AWUCRM_SDH1 (1 << 23) -#define MPMU_AWUCRM_SDH2 (1 << 22) -#define MPMU_AWUCRM_KEYPRESS (1 << 21) -#define MPMU_AWUCRM_TRACKBALL (1 << 20) -#define MPMU_AWUCRM_NEWROTARY (1 << 19) -#define MPMU_AWUCRM_RTC_ALARM (1 << 17) -#define MPMU_AWUCRM_AP2_TIMER_3 (1 << 13) -#define MPMU_AWUCRM_AP2_TIMER_2 (1 << 12) -#define MPMU_AWUCRM_AP2_TIMER_1 (1 << 11) -#define MPMU_AWUCRM_AP1_TIMER_3 (1 << 10) -#define MPMU_AWUCRM_AP1_TIMER_2 (1 << 9) -#define MPMU_AWUCRM_AP1_TIMER_1 (1 << 8) -#define MPMU_AWUCRM_WAKEUP(x) (1 << ((x) & 0x7)) - -enum { - POWER_MODE_ACTIVE = 0, - POWER_MODE_CORE_INTIDLE, - POWER_MODE_CORE_EXTIDLE, - POWER_MODE_APPS_IDLE, - POWER_MODE_APPS_SLEEP, - POWER_MODE_SYS_SLEEP, - POWER_MODE_HIBERNATE, - POWER_MODE_UDR, -}; - -extern int pxa910_set_wake(struct irq_data *data, unsigned int on); - -#endif diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c deleted file mode 100644 index 565d4a6c3bd5..000000000000 --- a/arch/arm/mach-mmp/pxa168.c +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-mmp/pxa168.c - * - * Code specific to PXA168 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "addr-map.h" -#include "common.h" -#include -#include -#include "devices.h" -#include "pxa168.h" - -#define MFPR_VIRT_BASE (APB_VIRT_BASE + 0x1e000) - -static struct mfp_addr_map pxa168_mfp_addr_map[] __initdata = -{ - MFP_ADDR_X(GPIO0, GPIO36, 0x04c), - MFP_ADDR_X(GPIO37, GPIO55, 0x000), - MFP_ADDR_X(GPIO56, GPIO123, 0x0e0), - MFP_ADDR_X(GPIO124, GPIO127, 0x0f4), - - MFP_ADDR_END, -}; - -static int __init pxa168_init(void) -{ - if (cpu_is_pxa168()) { - mfp_init_base(MFPR_VIRT_BASE); - mfp_init_addr(pxa168_mfp_addr_map); - pxa168_clk_init(APB_PHYS_BASE + 0x50000, - AXI_PHYS_BASE + 0x82800, - APB_PHYS_BASE + 0x15000); - } - - return 0; -} -postcore_initcall(pxa168_init); diff --git a/arch/arm/mach-mmp/pxa168.h b/arch/arm/mach-mmp/pxa168.h deleted file mode 100644 index 279783ef239d..000000000000 --- a/arch/arm/mach-mmp/pxa168.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_MACH_PXA168_H -#define __ASM_MACH_PXA168_H - -#include - -extern void pxa168_timer_init(void); -extern void __init pxa168_init_irq(void); -extern void pxa168_restart(enum reboot_mode, const char *); -extern void pxa168_clear_keypad_wakeup(void); - -#include -#include -#include - -#endif /* __ASM_MACH_PXA168_H */ diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c deleted file mode 100644 index f389b99cd9bd..000000000000 --- a/arch/arm/mach-mmp/pxa910.c +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * linux/arch/arm/mach-mmp/pxa910.c - * - * Code specific to PXA910 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "addr-map.h" -#include -#include -#include "irqs.h" -#include "pm-pxa910.h" - -#include "common.h" - -#define MFPR_VIRT_BASE (APB_VIRT_BASE + 0x1e000) - -static struct mfp_addr_map pxa910_mfp_addr_map[] __initdata = -{ - MFP_ADDR_X(GPIO0, GPIO54, 0xdc), - MFP_ADDR_X(GPIO67, GPIO98, 0x1b8), - MFP_ADDR_X(GPIO100, GPIO109, 0x238), - - MFP_ADDR(GPIO123, 0xcc), - MFP_ADDR(GPIO124, 0xd0), - - MFP_ADDR(DF_IO0, 0x40), - MFP_ADDR(DF_IO1, 0x3c), - MFP_ADDR(DF_IO2, 0x38), - MFP_ADDR(DF_IO3, 0x34), - MFP_ADDR(DF_IO4, 0x30), - MFP_ADDR(DF_IO5, 0x2c), - MFP_ADDR(DF_IO6, 0x28), - MFP_ADDR(DF_IO7, 0x24), - MFP_ADDR(DF_IO8, 0x20), - MFP_ADDR(DF_IO9, 0x1c), - MFP_ADDR(DF_IO10, 0x18), - MFP_ADDR(DF_IO11, 0x14), - MFP_ADDR(DF_IO12, 0x10), - MFP_ADDR(DF_IO13, 0xc), - MFP_ADDR(DF_IO14, 0x8), - MFP_ADDR(DF_IO15, 0x4), - - MFP_ADDR(DF_nCS0_SM_nCS2, 0x44), - MFP_ADDR(DF_nCS1_SM_nCS3, 0x48), - MFP_ADDR(SM_nCS0, 0x4c), - MFP_ADDR(SM_nCS1, 0x50), - MFP_ADDR(DF_WEn, 0x54), - MFP_ADDR(DF_REn, 0x58), - MFP_ADDR(DF_CLE_SM_OEn, 0x5c), - MFP_ADDR(DF_ALE_SM_WEn, 0x60), - MFP_ADDR(SM_SCLK, 0x64), - MFP_ADDR(DF_RDY0, 0x68), - MFP_ADDR(SM_BE0, 0x6c), - MFP_ADDR(SM_BE1, 0x70), - MFP_ADDR(SM_ADV, 0x74), - MFP_ADDR(DF_RDY1, 0x78), - MFP_ADDR(SM_ADVMUX, 0x7c), - MFP_ADDR(SM_RDY, 0x80), - - MFP_ADDR_X(MMC1_DAT7, MMC1_WP, 0x84), - - MFP_ADDR_END, -}; - -static int __init pxa910_init(void) -{ - if (cpu_is_pxa910()) { -#ifdef CONFIG_CACHE_TAUROS2 - tauros2_init(0); -#endif - mfp_init_base(MFPR_VIRT_BASE); - mfp_init_addr(pxa910_mfp_addr_map); - pxa910_clk_init(APB_PHYS_BASE + 0x50000, - AXI_PHYS_BASE + 0x82800, - APB_PHYS_BASE + 0x15000, - APB_PHYS_BASE + 0x3b000); - } - - return 0; -} -postcore_initcall(pxa910_init); diff --git a/arch/arm/mach-mmp/pxa910.h b/arch/arm/mach-mmp/pxa910.h deleted file mode 100644 index 66a691d89ae1..000000000000 --- a/arch/arm/mach-mmp/pxa910.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_MACH_PXA910_H -#define __ASM_MACH_PXA910_H - -extern void pxa910_timer_init(void); -extern void __init pxa910_init_irq(void); - -#include -#include - -#endif /* __ASM_MACH_PXA910_H */ diff --git a/arch/arm/mach-mmp/regs-icu.h b/arch/arm/mach-mmp/regs-icu.h deleted file mode 100644 index 410743d2b402..000000000000 --- a/arch/arm/mach-mmp/regs-icu.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Interrupt Control Unit - */ - -#ifndef __ASM_MACH_ICU_H -#define __ASM_MACH_ICU_H - -#include "addr-map.h" - -#define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000) -#define ICU_REG(x) (ICU_VIRT_BASE + (x)) - -#define ICU2_VIRT_BASE (AXI_VIRT_BASE + 0x84000) -#define ICU2_REG(x) (ICU2_VIRT_BASE + (x)) - -#define ICU_INT_CONF(n) ICU_REG((n) << 2) -#define ICU_INT_CONF_MASK (0xf) - -/************ PXA168/PXA910 (MMP) *********************/ -#define ICU_INT_CONF_AP_INT (1 << 6) -#define ICU_INT_CONF_CP_INT (1 << 5) -#define ICU_INT_CONF_IRQ (1 << 4) - -#define ICU_AP_FIQ_SEL_INT_NUM ICU_REG(0x108) /* AP FIQ Selected Interrupt */ -#define ICU_AP_IRQ_SEL_INT_NUM ICU_REG(0x10C) /* AP IRQ Selected Interrupt */ -#define ICU_AP_GBL_IRQ_MSK ICU_REG(0x114) /* AP Global Interrupt Mask */ -#define ICU_INT_STATUS_0 ICU_REG(0x128) /* Interrupt Stuats 0 */ -#define ICU_INT_STATUS_1 ICU_REG(0x12C) /* Interrupt Status 1 */ - -/************************** MMP2 ***********************/ - -/* - * IRQ0/FIQ0 is routed to SP IRQ/FIQ. - * IRQ1 is routed to PJ4 IRQ, and IRQ2 is routes to PJ4 FIQ. - */ -#define ICU_INT_ROUTE_SP_IRQ (1 << 4) -#define ICU_INT_ROUTE_PJ4_IRQ (1 << 5) -#define ICU_INT_ROUTE_PJ4_FIQ (1 << 6) - -#define MMP2_ICU_PJ4_IRQ_STATUS0 ICU_REG(0x138) -#define MMP2_ICU_PJ4_IRQ_STATUS1 ICU_REG(0x13c) -#define MMP2_ICU_PJ4_FIQ_STATUS0 ICU_REG(0x140) -#define MMP2_ICU_PJ4_FIQ_STATUS1 ICU_REG(0x144) - -#define MMP2_ICU_INT4_STATUS ICU_REG(0x150) -#define MMP2_ICU_INT5_STATUS ICU_REG(0x154) -#define MMP2_ICU_INT17_STATUS ICU_REG(0x158) -#define MMP2_ICU_INT35_STATUS ICU_REG(0x15c) -#define MMP2_ICU_INT51_STATUS ICU_REG(0x160) - -#define MMP2_ICU_INT4_MASK ICU_REG(0x168) -#define MMP2_ICU_INT5_MASK ICU_REG(0x16C) -#define MMP2_ICU_INT17_MASK ICU_REG(0x170) -#define MMP2_ICU_INT35_MASK ICU_REG(0x174) -#define MMP2_ICU_INT51_MASK ICU_REG(0x178) - -#define MMP2_ICU_SP_IRQ_SEL ICU_REG(0x100) -#define MMP2_ICU_PJ4_IRQ_SEL ICU_REG(0x104) -#define MMP2_ICU_PJ4_FIQ_SEL ICU_REG(0x108) - -#define MMP2_ICU_INVERT ICU_REG(0x164) - -#define MMP2_ICU_INV_PMIC (1 << 0) -#define MMP2_ICU_INV_PERF (1 << 1) -#define MMP2_ICU_INV_COMMTX (1 << 2) -#define MMP2_ICU_INV_COMMRX (1 << 3) - -#endif /* __ASM_MACH_ICU_H */ diff --git a/include/linux/soc/mmp/cputype.h b/include/linux/soc/mmp/cputype.h index 221790761e8e..f13d127fadc4 100644 --- a/include/linux/soc/mmp/cputype.h +++ b/include/linux/soc/mmp/cputype.h @@ -26,29 +26,7 @@ extern unsigned int mmp_chip_id; -#ifdef CONFIG_CPU_PXA168 -static inline int cpu_is_pxa168(void) -{ - return (((read_cpuid_id() >> 8) & 0xff) == 0x84) && - ((mmp_chip_id & 0xfff) == 0x168); -} -#else -#define cpu_is_pxa168() (0) -#endif - -/* cpu_is_pxa910() is shared on both pxa910 and pxa920 */ -#ifdef CONFIG_CPU_PXA910 -static inline int cpu_is_pxa910(void) -{ - return (((read_cpuid_id() >> 8) & 0xff) == 0x84) && - (((mmp_chip_id & 0xfff) == 0x910) || - ((mmp_chip_id & 0xfff) == 0x920)); -} -#else -#define cpu_is_pxa910() (0) -#endif - -#if defined(CONFIG_CPU_MMP2) || defined(CONFIG_MACH_MMP2_DT) +#if defined(CONFIG_MACH_MMP2_DT) static inline int cpu_is_mmp2(void) { return (((read_cpuid_id() >> 8) & 0xff) == 0x58) && -- cgit v1.2.3 From 61b7f8920b176e3cb86c3b5e7c866261720a7917 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 29 Sep 2022 15:33:15 +0200 Subject: ARM: s3c: remove all s3c24xx support The platform was deprecated in commit 6a5e69c7ddea ("ARM: s3c: mark as deprecated and schedule removal") and can be removed. This includes all files that are exclusively for s3c24xx and not shared with s3c64xx, as well as the glue logic in Kconfig and the maintainer file entries. Cc: Arnaud Patard Cc: Ben Dooks Cc: Christer Weinigel Cc: Guillaume GOURAT Cc: Heiko Stuebner Cc: Simtec Linux Team Cc: openmoko-kernel@lists.openmoko.org Acked-by: Heiko Stuebner Acked-by: Krzysztof Kozlowski Signed-off-by: Arnd Bergmann --- Documentation/arm/index.rst | 1 - Documentation/arm/samsung-s3c24xx/cpufreq.rst | 77 -- Documentation/arm/samsung-s3c24xx/eb2410itx.rst | 59 - Documentation/arm/samsung-s3c24xx/gpio.rst | 172 --- Documentation/arm/samsung-s3c24xx/h1940.rst | 41 - Documentation/arm/samsung-s3c24xx/index.rst | 20 - Documentation/arm/samsung-s3c24xx/nand.rst | 30 - Documentation/arm/samsung-s3c24xx/overview.rst | 311 ----- Documentation/arm/samsung-s3c24xx/s3c2412.rst | 121 -- Documentation/arm/samsung-s3c24xx/s3c2413.rst | 22 - Documentation/arm/samsung-s3c24xx/smdk2440.rst | 57 - Documentation/arm/samsung-s3c24xx/suspend.rst | 137 -- Documentation/arm/samsung-s3c24xx/usb-host.rst | 91 -- Documentation/arm/samsung/gpio.rst | 8 - Documentation/arm/samsung/overview.rst | 13 - .../bindings/clock/samsung,s3c2410-clock.txt | 49 - .../bindings/clock/samsung,s3c2412-clock.txt | 49 - .../bindings/clock/samsung,s3c2443-clock.txt | 55 - .../interrupt-controller/samsung,s3c24xx-irq.txt | 53 - .../devicetree/bindings/mmc/samsung,s3cmci.txt | 42 - MAINTAINERS | 16 - arch/arm/Kconfig | 1 - arch/arm/Kconfig.debug | 58 +- arch/arm/Makefile | 2 - arch/arm/boot/dts/Makefile | 2 - arch/arm/boot/dts/s3c2410-pinctrl.h | 19 - arch/arm/boot/dts/s3c2416-pinctrl.dtsi | 172 --- arch/arm/boot/dts/s3c2416-smdk2416.dts | 77 -- arch/arm/boot/dts/s3c2416.dtsi | 124 -- arch/arm/boot/dts/s3c24xx.dtsi | 92 -- arch/arm/configs/mini2440_defconfig | 338 ----- arch/arm/configs/s3c2410_defconfig | 437 ------- arch/arm/configs/tct_hammer_defconfig | 59 - arch/arm/mach-s3c/Kconfig | 27 +- arch/arm/mach-s3c/Kconfig.s3c24xx | 604 --------- arch/arm/mach-s3c/Makefile | 4 - arch/arm/mach-s3c/Makefile.s3c24xx | 102 -- arch/arm/mach-s3c/anubis.h | 50 - arch/arm/mach-s3c/bast-ide.c | 82 -- arch/arm/mach-s3c/bast-irq.c | 137 -- arch/arm/mach-s3c/bast.h | 194 --- arch/arm/mach-s3c/common-smdk-s3c24xx.c | 228 ---- arch/arm/mach-s3c/common-smdk-s3c24xx.h | 11 - arch/arm/mach-s3c/cpufreq-utils-s3c24xx.c | 94 -- arch/arm/mach-s3c/dma-s3c24xx.h | 51 - arch/arm/mach-s3c/fb-core-s3c24xx.h | 24 - arch/arm/mach-s3c/gpio-samsung-s3c24xx.h | 103 -- arch/arm/mach-s3c/gta02.h | 20 - arch/arm/mach-s3c/h1940-bluetooth.c | 140 -- arch/arm/mach-s3c/h1940.h | 52 - arch/arm/mach-s3c/hardware-s3c24xx.h | 14 - arch/arm/mach-s3c/iotiming-s3c2410.c | 472 ------- arch/arm/mach-s3c/iotiming-s3c2412.c | 278 ---- arch/arm/mach-s3c/irq-pm-s3c24xx.c | 115 -- arch/arm/mach-s3c/irq-s3c24xx-fiq-exports.c | 9 - arch/arm/mach-s3c/irq-s3c24xx-fiq.S | 112 -- arch/arm/mach-s3c/irq-s3c24xx.c | 1352 -------------------- arch/arm/mach-s3c/irqs-s3c24xx.h | 219 ---- arch/arm/mach-s3c/mach-amlm5900.c | 248 ---- arch/arm/mach-s3c/mach-anubis.c | 422 ------ arch/arm/mach-s3c/mach-at2440evb.c | 233 ---- arch/arm/mach-s3c/mach-bast.c | 583 --------- arch/arm/mach-s3c/mach-gta02.c | 588 --------- arch/arm/mach-s3c/mach-h1940.c | 809 ------------ arch/arm/mach-s3c/mach-jive.c | 693 ---------- arch/arm/mach-s3c/mach-mini2440.c | 804 ------------ arch/arm/mach-s3c/mach-n30.c | 682 ---------- arch/arm/mach-s3c/mach-nexcoder.c | 162 --- arch/arm/mach-s3c/mach-osiris-dvs.c | 178 --- arch/arm/mach-s3c/mach-osiris.c | 405 ------ arch/arm/mach-s3c/mach-otom.c | 124 -- arch/arm/mach-s3c/mach-qt2410.c | 375 ------ arch/arm/mach-s3c/mach-rx1950.c | 884 ------------- arch/arm/mach-s3c/mach-rx3715.c | 213 --- arch/arm/mach-s3c/mach-s3c2416-dt.c | 48 - arch/arm/mach-s3c/mach-smdk2410.c | 112 -- arch/arm/mach-s3c/mach-smdk2413.c | 169 --- arch/arm/mach-s3c/mach-smdk2416.c | 248 ---- arch/arm/mach-s3c/mach-smdk2440.c | 180 --- arch/arm/mach-s3c/mach-smdk2443.c | 126 -- arch/arm/mach-s3c/mach-tct_hammer.c | 157 --- arch/arm/mach-s3c/mach-vr1000.c | 364 ------ arch/arm/mach-s3c/mach-vstms.c | 166 --- arch/arm/mach-s3c/map-s3c24xx.h | 159 --- arch/arm/mach-s3c/nand-core-s3c24xx.h | 24 - arch/arm/mach-s3c/osiris.h | 50 - arch/arm/mach-s3c/pll-s3c2410.c | 83 -- arch/arm/mach-s3c/pll-s3c2440-12000000.c | 95 -- arch/arm/mach-s3c/pll-s3c2440-16934400.c | 122 -- arch/arm/mach-s3c/pm-core-s3c24xx.h | 96 -- arch/arm/mach-s3c/pm-h1940.S | 19 - arch/arm/mach-s3c/pm-s3c2410.c | 170 --- arch/arm/mach-s3c/pm-s3c2412.c | 126 -- arch/arm/mach-s3c/pm-s3c2416.c | 81 -- arch/arm/mach-s3c/pm-s3c24xx.c | 121 -- arch/arm/mach-s3c/regs-clock-s3c24xx.h | 146 --- arch/arm/mach-s3c/regs-dsc-s3c24xx.h | 22 - arch/arm/mach-s3c/regs-gpio-s3c24xx.h | 608 --------- arch/arm/mach-s3c/regs-irq-s3c24xx.h | 51 - arch/arm/mach-s3c/regs-mem-s3c24xx.h | 53 - arch/arm/mach-s3c/regs-s3c2443-clock.h | 238 ---- arch/arm/mach-s3c/rtc-core-s3c24xx.h | 23 - arch/arm/mach-s3c/s3c2410.c | 130 -- arch/arm/mach-s3c/s3c2412-power.h | 34 - arch/arm/mach-s3c/s3c2412.c | 175 --- arch/arm/mach-s3c/s3c2412.h | 25 - arch/arm/mach-s3c/s3c2416.c | 132 -- arch/arm/mach-s3c/s3c2440.c | 71 - arch/arm/mach-s3c/s3c2442.c | 62 - arch/arm/mach-s3c/s3c2443.c | 112 -- arch/arm/mach-s3c/s3c244x.c | 128 -- arch/arm/mach-s3c/s3c24xx.c | 687 ---------- arch/arm/mach-s3c/s3c24xx.h | 124 -- arch/arm/mach-s3c/setup-i2c-s3c24xx.c | 23 - arch/arm/mach-s3c/setup-sdhci-gpio-s3c24xx.c | 31 - arch/arm/mach-s3c/setup-spi-s3c24xx.c | 27 - arch/arm/mach-s3c/setup-ts-s3c24xx.c | 29 - arch/arm/mach-s3c/simtec-audio.c | 76 -- arch/arm/mach-s3c/simtec-nor.c | 74 -- arch/arm/mach-s3c/simtec-pm.c | 60 - arch/arm/mach-s3c/simtec-usb.c | 125 -- arch/arm/mach-s3c/simtec.h | 17 - arch/arm/mach-s3c/sleep-s3c2410.S | 54 - arch/arm/mach-s3c/sleep-s3c2412.S | 53 - arch/arm/mach-s3c/sleep-s3c24xx.S | 69 - arch/arm/mach-s3c/spi-core-s3c24xx.h | 21 - arch/arm/mach-s3c/vr1000.h | 113 -- drivers/soc/samsung/Kconfig | 4 - include/dt-bindings/clock/s3c2410.h | 59 - include/dt-bindings/clock/s3c2412.h | 70 - include/dt-bindings/clock/s3c2443.h | 91 -- include/linux/amba/pl093.h | 77 -- 132 files changed, 7 insertions(+), 21305 deletions(-) delete mode 100644 Documentation/arm/samsung-s3c24xx/cpufreq.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/eb2410itx.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/gpio.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/h1940.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/index.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/nand.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/overview.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/s3c2412.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/s3c2413.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/smdk2440.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/suspend.rst delete mode 100644 Documentation/arm/samsung-s3c24xx/usb-host.rst delete mode 100644 Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt delete mode 100644 Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt delete mode 100644 Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt delete mode 100644 Documentation/devicetree/bindings/mmc/samsung,s3cmci.txt delete mode 100644 arch/arm/boot/dts/s3c2410-pinctrl.h delete mode 100644 arch/arm/boot/dts/s3c2416-pinctrl.dtsi delete mode 100644 arch/arm/boot/dts/s3c2416-smdk2416.dts delete mode 100644 arch/arm/boot/dts/s3c2416.dtsi delete mode 100644 arch/arm/boot/dts/s3c24xx.dtsi delete mode 100644 arch/arm/configs/mini2440_defconfig delete mode 100644 arch/arm/configs/s3c2410_defconfig delete mode 100644 arch/arm/configs/tct_hammer_defconfig delete mode 100644 arch/arm/mach-s3c/Kconfig.s3c24xx delete mode 100644 arch/arm/mach-s3c/Makefile.s3c24xx delete mode 100644 arch/arm/mach-s3c/anubis.h delete mode 100644 arch/arm/mach-s3c/bast-ide.c delete mode 100644 arch/arm/mach-s3c/bast-irq.c delete mode 100644 arch/arm/mach-s3c/bast.h delete mode 100644 arch/arm/mach-s3c/common-smdk-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/common-smdk-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/cpufreq-utils-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/dma-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/fb-core-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/gpio-samsung-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/gta02.h delete mode 100644 arch/arm/mach-s3c/h1940-bluetooth.c delete mode 100644 arch/arm/mach-s3c/h1940.h delete mode 100644 arch/arm/mach-s3c/hardware-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/iotiming-s3c2410.c delete mode 100644 arch/arm/mach-s3c/iotiming-s3c2412.c delete mode 100644 arch/arm/mach-s3c/irq-pm-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/irq-s3c24xx-fiq-exports.c delete mode 100644 arch/arm/mach-s3c/irq-s3c24xx-fiq.S delete mode 100644 arch/arm/mach-s3c/irq-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/irqs-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/mach-amlm5900.c delete mode 100644 arch/arm/mach-s3c/mach-anubis.c delete mode 100644 arch/arm/mach-s3c/mach-at2440evb.c delete mode 100644 arch/arm/mach-s3c/mach-bast.c delete mode 100644 arch/arm/mach-s3c/mach-gta02.c delete mode 100644 arch/arm/mach-s3c/mach-h1940.c delete mode 100644 arch/arm/mach-s3c/mach-jive.c delete mode 100644 arch/arm/mach-s3c/mach-mini2440.c delete mode 100644 arch/arm/mach-s3c/mach-n30.c delete mode 100644 arch/arm/mach-s3c/mach-nexcoder.c delete mode 100644 arch/arm/mach-s3c/mach-osiris-dvs.c delete mode 100644 arch/arm/mach-s3c/mach-osiris.c delete mode 100644 arch/arm/mach-s3c/mach-otom.c delete mode 100644 arch/arm/mach-s3c/mach-qt2410.c delete mode 100644 arch/arm/mach-s3c/mach-rx1950.c delete mode 100644 arch/arm/mach-s3c/mach-rx3715.c delete mode 100644 arch/arm/mach-s3c/mach-s3c2416-dt.c delete mode 100644 arch/arm/mach-s3c/mach-smdk2410.c delete mode 100644 arch/arm/mach-s3c/mach-smdk2413.c delete mode 100644 arch/arm/mach-s3c/mach-smdk2416.c delete mode 100644 arch/arm/mach-s3c/mach-smdk2440.c delete mode 100644 arch/arm/mach-s3c/mach-smdk2443.c delete mode 100644 arch/arm/mach-s3c/mach-tct_hammer.c delete mode 100644 arch/arm/mach-s3c/mach-vr1000.c delete mode 100644 arch/arm/mach-s3c/mach-vstms.c delete mode 100644 arch/arm/mach-s3c/map-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/nand-core-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/osiris.h delete mode 100644 arch/arm/mach-s3c/pll-s3c2410.c delete mode 100644 arch/arm/mach-s3c/pll-s3c2440-12000000.c delete mode 100644 arch/arm/mach-s3c/pll-s3c2440-16934400.c delete mode 100644 arch/arm/mach-s3c/pm-core-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/pm-h1940.S delete mode 100644 arch/arm/mach-s3c/pm-s3c2410.c delete mode 100644 arch/arm/mach-s3c/pm-s3c2412.c delete mode 100644 arch/arm/mach-s3c/pm-s3c2416.c delete mode 100644 arch/arm/mach-s3c/pm-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/regs-clock-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/regs-dsc-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/regs-gpio-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/regs-irq-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/regs-mem-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/regs-s3c2443-clock.h delete mode 100644 arch/arm/mach-s3c/rtc-core-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/s3c2410.c delete mode 100644 arch/arm/mach-s3c/s3c2412-power.h delete mode 100644 arch/arm/mach-s3c/s3c2412.c delete mode 100644 arch/arm/mach-s3c/s3c2412.h delete mode 100644 arch/arm/mach-s3c/s3c2416.c delete mode 100644 arch/arm/mach-s3c/s3c2440.c delete mode 100644 arch/arm/mach-s3c/s3c2442.c delete mode 100644 arch/arm/mach-s3c/s3c2443.c delete mode 100644 arch/arm/mach-s3c/s3c244x.c delete mode 100644 arch/arm/mach-s3c/s3c24xx.c delete mode 100644 arch/arm/mach-s3c/s3c24xx.h delete mode 100644 arch/arm/mach-s3c/setup-i2c-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/setup-sdhci-gpio-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/setup-spi-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/setup-ts-s3c24xx.c delete mode 100644 arch/arm/mach-s3c/simtec-audio.c delete mode 100644 arch/arm/mach-s3c/simtec-nor.c delete mode 100644 arch/arm/mach-s3c/simtec-pm.c delete mode 100644 arch/arm/mach-s3c/simtec-usb.c delete mode 100644 arch/arm/mach-s3c/simtec.h delete mode 100644 arch/arm/mach-s3c/sleep-s3c2410.S delete mode 100644 arch/arm/mach-s3c/sleep-s3c2412.S delete mode 100644 arch/arm/mach-s3c/sleep-s3c24xx.S delete mode 100644 arch/arm/mach-s3c/spi-core-s3c24xx.h delete mode 100644 arch/arm/mach-s3c/vr1000.h delete mode 100644 include/dt-bindings/clock/s3c2410.h delete mode 100644 include/dt-bindings/clock/s3c2412.h delete mode 100644 include/dt-bindings/clock/s3c2443.h delete mode 100644 include/linux/amba/pl093.h (limited to 'include') diff --git a/Documentation/arm/index.rst b/Documentation/arm/index.rst index 8c636d4a061f..ae42fe886f0d 100644 --- a/Documentation/arm/index.rst +++ b/Documentation/arm/index.rst @@ -64,7 +64,6 @@ SoC-specific documents sunxi samsung/index - samsung-s3c24xx/index sunxi/clocks diff --git a/Documentation/arm/samsung-s3c24xx/cpufreq.rst b/Documentation/arm/samsung-s3c24xx/cpufreq.rst deleted file mode 100644 index cd22697cf606..000000000000 --- a/Documentation/arm/samsung-s3c24xx/cpufreq.rst +++ /dev/null @@ -1,77 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0-only - -======================= -S3C24XX CPUfreq support -======================= - -Introduction ------------- - - The S3C24XX series support a number of power saving systems, such as - the ability to change the core, memory and peripheral operating - frequencies. The core control is exported via the CPUFreq driver - which has a number of different manual or automatic controls over the - rate the core is running at. - - There are two forms of the driver depending on the specific CPU and - how the clocks are arranged. The first implementation used as single - PLL to feed the ARM, memory and peripherals via a series of dividers - and muxes and this is the implementation that is documented here. A - newer version where there is a separate PLL and clock divider for the - ARM core is available as a separate driver. - - -Layout ------- - - The code core manages the CPU specific drivers, any data that they - need to register and the interface to the generic drivers/cpufreq - system. Each CPU registers a driver to control the PLL, clock dividers - and anything else associated with it. Any board that wants to use this - framework needs to supply at least basic details of what is required. - - The core registers with drivers/cpufreq at init time if all the data - necessary has been supplied. - - -CPU support ------------ - - The support for each CPU depends on the facilities provided by the - SoC and the driver as each device has different PLL and clock chains - associated with it. - - -Slow Mode ---------- - - The SLOW mode where the PLL is turned off altogether and the - system is fed by the external crystal input is currently not - supported. - - -sysfs ------ - - The core code exports extra information via sysfs in the directory - devices/system/cpu/cpu0/arch-freq. - - -Board Support -------------- - - Each board that wants to use the cpufreq code must register some basic - information with the core driver to provide information about what the - board requires and any restrictions being placed on it. - - The board needs to supply information about whether it needs the IO bank - timings changing, any maximum frequency limits and information about the - SDRAM refresh rate. - - - - -Document Author ---------------- - -Ben Dooks, Copyright 2009 Simtec Electronics diff --git a/Documentation/arm/samsung-s3c24xx/eb2410itx.rst b/Documentation/arm/samsung-s3c24xx/eb2410itx.rst deleted file mode 100644 index 7863c93652f8..000000000000 --- a/Documentation/arm/samsung-s3c24xx/eb2410itx.rst +++ /dev/null @@ -1,59 +0,0 @@ -=================================== -Simtec Electronics EB2410ITX (BAST) -=================================== - - http://www.simtec.co.uk/products/EB2410ITX/ - -Introduction ------------- - - The EB2410ITX is a S3C2410 based development board with a variety of - peripherals and expansion connectors. This board is also known by - the shortened name of Bast. - - -Configuration -------------- - - To set the default configuration, use `make bast_defconfig` which - supports the commonly used features of this board. - - -Support -------- - - Official support information can be found on the Simtec Electronics - website, at the product page http://www.simtec.co.uk/products/EB2410ITX/ - - Useful links: - - - Resources Page http://www.simtec.co.uk/products/EB2410ITX/resources.html - - - Board FAQ at http://www.simtec.co.uk/products/EB2410ITX/faq.html - - - Bootloader info http://www.simtec.co.uk/products/SWABLE/resources.html - and FAQ http://www.simtec.co.uk/products/SWABLE/faq.html - - -MTD ---- - - The NAND and NOR support has been merged from the linux-mtd project. - Any problems, see http://www.linux-mtd.infradead.org/ for more - information or up-to-date versions of linux-mtd. - - -IDE ---- - - Both onboard IDE ports are supported, however there is no support for - changing speed of devices, PIO Mode 4 capable drives should be used. - - -Maintainers ------------ - - This board is maintained by Simtec Electronics. - - -Copyright 2004 Ben Dooks, Simtec Electronics diff --git a/Documentation/arm/samsung-s3c24xx/gpio.rst b/Documentation/arm/samsung-s3c24xx/gpio.rst deleted file mode 100644 index f4a8c800a457..000000000000 --- a/Documentation/arm/samsung-s3c24xx/gpio.rst +++ /dev/null @@ -1,172 +0,0 @@ -==================== -S3C24XX GPIO Control -==================== - -Introduction ------------- - - The s3c2410 kernel provides an interface to configure and - manipulate the state of the GPIO pins, and find out other - information about them. - - There are a number of conditions attached to the configuration - of the s3c2410 GPIO system, please read the Samsung provided - data-sheet/users manual to find out the complete list. - - See Documentation/arm/samsung/gpio.rst for the core implementation. - - -GPIOLIB -------- - - With the event of the GPIOLIB in drivers/gpio, support for some - of the GPIO functions such as reading and writing a pin will - be removed in favour of this common access method. - - Once all the extant drivers have been converted, the functions - listed below will be removed (they may be marked as __deprecated - in the near future). - - The following functions now either have a `s3c_` specific variant - or are merged into gpiolib. See the definitions in - arch/arm/mach-s3c/gpio-cfg.h: - - - s3c2410_gpio_setpin() gpio_set_value() or gpio_direction_output() - - s3c2410_gpio_getpin() gpio_get_value() or gpio_direction_input() - - s3c2410_gpio_getirq() gpio_to_irq() - - s3c2410_gpio_cfgpin() s3c_gpio_cfgpin() - - s3c2410_gpio_getcfg() s3c_gpio_getcfg() - - s3c2410_gpio_pullup() s3c_gpio_setpull() - - -GPIOLIB conversion ------------------- - -If you need to convert your board or driver to use gpiolib from the phased -out s3c2410 API, then here are some notes on the process. - -1) If your board is exclusively using an GPIO, say to control peripheral - power, then it will require to claim the gpio with gpio_request() before - it can use it. - - It is recommended to check the return value, with at least WARN_ON() - during initialisation. - -2) The s3c2410_gpio_cfgpin() can be directly replaced with s3c_gpio_cfgpin() - as they have the same arguments, and can either take the pin specific - values, or the more generic special-function-number arguments. - -3) s3c2410_gpio_pullup() changes have the problem that while the - s3c2410_gpio_pullup(x, 1) can be easily translated to the - s3c_gpio_setpull(x, S3C_GPIO_PULL_NONE), the s3c2410_gpio_pullup(x, 0) - are not so easy. - - The s3c2410_gpio_pullup(x, 0) case enables the pull-up (or in the case - of some of the devices, a pull-down) and as such the new API distinguishes - between the UP and DOWN case. There is currently no 'just turn on' setting - which may be required if this becomes a problem. - -4) s3c2410_gpio_setpin() can be replaced by gpio_set_value(), the old call - does not implicitly configure the relevant gpio to output. The gpio - direction should be changed before using gpio_set_value(). - -5) s3c2410_gpio_getpin() is replaceable by gpio_get_value() if the pin - has been set to input. It is currently unknown what the behaviour is - when using gpio_get_value() on an output pin (s3c2410_gpio_getpin - would return the value the pin is supposed to be outputting). - -6) s3c2410_gpio_getirq() should be directly replaceable with the - gpio_to_irq() call. - -The s3c2410_gpio and `gpio_` calls have always operated on the same gpio -numberspace, so there is no problem with converting the gpio numbering -between the calls. - - -Headers -------- - - See arch/arm/mach-s3c/regs-gpio-s3c24xx.h for the list - of GPIO pins, and the configuration values for them. This - is included by using #include - - -PIN Numbers ------------ - - Each pin has an unique number associated with it in regs-gpio.h, - e.g. S3C2410_GPA(0) or S3C2410_GPF(1). These defines are used to tell - the GPIO functions which pin is to be used. - - With the conversion to gpiolib, there is no longer a direct conversion - from gpio pin number to register base address as in earlier kernels. This - is due to the number space required for newer SoCs where the later - GPIOs are not contiguous. - - -Configuring a pin ------------------ - - The following function allows the configuration of a given pin to - be changed. - - void s3c_gpio_cfgpin(unsigned int pin, unsigned int function); - - e.g.: - - s3c_gpio_cfgpin(S3C2410_GPA(0), S3C_GPIO_SFN(1)); - s3c_gpio_cfgpin(S3C2410_GPE(8), S3C_GPIO_SFN(2)); - - which would turn GPA(0) into the lowest Address line A0, and set - GPE(8) to be connected to the SDIO/MMC controller's SDDAT1 line. - - -Reading the current configuration ---------------------------------- - - The current configuration of a pin can be read by using standard - gpiolib function: - - s3c_gpio_getcfg(unsigned int pin); - - The return value will be from the same set of values which can be - passed to s3c_gpio_cfgpin(). - - -Configuring a pull-up resistor ------------------------------- - - A large proportion of the GPIO pins on the S3C2410 can have weak - pull-up resistors enabled. This can be configured by the following - function: - - void s3c_gpio_setpull(unsigned int pin, unsigned int to); - - Where the to value is S3C_GPIO_PULL_NONE to set the pull-up off, - and S3C_GPIO_PULL_UP to enable the specified pull-up. Any other - values are currently undefined. - - -Getting and setting the state of a PIN --------------------------------------- - - These calls are now implemented by the relevant gpiolib calls, convert - your board or driver to use gpiolib. - - -Getting the IRQ number associated with a PIN --------------------------------------------- - - A standard gpiolib function can map the given pin number to an IRQ - number to pass to the IRQ system. - - int gpio_to_irq(unsigned int pin); - - Note, not all pins have an IRQ. - - -Author -------- - -Ben Dooks, 03 October 2004 -Copyright 2004 Ben Dooks, Simtec Electronics diff --git a/Documentation/arm/samsung-s3c24xx/h1940.rst b/Documentation/arm/samsung-s3c24xx/h1940.rst deleted file mode 100644 index 62a562c178e3..000000000000 --- a/Documentation/arm/samsung-s3c24xx/h1940.rst +++ /dev/null @@ -1,41 +0,0 @@ -============= -HP IPAQ H1940 -============= - -http://www.handhelds.org/projects/h1940.html - -Introduction ------------- - - The HP H1940 is a S3C2410 based handheld device, with - bluetooth connectivity. - - -Support -------- - - A variety of information is available - - handhelds.org project page: - - http://www.handhelds.org/projects/h1940.html - - handhelds.org wiki page: - - http://handhelds.org/moin/moin.cgi/HpIpaqH1940 - - Herbert Pötzl pages: - - http://vserver.13thfloor.at/H1940/ - - -Maintainers ------------ - - This project is being maintained and developed by a variety - of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl. - - Thanks to the many others who have also provided support. - - -(c) 2005 Ben Dooks diff --git a/Documentation/arm/samsung-s3c24xx/index.rst b/Documentation/arm/samsung-s3c24xx/index.rst deleted file mode 100644 index ccb951a0bedb..000000000000 --- a/Documentation/arm/samsung-s3c24xx/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -========================== -Samsung S3C24XX SoC Family -========================== - -.. toctree:: - :maxdepth: 1 - - h1940 - gpio - cpufreq - suspend - usb-host - s3c2412 - eb2410itx - nand - smdk2440 - s3c2413 - overview diff --git a/Documentation/arm/samsung-s3c24xx/nand.rst b/Documentation/arm/samsung-s3c24xx/nand.rst deleted file mode 100644 index 938995694ee7..000000000000 --- a/Documentation/arm/samsung-s3c24xx/nand.rst +++ /dev/null @@ -1,30 +0,0 @@ -==================== -S3C24XX NAND Support -==================== - -Introduction ------------- - -Small Page NAND ---------------- - -The driver uses a 512 byte (1 page) ECC code for this setup. The -ECC code is not directly compatible with the default kernel ECC -code, so the driver enforces its own OOB layout and ECC parameters - -Large Page NAND ---------------- - -The driver is capable of handling NAND flash with a 2KiB page -size, with support for hardware ECC generation and correction. - -Unlike the 512byte page mode, the driver generates ECC data for -each 256 byte block in an 2KiB page. This means that more than -one error in a page can be rectified. It also means that the -OOB layout remains the default kernel layout for these flashes. - - -Document Author ---------------- - -Ben Dooks, Copyright 2007 Simtec Electronics diff --git a/Documentation/arm/samsung-s3c24xx/overview.rst b/Documentation/arm/samsung-s3c24xx/overview.rst deleted file mode 100644 index 14535e5cffb7..000000000000 --- a/Documentation/arm/samsung-s3c24xx/overview.rst +++ /dev/null @@ -1,311 +0,0 @@ -========================== -S3C24XX ARM Linux Overview -========================== - - - -Introduction ------------- - - The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported - by the 's3c2410' architecture of ARM Linux. Currently the S3C2410, - S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443 and S3C2450 devices - are supported. - - Support for the S3C2400 and S3C24A0 series was never completed and the - corresponding code has been removed after a while. If someone wishes to - revive this effort, partial support can be retrieved from earlier Linux - versions. - - The S3C2416 and S3C2450 devices are very similar and S3C2450 support is - included under the arch/arm/mach-s3c directory. Note, while core - support for these SoCs is in, work on some of the extra peripherals - and extra interrupts is still ongoing. - - -Configuration -------------- - - A generic S3C2410 configuration is provided, and can be used as the - default by `make s3c2410_defconfig`. This configuration has support - for all the machines, and the commonly used features on them. - - Certain machines may have their own default configurations as well, - please check the machine specific documentation. - - -Layout ------- - - The core support files, register, kernel and paltform data are located in the - platform code contained in arch/arm/mach-s3c with headers in - arch/arm/mach-s3c/include - -arch/arm/mach-s3c: - - Files in here are either common to all the s3c24xx family, - or are common to only some of them with names to indicate this - status. The files that are not common to all are generally named - with the initial cpu they support in the series to ensure a short - name without any possibility of confusion with newer devices. - - As an example, initially s3c244x would cover s3c2440 and s3c2442, but - with the s3c2443 which does not share many of the same drivers in - this directory, the name becomes invalid. We stick to s3c2440- - to indicate a driver that is s3c2440 and s3c2442 compatible. - - This does mean that to find the status of any given SoC, a number - of directories may need to be searched. - - -Machines --------- - - The currently supported machines are as follows: - - Simtec Electronics EB2410ITX (BAST) - - A general purpose development board, see EB2410ITX.txt for further - details - - Simtec Electronics IM2440D20 (Osiris) - - CPU Module from Simtec Electronics, with a S3C2440A CPU, nand flash - and a PCMCIA controller. - - Samsung SMDK2410 - - Samsung's own development board, geared for PDA work. - - Samsung/Aiji SMDK2412 - - The S3C2412 version of the SMDK2440. - - Samsung/Aiji SMDK2413 - - The S3C2412 version of the SMDK2440. - - Samsung/Meritech SMDK2440 - - The S3C2440 compatible version of the SMDK2440, which has the - option of an S3C2440 or S3C2442 CPU module. - - Thorcom VR1000 - - Custom embedded board - - HP IPAQ 1940 - - Handheld (IPAQ), available in several varieties - - HP iPAQ rx3715 - - S3C2440 based IPAQ, with a number of variations depending on - features shipped. - - Acer N30 - - A S3C2410 based PDA from Acer. There is a Wiki page at - http://handhelds.org/moin/moin.cgi/AcerN30Documentation . - - AML M5900 - - American Microsystems' M5900 - - Nex Vision Nexcoder - Nex Vision Otom - - Two machines by Nex Vision - - -Adding New Machines -------------------- - - The architecture has been designed to support as many machines as can - be configured for it in one kernel build, and any future additions - should keep this in mind before altering items outside of their own - machine files. - - Machine definitions should be kept in arch/arm/mach-s3c, - and there are a number of examples that can be looked at. - - Read the kernel patch submission policies as well as the - Documentation/arm directory before submitting patches. The - ARM kernel series is managed by Russell King, and has a patch system - located at http://www.arm.linux.org.uk/developer/patches/ - as well as mailing lists that can be found from the same site. - - As a courtesy, please notify of any new - machines or other modifications. - - Any large scale modifications, or new drivers should be discussed - on the ARM kernel mailing list (linux-arm-kernel) before being - attempted. See http://www.arm.linux.org.uk/mailinglists/ for the - mailing list information. - - -I2C ---- - - The hardware I2C core in the CPU is supported in single master - mode, and can be configured via platform data. - - -RTC ---- - - Support for the onboard RTC unit, including alarm function. - - This has recently been upgraded to use the new RTC core, - and the module has been renamed to rtc-s3c to fit in with - the new rtc naming scheme. - - -Watchdog --------- - - The onchip watchdog is available via the standard watchdog - interface. - - -NAND ----- - - The current kernels now have support for the s3c2410 NAND - controller. If there are any problems the latest linux-mtd - code can be found from http://www.linux-mtd.infradead.org/ - - For more information see Documentation/arm/samsung-s3c24xx/nand.rst - - -SD/MMC ------- - - The SD/MMC hardware pre S3C2443 is supported in the current - kernel, the driver is drivers/mmc/host/s3cmci.c and supports - 1 and 4 bit SD or MMC cards. - - The SDIO behaviour of this driver has not been fully tested. There is no - current support for hardware SDIO interrupts. - - -Serial ------- - - The s3c2410 serial driver provides support for the internal - serial ports. These devices appear as /dev/ttySAC0 through 3. - - To create device nodes for these, use the following commands - - mknod ttySAC0 c 204 64 - mknod ttySAC1 c 204 65 - mknod ttySAC2 c 204 66 - - -GPIO ----- - - The core contains support for manipulating the GPIO, see the - documentation in GPIO.txt in the same directory as this file. - - Newer kernels carry GPIOLIB, and support is being moved towards - this with some of the older support in line to be removed. - - As of v2.6.34, the move towards using gpiolib support is almost - complete, and very little of the old calls are left. - - See Documentation/arm/samsung-s3c24xx/gpio.rst for the S3C24XX specific - support and Documentation/arm/samsung/gpio.rst for the core Samsung - implementation. - - -Clock Management ----------------- - - The core provides the interface defined in the header file - include/asm-arm/hardware/clock.h, to allow control over the - various clock units - - -Suspend to RAM --------------- - - For boards that provide support for suspend to RAM, the - system can be placed into low power suspend. - - See Suspend.txt for more information. - - -SPI ---- - - SPI drivers are available for both the in-built hardware - (although there is no DMA support yet) and a generic - GPIO based solution. - - -LEDs ----- - - There is support for GPIO based LEDs via a platform driver - in the LED subsystem. - - -Platform Data -------------- - - Whenever a device has platform specific data that is specified - on a per-machine basis, care should be taken to ensure the - following: - - 1) that default data is not left in the device to confuse the - driver if a machine does not set it at startup - - 2) the data should (if possible) be marked as __initdata, - to ensure that the data is thrown away if the machine is - not the one currently in use. - - The best way of doing this is to make a function that - kmalloc()s an area of memory, and copies the __initdata - and then sets the relevant device's platform data. Making - the function `__init` takes care of ensuring it is discarded - with the rest of the initialisation code:: - - static __init void s3c24xx_xxx_set_platdata(struct xxx_data *pd) - { - struct s3c2410_xxx_mach_info *npd; - - npd = kmalloc(sizeof(struct s3c2410_xxx_mach_info), GFP_KERNEL); - if (npd) { - memcpy(npd, pd, sizeof(struct s3c2410_xxx_mach_info)); - s3c_device_xxx.dev.platform_data = npd; - } else { - printk(KERN_ERR "no memory for xxx platform data\n"); - } - } - - Note, since the code is marked as __init, it should not be - exported outside arch/arm/mach-s3c/, or exported to - modules via EXPORT_SYMBOL() and related functions. - - -Port Contributors ------------------ - - Ben Dooks (BJD) - Vincent Sanders - Herbert Potzl - Arnaud Patard (RTP) - Roc Wu - Klaus Fetscher - Dimitry Andric - Shannon Holland - Guillaume Gourat (NexVision) - Christer Weinigel (wingel) (Acer N30) - Lucas Correia Villa Real (S3C2400 port) - - -Document Author ---------------- - -Ben Dooks, Copyright 2004-2006 Simtec Electronics diff --git a/Documentation/arm/samsung-s3c24xx/s3c2412.rst b/Documentation/arm/samsung-s3c24xx/s3c2412.rst deleted file mode 100644 index 68b985fc6bf4..000000000000 --- a/Documentation/arm/samsung-s3c24xx/s3c2412.rst +++ /dev/null @@ -1,121 +0,0 @@ -========================== -S3C2412 ARM Linux Overview -========================== - -Introduction ------------- - - The S3C2412 is part of the S3C24XX range of ARM9 System-on-Chip CPUs - from Samsung. This part has an ARM926-EJS core, capable of running up - to 266MHz (see data-sheet for more information) - - -Clock ------ - - The core clock code provides a set of clocks to the drivers, and allows - for source selection and a number of other features. - - -Power ------ - - No support for suspend/resume to RAM in the current system. - - -DMA ---- - - No current support for DMA. - - -GPIO ----- - - There is support for setting the GPIO to input/output/special function - and reading or writing to them. - - -UART ----- - - The UART hardware is similar to the S3C2440, and is supported by the - s3c2410 driver in the drivers/serial directory. - - -NAND ----- - - The NAND hardware is similar to the S3C2440, and is supported by the - s3c2410 driver in the drivers/mtd/nand/raw directory. - - -USB Host --------- - - The USB hardware is similar to the S3C2410, with extended clock source - control. The OHCI portion is supported by the ohci-s3c2410 driver, and - the clock control selection is supported by the core clock code. - - -USB Device ----------- - - No current support in the kernel - - -IRQs ----- - - All the standard, and external interrupt sources are supported. The - extra sub-sources are not yet supported. - - -RTC ---- - - The RTC hardware is similar to the S3C2410, and is supported by the - s3c2410-rtc driver. - - -Watchdog --------- - - The watchdog hardware is the same as the S3C2410, and is supported by - the s3c2410_wdt driver. - - -MMC/SD/SDIO ------------ - - No current support for the MMC/SD/SDIO block. - -IIC ---- - - The IIC hardware is the same as the S3C2410, and is supported by the - i2c-s3c24xx driver. - - -IIS ---- - - No current support for the IIS interface. - - -SPI ---- - - No current support for the SPI interfaces. - - -ATA ---- - - No current support for the on-board ATA block. - - -Document Author ---------------- - -Ben Dooks, Copyright 2006 Simtec Electronics diff --git a/Documentation/arm/samsung-s3c24xx/s3c2413.rst b/Documentation/arm/samsung-s3c24xx/s3c2413.rst deleted file mode 100644 index 1f51e207fc46..000000000000 --- a/Documentation/arm/samsung-s3c24xx/s3c2413.rst +++ /dev/null @@ -1,22 +0,0 @@ -========================== -S3C2413 ARM Linux Overview -========================== - -Introduction ------------- - - The S3C2413 is an extended version of the S3C2412, with an camera - interface and mobile DDR memory support. See the S3C2412 support - documentation for more information. - - -Camera Interface ----------------- - - This block is currently not supported. - - -Document Author ---------------- - -Ben Dooks, Copyright 2006 Simtec Electronics diff --git a/Documentation/arm/samsung-s3c24xx/smdk2440.rst b/Documentation/arm/samsung-s3c24xx/smdk2440.rst deleted file mode 100644 index 524fd0b4afaf..000000000000 --- a/Documentation/arm/samsung-s3c24xx/smdk2440.rst +++ /dev/null @@ -1,57 +0,0 @@ -========================= -Samsung/Meritech SMDK2440 -========================= - -Introduction ------------- - - The SMDK2440 is a two part evaluation board for the Samsung S3C2440 - processor. It includes support for LCD, SmartMedia, Audio, SD and - 10MBit Ethernet, and expansion headers for various signals, including - the camera and unused GPIO. - - -Configuration -------------- - - To set the default configuration, use `make smdk2440_defconfig` which - will configure the common features of this board, or use - `make s3c2410_config` to include support for all s3c2410/s3c2440 machines - - -Support -------- - - Ben Dooks' SMDK2440 site at http://www.fluff.org/ben/smdk2440/ which - includes linux based USB download tools. - - Some of the h1940 patches that can be found from the H1940 project - site at http://www.handhelds.org/projects/h1940.html can also be - applied to this board. - - -Peripherals ------------ - - There is no current support for any of the extra peripherals on the - base-board itself. - - -MTD ---- - - The NAND flash should be supported by the in kernel MTD NAND support, - NOR flash will be added later. - - -Maintainers ------------ - - This board is being maintained by Ben Dooks, for more info, see - http://www.fluff.org/ben/smdk2440/ - - Many thanks to Dimitry Andric of TomTom for the loan of the SMDK2440, - and to Simtec Electronics for allowing me time to work on this. - - -(c) 2004 Ben Dooks diff --git a/Documentation/arm/samsung-s3c24xx/suspend.rst b/Documentation/arm/samsung-s3c24xx/suspend.rst deleted file mode 100644 index b4f3ae9fe76e..000000000000 --- a/Documentation/arm/samsung-s3c24xx/suspend.rst +++ /dev/null @@ -1,137 +0,0 @@ -======================= -S3C24XX Suspend Support -======================= - - -Introduction ------------- - - The S3C24XX supports a low-power suspend mode, where the SDRAM is kept - in Self-Refresh mode, and all but the essential peripheral blocks are - powered down. For more information on how this works, please look - at the relevant CPU datasheet from Samsung. - - -Requirements ------------- - - 1) A bootloader that can support the necessary resume operation - - 2) Support for at least 1 source for resume - - 3) CONFIG_PM enabled in the kernel - - 4) Any peripherals that are going to be powered down at the same - time require suspend/resume support. - - -Resuming --------- - - The S3C2410 user manual defines the process of sending the CPU to - sleep and how it resumes. The default behaviour of the Linux code - is to set the GSTATUS3 register to the physical address of the - code to resume Linux operation. - - GSTATUS4 is currently left alone by the sleep code, and is free to - use for any other purposes (for example, the EB2410ITX uses this to - save memory configuration in). - - -Machine Support ---------------- - - The machine specific functions must call the s3c_pm_init() function - to say that its bootloader is capable of resuming. This can be as - simple as adding the following to the machine's definition: - - INITMACHINE(s3c_pm_init) - - A board can do its own setup before calling s3c_pm_init, if it - needs to setup anything else for power management support. - - There is currently no support for over-riding the default method of - saving the resume address, if your board requires it, then contact - the maintainer and discuss what is required. - - Note, the original method of adding an late_initcall() is wrong, - and will end up initialising all compiled machines' pm init! - - The following is an example of code used for testing wakeup from - an falling edge on IRQ_EINT0:: - - - static irqreturn_t button_irq(int irq, void *pw) - { - return IRQ_HANDLED; - } - - statuc void __init machine_init(void) - { - ... - - request_irq(IRQ_EINT0, button_irq, IRQF_TRIGGER_FALLING, - "button-irq-eint0", NULL); - - enable_irq_wake(IRQ_EINT0); - - s3c_pm_init(); - } - - -Debugging ---------- - - There are several important things to remember when using PM suspend: - - 1) The uart drivers will disable the clocks to the UART blocks when - suspending, which means that use of printascii() or similar direct - access to the UARTs will cause the debug to stop. - - 2) While the pm code itself will attempt to re-enable the UART clocks, - care should be taken that any external clock sources that the UARTs - rely on are still enabled at that point. - - 3) If any debugging is placed in the resume path, then it must have the - relevant clocks and peripherals setup before use (ie, bootloader). - - For example, if you transmit a character from the UART, the baud - rate and uart controls must be setup beforehand. - - -Configuration -------------- - - The S3C2410 specific configuration in `System Type` defines various - aspects of how the S3C2410 suspend and resume support is configured - - `S3C2410 PM Suspend debug` - - This option prints messages to the serial console before and after - the actual suspend, giving detailed information on what is - happening - - - `S3C2410 PM Suspend Memory CRC` - - Allows the entire memory to be checksummed before and after the - suspend to see if there has been any corruption of the contents. - - Note, the time to calculate the CRC is dependent on the CPU speed - and the size of memory. For an 64Mbyte RAM area on an 200MHz - S3C2410, this can take approximately 4 seconds to complete. - - This support requires the CRC32 function to be enabled. - - - `S3C2410 PM Suspend CRC Chunksize (KiB)` - - Defines the size of memory each CRC chunk covers. A smaller value - will mean that the CRC data block will take more memory, but will - identify any faults with better precision - - -Document Author ---------------- - -Ben Dooks, Copyright 2004 Simtec Electronics diff --git a/Documentation/arm/samsung-s3c24xx/usb-host.rst b/Documentation/arm/samsung-s3c24xx/usb-host.rst deleted file mode 100644 index 7aaffac89e04..000000000000 --- a/Documentation/arm/samsung-s3c24xx/usb-host.rst +++ /dev/null @@ -1,91 +0,0 @@ -======================== -S3C24XX USB Host support -======================== - - - -Introduction ------------- - - This document details the S3C2410/S3C2440 in-built OHCI USB host support. - -Configuration -------------- - - Enable at least the following kernel options: - - menuconfig:: - - Device Drivers ---> - USB support ---> - <*> Support for Host-side USB - <*> OHCI HCD support - - - .config: - - - CONFIG_USB - - CONFIG_USB_OHCI_HCD - - - Once these options are configured, the standard set of USB device - drivers can be configured and used. - - -Board Support -------------- - - The driver attaches to a platform device, which will need to be - added by the board specific support file in arch/arm/mach-s3c, - such as mach-bast.c or mach-smdk2410.c - - The platform device's platform_data field is only needed if the - board implements extra power control or over-current monitoring. - - The OHCI driver does not ensure the state of the S3C2410's MISCCTRL - register, so if both ports are to be used for the host, then it is - the board support file's responsibility to ensure that the second - port is configured to be connected to the OHCI core. - - -Platform Data -------------- - - See include/linux/platform_data/usb-ohci-s3c2410.h for the - descriptions of the platform device data. An implementation - can be found in arch/arm/mach-s3c/simtec-usb.c . - - The `struct s3c2410_hcd_info` contains a pair of functions - that get called to enable over-current detection, and to - control the port power status. - - The ports are numbered 0 and 1. - - power_control: - Called to enable or disable the power on the port. - - enable_oc: - Called to enable or disable the over-current monitoring. - This should claim or release the resources being used to - check the power condition on the port, such as an IRQ. - - report_oc: - The OHCI driver fills this field in for the over-current code - to call when there is a change to the over-current state on - an port. The ports argument is a bitmask of 1 bit per port, - with bit X being 1 for an over-current on port X. - - The function s3c2410_usb_report_oc() has been provided to - ensure this is called correctly. - - port[x]: - This is struct describes each port, 0 or 1. The platform driver - should set the flags field of each port to S3C_HCDFLG_USED if - the port is enabled. - - - -Document Author ---------------- - -Ben Dooks, Copyright 2005 Simtec Electronics diff --git a/Documentation/arm/samsung/gpio.rst b/Documentation/arm/samsung/gpio.rst index f6e27b07c993..27fae0d50361 100644 --- a/Documentation/arm/samsung/gpio.rst +++ b/Documentation/arm/samsung/gpio.rst @@ -9,14 +9,6 @@ This outlines the Samsung GPIO implementation and the architecture specific calls provided alongside the drivers/gpio core. -S3C24XX (Legacy) ----------------- - -See Documentation/arm/samsung-s3c24xx/gpio.rst for more information -about these devices. Their implementation has been brought into line -with the core samsung implementation described in this document. - - GPIOLIB integration ------------------- diff --git a/Documentation/arm/samsung/overview.rst b/Documentation/arm/samsung/overview.rst index e74307897416..8b15a190169b 100644 --- a/Documentation/arm/samsung/overview.rst +++ b/Documentation/arm/samsung/overview.rst @@ -12,21 +12,10 @@ Introduction The currently supported SoCs are: - - S3C24XX: See Documentation/arm/samsung-s3c24xx/overview.rst for full list - S3C64XX: S3C6400 and S3C6410 - S5PC110 / S5PV210 -S3C24XX Systems ---------------- - - There is still documentation in Documnetation/arm/Samsung-S3C24XX/ which - deals with the architecture and drivers specific to these devices. - - See Documentation/arm/samsung-s3c24xx/overview.rst for more information - on the implementation details and specific support. - - Configuration ------------- @@ -51,8 +40,6 @@ Layout specific information. It contains the base clock, GPIO and device definitions to get the system running. - plat-s3c24xx is for s3c24xx specific builds, see the S3C24XX docs. - plat-s5p is for s5p specific builds, and contains common support for the S5P specific systems. Not all S5Ps use all the features in this directory due to differences in the hardware. diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt deleted file mode 100644 index 2632d3f13004..000000000000 --- a/Documentation/devicetree/bindings/clock/samsung,s3c2410-clock.txt +++ /dev/null @@ -1,49 +0,0 @@ -* Samsung S3C2410 Clock Controller - -The S3C2410 clock controller generates and supplies clock to various controllers -within the SoC. The clock binding described here is applicable to the s3c2410, -s3c2440 and s3c2442 SoCs in the s3c24x family. - -Required Properties: - -- compatible: should be one of the following. - - "samsung,s3c2410-clock" - controller compatible with S3C2410 SoC. - - "samsung,s3c2440-clock" - controller compatible with S3C2440 SoC. - - "samsung,s3c2442-clock" - controller compatible with S3C2442 SoC. -- reg: physical base address of the controller and length of memory mapped - region. -- #clock-cells: should be 1. - -Each clock is assigned an identifier and client nodes can use this identifier -to specify the clock which they consume. Some of the clocks are available only -on a particular SoC. - -All available clocks are defined as preprocessor macros in -dt-bindings/clock/s3c2410.h header and can be used in device -tree sources. - -External clocks: - -The xti clock used as input for the plls is generated outside the SoC. It is -expected that is are defined using standard clock bindings with a -clock-output-names value of "xti". - -Example: Clock controller node: - - clocks: clock-controller@4c000000 { - compatible = "samsung,s3c2410-clock"; - reg = <0x4c000000 0x20>; - #clock-cells = <1>; - }; - -Example: UART controller node that consumes the clock generated by the clock - controller (refer to the standard clock bindings for information about - "clocks" and "clock-names" properties): - - serial@50004000 { - compatible = "samsung,s3c2440-uart"; - reg = <0x50004000 0x4000>; - interrupts = <1 23 3 4>, <1 23 4 4>; - clock-names = "uart", "clk_uart_baud2"; - clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>; - }; diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt deleted file mode 100644 index 21a8c23e658f..000000000000 --- a/Documentation/devicetree/bindings/clock/samsung,s3c2412-clock.txt +++ /dev/null @@ -1,49 +0,0 @@ -* Samsung S3C2412 Clock Controller - -The S3C2412 clock controller generates and supplies clock to various controllers -within the SoC. The clock binding described here is applicable to the s3c2412 -and s3c2413 SoCs in the s3c24x family. - -Required Properties: - -- compatible: should be "samsung,s3c2412-clock" -- reg: physical base address of the controller and length of memory mapped - region. -- #clock-cells: should be 1. - -Each clock is assigned an identifier and client nodes can use this identifier -to specify the clock which they consume. Some of the clocks are available only -on a particular SoC. - -All available clocks are defined as preprocessor macros in -dt-bindings/clock/s3c2412.h header and can be used in device -tree sources. - -External clocks: - -There are several clocks that are generated outside the SoC. It is expected -that they are defined using standard clock bindings with following -clock-output-names: - - "xti" - crystal input - required, - - "ext" - external clock source - optional, - -Example: Clock controller node: - - clocks: clock-controller@4c000000 { - compatible = "samsung,s3c2412-clock"; - reg = <0x4c000000 0x20>; - #clock-cells = <1>; - }; - -Example: UART controller node that consumes the clock generated by the clock - controller (refer to the standard clock bindings for information about - "clocks" and "clock-names" properties): - - serial@50004000 { - compatible = "samsung,s3c2412-uart"; - reg = <0x50004000 0x4000>; - interrupts = <1 23 3 4>, <1 23 4 4>; - clock-names = "uart", "clk_uart_baud2", "clk_uart_baud3"; - clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>, - <&clocks SCLK_UART>; - }; diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt deleted file mode 100644 index 985c0f574e9a..000000000000 --- a/Documentation/devicetree/bindings/clock/samsung,s3c2443-clock.txt +++ /dev/null @@ -1,55 +0,0 @@ -* Samsung S3C2443 Clock Controller - -The S3C2443 clock controller generates and supplies clock to various controllers -within the SoC. The clock binding described here is applicable to all SoCs in -the s3c24x family starting with the s3c2443. - -Required Properties: - -- compatible: should be one of the following. - - "samsung,s3c2416-clock" - controller compatible with S3C2416 SoC. - - "samsung,s3c2443-clock" - controller compatible with S3C2443 SoC. - - "samsung,s3c2450-clock" - controller compatible with S3C2450 SoC. -- reg: physical base address of the controller and length of memory mapped - region. -- #clock-cells: should be 1. - -Each clock is assigned an identifier and client nodes can use this identifier -to specify the clock which they consume. Some of the clocks are available only -on a particular SoC. - -All available clocks are defined as preprocessor macros in -dt-bindings/clock/s3c2443.h header and can be used in device -tree sources. - -External clocks: - -There are several clocks that are generated outside the SoC. It is expected -that they are defined using standard clock bindings with following -clock-output-names: - - "xti" - crystal input - required, - - "ext" - external clock source - optional, - - "ext_i2s" - external I2S clock - optional, - - "ext_uart" - external uart clock - optional, - -Example: Clock controller node: - - clocks: clock-controller@4c000000 { - compatible = "samsung,s3c2416-clock"; - reg = <0x4c000000 0x40>; - #clock-cells = <1>; - }; - -Example: UART controller node that consumes the clock generated by the clock - controller (refer to the standard clock bindings for information about - "clocks" and "clock-names" properties): - - serial@50004000 { - compatible = "samsung,s3c2440-uart"; - reg = <0x50004000 0x4000>; - interrupts = <1 23 3 4>, <1 23 4 4>; - clock-names = "uart", "clk_uart_baud2", - "clk_uart_baud3"; - clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>, - <&clocks SCLK_UART>; - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt deleted file mode 100644 index c54c5a9a2a90..000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt +++ /dev/null @@ -1,53 +0,0 @@ -Samsung S3C24XX Interrupt Controllers - -The S3C24XX SoCs contain a custom set of interrupt controllers providing a -varying number of interrupt sources. The set consists of a main- and sub- -controller and on newer SoCs even a second main controller. - -Required properties: -- compatible: Compatible property value should be "samsung,s3c2410-irq" - for machines before s3c2416 and "samsung,s3c2416-irq" for s3c2416 and later. - -- reg: Physical base address of the controller and length of memory mapped - region. - -- interrupt-controller : Identifies the node as an interrupt controller - -- #interrupt-cells : Specifies the number of cells needed to encode an - interrupt source. The value shall be 4 and interrupt descriptor shall - have the following format: - - - ctrl_num contains the controller to use: - - 0 ... main controller - - 1 ... sub controller - - 2 ... second main controller on s3c2416 and s3c2450 - parent_irq contains the parent bit in the main controller and will be - ignored in main controllers - ctrl_irq contains the interrupt bit of the controller - type contains the trigger type to use - -Example: - - interrupt-controller@4a000000 { - compatible = "samsung,s3c2410-irq"; - reg = <0x4a000000 0x100>; - interrupt-controller; - #interrupt-cells=<4>; - }; - - [...] - - serial@50000000 { - compatible = "samsung,s3c2410-uart"; - reg = <0x50000000 0x4000>; - interrupt-parent = <&subintc>; - interrupts = <1 28 0 4>, <1 28 1 4>; - }; - - rtc@57000000 { - compatible = "samsung,s3c2410-rtc"; - reg = <0x57000000 0x100>; - interrupt-parent = <&intc>; - interrupts = <0 30 0 3>, <0 8 0 3>; - }; diff --git a/Documentation/devicetree/bindings/mmc/samsung,s3cmci.txt b/Documentation/devicetree/bindings/mmc/samsung,s3cmci.txt deleted file mode 100644 index 5f68feb9f9d6..000000000000 --- a/Documentation/devicetree/bindings/mmc/samsung,s3cmci.txt +++ /dev/null @@ -1,42 +0,0 @@ -* Samsung's S3C24XX MMC/SD/SDIO controller device tree bindings - -Samsung's S3C24XX MMC/SD/SDIO controller is used as a connectivity interface -with external MMC, SD and SDIO storage mediums. - -This file documents differences between the core mmc properties described by -mmc.txt and the properties used by the Samsung S3C24XX MMC/SD/SDIO controller -implementation. - -Required SoC Specific Properties: -- compatible: should be one of the following - - "samsung,s3c2410-sdi": for controllers compatible with s3c2410 - - "samsung,s3c2412-sdi": for controllers compatible with s3c2412 - - "samsung,s3c2440-sdi": for controllers compatible with s3c2440 -- reg: register location and length -- interrupts: mmc controller interrupt -- clocks: Should reference the controller clock -- clock-names: Should contain "sdi" - -Required Board Specific Properties: -- pinctrl-0: Should specify pin control groups used for this controller. -- pinctrl-names: Should contain only one value - "default". - -Optional Properties: -- bus-width: number of data lines (see mmc.txt) -- cd-gpios: gpio for card detection (see mmc.txt) -- wp-gpios: gpio for write protection (see mmc.txt) - -Example: - - mmc0: mmc@5a000000 { - compatible = "samsung,s3c2440-sdi"; - pinctrl-names = "default"; - pinctrl-0 = <&sdi_pins>; - reg = <0x5a000000 0x100000>; - interrupts = <0 0 21 3>; - clocks = <&clocks PCLK_SDI>; - clock-names = "sdi"; - bus-width = <4>; - cd-gpios = <&gpg 8 GPIO_ACTIVE_LOW>; - wp-gpios = <&gph 8 GPIO_ACTIVE_LOW>; - }; diff --git a/MAINTAINERS b/MAINTAINERS index c03be77e8060..5414b920f411 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2583,13 +2583,6 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm64/boot/dts/freescale/s32g*.dts* -ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT -L: openmoko-kernel@lists.openmoko.org (subscribers-only) -S: Orphan -W: http://wiki.openmoko.org/wiki/Neo_FreeRunner -F: arch/arm/mach-s3c/gta02.h -F: arch/arm/mach-s3c/mach-gta02.c - ARM/Orion SoC/Technologic Systems TS-78xx platform support M: Alexander Clouter L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -2796,7 +2789,6 @@ F: include/linux/platform_data/*s3c* F: include/linux/serial_s3c.h F: include/linux/soc/samsung/ N: exynos -N: s3c2410 N: s3c64xx N: s5pv210 @@ -19042,14 +19034,6 @@ M: Simtec Linux Team S: Supported W: http://www.simtec.co.uk/products/EB110ATX/ -SIMTEC EB2410ITX (BAST) -M: Simtec Linux Team -S: Supported -W: http://www.simtec.co.uk/products/EB2410ITX/ -F: arch/arm/mach-s3c/bast-ide.c -F: arch/arm/mach-s3c/bast-irq.c -F: arch/arm/mach-s3c/mach-bast.c - SIOX M: Thorsten Scherer M: Uwe Kleine-König diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7742b35fe23a..67d96a7ddf1b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -282,7 +282,6 @@ config PHYS_OFFSET default DRAM_BASE if !MMU default 0x00000000 if ARCH_FOOTBRIDGE default 0x10000000 if ARCH_OMAP1 || ARCH_RPC - default 0x30000000 if ARCH_S3C24XX default 0xa0000000 if ARCH_PXA default 0xc0000000 if ARCH_EP93XX || ARCH_SA1100 default 0 diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 20312792340d..874551895181 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -1006,7 +1006,6 @@ choice config DEBUG_S3C_UART0 depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS select DEBUG_EXYNOS_UART if ARCH_EXYNOS - select DEBUG_S3C24XX_UART if ARCH_S3C24XX select DEBUG_S3C64XX_UART if ARCH_S3C64XX select DEBUG_S5PV210_UART if ARCH_S5PV210 bool "Use Samsung S3C UART 0 for low-level debug" @@ -1018,7 +1017,6 @@ choice config DEBUG_S3C_UART1 depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS select DEBUG_EXYNOS_UART if ARCH_EXYNOS - select DEBUG_S3C24XX_UART if ARCH_S3C24XX select DEBUG_S3C64XX_UART if ARCH_S3C64XX select DEBUG_S5PV210_UART if ARCH_S5PV210 bool "Use Samsung S3C UART 1 for low-level debug" @@ -1030,7 +1028,6 @@ choice config DEBUG_S3C_UART2 depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS select DEBUG_EXYNOS_UART if ARCH_EXYNOS - select DEBUG_S3C24XX_UART if ARCH_S3C24XX select DEBUG_S3C64XX_UART if ARCH_S3C64XX select DEBUG_S5PV210_UART if ARCH_S5PV210 bool "Use Samsung S3C UART 2 for low-level debug" @@ -1050,33 +1047,6 @@ choice their output to UART 3. The port must have been initialised by the boot-loader before use. - config DEBUG_S3C2410_UART0 - depends on ARCH_S3C24XX - select DEBUG_S3C2410_UART - bool "Use S3C2410/S3C2412 UART 0 for low-level debug" - help - Say Y here if you want the debug print routines to direct - their output to UART 0. The port must have been initialised - by the boot-loader before use. - - config DEBUG_S3C2410_UART1 - depends on ARCH_S3C24XX - select DEBUG_S3C2410_UART - bool "Use S3C2410/S3C2412 UART 1 for low-level debug" - help - Say Y here if you want the debug print routines to direct - their output to UART 1. The port must have been initialised - by the boot-loader before use. - - config DEBUG_S3C2410_UART2 - depends on ARCH_S3C24XX - select DEBUG_S3C2410_UART - bool "Use S3C2410/S3C2412 UART 2 for low-level debug" - help - Say Y here if you want the debug print routines to direct - their output to UART 2. The port must have been initialised - by the boot-loader before use. - config DEBUG_SA1100 depends on ARCH_SA1100 bool "Use SA1100 UARTs for low-level debug" @@ -1439,13 +1409,6 @@ config DEBUG_AT91_UART config DEBUG_EXYNOS_UART bool -config DEBUG_S3C2410_UART - bool - select DEBUG_S3C24XX_UART - -config DEBUG_S3C24XX_UART - bool - config DEBUG_S3C64XX_UART bool @@ -1453,8 +1416,7 @@ config DEBUG_S5PV210_UART bool config DEBUG_S3C_UART - depends on DEBUG_S3C2410_UART || DEBUG_S3C24XX_UART || \ - DEBUG_S3C64XX_UART || DEBUG_S5PV210_UART || \ + depends on DEBUG_S3C64XX_UART || DEBUG_S5PV210_UART || \ DEBUG_EXYNOS_UART int default "0" if DEBUG_S3C_UART0 @@ -1555,7 +1517,7 @@ config DEBUG_LL_INCLUDE default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA0 default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA1 default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA4 - default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART || DEBUG_S3C64XX_UART + default "debug/s3c24xx.S" if DEBUG_S3C64XX_UART default "debug/s5pv210.S" if DEBUG_S5PV210_UART default "debug/sti.S" if DEBUG_STIH41X_ASC2 default "debug/sti.S" if DEBUG_STIH41X_SBC_ASC1 @@ -1638,12 +1600,6 @@ config DEBUG_UART_PHYS default 0x4806e000 if DEBUG_OMAP2UART3 || DEBUG_OMAP4UART4 default 0x49020000 if DEBUG_OMAP3UART3 default 0x49042000 if DEBUG_OMAP3UART4 - default 0x50000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \ - DEBUG_S3C2410_UART0) - default 0x50004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \ - DEBUG_S3C2410_UART1) - default 0x50008000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART2 || \ - DEBUG_S3C2410_UART2) default 0x7c0003f8 if DEBUG_FOOTBRIDGE_COM1 default 0x7f005000 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART0 default 0x7f005400 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART1 @@ -1711,7 +1667,7 @@ config DEBUG_UART_PHYS DEBUG_RCAR_GEN2_SCIF2 || DEBUG_RCAR_GEN2_SCIF4 || \ DEBUG_RCAR_GEN2_SCIFA2 || \ DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ - DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \ + DEBUG_RMOBILE_SCIFA4 || \ DEBUG_S3C64XX_UART || \ DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ DEBUG_DIGICOLOR_UA0 || \ @@ -1748,15 +1704,9 @@ config DEBUG_UART_VIRT default 0xf6200000 if DEBUG_PXA_UART1 default 0xf7000000 if DEBUG_SUN9I_UART0 default 0xf7000000 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART0 - default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \ - DEBUG_S3C2410_UART0) default 0xf7000400 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART1 default 0xf7000800 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART2 default 0xf7000c00 if DEBUG_S3C64XX_UART && DEBUG_S3C_UART3 - default 0xf7004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \ - DEBUG_S3C2410_UART1) - default 0xf7008000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART2 || \ - DEBUG_S3C2410_UART2) default 0xf7020000 if DEBUG_AT91_SAMA5D2_UART1 default 0xf7fc9000 if DEBUG_BERLIN_UART default 0xf8007000 if DEBUG_HIP04_UART @@ -1820,7 +1770,7 @@ config DEBUG_UART_VIRT default DEBUG_UART_PHYS if !MMU depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ - DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ + DEBUG_QCOM_UARTDM || \ DEBUG_S3C64XX_UART || \ DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ DEBUG_DIGICOLOR_UA0 || \ diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 8fc34ec5dd84..02d07a07174e 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -152,8 +152,6 @@ CHECKFLAGS += -D__arm__ # during boot, and this offset is critical to the functioning of # kexec-tools. textofs-y := 0x00008000 -# We don't want the htc bootloader to corrupt kernel during resume -textofs-$(CONFIG_PM_H1940) := 0x00108000 # RTD1195 has Boot ROM at start of address space textofs-$(CONFIG_ARCH_REALTEK) := 0x00108000 # SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index d08a3c450ce7..aee97fa75dd1 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1163,8 +1163,6 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-veyron-speedy.dtb \ rk3288-veyron-tiger.dtb \ rk3288-vyasa.dtb -dtb-$(CONFIG_ARCH_S3C24XX) += \ - s3c2416-smdk2416.dtb dtb-$(CONFIG_ARCH_S3C64XX) += \ s3c6410-mini6410.dtb \ s3c6410-smdk6410.dtb diff --git a/arch/arm/boot/dts/s3c2410-pinctrl.h b/arch/arm/boot/dts/s3c2410-pinctrl.h deleted file mode 100644 index 76b6171ae149..000000000000 --- a/arch/arm/boot/dts/s3c2410-pinctrl.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Samsung S3C2410 DTS pinctrl constants - * - * Copyright (c) 2016 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * Copyright (c) 2022 Linaro Ltd - * Author: Krzysztof Kozlowski - */ - -#ifndef __DTS_ARM_SAMSUNG_S3C2410_PINCTRL_H__ -#define __DTS_ARM_SAMSUNG_S3C2410_PINCTRL_H__ - -#define S3C2410_PIN_FUNC_INPUT 0 -#define S3C2410_PIN_FUNC_OUTPUT 1 -#define S3C2410_PIN_FUNC_2 2 -#define S3C2410_PIN_FUNC_3 3 - -#endif /* __DTS_ARM_SAMSUNG_S3C2410_PINCTRL_H__ */ diff --git a/arch/arm/boot/dts/s3c2416-pinctrl.dtsi b/arch/arm/boot/dts/s3c2416-pinctrl.dtsi deleted file mode 100644 index 3268366bd8bc..000000000000 --- a/arch/arm/boot/dts/s3c2416-pinctrl.dtsi +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Samsung S3C2416 pinctrl settings - * - * Copyright (c) 2013 Heiko Stuebner - */ - -#include "s3c2410-pinctrl.h" - -&pinctrl_0 { - /* - * Pin banks - */ - - gpa: gpa-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpb: gpb-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpc: gpc-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpd: gpd-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpe: gpe-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpf: gpf-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpg: gpg-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gph: gph-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpj: gpj-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpk: gpk-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpl: gpl-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - gpm: gpm-gpio-bank { - gpio-controller; - #gpio-cells = <2>; - }; - - /* - * Pin groups - */ - - uart0_data: uart0-data-pins { - samsung,pins = "gph-0", "gph-1"; - samsung,pin-function = ; - }; - - uart0_fctl: uart0-fctl-pins { - samsung,pins = "gph-8", "gph-9"; - samsung,pin-function = ; - }; - - uart1_data: uart1-data-pins { - samsung,pins = "gph-2", "gph-3"; - samsung,pin-function = ; - }; - - uart1_fctl: uart1-fctl-pins { - samsung,pins = "gph-10", "gph-11"; - samsung,pin-function = ; - }; - - uart2_data: uart2-data-pins { - samsung,pins = "gph-4", "gph-5"; - samsung,pin-function = ; - }; - - uart2_fctl: uart2-fctl-pins { - samsung,pins = "gph-6", "gph-7"; - samsung,pin-function = ; - }; - - uart3_data: uart3-data-pins { - samsung,pins = "gph-6", "gph-7"; - samsung,pin-function = ; - }; - - extuart_clk: extuart-clk-pins { - samsung,pins = "gph-12"; - samsung,pin-function = ; - }; - - i2c0_bus: i2c0-bus-pins { - samsung,pins = "gpe-14", "gpe-15"; - samsung,pin-function = ; - }; - - spi0_bus: spi0-bus-pins { - samsung,pins = "gpe-11", "gpe-12", "gpe-13"; - samsung,pin-function = ; - }; - - sd0_clk: sd0-clk-pins { - samsung,pins = "gpe-5"; - samsung,pin-function = ; - }; - - sd0_cmd: sd0-cmd-pins { - samsung,pins = "gpe-6"; - samsung,pin-function = ; - }; - - sd0_bus1: sd0-bus1-pins { - samsung,pins = "gpe-7"; - samsung,pin-function = ; - }; - - sd0_bus4: sd0-bus4-pins { - samsung,pins = "gpe-8", "gpe-9", "gpe-10"; - samsung,pin-function = ; - }; - - sd1_cmd: sd1-cmd-pins { - samsung,pins = "gpl-8"; - samsung,pin-function = ; - }; - - sd1_clk: sd1-clk-pins { - samsung,pins = "gpl-9"; - samsung,pin-function = ; - }; - - sd1_bus1: sd1-bus1-pins { - samsung,pins = "gpl-0"; - samsung,pin-function = ; - }; - - sd1_bus4: sd1-bus4-pins { - samsung,pins = "gpl-1", "gpl-2", "gpl-3"; - samsung,pin-function = ; - }; -}; diff --git a/arch/arm/boot/dts/s3c2416-smdk2416.dts b/arch/arm/boot/dts/s3c2416-smdk2416.dts deleted file mode 100644 index e7c379a9842e..000000000000 --- a/arch/arm/boot/dts/s3c2416-smdk2416.dts +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Samsung SMDK2416 board device tree source - * - * Copyright (c) 2013 Heiko Stuebner - */ - -/dts-v1/; -#include "s3c2416.dtsi" - -/ { - model = "SMDK2416"; - compatible = "samsung,smdk2416", "samsung,s3c2416"; - - memory@30000000 { - device_type = "memory"; - reg = <0x30000000 0x4000000>; - }; - - xti: clock-0 { - compatible = "fixed-clock"; - clock-frequency = <12000000>; - clock-output-names = "xti"; - #clock-cells = <0>; - }; -}; - -&rtc { - status = "okay"; -}; - -&sdhci_0 { - pinctrl-names = "default"; - pinctrl-0 = <&sd1_clk>, <&sd1_cmd>, - <&sd1_bus1>, <&sd1_bus4>; - bus-width = <4>; - broken-cd; - status = "okay"; -}; - -&sdhci_1 { - pinctrl-names = "default"; - pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, - <&sd0_bus1>, <&sd0_bus4>; - bus-width = <4>; - cd-gpios = <&gpf 1 0>; - cd-inverted; - status = "okay"; -}; - -&uart_0 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&uart0_data>, <&uart0_fctl>; -}; - -&uart_1 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&uart1_data>, <&uart1_fctl>; -}; - -&uart_2 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&uart2_data>; -}; - -&uart_3 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&uart3_data>; -}; - -&watchdog { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/s3c2416.dtsi b/arch/arm/boot/dts/s3c2416.dtsi deleted file mode 100644 index 4660751cb207..000000000000 --- a/arch/arm/boot/dts/s3c2416.dtsi +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Samsung's S3C2416 SoC device tree source - * - * Copyright (c) 2013 Heiko Stuebner - */ - -#include -#include "s3c24xx.dtsi" -#include "s3c2416-pinctrl.dtsi" - -/ { - model = "Samsung S3C2416 SoC"; - compatible = "samsung,s3c2416"; - - aliases { - serial3 = &uart_3; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - compatible = "arm,arm926ej-s"; - reg = <0x0>; - }; - }; - - clocks: clock-controller@4c000000 { - compatible = "samsung,s3c2416-clock"; - reg = <0x4c000000 0x40>; - #clock-cells = <1>; - }; - - uart_3: serial@5000c000 { - compatible = "samsung,s3c2440-uart"; - reg = <0x5000C000 0x4000>; - interrupts = <1 18 24 4>, <1 18 25 4>; - clock-names = "uart", "clk_uart_baud2", - "clk_uart_baud3"; - clocks = <&clocks PCLK_UART3>, <&clocks PCLK_UART3>, - <&clocks SCLK_UART>; - status = "disabled"; - }; - - sdhci_1: mmc@4ac00000 { - compatible = "samsung,s3c6410-sdhci"; - reg = <0x4AC00000 0x100>; - interrupts = <0 0 21 3>; - clock-names = "hsmmc", "mmc_busclk.0", - "mmc_busclk.2"; - clocks = <&clocks HCLK_HSMMC0>, <&clocks HCLK_HSMMC0>, - <&clocks MUX_HSMMC0>; - status = "disabled"; - }; - - sdhci_0: mmc@4a800000 { - compatible = "samsung,s3c6410-sdhci"; - reg = <0x4A800000 0x100>; - interrupts = <0 0 20 3>; - clock-names = "hsmmc", "mmc_busclk.0", - "mmc_busclk.2"; - clocks = <&clocks HCLK_HSMMC1>, <&clocks HCLK_HSMMC1>, - <&clocks MUX_HSMMC1>; - status = "disabled"; - }; -}; - -&i2c { - compatible = "samsung,s3c2440-i2c"; - clocks = <&clocks PCLK_I2C0>; - clock-names = "i2c"; -}; - -&intc { - compatible = "samsung,s3c2416-irq"; -}; - -&pinctrl_0 { - compatible = "samsung,s3c2416-pinctrl"; -}; - -&rtc { - compatible = "samsung,s3c2416-rtc"; - clocks = <&clocks PCLK_RTC>; - clock-names = "rtc"; -}; - -&timer { - clocks = <&clocks PCLK_PWM>; - clock-names = "timers"; -}; - -&uart_0 { - compatible = "samsung,s3c2440-uart"; - clock-names = "uart", "clk_uart_baud2", - "clk_uart_baud3"; - clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>, - <&clocks SCLK_UART>; -}; - -&uart_1 { - compatible = "samsung,s3c2440-uart"; - clock-names = "uart", "clk_uart_baud2", - "clk_uart_baud3"; - clocks = <&clocks PCLK_UART1>, <&clocks PCLK_UART1>, - <&clocks SCLK_UART>; -}; - -&uart_2 { - compatible = "samsung,s3c2440-uart"; - clock-names = "uart", "clk_uart_baud2", - "clk_uart_baud3"; - clocks = <&clocks PCLK_UART2>, <&clocks PCLK_UART2>, - <&clocks SCLK_UART>; -}; - -&watchdog { - interrupts = <1 9 27 3>; - clocks = <&clocks PCLK_WDT>; - clock-names = "watchdog"; -}; diff --git a/arch/arm/boot/dts/s3c24xx.dtsi b/arch/arm/boot/dts/s3c24xx.dtsi deleted file mode 100644 index 06f82c7e458e..000000000000 --- a/arch/arm/boot/dts/s3c24xx.dtsi +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Samsung's S3C24XX family device tree source - * - * Copyright (c) 2013 Heiko Stuebner - */ - -/ { - compatible = "samsung,s3c24xx"; - interrupt-parent = <&intc>; - #address-cells = <1>; - #size-cells = <1>; - - aliases { - pinctrl0 = &pinctrl_0; - serial0 = &uart_0; - serial1 = &uart_1; - serial2 = &uart_2; - }; - - intc: interrupt-controller@4a000000 { - compatible = "samsung,s3c2410-irq"; - reg = <0x4a000000 0x100>; - interrupt-controller; - #interrupt-cells = <4>; - }; - - pinctrl_0: pinctrl@56000000 { - reg = <0x56000000 0x1000>; - - wakeup-interrupt-controller { - compatible = "samsung,s3c2410-wakeup-eint"; - interrupts = <0 0 0 3>, - <0 0 1 3>, - <0 0 2 3>, - <0 0 3 3>, - <0 0 4 4>, - <0 0 5 4>; - }; - }; - - timer: pwm@51000000 { - compatible = "samsung,s3c2410-pwm"; - reg = <0x51000000 0x1000>; - interrupts = <0 0 10 3>, <0 0 11 3>, <0 0 12 3>, <0 0 13 3>, <0 0 14 3>; - #pwm-cells = <3>; - }; - - uart_0: serial@50000000 { - compatible = "samsung,s3c2410-uart"; - reg = <0x50000000 0x4000>; - interrupts = <1 28 0 4>, <1 28 1 4>; - status = "disabled"; - }; - - uart_1: serial@50004000 { - compatible = "samsung,s3c2410-uart"; - reg = <0x50004000 0x4000>; - interrupts = <1 23 3 4>, <1 23 4 4>; - status = "disabled"; - }; - - uart_2: serial@50008000 { - compatible = "samsung,s3c2410-uart"; - reg = <0x50008000 0x4000>; - interrupts = <1 15 6 4>, <1 15 7 4>; - status = "disabled"; - }; - - watchdog: watchdog@53000000 { - compatible = "samsung,s3c2410-wdt"; - reg = <0x53000000 0x100>; - interrupts = <0 0 9 3>; - status = "disabled"; - }; - - rtc: rtc@57000000 { - compatible = "samsung,s3c2410-rtc"; - reg = <0x57000000 0x100>; - interrupts = <0 0 30 3>, <0 0 8 3>; - status = "disabled"; - }; - - i2c: i2c@54000000 { - compatible = "samsung,s3c2410-i2c"; - reg = <0x54000000 0x100>; - interrupts = <0 0 27 3>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; -}; diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig deleted file mode 100644 index 86e00f684e16..000000000000 --- a/arch/arm/configs/mini2440_defconfig +++ /dev/null @@ -1,338 +0,0 @@ -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_ARCH_MULTI_V4T=y -# CONFIG_ARCH_MULTI_V7 is not set -CONFIG_ARCH_S3C24XX=y -CONFIG_S3C_ADC=y -# CONFIG_CPU_S3C2410 is not set -CONFIG_CPU_S3C2440=y -CONFIG_MACH_MINI2440=y -CONFIG_AEABI=y -CONFIG_UNUSED_BOARD_FILES=y -CONFIG_KEXEC=y -CONFIG_CPU_IDLE=y -CONFIG_APM_EMULATION=y -CONFIG_MODULES=y -CONFIG_MODULE_FORCE_LOAD=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_BLK_DEV_INTEGRITY=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -CONFIG_LDM_PARTITION=y -CONFIG_BINFMT_MISC=m -# CONFIG_COMPAT_BRK is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_NET_KEY=m -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_SYN_COOKIES=y -CONFIG_INET_DIAG=m -# CONFIG_IPV6 is not set -CONFIG_NETFILTER=y -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m -CONFIG_VLAN_8021Q_GVRP=y -CONFIG_NET_PKTGEN=m -CONFIG_BT=m -CONFIG_BT_RFCOMM=m -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=m -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=m -CONFIG_BT_HCIBTUSB=m -CONFIG_BT_HCIBTSDIO=m -CONFIG_BT_HCIUART=m -CONFIG_BT_HCIUART_BCSP=y -CONFIG_BT_HCIUART_LL=y -CONFIG_BT_HCIBCM203X=m -CONFIG_BT_HCIBPA10X=m -CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIVHCI=m -CONFIG_CFG80211=m -CONFIG_MAC80211=m -CONFIG_MAC80211_MESH=y -CONFIG_MAC80211_LEDS=y -CONFIG_CONNECTOR=m -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=y -CONFIG_FTL=y -CONFIG_NFTL=y -CONFIG_NFTL_RW=y -CONFIG_INFTL=y -CONFIG_RFD_FTL=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_CFI_STAA=y -CONFIG_MTD_RAM=y -CONFIG_MTD_ROM=y -CONFIG_MTD_RAW_NAND=y -CONFIG_MTD_NAND_S3C2410=y -CONFIG_MTD_NAND_PLATFORM=y -CONFIG_MTD_LPDDR=y -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=65536 -CONFIG_CDROM_PKTCDVD=m -CONFIG_SENSORS_TSL2550=m -CONFIG_EEPROM_AT24=y -CONFIG_SCSI=m -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=m -CONFIG_CHR_DEV_SG=m -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_SCSI_LOWLEVEL is not set -CONFIG_NETDEVICES=y -CONFIG_TUN=m -CONFIG_DM9000=y -CONFIG_PPP=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_MPPE=m -CONFIG_PPP_MULTILINK=y -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_HOSTAP=m -CONFIG_HOSTAP_FIRMWARE=y -CONFIG_HOSTAP_FIRMWARE_NVRAM=y -CONFIG_LIBERTAS=m -CONFIG_LIBERTAS_SDIO=m -CONFIG_ZD1211RW=m -CONFIG_ZD1211RW_DEBUG=y -CONFIG_INPUT_EVDEV=y -CONFIG_INPUT_EVBUG=m -# CONFIG_KEYBOARD_ATKBD is not set -CONFIG_KEYBOARD_GPIO=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_SERIO_RAW=y -CONFIG_LEGACY_PTY_COUNT=128 -CONFIG_SERIAL_SAMSUNG=y -CONFIG_SERIAL_SAMSUNG_CONSOLE=y -CONFIG_SERIAL_DEV_BUS=m -CONFIG_IPMI_HANDLER=m -CONFIG_IPMI_DEVICE_INTERFACE=m -CONFIG_IPMI_SI=m -CONFIG_IPMI_WATCHDOG=m -CONFIG_IPMI_POWEROFF=m -CONFIG_HW_RANDOM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_S3C2410=y -CONFIG_I2C_SIMTEC=y -CONFIG_SPI=y -CONFIG_SPI_S3C24XX=y -CONFIG_SPI_SPIDEV=y -CONFIG_GPIO_SYSFS=y -CONFIG_SENSORS_LM75=y -CONFIG_THERMAL=y -CONFIG_WATCHDOG=y -CONFIG_S3C2410_WATCHDOG=y -CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_TILEBLITTING=y -CONFIG_FB_S3C2410=y -CONFIG_LCD_CLASS_DEVICE=y -CONFIG_LCD_PLATFORM=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y -CONFIG_BACKLIGHT_PWM=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y -CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y -CONFIG_LOGO=y -# CONFIG_LOGO_LINUX_MONO is not set -# CONFIG_LOGO_LINUX_VGA16 is not set -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_DYNAMIC_MINORS=y -CONFIG_SND_SEQUENCER=m -CONFIG_SND_SEQ_DUMMY=m -# CONFIG_SND_DRIVERS is not set -# CONFIG_SND_ARM is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=m -CONFIG_SND_USB_CAIAQ=m -CONFIG_SND_USB_CAIAQ_INPUT=y -CONFIG_SND_SOC=y -CONFIG_HIDRAW=y -CONFIG_HID_GYRATION=y -CONFIG_HID_NTRIG=y -CONFIG_HID_PANTHERLORD=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_PID=y -CONFIG_USB_HIDDEV=y -CONFIG_USB=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_ACM=m -CONFIG_USB_WDM=m -CONFIG_USB_STORAGE=m -CONFIG_USB_STORAGE_DATAFAB=m -CONFIG_USB_STORAGE_ISD200=m -CONFIG_USB_STORAGE_USBAT=m -CONFIG_USB_STORAGE_SDDR09=m -CONFIG_USB_STORAGE_SDDR55=m -CONFIG_USB_STORAGE_JUMPSHOT=m -CONFIG_USB_STORAGE_ALAUDA=m -CONFIG_USB_SERIAL=m -CONFIG_USB_SERIAL_CP210X=m -CONFIG_USB_SERIAL_FTDI_SIO=m -CONFIG_USB_SERIAL_SPCP8X5=m -CONFIG_USB_GADGET=y -CONFIG_USB_S3C2410=y -CONFIG_USB_ZERO=m -CONFIG_USB_ETH=m -CONFIG_USB_GADGETFS=m -CONFIG_USB_MASS_STORAGE=m -CONFIG_USB_G_SERIAL=m -CONFIG_USB_CDC_COMPOSITE=m -CONFIG_MMC=y -CONFIG_SDIO_UART=y -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SPI=y -CONFIG_MMC_S3C=y -CONFIG_LEDS_S3C24XX=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_TRIGGER_TIMER=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_LEDS_TRIGGER_GPIO=y -CONFIG_LEDS_TRIGGER_DEFAULT_ON=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_INTF_DEV_UIE_EMUL=y -CONFIG_RTC_DRV_S3C=y -CONFIG_DMADEVICES=y -CONFIG_S3C24XX_DMAC=y -CONFIG_PWM=y -CONFIG_PWM_SAMSUNG=y -CONFIG_EXT2_FS=m -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -CONFIG_AUTOFS4_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_JFFS2_FS=y -CONFIG_CRAMFS=y -CONFIG_ROMFS_FS=y -CONFIG_ROMFS_BACKED_BY_BOTH=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_DEFAULT="cp437" -CONFIG_NLS_CODEPAGE_437=m -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=m -CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_AUTHENC=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_CTS=m -CONFIG_CRYPTO_ECB=y -CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_XTS=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MICHAEL_MIC=y -CONFIG_CRYPTO_RMD128=m -CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_ARC4=y -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_CAMELLIA=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_FCRYPT=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SALSA20=m -CONFIG_CRYPTO_SEED=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_LZO=m -CONFIG_LIBCRC32C=m -CONFIG_FONTS=y -CONFIG_FONT_8x8=y -CONFIG_FONT_MINI_4x6=y -CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_DEBUG_KERNEL=y -CONFIG_STRIP_ASM_SYMS=y -CONFIG_DEBUG_FS=y -# CONFIG_SCHED_DEBUG is not set -CONFIG_DEBUG_USER=y diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig deleted file mode 100644 index 41b40863a78e..000000000000 --- a/arch/arm/configs/s3c2410_defconfig +++ /dev/null @@ -1,437 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_IKCONFIG=m -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=16 -CONFIG_BLK_DEV_INITRD=y -CONFIG_ARCH_MULTI_V4T=y -CONFIG_ARCH_MULTI_V5=y -# CONFIG_ARCH_MULTI_V7 is not set -CONFIG_ARCH_S3C24XX=y -CONFIG_S3C_ADC=y -CONFIG_CPU_S3C2412=y -CONFIG_CPU_S3C2416=y -CONFIG_CPU_S3C2440=y -CONFIG_CPU_S3C2442=y -CONFIG_CPU_S3C2443=y -CONFIG_MACH_AML_M5900=y -CONFIG_ARCH_BAST=y -CONFIG_ARCH_H1940=y -CONFIG_MACH_N30=y -CONFIG_MACH_OTOM=y -CONFIG_MACH_QT2410=y -CONFIG_ARCH_SMDK2410=y -CONFIG_MACH_TCT_HAMMER=y -CONFIG_MACH_VR1000=y -CONFIG_MACH_JIVE=y -CONFIG_MACH_SMDK2412=y -CONFIG_MACH_VSTMS=y -CONFIG_MACH_SMDK2416=y -CONFIG_MACH_ANUBIS=y -CONFIG_MACH_AT2440EVB=y -CONFIG_MACH_MINI2440=y -CONFIG_MACH_NEXCODER_2440=y -CONFIG_MACH_OSIRIS=y -CONFIG_MACH_OSIRIS_DVS=m -CONFIG_MACH_RX3715=y -CONFIG_ARCH_S3C2440=y -CONFIG_MACH_NEO1973_GTA02=y -CONFIG_MACH_RX1950=y -CONFIG_MACH_SMDK2443=y -CONFIG_UNUSED_BOARD_FILES=y -CONFIG_CMDLINE="root=/dev/hda1 ro init=/bin/bash console=ttySAC0" -CONFIG_FPE_NWFPE=y -CONFIG_FPE_NWFPE_XP=y -CONFIG_APM_EMULATION=m -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_BSD_DISKLABEL=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_SLAB=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_NET_KEY=m -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_NET_IPIP=m -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_TCP_CONG_ADVANCED=y -CONFIG_TCP_CONG_HSTCP=m -CONFIG_TCP_CONG_HYBLA=m -CONFIG_TCP_CONG_SCALABLE=m -CONFIG_TCP_CONG_LP=m -CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_YEAH=m -CONFIG_TCP_CONG_ILLINOIS=m -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -CONFIG_INET6_IPCOMP=m -CONFIG_IPV6_MIP6=m -CONFIG_IPV6_TUNNEL=m -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -CONFIG_NETFILTER_XT_TARGET_LED=m -CONFIG_NETFILTER_XT_TARGET_LOG=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_CLUSTER=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_DCCP=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_IPRANGE=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -CONFIG_NETFILTER_XT_MATCH_OWNER=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_RATEEST=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_RECENT=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_TIME=m -CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_IP_VS=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_EUI64=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_RAW=m -CONFIG_BT=m -CONFIG_BT_RFCOMM=m -CONFIG_BT_RFCOMM_TTY=y -CONFIG_BT_BNEP=m -CONFIG_BT_BNEP_MC_FILTER=y -CONFIG_BT_BNEP_PROTO_FILTER=y -CONFIG_BT_HIDP=m -CONFIG_BT_HCIUART=m -CONFIG_BT_HCIUART_BCSP=y -CONFIG_BT_HCIUART_LL=y -CONFIG_BT_HCIBCM203X=m -CONFIG_BT_HCIBPA10X=m -CONFIG_BT_HCIBFUSB=m -CONFIG_BT_HCIVHCI=m -CONFIG_CFG80211=m -CONFIG_MAC80211=m -CONFIG_MAC80211_MESH=y -CONFIG_MAC80211_LEDS=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_REDBOOT_PARTS=y -CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_ROM=y -CONFIG_MTD_RAW_NAND=y -CONFIG_MTD_NAND_S3C2410=y -CONFIG_PARPORT=y -CONFIG_PARPORT_PC=m -CONFIG_PARPORT_AX88796=m -CONFIG_PARPORT_1284=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_ATA_OVER_ETH=m -CONFIG_EEPROM_AT24=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=m -CONFIG_BLK_DEV_SR=y -CONFIG_CHR_DEV_SG=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_CHR_DEV_SCH=m -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_ATA=y -CONFIG_PATA_PLATFORM=y -CONFIG_NETDEVICES=y -CONFIG_DM9000=y -CONFIG_INPUT_EVDEV=y -CONFIG_MOUSE_APPLETOUCH=m -CONFIG_MOUSE_BCM5974=m -CONFIG_INPUT_JOYSTICK=y -CONFIG_JOYSTICK_ANALOG=m -CONFIG_JOYSTICK_A3D=m -CONFIG_JOYSTICK_ADI=m -CONFIG_JOYSTICK_COBRA=m -CONFIG_JOYSTICK_GF2K=m -CONFIG_JOYSTICK_GRIP=m -CONFIG_JOYSTICK_GRIP_MP=m -CONFIG_JOYSTICK_GUILLEMOT=m -CONFIG_JOYSTICK_INTERACT=m -CONFIG_JOYSTICK_SIDEWINDER=m -CONFIG_JOYSTICK_TMDC=m -CONFIG_JOYSTICK_IFORCE=m -CONFIG_JOYSTICK_MAGELLAN=m -CONFIG_JOYSTICK_SPACEORB=m -CONFIG_JOYSTICK_SPACEBALL=m -CONFIG_JOYSTICK_STINGER=m -CONFIG_JOYSTICK_TWIDJOY=m -CONFIG_JOYSTICK_ZHENHUA=m -CONFIG_JOYSTICK_DB9=m -CONFIG_JOYSTICK_GAMECON=m -CONFIG_JOYSTICK_TURBOGRAFX=m -CONFIG_JOYSTICK_JOYDUMP=m -CONFIG_JOYSTICK_XPAD=m -CONFIG_JOYSTICK_XPAD_FF=y -CONFIG_JOYSTICK_XPAD_LEDS=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_USB_COMPOSITE=m -CONFIG_INPUT_MISC=y -CONFIG_INPUT_ATI_REMOTE2=m -CONFIG_INPUT_KEYSPAN_REMOTE=m -CONFIG_INPUT_POWERMATE=m -CONFIG_INPUT_YEALINK=m -CONFIG_INPUT_CM109=m -CONFIG_INPUT_UINPUT=m -CONFIG_INPUT_GPIO_ROTARY_ENCODER=m -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=8 -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_MANY_PORTS=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_SAMSUNG=y -CONFIG_SERIAL_SAMSUNG_CONSOLE=y -CONFIG_SERIAL_NONSTANDARD=y -CONFIG_SERIAL_DEV_BUS=m -CONFIG_PRINTER=y -CONFIG_PPDEV=y -CONFIG_HW_RANDOM=y -CONFIG_I2C_CHARDEV=m -CONFIG_I2C_S3C2410=y -CONFIG_I2C_SIMTEC=y -CONFIG_SPI=y -CONFIG_SPI_GPIO=m -CONFIG_SPI_S3C24XX=m -CONFIG_SPI_SPIDEV=m -CONFIG_SPI_TLE62X0=m -CONFIG_SENSORS_LM75=m -CONFIG_SENSORS_LM78=m -CONFIG_SENSORS_LM85=m -CONFIG_WATCHDOG=y -CONFIG_S3C2410_WATCHDOG=y -CONFIG_MFD_SM501=y -CONFIG_TPS65010=y -CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_S3C2410=y -CONFIG_FB_SM501=y -CONFIG_BACKLIGHT_PWM=m -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_VERBOSE_PRINTK=y -CONFIG_SND_SEQUENCER=m -# CONFIG_SND_DRIVERS is not set -# CONFIG_SND_ARM is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_USB_AUDIO=m -CONFIG_SND_USB_CAIAQ=m -CONFIG_SND_SOC=y -# CONFIG_USB_HID is not set -CONFIG_USB=y -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_ACM=m -CONFIG_USB_PRINTER=m -CONFIG_USB_WDM=m -CONFIG_USB_STORAGE=m -CONFIG_USB_STORAGE_DATAFAB=m -CONFIG_USB_STORAGE_FREECOM=m -CONFIG_USB_STORAGE_ISD200=m -CONFIG_USB_STORAGE_USBAT=m -CONFIG_USB_STORAGE_SDDR09=m -CONFIG_USB_STORAGE_SDDR55=m -CONFIG_USB_STORAGE_JUMPSHOT=m -CONFIG_USB_STORAGE_ALAUDA=m -CONFIG_USB_STORAGE_ONETOUCH=m -CONFIG_USB_STORAGE_KARMA=m -CONFIG_USB_STORAGE_CYPRESS_ATACB=m -CONFIG_USB_MDC800=m -CONFIG_USB_MICROTEK=m -CONFIG_USB_USS720=m -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_FTDI_SIO=y -CONFIG_USB_SERIAL_NAVMAN=m -CONFIG_USB_SERIAL_PL2303=y -CONFIG_USB_SERIAL_OPTION=m -CONFIG_USB_EMI62=m -CONFIG_USB_EMI26=m -CONFIG_USB_ADUTUX=m -CONFIG_USB_SEVSEG=m -CONFIG_USB_LEGOTOWER=m -CONFIG_USB_LCD=m -CONFIG_USB_CYPRESS_CY7C63=m -CONFIG_USB_CYTHERM=m -CONFIG_USB_IDMOUSE=m -CONFIG_USB_FTDI_ELAN=m -CONFIG_USB_APPLEDISPLAY=m -CONFIG_USB_LD=m -CONFIG_USB_TRANCEVIBRATOR=m -CONFIG_USB_IOWARRIOR=m -CONFIG_USB_TEST=m -CONFIG_MMC=y -CONFIG_SDIO_UART=m -CONFIG_MMC_TEST=m -CONFIG_MMC_SDHCI=m -CONFIG_MMC_SPI=m -CONFIG_MMC_S3C=y -CONFIG_LEDS_S3C24XX=m -CONFIG_LEDS_PCA9532=m -CONFIG_LEDS_GPIO=m -CONFIG_LEDS_PCA955X=m -CONFIG_LEDS_DAC124S085=m -CONFIG_LEDS_PWM=m -CONFIG_LEDS_BD2802=m -CONFIG_LEDS_TRIGGER_TIMER=m -CONFIG_LEDS_TRIGGER_HEARTBEAT=m -CONFIG_LEDS_TRIGGER_GPIO=m -CONFIG_LEDS_TRIGGER_DEFAULT_ON=m -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_S3C=y -CONFIG_DMADEVICES=y -CONFIG_S3C24XX_DMAC=y -CONFIG_PWM=y -CONFIG_PWM_SAMSUNG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_AUTOFS4_FS=m -CONFIG_FUSE_FS=m -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_NTFS_FS=m -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_CONFIGFS_FS=m -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_CRAMFS=y -CONFIG_SQUASHFS=m -CONFIG_ROMFS_FS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3_ACL=y -CONFIG_ROOT_NFS=y -CONFIG_NFSD=m -CONFIG_NFSD_V3_ACL=y -CONFIG_NFSD_V4=y -CONFIG_CIFS=m -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=m -CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y -CONFIG_DEBUG_KERNEL=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/configs/tct_hammer_defconfig b/arch/arm/configs/tct_hammer_defconfig deleted file mode 100644 index 6bd38b6f22c4..000000000000 --- a/arch/arm/configs/tct_hammer_defconfig +++ /dev/null @@ -1,59 +0,0 @@ -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -# CONFIG_ELF_CORE is not set -# CONFIG_SHMEM is not set -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_KALLSYMS is not set -CONFIG_ARCH_MULTI_V4T=y -# CONFIG_ARCH_MULTI_V7 is not set -CONFIG_ARCH_S3C24XX=y -CONFIG_MACH_TCT_HAMMER=y -CONFIG_UNUSED_BOARD_FILES=y -CONFIG_CMDLINE="mem=64M root=/dev/ram0 init=/linuxrc rw" -CONFIG_FPE_NWFPE=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_SWAP is not set -CONFIG_SLUB=y -CONFIG_SLUB_TINY=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -# CONFIG_PREVENT_FIRMWARE_BUILD is not set -CONFIG_MTD=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_ADV_OPTIONS=y -CONFIG_MTD_CFI_GEOMETRY=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_PHYSMAP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=10240 -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT_CONSOLE is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -CONFIG_USB=y -CONFIG_USB_MON=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_GADGET=y -CONFIG_USB_S3C2410=y -CONFIG_USB_ETH=m -CONFIG_EXT2_FS=y -# CONFIG_DNOTIFY is not set -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -# CONFIG_PROC_SYSCTL is not set -CONFIG_JFFS2_FS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_CRC_CCITT=y -CONFIG_DEBUG_LL=y diff --git a/arch/arm/mach-s3c/Kconfig b/arch/arm/mach-s3c/Kconfig index a64143574546..809f84fca0b8 100644 --- a/arch/arm/mach-s3c/Kconfig +++ b/arch/arm/mach-s3c/Kconfig @@ -2,13 +2,10 @@ # # Copyright 2009 Simtec Electronics -source "arch/arm/mach-s3c/Kconfig.s3c24xx" source "arch/arm/mach-s3c/Kconfig.s3c64xx" config PLAT_SAMSUNG - bool - depends on PLAT_S3C24XX || ARCH_S3C64XX - default y + def_bool ARCH_S3C64XX select GENERIC_IRQ_CHIP select NO_IOPORT_MAP select SOC_SAMSUNG @@ -16,9 +13,8 @@ config PLAT_SAMSUNG Base platform code for all Samsung SoC based systems config SAMSUNG_PM - bool - depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX) - default y + def_bool ARCH_S3C64XX + depends on PM help Base platform power management code for samsung code @@ -99,11 +95,6 @@ config S3C_DEV_HSMMC3 help Compile in platform device definitions for HSMMC channel 3 -config S3C_DEV_HWMON - bool - help - Compile in platform device definitions for HWMON - config S3C_DEV_I2C1 bool help @@ -156,7 +147,6 @@ config S3C_DEV_USB_HSOTG config S3C_DEV_WDT bool - default y if ARCH_S3C24XX help Compile in platform device definition for Watchdog Timer @@ -180,22 +170,12 @@ config SAMSUNG_DEV_ADC help Compile in platform device definition for ADC controller -config SAMSUNG_DEV_IDE - bool - help - Compile in platform device definitions for IDE - config S3C64XX_DEV_SPI0 bool help Compile in platform device definitions for S3C64XX's type SPI controller 0 -config SAMSUNG_DEV_TS - bool - help - Common in platform device definitions for touchscreen device - config SAMSUNG_DEV_KEYPAD bool help @@ -203,7 +183,6 @@ config SAMSUNG_DEV_KEYPAD config SAMSUNG_DEV_PWM bool - default y if ARCH_S3C24XX help Compile in platform device definition for PWM Timer diff --git a/arch/arm/mach-s3c/Kconfig.s3c24xx b/arch/arm/mach-s3c/Kconfig.s3c24xx deleted file mode 100644 index 7287e173f30e..000000000000 --- a/arch/arm/mach-s3c/Kconfig.s3c24xx +++ /dev/null @@ -1,604 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Copyright (c) 2012 Samsung Electronics Co., Ltd. -# http://www.samsung.com/ -# -# Copyright 2007 Simtec Electronics -menuconfig ARCH_S3C24XX - bool "Samsung S3C24XX SoCs (deprecated, see help)" - depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 - depends on CPU_LITTLE_ENDIAN - depends on ATAGS && UNUSED_BOARD_FILES - select CLKSRC_SAMSUNG_PWM - select GPIO_SAMSUNG - select GPIOLIB - select S3C2410_WATCHDOG - select SAMSUNG_ATAGS - select WATCHDOG - help - Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443 - and S3C2450 SoCs based systems, such as the Simtec Electronics BAST - (), the IPAQ 1940 or the - Samsung SMDK2410 development board (and derivatives). - - The platform is deprecated and scheduled for removal. Please reach to - the maintainers of the platform and linux-samsung-soc@vger.kernel.org if - you still use it. - Without such feedback, the platform will be removed after 2022. - -if ARCH_S3C24XX - -config PLAT_S3C24XX - def_bool y - select GPIOLIB - select NO_IOPORT_MAP - select S3C_DEV_NAND - select COMMON_CLK - help - Base platform code for any Samsung S3C24XX device - -menu "Samsung S3C24XX SoCs Support" - -comment "S3C24XX SoCs" - -config CPU_S3C2410 - bool "Samsung S3C2410" - depends on ARCH_MULTI_V4T - default y - select CPU_ARM920T - select S3C2410_COMMON_CLK - select ARM_S3C2410_CPUFREQ if ARM_S3C24XX_CPUFREQ - select S3C2410_PM if PM - help - Support for S3C2410 and S3C2410A family from the S3C24XX line - of Samsung Mobile CPUs. - -config CPU_S3C2412 - bool "Samsung S3C2412" - depends on ARCH_MULTI_V5 - select CPU_ARM926T - select S3C2412_COMMON_CLK - select S3C2412_PM if PM_SLEEP - help - Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line - -config CPU_S3C2416 - bool "Samsung S3C2416/S3C2450" - depends on ARCH_MULTI_V5 - select CPU_ARM926T - select S3C2416_PM if PM_SLEEP - select S3C2443_COMMON_CLK - help - Support for the S3C2416 SoC from the S3C24XX line - -config CPU_S3C2440 - bool "Samsung S3C2440" - depends on ARCH_MULTI_V4T - select CPU_ARM920T - select S3C2410_COMMON_CLK - select S3C2410_PM if PM_SLEEP - help - Support for S3C2440 Samsung Mobile CPU based systems. - -config CPU_S3C2442 - bool "Samsung S3C2442" - depends on ARCH_MULTI_V4T - select CPU_ARM920T - select S3C2410_COMMON_CLK - select S3C2410_PM if PM_SLEEP - help - Support for S3C2442 Samsung Mobile CPU based systems. - -config CPU_S3C244X - def_bool y - depends on CPU_S3C2440 || CPU_S3C2442 - -config CPU_S3C2443 - bool "Samsung S3C2443" - depends on ARCH_MULTI_V4T - select CPU_ARM920T - select S3C2443_COMMON_CLK - help - Support for the S3C2443 SoC from the S3C24XX line - -# common code - -config S3C24XX_SMDK - bool - help - Common machine code for SMDK2410 and SMDK2440 - -config S3C24XX_SIMTEC_AUDIO - bool - depends on (ARCH_BAST || MACH_VR1000 || MACH_OSIRIS || MACH_ANUBIS) - default y - help - Add audio devices for common Simtec S3C24XX boards - -config S3C24XX_SIMTEC_PM - bool - help - Common power management code for systems that are - compatible with the Simtec style of power management - -config S3C24XX_SIMTEC_USB - bool - help - USB management code for common Simtec S3C24XX boards - -config S3C24XX_SETUP_TS - bool - help - Compile in platform device definition for Samsung TouchScreen. - -config S3C2410_PM - bool - help - Power Management code common to S3C2410 and better - -config S3C24XX_PLL - bool "Support CPUfreq changing of PLL frequency (EXPERIMENTAL)" - depends on ARM_S3C24XX_CPUFREQ - help - Compile in support for changing the PLL frequency from the - S3C24XX series CPUfreq driver. The PLL takes time to settle - after a frequency change, so by default it is not enabled. - - This also means that the PLL tables for the selected CPU(s) will - be built which may increase the size of the kernel image. - -# cpu frequency items common between s3c2410 and s3c2440/s3c2442 - -config S3C2410_IOTIMING - bool - depends on ARM_S3C24XX_CPUFREQ - help - Internal node to select io timing code that is common to the s3c2410 - and s3c2440/s3c2442 cpu frequency support. - -# cpu frequency support common to s3c2412, s3c2413 and s3c2442 - -config S3C2412_IOTIMING - bool - depends on ARM_S3C24XX_CPUFREQ && (CPU_S3C2412 || CPU_S3C2443) - help - Intel node to select io timing code that is common to the s3c2412 - and the s3c2443. - -# cpu-specific sections - -if CPU_S3C2410 - -config S3C2410_PLL - bool - depends on ARM_S3C2410_CPUFREQ && S3C24XX_PLL - default y - help - Select the PLL table for the S3C2410 - -config S3C24XX_SIMTEC_NOR - bool - help - Internal node to specify machine has simtec NOR mapping - -config MACH_BAST_IDE - bool - select HAVE_PATA_PLATFORM - help - Internal node for machines with an BAST style IDE - interface - -comment "S3C2410 Boards" - -# -# The "S3C2410 Boards" list is ordered alphabetically by option text. -# (without ARCH_ or MACH_) -# - -config MACH_AML_M5900 - bool "AML M5900 Series" - select S3C24XX_SIMTEC_PM if PM - select S3C_DEV_USB_HOST - help - Say Y here if you are using the American Microsystems M5900 Series - - -config ARCH_BAST - bool "Simtec Electronics BAST (EB2410ITX)" - select MACH_BAST_IDE - select S3C2410_COMMON_DCLK - select S3C2410_IOTIMING if ARM_S3C2410_CPUFREQ - select S3C24XX_SIMTEC_NOR - select S3C24XX_SIMTEC_PM if PM - select S3C24XX_SIMTEC_USB - select S3C_DEV_HWMON - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Simtec Electronics EB2410ITX - development board (also known as BAST) - -config BAST_PC104_IRQ - bool "BAST PC104 IRQ support" - depends on ARCH_BAST - default y - help - Say Y here to enable the PC104 IRQ routing on the - Simtec BAST (EB2410ITX) - -config ARCH_H1940 - bool "IPAQ H1940" - select PM_H1940 if PM - select S3C24XX_SETUP_TS - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the HP IPAQ H1940 - -config H1940BT - tristate "Control the state of H1940 bluetooth chip" - depends on ARCH_H1940 - depends on RFKILL - help - This is a simple driver that is able to control - the state of built in bluetooth chip on h1940. - -config MACH_N30 - bool "Acer N30 family" - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you want suppt for the Acer N30, Acer N35, - Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs. - -config MACH_OTOM - bool "NexVision OTOM Board" - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Nex Vision OTOM board - -config MACH_QT2410 - bool "QT2410" - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Armzone QT2410 - -config ARCH_SMDK2410 - bool "SMDK2410/A9M2410" - select S3C24XX_SMDK - select S3C_DEV_USB_HOST - help - Say Y here if you are using the SMDK2410 or the derived module A9M2410 - - -config MACH_TCT_HAMMER - bool "TCT Hammer Board" - select S3C_DEV_USB_HOST - help - Say Y here if you are using the TinCanTools Hammer Board - - -config MACH_VR1000 - bool "Thorcom VR1000" - select MACH_BAST_IDE - select S3C2410_COMMON_DCLK - select S3C24XX_SIMTEC_NOR - select S3C24XX_SIMTEC_PM if PM - select S3C24XX_SIMTEC_USB - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Thorcom VR1000 board. - -endif # CPU_S3C2410 - -config S3C2412_PM_SLEEP - bool - help - Internal config node to apply sleep for S3C2412 power management. - Can be selected by another SoCs such as S3C2416 with similar - sleep procedure. - -if CPU_S3C2412 - -config CPU_S3C2412_ONLY - bool - depends on !CPU_S3C2410 && !CPU_S3C2416 && !CPU_S3C2440 && \ - !CPU_S3C2442 && !CPU_S3C2443 - default y - -config S3C2412_PM - bool - select S3C2412_PM_SLEEP - select SAMSUNG_WAKEMASK - help - Internal config node to apply S3C2412 power management - -comment "S3C2412 Boards" - -# -# The "S3C2412 Boards" list is ordered alphabetically by option text. -# (without ARCH_ or MACH_) -# - -config MACH_JIVE - bool "Logitech Jive" - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Logitech Jive. - -config MACH_JIVE_SHOW_BOOTLOADER - bool "Allow access to bootloader partitions in MTD" - depends on MACH_JIVE - -config MACH_S3C2413 - bool - help - Internal node for S3C2413 version of SMDK2413, so that - machine_is_s3c2413() will work when MACH_SMDK2413 is - selected - -config MACH_SMDK2412 - bool "SMDK2412" - select MACH_SMDK2413 - help - Say Y here if you are using an SMDK2412 - - Note, this shares support with SMDK2413, so will automatically - select MACH_SMDK2413. - -config MACH_SMDK2413 - bool "SMDK2413" - select MACH_S3C2413 - select S3C24XX_SMDK - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using an SMDK2413 - -config MACH_VSTMS - bool "VMSTMS" - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using an VSTMS board - -endif # CPU_S3C2412 - -if CPU_S3C2416 - -config S3C2416_PM - bool - select S3C2412_PM_SLEEP - select SAMSUNG_WAKEMASK - help - Internal config node to apply S3C2416 power management - -config S3C2416_SETUP_SDHCI - bool - select S3C2416_SETUP_SDHCI_GPIO - help - Internal helper functions for S3C2416 based SDHCI systems - -config S3C2416_SETUP_SDHCI_GPIO - bool - help - Common setup code for SDHCI gpio. - -comment "S3C2416 Boards" - -config MACH_SMDK2416 - bool "SMDK2416" - select S3C2416_SETUP_SDHCI - select S3C24XX_SMDK - select S3C_DEV_FB - select S3C_DEV_HSMMC - select S3C_DEV_HSMMC1 - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using an SMDK2416 - -config MACH_S3C2416_DT - bool "Samsung S3C2416 machine using devicetree" - select TIMER_OF - select USE_OF - select PINCTRL - select PINCTRL_S3C24XX - help - Machine support for Samsung S3C2416 machines with device tree enabled. - Select this if a fdt blob is available for the S3C2416 SoC based board. - Note: This is under development and not all peripherals can be supported - with this machine file. - -endif # CPU_S3C2416 - -if CPU_S3C2440 || CPU_S3C2442 - -config S3C2440_XTAL_12000000 - bool - help - Indicate that the build needs to support 12MHz system - crystal. - -config S3C2440_XTAL_16934400 - bool - help - Indicate that the build needs to support 16.9344MHz system - crystal. - -config S3C2440_PLL_12000000 - bool - depends on ARM_S3C2440_CPUFREQ && S3C2440_XTAL_12000000 - default y if S3C24XX_PLL - help - PLL tables for S3C2440 or S3C2442 CPUs with 12MHz crystals. - -config S3C2440_PLL_16934400 - bool - depends on ARM_S3C2440_CPUFREQ && S3C2440_XTAL_16934400 - default y if S3C24XX_PLL - help - PLL tables for S3C2440 or S3C2442 CPUs with 16.934MHz crystals. -endif # CPU_S3C2440 || CPU_S3C2442 - -if CPU_S3C2440 - -comment "S3C2440 Boards" - -# -# The "S3C2440 Boards" list is ordered alphabetically by option text. -# (without ARCH_ or MACH_) -# - -config MACH_ANUBIS - bool "Simtec Electronics ANUBIS" - select HAVE_PATA_PLATFORM - select S3C2410_COMMON_DCLK - select S3C2440_XTAL_12000000 - select S3C24XX_SIMTEC_PM if PM - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Simtec Electronics ANUBIS - development system - -config MACH_AT2440EVB - bool "Avantech AT2440EVB development board" - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the AT2440EVB development board - -config MACH_MINI2440 - bool "MINI2440 development board" - select LEDS_CLASS - select LEDS_TRIGGERS - select LEDS_TRIGGER_BACKLIGHT - select NEW_LEDS - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here to select support for the MINI2440. Is a 10cm x 10cm board - available via various sources. It can come with a 3.5" or 7" touch LCD. - -config MACH_NEXCODER_2440 - bool "NexVision NEXCODER 2440 Light Board" - select S3C2440_XTAL_12000000 - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board - -config MACH_OSIRIS - bool "Simtec IM2440D20 (OSIRIS) module" - select S3C2410_COMMON_DCLK - select S3C2410_IOTIMING if ARM_S3C2440_CPUFREQ - select S3C2440_XTAL_12000000 - select S3C24XX_SIMTEC_PM if PM - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Simtec IM2440D20 module, also - known as the Osiris. - -config MACH_OSIRIS_DVS - tristate "Simtec IM2440D20 (OSIRIS) Dynamic Voltage Scaling driver" - depends on MACH_OSIRIS - depends on TPS65010 - help - Say Y/M here if you want to have dynamic voltage scaling support - on the Simtec IM2440D20 (OSIRIS) module via the TPS65011. - - The DVS driver alters the voltage supplied to the ARM core - depending on the frequency it is running at. The driver itself - does not do any of the frequency alteration, which is left up - to the cpufreq driver. - -config MACH_RX3715 - bool "HP iPAQ rx3715" - select PM_H1940 if PM - select S3C2440_XTAL_16934400 - select S3C_DEV_NAND - help - Say Y here if you are using the HP iPAQ rx3715. - -config ARCH_S3C2440 - bool "SMDK2440" - select S3C2440_XTAL_16934400 - select S3C24XX_SMDK - select S3C_DEV_NAND - select S3C_DEV_USB_HOST - help - Say Y here if you are using the SMDK2440. - -config SMDK2440_CPU2440 - bool "SMDK2440 with S3C2440 CPU module" - default y if ARCH_S3C2440 - select S3C2440_XTAL_16934400 - -endif # CPU_S3C2440 - -if CPU_S3C2442 - -comment "S3C2442 Boards" - -# -# The "S3C2442 Boards" list is ordered alphabetically by option text. -# (without ARCH_ or MACH_) -# - -config MACH_NEO1973_GTA02 - bool "Openmoko GTA02 / Freerunner phone" - select I2C - select MFD_PCF50633 - select PCF50633_GPIO - select POWER_SUPPLY - select S3C_DEV_USB_HOST - help - Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone - -config MACH_RX1950 - bool "HP iPAQ rx1950" - select I2C - select PM_H1940 if PM - select S3C2410_COMMON_DCLK - select S3C2410_IOTIMING if ARM_S3C2440_CPUFREQ - select S3C2440_XTAL_16934400 - select S3C_DEV_NAND - help - Say Y here if you're using HP iPAQ rx1950 - -endif # CPU_S3C2442 - -if CPU_S3C2443 || CPU_S3C2416 - -config S3C2443_SETUP_SPI - bool - help - Common setup code for SPI GPIO configurations - -endif # CPU_S3C2443 || CPU_S3C2416 - -if CPU_S3C2443 - -comment "S3C2443 Boards" - -config MACH_SMDK2443 - bool "SMDK2443" - select S3C24XX_SMDK - select S3C_DEV_HSMMC1 - help - Say Y here if you are using an SMDK2443 - -endif # CPU_S3C2443 - -config PM_H1940 - bool - help - Internal node for H1940 and related PM - -endmenu # "Samsung S3C24XX SoCs Support" - -endif # ARCH_S3C24XX diff --git a/arch/arm/mach-s3c/Makefile b/arch/arm/mach-s3c/Makefile index 7c7d3318fd61..e7f18039b149 100644 --- a/arch/arm/mach-s3c/Makefile +++ b/arch/arm/mach-s3c/Makefile @@ -2,10 +2,6 @@ # # Copyright 2009 Simtec Electronics -ifdef CONFIG_ARCH_S3C24XX -include $(src)/Makefile.s3c24xx -endif - ifdef CONFIG_ARCH_S3C64XX include $(src)/Makefile.s3c64xx endif diff --git a/arch/arm/mach-s3c/Makefile.s3c24xx b/arch/arm/mach-s3c/Makefile.s3c24xx deleted file mode 100644 index 3483ab3a2b81..000000000000 --- a/arch/arm/mach-s3c/Makefile.s3c24xx +++ /dev/null @@ -1,102 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Copyright (c) 2012 Samsung Electronics Co., Ltd. -# http://www.samsung.com/ -# -# Copyright 2007 Simtec Electronics - -# core - -obj-y += s3c24xx.o -obj-y += irq-s3c24xx.o -obj-$(CONFIG_SPI_S3C24XX_FIQ) += irq-s3c24xx-fiq.o -obj-$(CONFIG_SPI_S3C24XX_FIQ) += irq-s3c24xx-fiq-exports.o - -obj-$(CONFIG_CPU_S3C2410) += s3c2410.o -obj-$(CONFIG_S3C2410_PLL) += pll-s3c2410.o -obj-$(CONFIG_S3C2410_PM) += pm-s3c2410.o sleep-s3c2410.o - -obj-$(CONFIG_CPU_S3C2412) += s3c2412.o -obj-$(CONFIG_S3C2412_PM) += pm-s3c2412.o -obj-$(CONFIG_S3C2412_PM_SLEEP) += sleep-s3c2412.o - -obj-$(CONFIG_CPU_S3C2416) += s3c2416.o -obj-$(CONFIG_S3C2416_PM) += pm-s3c2416.o - -obj-$(CONFIG_CPU_S3C2440) += s3c2440.o -obj-$(CONFIG_CPU_S3C2442) += s3c2442.o -obj-$(CONFIG_CPU_S3C244X) += s3c244x.o -obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o -obj-$(CONFIG_S3C2440_PLL_16934400) += pll-s3c2440-16934400.o - -obj-$(CONFIG_CPU_S3C2443) += s3c2443.o - -# PM - -obj-$(CONFIG_PM) += pm-s3c24xx.o -obj-$(CONFIG_PM_SLEEP) += irq-pm-s3c24xx.o sleep-s3c24xx.o - -# common code - -obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += cpufreq-utils-s3c24xx.o - -obj-$(CONFIG_S3C2410_IOTIMING) += iotiming-s3c2410.o -obj-$(CONFIG_S3C2412_IOTIMING) += iotiming-s3c2412.o - -# -# machine support -# following is ordered alphabetically by option text. -# - -obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o -obj-$(CONFIG_ARCH_BAST) += mach-bast.o -obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o -obj-$(CONFIG_ARCH_H1940) += mach-h1940.o -obj-$(CONFIG_H1940BT) += h1940-bluetooth.o -obj-$(CONFIG_PM_H1940) += pm-h1940.o -obj-$(CONFIG_MACH_N30) += mach-n30.o -obj-$(CONFIG_MACH_OTOM) += mach-otom.o -obj-$(CONFIG_MACH_QT2410) += mach-qt2410.o -obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o -obj-$(CONFIG_MACH_TCT_HAMMER) += mach-tct_hammer.o -obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o - -obj-$(CONFIG_MACH_JIVE) += mach-jive.o -obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o -obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o - -obj-$(CONFIG_MACH_SMDK2416) += mach-smdk2416.o -obj-$(CONFIG_MACH_S3C2416_DT) += mach-s3c2416-dt.o - -obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o -obj-$(CONFIG_MACH_AT2440EVB) += mach-at2440evb.o -obj-$(CONFIG_MACH_MINI2440) += mach-mini2440.o -obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o -obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o -obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o -obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o - -obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o -obj-$(CONFIG_MACH_RX1950) += mach-rx1950.o - -obj-$(CONFIG_MACH_SMDK2443) += mach-smdk2443.o - -# common bits of machine support - -obj-$(CONFIG_S3C24XX_SMDK) += common-smdk-s3c24xx.o -obj-$(CONFIG_S3C24XX_SIMTEC_AUDIO) += simtec-audio.o -obj-$(CONFIG_S3C24XX_SIMTEC_NOR) += simtec-nor.o -obj-$(CONFIG_S3C24XX_SIMTEC_PM) += simtec-pm.o -obj-$(CONFIG_S3C24XX_SIMTEC_USB) += simtec-usb.o - -# machine additions - -obj-$(CONFIG_MACH_BAST_IDE) += bast-ide.o -obj-$(CONFIG_MACH_OSIRIS_DVS) += mach-osiris-dvs.o - -# device setup - -obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO) += setup-sdhci-gpio-s3c24xx.o -obj-$(CONFIG_S3C2443_SETUP_SPI) += setup-spi-s3c24xx.o -obj-$(CONFIG_ARCH_S3C24XX) += setup-i2c-s3c24xx.o -obj-$(CONFIG_S3C24XX_SETUP_TS) += setup-ts-s3c24xx.o diff --git a/arch/arm/mach-s3c/anubis.h b/arch/arm/mach-s3c/anubis.h deleted file mode 100644 index 13847292e6c7..000000000000 --- a/arch/arm/mach-s3c/anubis.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2005 Simtec Electronics - * http://www.simtec.co.uk/products/ - * Ben Dooks - * - * ANUBIS - CPLD control constants - * ANUBIS - IRQ Number definitions - * ANUBIS - Memory map definitions - */ - -#ifndef __MACH_S3C24XX_ANUBIS_H -#define __MACH_S3C24XX_ANUBIS_H __FILE__ - -/* CTRL2 - NAND WP control, IDE Reset assert/check */ - -#define ANUBIS_CTRL1_NANDSEL (0x3) - -/* IDREG - revision */ - -#define ANUBIS_IDREG_REVMASK (0x7) - -/* irq */ - -#define ANUBIS_IRQ_IDE0 IRQ_EINT2 -#define ANUBIS_IRQ_IDE1 IRQ_EINT3 -#define ANUBIS_IRQ_ASIX IRQ_EINT1 - -/* map */ - -/* start peripherals off after the S3C2410 */ - -#define ANUBIS_IOADDR(x) (S3C2410_ADDR((x) + 0x01800000)) - -#define ANUBIS_PA_CPLD (S3C2410_CS1 | (1<<26)) - -/* we put the CPLD registers next, to get them out of the way */ - -#define ANUBIS_VA_CTRL1 ANUBIS_IOADDR(0x00000000) -#define ANUBIS_PA_CTRL1 ANUBIS_PA_CPLD - -#define ANUBIS_VA_IDREG ANUBIS_IOADDR(0x00300000) -#define ANUBIS_PA_IDREG (ANUBIS_PA_CPLD + (3 << 23)) - -#define ANUBIS_IDEPRI ANUBIS_IOADDR(0x01000000) -#define ANUBIS_IDEPRIAUX ANUBIS_IOADDR(0x01100000) -#define ANUBIS_IDESEC ANUBIS_IOADDR(0x01200000) -#define ANUBIS_IDESECAUX ANUBIS_IOADDR(0x01300000) - -#endif /* __MACH_S3C24XX_ANUBIS_H */ diff --git a/arch/arm/mach-s3c/bast-ide.c b/arch/arm/mach-s3c/bast-ide.c deleted file mode 100644 index 67f0adc1fec0..000000000000 --- a/arch/arm/mach-s3c/bast-ide.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright 2007 Simtec Electronics -// http://www.simtec.co.uk/products/EB2410ITX/ -// http://armlinux.simtec.co.uk/ -// Ben Dooks - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#include "map.h" -#include "irqs.h" - -#include "bast.h" - -/* IDE ports */ - -static struct pata_platform_info bast_ide_platdata = { - .ioport_shift = 5, -}; - -static struct resource bast_ide0_resource[] = { - [0] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDEPRI, 8 * 0x20), - [1] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20), 0x20), - [2] = DEFINE_RES_IRQ(BAST_IRQ_IDE0), -}; - -static struct platform_device bast_device_ide0 = { - .name = "pata_platform", - .id = 0, - .num_resources = ARRAY_SIZE(bast_ide0_resource), - .resource = bast_ide0_resource, - .dev = { - .platform_data = &bast_ide_platdata, - .coherent_dma_mask = ~0, - } - -}; - -static struct resource bast_ide1_resource[] = { - [0] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDESEC, 8 * 0x20), - [1] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20), 0x20), - [2] = DEFINE_RES_IRQ(BAST_IRQ_IDE1), -}; - -static struct platform_device bast_device_ide1 = { - .name = "pata_platform", - .id = 1, - .num_resources = ARRAY_SIZE(bast_ide1_resource), - .resource = bast_ide1_resource, - .dev = { - .platform_data = &bast_ide_platdata, - .coherent_dma_mask = ~0, - } -}; - -static struct platform_device *bast_ide_devices[] __initdata = { - &bast_device_ide0, - &bast_device_ide1, -}; - -static __init int bast_ide_init(void) -{ - if (machine_is_bast() || machine_is_vr1000()) - return platform_add_devices(bast_ide_devices, - ARRAY_SIZE(bast_ide_devices)); - - return 0; -} - -fs_initcall(bast_ide_init); diff --git a/arch/arm/mach-s3c/bast-irq.c b/arch/arm/mach-s3c/bast-irq.c deleted file mode 100644 index cfc2ddc65513..000000000000 --- a/arch/arm/mach-s3c/bast-irq.c +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// Copyright 2003-2005 Simtec Electronics -// Ben Dooks -// -// http://www.simtec.co.uk/products/EB2410ITX/ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "regs-irq.h" -#include "irqs.h" - -#include "bast.h" - -#define irqdbf(x...) -#define irqdbf2(x...) - -/* handle PC104 ISA interrupts from the system CPLD */ - -/* table of ISA irq nos to the relevant mask... zero means - * the irq is not implemented -*/ -static const unsigned char bast_pc104_irqmasks[] = { - 0, /* 0 */ - 0, /* 1 */ - 0, /* 2 */ - 1, /* 3 */ - 0, /* 4 */ - 2, /* 5 */ - 0, /* 6 */ - 4, /* 7 */ - 0, /* 8 */ - 0, /* 9 */ - 8, /* 10 */ - 0, /* 11 */ - 0, /* 12 */ - 0, /* 13 */ - 0, /* 14 */ - 0, /* 15 */ -}; - -static const unsigned char bast_pc104_irqs[] = { 3, 5, 7, 10 }; - -static void -bast_pc104_mask(struct irq_data *data) -{ - unsigned long temp; - - temp = __raw_readb(BAST_VA_PC104_IRQMASK); - temp &= ~bast_pc104_irqmasks[data->irq]; - __raw_writeb(temp, BAST_VA_PC104_IRQMASK); -} - -static void -bast_pc104_maskack(struct irq_data *data) -{ - struct irq_desc *desc = irq_to_desc(BAST_IRQ_ISA); - - bast_pc104_mask(data); - desc->irq_data.chip->irq_ack(&desc->irq_data); -} - -static void -bast_pc104_unmask(struct irq_data *data) -{ - unsigned long temp; - - temp = __raw_readb(BAST_VA_PC104_IRQMASK); - temp |= bast_pc104_irqmasks[data->irq]; - __raw_writeb(temp, BAST_VA_PC104_IRQMASK); -} - -static struct irq_chip bast_pc104_chip = { - .irq_mask = bast_pc104_mask, - .irq_unmask = bast_pc104_unmask, - .irq_ack = bast_pc104_maskack -}; - -static void bast_irq_pc104_demux(struct irq_desc *desc) -{ - unsigned int stat; - unsigned int irqno; - int i; - - stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf; - - if (unlikely(stat == 0)) { - /* ack if we get an irq with nothing (ie, startup) */ - desc->irq_data.chip->irq_ack(&desc->irq_data); - } else { - /* handle the IRQ */ - - for (i = 0; stat != 0; i++, stat >>= 1) { - if (stat & 1) { - irqno = bast_pc104_irqs[i]; - generic_handle_irq(irqno); - } - } - } -} - -static __init int bast_irq_init(void) -{ - unsigned int i; - - if (machine_is_bast()) { - printk(KERN_INFO "BAST PC104 IRQ routing, Copyright 2005 Simtec Electronics\n"); - - /* zap all the IRQs */ - - __raw_writeb(0x0, BAST_VA_PC104_IRQMASK); - - irq_set_chained_handler(BAST_IRQ_ISA, bast_irq_pc104_demux); - - /* register our IRQs */ - - for (i = 0; i < 4; i++) { - unsigned int irqno = bast_pc104_irqs[i]; - - irq_set_chip_and_handler(irqno, &bast_pc104_chip, - handle_level_irq); - irq_clear_status_flags(irqno, IRQ_NOREQUEST); - } - } - - return 0; -} - -arch_initcall(bast_irq_init); diff --git a/arch/arm/mach-s3c/bast.h b/arch/arm/mach-s3c/bast.h deleted file mode 100644 index a7726f93f5eb..000000000000 --- a/arch/arm/mach-s3c/bast.h +++ /dev/null @@ -1,194 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2003-2004 Simtec Electronics - * Ben Dooks - * - * BAST - CPLD control constants - * BAST - IRQ Number definitions - * BAST - Memory map definitions - */ - -#ifndef __MACH_S3C24XX_BAST_H -#define __MACH_S3C24XX_BAST_H __FILE__ - -/* CTRL1 - Audio LR routing */ - -#define BAST_CPLD_CTRL1_LRCOFF (0x00) -#define BAST_CPLD_CTRL1_LRCADC (0x01) -#define BAST_CPLD_CTRL1_LRCDAC (0x02) -#define BAST_CPLD_CTRL1_LRCARM (0x03) -#define BAST_CPLD_CTRL1_LRMASK (0x03) - -/* CTRL2 - NAND WP control, IDE Reset assert/check */ - -#define BAST_CPLD_CTRL2_WNAND (0x04) -#define BAST_CPLD_CTLR2_IDERST (0x08) - -/* CTRL3 - rom write control, CPLD identity */ - -#define BAST_CPLD_CTRL3_IDMASK (0x0e) -#define BAST_CPLD_CTRL3_ROMWEN (0x01) - -/* CTRL4 - 8bit LCD interface control/status */ - -#define BAST_CPLD_CTRL4_LLAT (0x01) -#define BAST_CPLD_CTRL4_LCDRW (0x02) -#define BAST_CPLD_CTRL4_LCDCMD (0x04) -#define BAST_CPLD_CTRL4_LCDE2 (0x01) - -/* CTRL5 - DMA routing */ - -#define BAST_CPLD_DMA0_PRIIDE (0) -#define BAST_CPLD_DMA0_SECIDE (1) -#define BAST_CPLD_DMA0_ISA15 (2) -#define BAST_CPLD_DMA0_ISA36 (3) - -#define BAST_CPLD_DMA1_PRIIDE (0 << 2) -#define BAST_CPLD_DMA1_SECIDE (1 << 2) -#define BAST_CPLD_DMA1_ISA15 (2 << 2) -#define BAST_CPLD_DMA1_ISA36 (3 << 2) - -/* irq numbers to onboard peripherals */ - -#define BAST_IRQ_USBOC IRQ_EINT18 -#define BAST_IRQ_IDE0 IRQ_EINT16 -#define BAST_IRQ_IDE1 IRQ_EINT17 -#define BAST_IRQ_PCSERIAL1 IRQ_EINT15 -#define BAST_IRQ_PCSERIAL2 IRQ_EINT14 -#define BAST_IRQ_PCPARALLEL IRQ_EINT13 -#define BAST_IRQ_ASIX IRQ_EINT11 -#define BAST_IRQ_DM9000 IRQ_EINT10 -#define BAST_IRQ_ISA IRQ_EINT9 -#define BAST_IRQ_SMALERT IRQ_EINT8 - -/* map */ - -/* - * ok, we've used up to 0x13000000, now we need to find space for the - * peripherals that live in the nGCS[x] areas, which are quite numerous - * in their space. We also have the board's CPLD to find register space - * for. - */ - -#define BAST_IOADDR(x) (S3C2410_ADDR((x) + 0x01300000)) - -/* we put the CPLD registers next, to get them out of the way */ - -#define BAST_VA_CTRL1 BAST_IOADDR(0x00000000) -#define BAST_PA_CTRL1 (S3C2410_CS5 | 0x7800000) - -#define BAST_VA_CTRL2 BAST_IOADDR(0x00100000) -#define BAST_PA_CTRL2 (S3C2410_CS1 | 0x6000000) - -#define BAST_VA_CTRL3 BAST_IOADDR(0x00200000) -#define BAST_PA_CTRL3 (S3C2410_CS1 | 0x6800000) - -#define BAST_VA_CTRL4 BAST_IOADDR(0x00300000) -#define BAST_PA_CTRL4 (S3C2410_CS1 | 0x7000000) - -/* next, we have the PC104 ISA interrupt registers */ - -#define BAST_PA_PC104_IRQREQ (S3C2410_CS5 | 0x6000000) -#define BAST_VA_PC104_IRQREQ BAST_IOADDR(0x00400000) - -#define BAST_PA_PC104_IRQRAW (S3C2410_CS5 | 0x6800000) -#define BAST_VA_PC104_IRQRAW BAST_IOADDR(0x00500000) - -#define BAST_PA_PC104_IRQMASK (S3C2410_CS5 | 0x7000000) -#define BAST_VA_PC104_IRQMASK BAST_IOADDR(0x00600000) - -#define BAST_PA_LCD_RCMD1 (0x8800000) -#define BAST_VA_LCD_RCMD1 BAST_IOADDR(0x00700000) - -#define BAST_PA_LCD_WCMD1 (0x8000000) -#define BAST_VA_LCD_WCMD1 BAST_IOADDR(0x00800000) - -#define BAST_PA_LCD_RDATA1 (0x9800000) -#define BAST_VA_LCD_RDATA1 BAST_IOADDR(0x00900000) - -#define BAST_PA_LCD_WDATA1 (0x9000000) -#define BAST_VA_LCD_WDATA1 BAST_IOADDR(0x00A00000) - -#define BAST_PA_LCD_RCMD2 (0xA800000) -#define BAST_VA_LCD_RCMD2 BAST_IOADDR(0x00B00000) - -#define BAST_PA_LCD_WCMD2 (0xA000000) -#define BAST_VA_LCD_WCMD2 BAST_IOADDR(0x00C00000) - -#define BAST_PA_LCD_RDATA2 (0xB800000) -#define BAST_VA_LCD_RDATA2 BAST_IOADDR(0x00D00000) - -#define BAST_PA_LCD_WDATA2 (0xB000000) -#define BAST_VA_LCD_WDATA2 BAST_IOADDR(0x00E00000) - - -/* - * 0xE0000000 contains the IO space that is split by speed and - * whether the access is for 8 or 16bit IO... this ensures that - * the correct access is made - * - * 0x10000000 of space, partitioned as so: - * - * 0x00000000 to 0x04000000 8bit, slow - * 0x04000000 to 0x08000000 16bit, slow - * 0x08000000 to 0x0C000000 16bit, net - * 0x0C000000 to 0x10000000 16bit, fast - * - * each of these spaces has the following in: - * - * 0x00000000 to 0x01000000 16MB ISA IO space - * 0x01000000 to 0x02000000 16MB ISA memory space - * 0x02000000 to 0x02100000 1MB IDE primary channel - * 0x02100000 to 0x02200000 1MB IDE primary channel aux - * 0x02200000 to 0x02400000 1MB IDE secondary channel - * 0x02300000 to 0x02400000 1MB IDE secondary channel aux - * 0x02400000 to 0x02500000 1MB ASIX ethernet controller - * 0x02500000 to 0x02600000 1MB Davicom DM9000 ethernet controller - * 0x02600000 to 0x02700000 1MB PC SuperIO controller - * - * the phyiscal layout of the zones are: - * nGCS2 - 8bit, slow - * nGCS3 - 16bit, slow - * nGCS4 - 16bit, net - * nGCS5 - 16bit, fast - */ - -#define BAST_VA_MULTISPACE (0xE0000000) - -#define BAST_VA_ISAIO (BAST_VA_MULTISPACE + 0x00000000) -#define BAST_VA_ISAMEM (BAST_VA_MULTISPACE + 0x01000000) -#define BAST_VA_IDEPRI (BAST_VA_MULTISPACE + 0x02000000) -#define BAST_VA_IDEPRIAUX (BAST_VA_MULTISPACE + 0x02100000) -#define BAST_VA_IDESEC (BAST_VA_MULTISPACE + 0x02200000) -#define BAST_VA_IDESECAUX (BAST_VA_MULTISPACE + 0x02300000) -#define BAST_VA_ASIXNET (BAST_VA_MULTISPACE + 0x02400000) -#define BAST_VA_DM9000 (BAST_VA_MULTISPACE + 0x02500000) -#define BAST_VA_SUPERIO (BAST_VA_MULTISPACE + 0x02600000) - -#define BAST_VAM_CS2 (0x00000000) -#define BAST_VAM_CS3 (0x04000000) -#define BAST_VAM_CS4 (0x08000000) -#define BAST_VAM_CS5 (0x0C000000) - -/* physical offset addresses for the peripherals */ - -#define BAST_PA_ISAIO (0x00000000) -#define BAST_PA_ASIXNET (0x01000000) -#define BAST_PA_SUPERIO (0x01800000) -#define BAST_PA_IDEPRI (0x02000000) -#define BAST_PA_IDEPRIAUX (0x02800000) -#define BAST_PA_IDESEC (0x03000000) -#define BAST_PA_IDESECAUX (0x03800000) -#define BAST_PA_ISAMEM (0x04000000) -#define BAST_PA_DM9000 (0x05000000) - -/* some configurations for the peripherals */ - -#define BAST_PCSIO (BAST_VA_SUPERIO + BAST_VAM_CS2) - -#define BAST_ASIXNET_CS BAST_VAM_CS5 -#define BAST_DM9000_CS BAST_VAM_CS4 - -#define BAST_IDE_CS S3C2410_CS5 - -#endif /* __MACH_S3C24XX_BAST_H */ diff --git a/arch/arm/mach-s3c/common-smdk-s3c24xx.c b/arch/arm/mach-s3c/common-smdk-s3c24xx.c deleted file mode 100644 index 6d124bbd384c..000000000000 --- a/arch/arm/mach-s3c/common-smdk-s3c24xx.c +++ /dev/null @@ -1,228 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (c) 2006 Simtec Electronics -// Ben Dooks -// -// Common code for SMDK2410 and SMDK2440 boards -// -// http://www.fluff.org/ben/smdk2440/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "regs-gpio.h" -#include "gpio-samsung.h" -#include -#include - -#include "gpio-cfg.h" -#include "devs.h" -#include "pm.h" - -#include "common-smdk-s3c24xx.h" - -/* LED devices */ - -static struct gpiod_lookup_table smdk_led4_gpio_table = { - .dev_id = "s3c24xx_led.0", - .table = { - GPIO_LOOKUP("GPF", 4, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), - { }, - }, -}; - -static struct gpiod_lookup_table smdk_led5_gpio_table = { - .dev_id = "s3c24xx_led.1", - .table = { - GPIO_LOOKUP("GPF", 5, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), - { }, - }, -}; - -static struct gpiod_lookup_table smdk_led6_gpio_table = { - .dev_id = "s3c24xx_led.2", - .table = { - GPIO_LOOKUP("GPF", 6, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), - { }, - }, -}; - -static struct gpiod_lookup_table smdk_led7_gpio_table = { - .dev_id = "s3c24xx_led.3", - .table = { - GPIO_LOOKUP("GPF", 7, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), - { }, - }, -}; - -static struct s3c24xx_led_platdata smdk_pdata_led4 = { - .name = "led4", - .def_trigger = "timer", -}; - -static struct s3c24xx_led_platdata smdk_pdata_led5 = { - .name = "led5", - .def_trigger = "nand-disk", -}; - -static struct s3c24xx_led_platdata smdk_pdata_led6 = { - .name = "led6", -}; - -static struct s3c24xx_led_platdata smdk_pdata_led7 = { - .name = "led7", -}; - -static struct platform_device smdk_led4 = { - .name = "s3c24xx_led", - .id = 0, - .dev = { - .platform_data = &smdk_pdata_led4, - }, -}; - -static struct platform_device smdk_led5 = { - .name = "s3c24xx_led", - .id = 1, - .dev = { - .platform_data = &smdk_pdata_led5, - }, -}; - -static struct platform_device smdk_led6 = { - .name = "s3c24xx_led", - .id = 2, - .dev = { - .platform_data = &smdk_pdata_led6, - }, -}; - -static struct platform_device smdk_led7 = { - .name = "s3c24xx_led", - .id = 3, - .dev = { - .platform_data = &smdk_pdata_led7, - }, -}; - -/* NAND parititon from 2.4.18-swl5 */ - -static struct mtd_partition smdk_default_nand_part[] = { - [0] = { - .name = "Boot Agent", - .size = SZ_16K, - .offset = 0, - }, - [1] = { - .name = "S3C2410 flash partition 1", - .offset = 0, - .size = SZ_2M, - }, - [2] = { - .name = "S3C2410 flash partition 2", - .offset = SZ_4M, - .size = SZ_4M, - }, - [3] = { - .name = "S3C2410 flash partition 3", - .offset = SZ_8M, - .size = SZ_2M, - }, - [4] = { - .name = "S3C2410 flash partition 4", - .offset = SZ_1M * 10, - .size = SZ_4M, - }, - [5] = { - .name = "S3C2410 flash partition 5", - .offset = SZ_1M * 14, - .size = SZ_1M * 10, - }, - [6] = { - .name = "S3C2410 flash partition 6", - .offset = SZ_1M * 24, - .size = SZ_1M * 24, - }, - [7] = { - .name = "S3C2410 flash partition 7", - .offset = SZ_1M * 48, - .size = MTDPART_SIZ_FULL, - } -}; - -static struct s3c2410_nand_set smdk_nand_sets[] = { - [0] = { - .name = "NAND", - .nr_chips = 1, - .nr_partitions = ARRAY_SIZE(smdk_default_nand_part), - .partitions = smdk_default_nand_part, - }, -}; - -/* choose a set of timings which should suit most 512Mbit - * chips and beyond. -*/ - -static struct s3c2410_platform_nand smdk_nand_info = { - .tacls = 20, - .twrph0 = 60, - .twrph1 = 20, - .nr_sets = ARRAY_SIZE(smdk_nand_sets), - .sets = smdk_nand_sets, - .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, -}; - -/* devices we initialise */ - -static struct platform_device __initdata *smdk_devs[] = { - &s3c_device_nand, - &smdk_led4, - &smdk_led5, - &smdk_led6, - &smdk_led7, -}; - -void __init smdk_machine_init(void) -{ - if (machine_is_smdk2443()) - smdk_nand_info.twrph0 = 50; - - s3c_nand_set_platdata(&smdk_nand_info); - - /* Disable pull-up on the LED lines */ - s3c_gpio_setpull(S3C2410_GPF(4), S3C_GPIO_PULL_NONE); - s3c_gpio_setpull(S3C2410_GPF(5), S3C_GPIO_PULL_NONE); - s3c_gpio_setpull(S3C2410_GPF(6), S3C_GPIO_PULL_NONE); - s3c_gpio_setpull(S3C2410_GPF(7), S3C_GPIO_PULL_NONE); - - /* Add lookups for the lines */ - gpiod_add_lookup_table(&smdk_led4_gpio_table); - gpiod_add_lookup_table(&smdk_led5_gpio_table); - gpiod_add_lookup_table(&smdk_led6_gpio_table); - gpiod_add_lookup_table(&smdk_led7_gpio_table); - - platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs)); - - s3c_pm_init(); -} diff --git a/arch/arm/mach-s3c/common-smdk-s3c24xx.h b/arch/arm/mach-s3c/common-smdk-s3c24xx.h deleted file mode 100644 index c0352b06e435..000000000000 --- a/arch/arm/mach-s3c/common-smdk-s3c24xx.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2006 Simtec Electronics - * Ben Dooks - * - * Common code for SMDK2410 and SMDK2440 boards - * - * http://www.fluff.org/ben/smdk2440/ - */ - -extern void smdk_machine_init(void); diff --git a/arch/arm/mach-s3c/cpufreq-utils-s3c24xx.c b/arch/arm/mach-s3c/cpufreq-utils-s3c24xx.c deleted file mode 100644 index c1784d8facdf..000000000000 --- a/arch/arm/mach-s3c/cpufreq-utils-s3c24xx.c +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (c) 2009 Simtec Electronics -// http://armlinux.simtec.co.uk/ -// Ben Dooks -// -// S3C24XX CPU Frequency scaling - utils for S3C2410/S3C2440/S3C2442 - -#include -#include -#include -#include -#include - -#include "map.h" -#include "regs-clock.h" - -#include - -#include "regs-mem-s3c24xx.h" - -/** - * s3c2410_cpufreq_setrefresh - set SDRAM refresh value - * @cfg: The frequency configuration - * - * Set the SDRAM refresh value appropriately for the configured - * frequency. - */ -void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg) -{ - struct s3c_cpufreq_board *board = cfg->board; - unsigned long refresh; - unsigned long refval; - - /* Reduce both the refresh time (in ns) and the frequency (in MHz) - * down to ensure that we do not overflow 32 bit numbers. - * - * This should work for HCLK up to 133MHz and refresh period up - * to 30usec. - */ - - refresh = (cfg->freq.hclk / 100) * (board->refresh / 10); - refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale */ - refresh = (1 << 11) + 1 - refresh; - - s3c_freq_dbg("%s: refresh value %lu\n", __func__, refresh); - - refval = __raw_readl(S3C2410_REFRESH); - refval &= ~((1 << 12) - 1); - refval |= refresh; - __raw_writel(refval, S3C2410_REFRESH); -} - -/** - * s3c2410_set_fvco - set the PLL value - * @cfg: The frequency configuration - */ -void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg) -{ - if (!IS_ERR(cfg->mpll)) - clk_set_rate(cfg->mpll, cfg->pll.frequency); -} - -#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) -u32 s3c2440_read_camdivn(void) -{ - return __raw_readl(S3C2440_CAMDIVN); -} - -void s3c2440_write_camdivn(u32 camdiv) -{ - __raw_writel(camdiv, S3C2440_CAMDIVN); -} -#endif - -u32 s3c24xx_read_clkdivn(void) -{ - return __raw_readl(S3C2410_CLKDIVN); -} - -void s3c24xx_write_clkdivn(u32 clkdiv) -{ - __raw_writel(clkdiv, S3C2410_CLKDIVN); -} - -u32 s3c24xx_read_mpllcon(void) -{ - return __raw_readl(S3C2410_MPLLCON); -} - -void s3c24xx_write_locktime(u32 locktime) -{ - return __raw_writel(locktime, S3C2410_LOCKTIME); -} diff --git a/arch/arm/mach-s3c/dma-s3c24xx.h b/arch/arm/mach-s3c/dma-s3c24xx.h deleted file mode 100644 index 25fc9c258fc1..000000000000 --- a/arch/arm/mach-s3c/dma-s3c24xx.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2003-2006 Simtec Electronics - * Ben Dooks - * - * Samsung S3C24XX DMA support - */ - -#ifndef __ASM_ARCH_DMA_H -#define __ASM_ARCH_DMA_H __FILE__ - -#include - -/* We use `virtual` dma channels to hide the fact we have only a limited - * number of DMA channels, and not of all of them (dependent on the device) - * can be attached to any DMA source. We therefore let the DMA core handle - * the allocation of hardware channels to clients. -*/ - -enum dma_ch { - DMACH_XD0 = 0, - DMACH_XD1, - DMACH_SDI, - DMACH_SPI0, - DMACH_SPI1, - DMACH_UART0, - DMACH_UART1, - DMACH_UART2, - DMACH_TIMER, - DMACH_I2S_IN, - DMACH_I2S_OUT, - DMACH_PCM_IN, - DMACH_PCM_OUT, - DMACH_MIC_IN, - DMACH_USB_EP1, - DMACH_USB_EP2, - DMACH_USB_EP3, - DMACH_USB_EP4, - DMACH_UART0_SRC2, /* s3c2412 second uart sources */ - DMACH_UART1_SRC2, - DMACH_UART2_SRC2, - DMACH_UART3, /* s3c2443 has extra uart */ - DMACH_UART3_SRC2, - DMACH_SPI0_TX, /* s3c2443/2416/2450 hsspi0 */ - DMACH_SPI0_RX, /* s3c2443/2416/2450 hsspi0 */ - DMACH_SPI1_TX, /* s3c2443/2450 hsspi1 */ - DMACH_SPI1_RX, /* s3c2443/2450 hsspi1 */ - DMACH_MAX, /* the end entry */ -}; - -#endif /* __ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-s3c/fb-core-s3c24xx.h b/arch/arm/mach-s3c/fb-core-s3c24xx.h deleted file mode 100644 index 0e07f3ba4aef..000000000000 --- a/arch/arm/mach-s3c/fb-core-s3c24xx.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright 2010 Samsung Electronics Co., Ltd. - * Pawel Osciak - * - * Samsung framebuffer driver core functions - */ -#ifndef __ASM_PLAT_FB_CORE_S3C24XX_H -#define __ASM_PLAT_FB_CORE_S3C24XX_H __FILE__ - -/* - * These functions are only for use with the core support code, such as - * the CPU-specific initialization code. - */ - -/* Re-define device name depending on support. */ -static inline void s3c_fb_setname(char *name) -{ -#ifdef CONFIG_S3C_DEV_FB - s3c_device_fb.name = name; -#endif -} - -#endif /* __ASM_PLAT_FB_CORE_S3C24XX_H */ diff --git a/arch/arm/mach-s3c/gpio-samsung-s3c24xx.h b/arch/arm/mach-s3c/gpio-samsung-s3c24xx.h deleted file mode 100644 index c29fdc95f883..000000000000 --- a/arch/arm/mach-s3c/gpio-samsung-s3c24xx.h +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C2410 - GPIO lib support - */ - -/* some boards require extra gpio capacity to support external - * devices that need GPIO. - */ - -#ifndef GPIO_SAMSUNG_S3C24XX_H -#define GPIO_SAMSUNG_S3C24XX_H - -#include "map.h" - -/* - * GPIO sizes for various SoCs: - * - * 2410 2412 2440 2443 2416 - * 2442 - * ---- ---- ---- ---- ---- - * A 23 22 25 16 27 - * B 11 11 11 11 11 - * C 16 16 16 16 16 - * D 16 16 16 16 16 - * E 16 16 16 16 16 - * F 8 8 8 8 8 - * G 16 16 16 16 8 - * H 11 11 11 15 15 - * J -- -- 13 16 -- - * K -- -- -- -- 16 - * L -- -- -- 15 14 - * M -- -- -- 2 2 - */ - -/* GPIO bank sizes */ - -#define S3C2410_GPIO_A_NR (32) -#define S3C2410_GPIO_B_NR (32) -#define S3C2410_GPIO_C_NR (32) -#define S3C2410_GPIO_D_NR (32) -#define S3C2410_GPIO_E_NR (32) -#define S3C2410_GPIO_F_NR (32) -#define S3C2410_GPIO_G_NR (32) -#define S3C2410_GPIO_H_NR (32) -#define S3C2410_GPIO_J_NR (32) /* technically 16. */ -#define S3C2410_GPIO_K_NR (32) /* technically 16. */ -#define S3C2410_GPIO_L_NR (32) /* technically 15. */ -#define S3C2410_GPIO_M_NR (32) /* technically 2. */ - -#if CONFIG_S3C_GPIO_SPACE != 0 -#error CONFIG_S3C_GPIO_SPACE cannot be nonzero at the moment -#endif - -#define S3C2410_GPIO_NEXT(__gpio) \ - ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0) - -#ifndef __ASSEMBLY__ - -enum s3c_gpio_number { - S3C2410_GPIO_A_START = 0, - S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A), - S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B), - S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C), - S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D), - S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E), - S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F), - S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G), - S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H), - S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J), - S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K), - S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L), -}; - -#endif /* __ASSEMBLY__ */ - -/* S3C2410 GPIO number definitions. */ - -#define S3C2410_GPA(_nr) (S3C2410_GPIO_A_START + (_nr)) -#define S3C2410_GPB(_nr) (S3C2410_GPIO_B_START + (_nr)) -#define S3C2410_GPC(_nr) (S3C2410_GPIO_C_START + (_nr)) -#define S3C2410_GPD(_nr) (S3C2410_GPIO_D_START + (_nr)) -#define S3C2410_GPE(_nr) (S3C2410_GPIO_E_START + (_nr)) -#define S3C2410_GPF(_nr) (S3C2410_GPIO_F_START + (_nr)) -#define S3C2410_GPG(_nr) (S3C2410_GPIO_G_START + (_nr)) -#define S3C2410_GPH(_nr) (S3C2410_GPIO_H_START + (_nr)) -#define S3C2410_GPJ(_nr) (S3C2410_GPIO_J_START + (_nr)) -#define S3C2410_GPK(_nr) (S3C2410_GPIO_K_START + (_nr)) -#define S3C2410_GPL(_nr) (S3C2410_GPIO_L_START + (_nr)) -#define S3C2410_GPM(_nr) (S3C2410_GPIO_M_START + (_nr)) - -#ifdef CONFIG_CPU_S3C244X -#define S3C_GPIO_END (S3C2410_GPJ(0) + 32) -#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) -#define S3C_GPIO_END (S3C2410_GPM(0) + 32) -#else -#define S3C_GPIO_END (S3C2410_GPH(0) + 32) -#endif - -#endif /* GPIO_SAMSUNG_S3C24XX_H */ diff --git a/arch/arm/mach-s3c/gta02.h b/arch/arm/mach-s3c/gta02.h deleted file mode 100644 index 043ae382bfc5..000000000000 --- a/arch/arm/mach-s3c/gta02.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * GTA02 header - */ - -#ifndef __MACH_S3C24XX_GTA02_H -#define __MACH_S3C24XX_GTA02_H __FILE__ - -#include "regs-gpio.h" - -#define GTA02_GPIO_AUX_LED S3C2410_GPB(2) -#define GTA02_GPIO_USB_PULLUP S3C2410_GPB(9) -#define GTA02_GPIO_AUX_KEY S3C2410_GPF(6) -#define GTA02_GPIO_HOLD_KEY S3C2410_GPF(7) -#define GTA02_GPIO_AMP_SHUT S3C2410_GPJ(1) /* v2 + v3 + v4 only */ -#define GTA02_GPIO_HP_IN S3C2410_GPJ(2) /* v2 + v3 + v4 only */ - -#define GTA02_IRQ_PCF50633 IRQ_EINT9 - -#endif /* __MACH_S3C24XX_GTA02_H */ diff --git a/arch/arm/mach-s3c/h1940-bluetooth.c b/arch/arm/mach-s3c/h1940-bluetooth.c deleted file mode 100644 index 59edcf8a620d..000000000000 --- a/arch/arm/mach-s3c/h1940-bluetooth.c +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: GPL-1.0+ -// -// Copyright (c) Arnaud Patard -// -// S3C2410 bluetooth "driver" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gpio-cfg.h" -#include "regs-gpio.h" -#include "gpio-samsung.h" - -#include "h1940.h" - -#define DRV_NAME "h1940-bt" - -/* Bluetooth control */ -static void h1940bt_enable(int on) -{ - if (on) { - /* Power on the chip */ - gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 1); - /* Reset the chip */ - mdelay(10); - - gpio_set_value(S3C2410_GPH(1), 1); - mdelay(10); - gpio_set_value(S3C2410_GPH(1), 0); - - h1940_led_blink_set(NULL, GPIO_LED_BLINK, NULL, NULL); - } - else { - gpio_set_value(S3C2410_GPH(1), 1); - mdelay(10); - gpio_set_value(S3C2410_GPH(1), 0); - mdelay(10); - gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0); - - h1940_led_blink_set(NULL, GPIO_LED_NO_BLINK_LOW, NULL, NULL); - } -} - -static int h1940bt_set_block(void *data, bool blocked) -{ - h1940bt_enable(!blocked); - return 0; -} - -static const struct rfkill_ops h1940bt_rfkill_ops = { - .set_block = h1940bt_set_block, -}; - -static int h1940bt_probe(struct platform_device *pdev) -{ - struct rfkill *rfk; - int ret = 0; - - ret = gpio_request(S3C2410_GPH(1), dev_name(&pdev->dev)); - if (ret) { - dev_err(&pdev->dev, "could not get GPH1\n"); - return ret; - } - - ret = gpio_request(H1940_LATCH_BLUETOOTH_POWER, dev_name(&pdev->dev)); - if (ret) { - gpio_free(S3C2410_GPH(1)); - dev_err(&pdev->dev, "could not get BT_POWER\n"); - return ret; - } - - /* Configures BT serial port GPIOs */ - s3c_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0); - s3c_gpio_setpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT); - s3c_gpio_setpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0); - s3c_gpio_setpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE); - s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0); - s3c_gpio_setpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE); - - rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH, - &h1940bt_rfkill_ops, NULL); - if (!rfk) { - ret = -ENOMEM; - goto err_rfk_alloc; - } - - ret = rfkill_register(rfk); - if (ret) - goto err_rfkill; - - platform_set_drvdata(pdev, rfk); - - return 0; - -err_rfkill: - rfkill_destroy(rfk); -err_rfk_alloc: - return ret; -} - -static int h1940bt_remove(struct platform_device *pdev) -{ - struct rfkill *rfk = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - gpio_free(S3C2410_GPH(1)); - - if (rfk) { - rfkill_unregister(rfk); - rfkill_destroy(rfk); - } - rfk = NULL; - - h1940bt_enable(0); - - return 0; -} - - -static struct platform_driver h1940bt_driver = { - .driver = { - .name = DRV_NAME, - }, - .probe = h1940bt_probe, - .remove = h1940bt_remove, -}; - -module_platform_driver(h1940bt_driver); - -MODULE_AUTHOR("Arnaud Patard "); -MODULE_DESCRIPTION("Driver for the iPAQ H1940 bluetooth chip"); -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-s3c/h1940.h b/arch/arm/mach-s3c/h1940.h deleted file mode 100644 index 5dfe9d10cd15..000000000000 --- a/arch/arm/mach-s3c/h1940.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright 2006 Ben Dooks - * - * Copyright (c) 2005 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * iPAQ H1940 series definitions - */ - -#ifndef __MACH_S3C24XX_H1940_H -#define __MACH_S3C24XX_H1940_H __FILE__ - -#define H1940_SUSPEND_CHECKSUM (0x30003ff8) -#define H1940_SUSPEND_RESUMEAT (0x30081000) -#define H1940_SUSPEND_CHECK (0x30080000) - -struct gpio_desc; - -extern void h1940_pm_return(void); -extern int h1940_led_blink_set(struct gpio_desc *desc, int state, - unsigned long *delay_on, - unsigned long *delay_off); - -#include - -#define H1940_LATCH_GPIO(x) (S3C_GPIO_END + (x)) - -/* SD layer latch */ - -#define H1940_LATCH_LCD_P0 H1940_LATCH_GPIO(0) -#define H1940_LATCH_LCD_P1 H1940_LATCH_GPIO(1) -#define H1940_LATCH_LCD_P2 H1940_LATCH_GPIO(2) -#define H1940_LATCH_LCD_P3 H1940_LATCH_GPIO(3) -#define H1940_LATCH_MAX1698_nSHUTDOWN H1940_LATCH_GPIO(4) -#define H1940_LATCH_LED_RED H1940_LATCH_GPIO(5) -#define H1940_LATCH_SDQ7 H1940_LATCH_GPIO(6) -#define H1940_LATCH_USB_DP H1940_LATCH_GPIO(7) - -/* CPU layer latch */ - -#define H1940_LATCH_UDA_POWER H1940_LATCH_GPIO(8) -#define H1940_LATCH_AUDIO_POWER H1940_LATCH_GPIO(9) -#define H1940_LATCH_SM803_ENABLE H1940_LATCH_GPIO(10) -#define H1940_LATCH_LCD_P4 H1940_LATCH_GPIO(11) -#define H1940_LATCH_SD_POWER H1940_LATCH_GPIO(12) -#define H1940_LATCH_BLUETOOTH_POWER H1940_LATCH_GPIO(13) -#define H1940_LATCH_LED_GREEN H1940_LATCH_GPIO(14) -#define H1940_LATCH_LED_FLASH H1940_LATCH_GPIO(15) - -#endif /* __MACH_S3C24XX_H1940_H */ diff --git a/arch/arm/mach-s3c/hardware-s3c24xx.h b/arch/arm/mach-s3c/hardware-s3c24xx.h deleted file mode 100644 index 33b37467d05f..000000000000 --- a/arch/arm/mach-s3c/hardware-s3c24xx.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2003 Simtec Electronics - * Ben Dooks - * - * S3C2410 - hardware - */ - -#ifndef __ASM_ARCH_HARDWARE_S3C24XX_H -#define __ASM_ARCH_HARDWARE_S3C24XX_H - -extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg); - -#endif /* __ASM_ARCH_HARDWARE_S3C24XX_H */ diff --git a/arch/arm/mach-s3c/iotiming-s3c2410.c b/arch/arm/mach-s3c/iotiming-s3c2410.c deleted file mode 100644 index 09f388d8f824..000000000000 --- a/arch/arm/mach-s3c/iotiming-s3c2410.c +++ /dev/null @@ -1,472 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (c) 2006-2009 Simtec Electronics -// http://armlinux.simtec.co.uk/ -// Ben Dooks -// -// S3C24XX CPU Frequency scaling - IO timing for S3C2410/S3C2440/S3C2442 - -#include -#include -#include -#include -#include -#include -#include - -#include "map.h" -#include "regs-clock.h" - -#include - -#include "regs-mem-s3c24xx.h" - -#define print_ns(x) ((x) / 10), ((x) % 10) - -/** - * s3c2410_print_timing - print bank timing data for debug purposes - * @pfx: The prefix to put on the output - * @timings: The timing inforamtion to print. -*/ -static void s3c2410_print_timing(const char *pfx, - struct s3c_iotimings *timings) -{ - struct s3c2410_iobank_timing *bt; - int bank; - - for (bank = 0; bank < MAX_BANKS; bank++) { - bt = timings->bank[bank].io_2410; - if (!bt) - continue; - - printk(KERN_DEBUG "%s %d: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, " - "Tcoh=%d.%d, Tcah=%d.%d\n", pfx, bank, - print_ns(bt->tacs), - print_ns(bt->tcos), - print_ns(bt->tacc), - print_ns(bt->tcoh), - print_ns(bt->tcah)); - } -} - -/** - * bank_reg - convert bank number to pointer to the control register. - * @bank: The IO bank number. - */ -static inline void __iomem *bank_reg(unsigned int bank) -{ - return S3C2410_BANKCON0 + (bank << 2); -} - -/** - * bank_is_io - test whether bank is used for IO - * @bankcon: The bank control register. - * - * This is a simplistic test to see if any BANKCON[x] is not an IO - * bank. It currently does not take into account whether BWSCON has - * an illegal width-setting in it, or if the pin connected to nCS[x] - * is actually being handled as a chip-select. - */ -static inline int bank_is_io(unsigned long bankcon) -{ - return !(bankcon & S3C2410_BANKCON_SDRAM); -} - -/** - * to_div - convert cycle time to divisor - * @cyc: The cycle time, in 10ths of nanoseconds. - * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. - * - * Convert the given cycle time into the divisor to use to obtain it from - * HCLK. -*/ -static inline unsigned int to_div(unsigned int cyc, unsigned int hclk_tns) -{ - if (cyc == 0) - return 0; - - return DIV_ROUND_UP(cyc, hclk_tns); -} - -/** - * calc_0124 - calculate divisor control for divisors that do /0, /1. /2 and /4 - * @cyc: The cycle time, in 10ths of nanoseconds. - * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. - * @v: Pointer to register to alter. - * @shift: The shift to get to the control bits. - * - * Calculate the divisor, and turn it into the correct control bits to - * set in the result, @v. - */ -static unsigned int calc_0124(unsigned int cyc, unsigned long hclk_tns, - unsigned long *v, int shift) -{ - unsigned int div = to_div(cyc, hclk_tns); - unsigned long val; - - s3c_freq_iodbg("%s: cyc=%d, hclk=%lu, shift=%d => div %d\n", - __func__, cyc, hclk_tns, shift, div); - - switch (div) { - case 0: - val = 0; - break; - case 1: - val = 1; - break; - case 2: - val = 2; - break; - case 3: - case 4: - val = 3; - break; - default: - return -1; - } - - *v |= val << shift; - return 0; -} - -static int calc_tacp(unsigned int cyc, unsigned long hclk, unsigned long *v) -{ - /* Currently no support for Tacp calculations. */ - return 0; -} - -/** - * calc_tacc - calculate divisor control for tacc. - * @cyc: The cycle time, in 10ths of nanoseconds. - * @nwait_en: IS nWAIT enabled for this bank. - * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. - * @v: Pointer to register to alter. - * - * Calculate the divisor control for tACC, taking into account whether - * the bank has nWAIT enabled. The result is used to modify the value - * pointed to by @v. -*/ -static int calc_tacc(unsigned int cyc, int nwait_en, - unsigned long hclk_tns, unsigned long *v) -{ - unsigned int div = to_div(cyc, hclk_tns); - unsigned long val; - - s3c_freq_iodbg("%s: cyc=%u, nwait=%d, hclk=%lu => div=%u\n", - __func__, cyc, nwait_en, hclk_tns, div); - - /* if nWait enabled on an bank, Tacc must be at-least 4 cycles. */ - if (nwait_en && div < 4) - div = 4; - - switch (div) { - case 0: - val = 0; - break; - - case 1: - case 2: - case 3: - case 4: - val = div - 1; - break; - - case 5: - case 6: - val = 4; - break; - - case 7: - case 8: - val = 5; - break; - - case 9: - case 10: - val = 6; - break; - - case 11: - case 12: - case 13: - case 14: - val = 7; - break; - - default: - return -1; - } - - *v |= val << 8; - return 0; -} - -/** - * s3c2410_calc_bank - calculate bank timing information - * @cfg: The configuration we need to calculate for. - * @bt: The bank timing information. - * - * Given the cycle timine for a bank @bt, calculate the new BANKCON - * setting for the @cfg timing. This updates the timing information - * ready for the cpu frequency change. - */ -static int s3c2410_calc_bank(struct s3c_cpufreq_config *cfg, - struct s3c2410_iobank_timing *bt) -{ - unsigned long hclk = cfg->freq.hclk_tns; - unsigned long res; - int ret; - - res = bt->bankcon; - res &= (S3C2410_BANKCON_SDRAM | S3C2410_BANKCON_PMC16); - - /* tacp: 2,3,4,5 */ - /* tcah: 0,1,2,4 */ - /* tcoh: 0,1,2,4 */ - /* tacc: 1,2,3,4,6,7,10,14 (>4 for nwait) */ - /* tcos: 0,1,2,4 */ - /* tacs: 0,1,2,4 */ - - ret = calc_0124(bt->tacs, hclk, &res, S3C2410_BANKCON_Tacs_SHIFT); - ret |= calc_0124(bt->tcos, hclk, &res, S3C2410_BANKCON_Tcos_SHIFT); - ret |= calc_0124(bt->tcah, hclk, &res, S3C2410_BANKCON_Tcah_SHIFT); - ret |= calc_0124(bt->tcoh, hclk, &res, S3C2410_BANKCON_Tcoh_SHIFT); - - if (ret) - return -EINVAL; - - ret |= calc_tacp(bt->tacp, hclk, &res); - ret |= calc_tacc(bt->tacc, bt->nwait_en, hclk, &res); - - if (ret) - return -EINVAL; - - bt->bankcon = res; - return 0; -} - -static const unsigned int tacc_tab[] = { - [0] = 1, - [1] = 2, - [2] = 3, - [3] = 4, - [4] = 6, - [5] = 9, - [6] = 10, - [7] = 14, -}; - -/** - * get_tacc - turn tACC value into cycle time - * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. - * @val: The bank timing register value, shifted down. - */ -static unsigned int get_tacc(unsigned long hclk_tns, - unsigned long val) -{ - val &= 7; - return hclk_tns * tacc_tab[val]; -} - -/** - * get_0124 - turn 0/1/2/4 divider into cycle time - * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. - * @val: The bank timing register value, shifed down. - */ -static unsigned int get_0124(unsigned long hclk_tns, - unsigned long val) -{ - val &= 3; - return hclk_tns * ((val == 3) ? 4 : val); -} - -/** - * s3c2410_iotiming_getbank - turn BANKCON into cycle time information - * @cfg: The frequency configuration - * @bt: The bank timing to fill in (uses cached BANKCON) - * - * Given the BANKCON setting in @bt and the current frequency settings - * in @cfg, update the cycle timing information. - */ -static void s3c2410_iotiming_getbank(struct s3c_cpufreq_config *cfg, - struct s3c2410_iobank_timing *bt) -{ - unsigned long bankcon = bt->bankcon; - unsigned long hclk = cfg->freq.hclk_tns; - - bt->tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT); - bt->tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT); - bt->tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT); - bt->tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT); - bt->tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT); -} - -/** - * s3c2410_iotiming_debugfs - debugfs show io bank timing information - * @seq: The seq_file to write output to using seq_printf(). - * @cfg: The current configuration. - * @iob: The IO bank information to decode. - */ -void s3c2410_iotiming_debugfs(struct seq_file *seq, - struct s3c_cpufreq_config *cfg, - union s3c_iobank *iob) -{ - struct s3c2410_iobank_timing *bt = iob->io_2410; - unsigned long bankcon = bt->bankcon; - unsigned long hclk = cfg->freq.hclk_tns; - unsigned int tacs; - unsigned int tcos; - unsigned int tacc; - unsigned int tcoh; - unsigned int tcah; - - seq_printf(seq, "BANKCON=0x%08lx\n", bankcon); - - tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT); - tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT); - tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT); - tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT); - tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT); - - seq_printf(seq, - "\tRead: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n", - print_ns(bt->tacs), - print_ns(bt->tcos), - print_ns(bt->tacc), - print_ns(bt->tcoh), - print_ns(bt->tcah)); - - seq_printf(seq, - "\t Set: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n", - print_ns(tacs), - print_ns(tcos), - print_ns(tacc), - print_ns(tcoh), - print_ns(tcah)); -} - -/** - * s3c2410_iotiming_calc - Calculate bank timing for frequency change. - * @cfg: The frequency configuration - * @iot: The IO timing information to fill out. - * - * Calculate the new values for the banks in @iot based on the new - * frequency information in @cfg. This is then used by s3c2410_iotiming_set() - * to update the timing when necessary. - */ -int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg, - struct s3c_iotimings *iot) -{ - struct s3c2410_iobank_timing *bt; - unsigned long bankcon; - int bank; - int ret; - - for (bank = 0; bank < MAX_BANKS; bank++) { - bankcon = __raw_readl(bank_reg(bank)); - bt = iot->bank[bank].io_2410; - - if (!bt) - continue; - - bt->bankcon = bankcon; - - ret = s3c2410_calc_bank(cfg, bt); - if (ret) { - printk(KERN_ERR "%s: cannot calculate bank %d io\n", - __func__, bank); - goto err; - } - - s3c_freq_iodbg("%s: bank %d: con=%08lx\n", - __func__, bank, bt->bankcon); - } - - return 0; - err: - return ret; -} - -/** - * s3c2410_iotiming_set - set the IO timings from the given setup. - * @cfg: The frequency configuration - * @iot: The IO timing information to use. - * - * Set all the currently used IO bank timing information generated - * by s3c2410_iotiming_calc() once the core has validated that all - * the new values are within permitted bounds. - */ -void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg, - struct s3c_iotimings *iot) -{ - struct s3c2410_iobank_timing *bt; - int bank; - - /* set the io timings from the specifier */ - - for (bank = 0; bank < MAX_BANKS; bank++) { - bt = iot->bank[bank].io_2410; - if (!bt) - continue; - - __raw_writel(bt->bankcon, bank_reg(bank)); - } -} - -/** - * s3c2410_iotiming_get - Get the timing information from current registers. - * @cfg: The frequency configuration - * @timings: The IO timing information to fill out. - * - * Calculate the @timings timing information from the current frequency - * information in @cfg, and the new frequency configuration - * through all the IO banks, reading the state and then updating @iot - * as necessary. - * - * This is used at the moment on initialisation to get the current - * configuration so that boards do not have to carry their own setup - * if the timings are correct on initialisation. - */ - -int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg, - struct s3c_iotimings *timings) -{ - struct s3c2410_iobank_timing *bt; - unsigned long bankcon; - unsigned long bwscon; - int bank; - - bwscon = __raw_readl(S3C2410_BWSCON); - - /* look through all banks to see what is currently set. */ - - for (bank = 0; bank < MAX_BANKS; bank++) { - bankcon = __raw_readl(bank_reg(bank)); - - if (!bank_is_io(bankcon)) - continue; - - s3c_freq_iodbg("%s: bank %d: con %08lx\n", - __func__, bank, bankcon); - - bt = kzalloc(sizeof(*bt), GFP_KERNEL); - if (!bt) - return -ENOMEM; - - /* find out in nWait is enabled for bank. */ - - if (bank != 0) { - unsigned long tmp = S3C2410_BWSCON_GET(bwscon, bank); - if (tmp & S3C2410_BWSCON_WS) - bt->nwait_en = 1; - } - - timings->bank[bank].io_2410 = bt; - bt->bankcon = bankcon; - - s3c2410_iotiming_getbank(cfg, bt); - } - - s3c2410_print_timing("get", timings); - return 0; -} diff --git a/arch/arm/mach-s3c/iotiming-s3c2412.c b/arch/arm/mach-s3c/iotiming-s3c2412.c deleted file mode 100644 index 003f89c4dc53..000000000000 --- a/arch/arm/mach-s3c/iotiming-s3c2412.c +++ /dev/null @@ -1,278 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (c) 2006-2008 Simtec Electronics -// http://armlinux.simtec.co.uk/ -// Ben Dooks -// -// S3C2412/S3C2443 (PL093 based) IO timing support - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "cpu.h" -#include - -#include "s3c2412.h" - -#define print_ns(x) ((x) / 10), ((x) % 10) - -/** - * s3c2412_print_timing - print timing information via printk. - * @pfx: The prefix to print each line with. - * @iot: The IO timing information - */ -static void s3c2412_print_timing(const char *pfx, struct s3c_iotimings *iot) -{ - struct s3c2412_iobank_timing *bt; - unsigned int bank; - - for (bank = 0; bank < MAX_BANKS; bank++) { - bt = iot->bank[bank].io_2412; - if (!bt) - continue; - - printk(KERN_DEBUG "%s: %d: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d" - "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n", pfx, bank, - print_ns(bt->idcy), - print_ns(bt->wstrd), - print_ns(bt->wstwr), - print_ns(bt->wstoen), - print_ns(bt->wstwen), - print_ns(bt->wstbrd)); - } -} - -/** - * to_div - turn a cycle length into a divisor setting. - * @cyc_tns: The cycle time in 10ths of nanoseconds. - * @clk_tns: The clock period in 10ths of nanoseconds. - */ -static inline unsigned int to_div(unsigned int cyc_tns, unsigned int clk_tns) -{ - return cyc_tns ? DIV_ROUND_UP(cyc_tns, clk_tns) : 0; -} - -/** - * calc_timing - calculate timing divisor value and check in range. - * @hwtm: The hardware timing in 10ths of nanoseconds. - * @clk_tns: The clock period in 10ths of nanoseconds. - * @err: Pointer to err variable to update in event of failure. - */ -static unsigned int calc_timing(unsigned int hwtm, unsigned int clk_tns, - unsigned int *err) -{ - unsigned int ret = to_div(hwtm, clk_tns); - - if (ret > 0xf) - *err = -EINVAL; - - return ret; -} - -/** - * s3c2412_calc_bank - calculate the bank divisor settings. - * @cfg: The current frequency configuration. - * @bt: The bank timing. - */ -static int s3c2412_calc_bank(struct s3c_cpufreq_config *cfg, - struct s3c2412_iobank_timing *bt) -{ - unsigned int hclk = cfg->freq.hclk_tns; - int err = 0; - - bt->smbidcyr = calc_timing(bt->idcy, hclk, &err); - bt->smbwstrd = calc_timing(bt->wstrd, hclk, &err); - bt->smbwstwr = calc_timing(bt->wstwr, hclk, &err); - bt->smbwstoen = calc_timing(bt->wstoen, hclk, &err); - bt->smbwstwen = calc_timing(bt->wstwen, hclk, &err); - bt->smbwstbrd = calc_timing(bt->wstbrd, hclk, &err); - - return err; -} - -/** - * s3c2412_iotiming_debugfs - debugfs show io bank timing information - * @seq: The seq_file to write output to using seq_printf(). - * @cfg: The current configuration. - * @iob: The IO bank information to decode. -*/ -void s3c2412_iotiming_debugfs(struct seq_file *seq, - struct s3c_cpufreq_config *cfg, - union s3c_iobank *iob) -{ - struct s3c2412_iobank_timing *bt = iob->io_2412; - - seq_printf(seq, - "\tRead: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d" - "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n", - print_ns(bt->idcy), - print_ns(bt->wstrd), - print_ns(bt->wstwr), - print_ns(bt->wstoen), - print_ns(bt->wstwen), - print_ns(bt->wstbrd)); -} - -/** - * s3c2412_iotiming_calc - calculate all the bank divisor settings. - * @cfg: The current frequency configuration. - * @iot: The bank timing information. - * - * Calculate the timing information for all the banks that are - * configured as IO, using s3c2412_calc_bank(). - */ -int s3c2412_iotiming_calc(struct s3c_cpufreq_config *cfg, - struct s3c_iotimings *iot) -{ - struct s3c2412_iobank_timing *bt; - int bank; - int ret; - - for (bank = 0; bank < MAX_BANKS; bank++) { - bt = iot->bank[bank].io_2412; - if (!bt) - continue; - - ret = s3c2412_calc_bank(cfg, bt); - if (ret) { - printk(KERN_ERR "%s: cannot calculate bank %d io\n", - __func__, bank); - goto err; - } - } - - return 0; - err: - return ret; -} - -/** - * s3c2412_iotiming_set - set the timing information - * @cfg: The current frequency configuration. - * @iot: The bank timing information. - * - * Set the IO bank information from the details calculated earlier from - * calling s3c2412_iotiming_calc(). - */ -void s3c2412_iotiming_set(struct s3c_cpufreq_config *cfg, - struct s3c_iotimings *iot) -{ - struct s3c2412_iobank_timing *bt; - void __iomem *regs; - int bank; - - /* set the io timings from the specifier */ - - for (bank = 0; bank < MAX_BANKS; bank++) { - bt = iot->bank[bank].io_2412; - if (!bt) - continue; - - regs = S3C2412_SSMC_BANK(bank); - - __raw_writel(bt->smbidcyr, regs + SMBIDCYR); - __raw_writel(bt->smbwstrd, regs + SMBWSTRDR); - __raw_writel(bt->smbwstwr, regs + SMBWSTWRR); - __raw_writel(bt->smbwstoen, regs + SMBWSTOENR); - __raw_writel(bt->smbwstwen, regs + SMBWSTWENR); - __raw_writel(bt->smbwstbrd, regs + SMBWSTBRDR); - } -} - -static inline unsigned int s3c2412_decode_timing(unsigned int clock, u32 reg) -{ - return (reg & 0xf) * clock; -} - -static void s3c2412_iotiming_getbank(struct s3c_cpufreq_config *cfg, - struct s3c2412_iobank_timing *bt, - unsigned int bank) -{ - unsigned long clk = cfg->freq.hclk_tns; /* ssmc clock??? */ - void __iomem *regs = S3C2412_SSMC_BANK(bank); - - bt->idcy = s3c2412_decode_timing(clk, __raw_readl(regs + SMBIDCYR)); - bt->wstrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTRDR)); - bt->wstoen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTOENR)); - bt->wstwen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTWENR)); - bt->wstbrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTBRDR)); -} - -/** - * bank_is_io - return true if bank is (possibly) IO. - * @bank: The bank number. - * @bankcfg: The value of S3C2412_EBI_BANKCFG. - */ -static inline bool bank_is_io(unsigned int bank, u32 bankcfg) -{ - if (bank < 2) - return true; - - return !(bankcfg & (1 << bank)); -} - -int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg, - struct s3c_iotimings *timings) -{ - struct s3c2412_iobank_timing *bt; - u32 bankcfg = __raw_readl(S3C2412_EBI_BANKCFG); - unsigned int bank; - - /* look through all banks to see what is currently set. */ - - for (bank = 0; bank < MAX_BANKS; bank++) { - if (!bank_is_io(bank, bankcfg)) - continue; - - bt = kzalloc(sizeof(*bt), GFP_KERNEL); - if (!bt) - return -ENOMEM; - - timings->bank[bank].io_2412 = bt; - s3c2412_iotiming_getbank(cfg, bt, bank); - } - - s3c2412_print_timing("get", timings); - return 0; -} - -/* this is in here as it is so small, it doesn't currently warrant a file - * to itself. We expect that any s3c24xx needing this is going to also - * need the iotiming support. - */ -void s3c2412_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg) -{ - struct s3c_cpufreq_board *board = cfg->board; - u32 refresh; - - WARN_ON(board == NULL); - - /* Reduce both the refresh time (in ns) and the frequency (in MHz) - * down to ensure that we do not overflow 32 bit numbers. - * - * This should work for HCLK up to 133MHz and refresh period up - * to 30usec. - */ - - refresh = (cfg->freq.hclk / 100) * (board->refresh / 10); - refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale */ - refresh &= ((1 << 16) - 1); - - s3c_freq_dbg("%s: refresh value %u\n", __func__, (unsigned int)refresh); - - __raw_writel(refresh, S3C2412_REFRESH); -} diff --git a/arch/arm/mach-s3c/irq-pm-s3c24xx.c b/arch/arm/mach-s3c/irq-pm-s3c24xx.c deleted file mode 100644 index 55f41135ad70..000000000000 --- a/arch/arm/mach-s3c/irq-pm-s3c24xx.c +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (c) 2003-2004 Simtec Electronics -// Ben Dooks -// http://armlinux.simtec.co.uk/ -// -// S3C24XX - IRQ PM code - -#include -#include -#include -#include -#include -#include - -#include "cpu.h" -#include "pm.h" -#include "map-base.h" -#include "map-s3c.h" - -#include "regs-irq.h" -#include "regs-gpio.h" -#include "pm-core.h" - -#include - -int s3c_irq_wake(struct irq_data *data, unsigned int state) -{ - unsigned long irqbit = 1 << data->hwirq; - - if (!(s3c_irqwake_intallow & irqbit)) - return -ENOENT; - - pr_info("wake %s for hwirq %lu\n", - state ? "enabled" : "disabled", data->hwirq); - - if (!state) - s3c_irqwake_intmask |= irqbit; - else - s3c_irqwake_intmask &= ~irqbit; - - return 0; -} - -static struct sleep_save irq_save[] = { - SAVE_ITEM(S3C2410_INTMSK), - SAVE_ITEM(S3C2410_INTSUBMSK), -}; - -/* the extint values move between the s3c2410/s3c2440 and the s3c2412 - * so we use an array to hold them, and to calculate the address of - * the register at run-time -*/ - -static unsigned long save_extint[3]; -static unsigned long save_eintflt[4]; -static unsigned long save_eintmask; - -static int s3c24xx_irq_suspend(void) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(save_extint); i++) - save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4)); - - for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) - save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4)); - - s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); - save_eintmask = __raw_readl(S3C24XX_EINTMASK); - - return 0; -} - -static void s3c24xx_irq_resume(void) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(save_extint); i++) - __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4)); - - for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) - __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4)); - - s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); - __raw_writel(save_eintmask, S3C24XX_EINTMASK); -} - -struct syscore_ops s3c24xx_irq_syscore_ops = { - .suspend = s3c24xx_irq_suspend, - .resume = s3c24xx_irq_resume, -}; - -#ifdef CONFIG_CPU_S3C2416 -static struct sleep_save s3c2416_irq_save[] = { - SAVE_ITEM(S3C2416_INTMSK2), -}; - -static int s3c2416_irq_suspend(void) -{ - s3c_pm_do_save(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save)); - - return 0; -} - -static void s3c2416_irq_resume(void) -{ - s3c_pm_do_restore(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save)); -} - -struct syscore_ops s3c2416_irq_syscore_ops = { - .suspend = s3c2416_irq_suspend, - .resume = s3c2416_irq_resume, -}; -#endif diff --git a/arch/arm/mach-s3c/irq-s3c24xx-fiq-exports.c b/arch/arm/mach-s3c/irq-s3c24xx-fiq-exports.c deleted file mode 100644 index 84cf86376ded..000000000000 --- a/arch/arm/mach-s3c/irq-s3c24xx-fiq-exports.c +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include -#include -#include - -EXPORT_SYMBOL(s3c24xx_spi_fiq_rx); -EXPORT_SYMBOL(s3c24xx_spi_fiq_txrx); -EXPORT_SYMBOL(s3c24xx_spi_fiq_tx); diff --git a/arch/arm/mach-s3c/irq-s3c24xx-fiq.S b/arch/arm/mach-s3c/irq-s3c24xx-fiq.S deleted file mode 100644 index 5d238d9a798e..000000000000 --- a/arch/arm/mach-s3c/irq-s3c24xx-fiq.S +++ /dev/null @@ -1,112 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* linux/drivers/spi/spi_s3c24xx_fiq.S - * - * Copyright 2009 Simtec Electronics - * Ben Dooks - * - * S3C24XX SPI - FIQ pseudo-DMA transfer code -*/ - -#include -#include - -#include "map.h" -#include "regs-irq.h" - -#include - -#define S3C2410_SPTDAT (0x10) -#define S3C2410_SPRDAT (0x14) - - .text - - @ entry to these routines is as follows, with the register names - @ defined in fiq.h so that they can be shared with the C files which - @ setup the calling registers. - @ - @ fiq_rirq The base of the IRQ registers to find S3C2410_SRCPND - @ fiq_rtmp Temporary register to hold tx/rx data - @ fiq_rspi The base of the SPI register block - @ fiq_rtx The tx buffer pointer - @ fiq_rrx The rx buffer pointer - @ fiq_rcount The number of bytes to move - - @ each entry starts with a word entry of how long it is - @ and an offset to the irq acknowledgment word - -ENTRY(s3c24xx_spi_fiq_rx) - .word fiq_rx_end - fiq_rx_start - .word fiq_rx_irq_ack - fiq_rx_start -fiq_rx_start: - ldr fiq_rtmp, fiq_rx_irq_ack - str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] - - ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] - strb fiq_rtmp, [ fiq_rrx ], #1 - - mov fiq_rtmp, #0xff - strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] - - subs fiq_rcount, fiq_rcount, #1 - subsne pc, lr, #4 @@ return, still have work to do - - @@ set IRQ controller so that next op will trigger IRQ - mov fiq_rtmp, #0 - str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] - subs pc, lr, #4 - -fiq_rx_irq_ack: - .word 0 -fiq_rx_end: - -ENTRY(s3c24xx_spi_fiq_txrx) - .word fiq_txrx_end - fiq_txrx_start - .word fiq_txrx_irq_ack - fiq_txrx_start -fiq_txrx_start: - - ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] - strb fiq_rtmp, [ fiq_rrx ], #1 - - ldr fiq_rtmp, fiq_txrx_irq_ack - str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] - - ldrb fiq_rtmp, [ fiq_rtx ], #1 - strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] - - subs fiq_rcount, fiq_rcount, #1 - subsne pc, lr, #4 @@ return, still have work to do - - mov fiq_rtmp, #0 - str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] - subs pc, lr, #4 - -fiq_txrx_irq_ack: - .word 0 - -fiq_txrx_end: - -ENTRY(s3c24xx_spi_fiq_tx) - .word fiq_tx_end - fiq_tx_start - .word fiq_tx_irq_ack - fiq_tx_start -fiq_tx_start: - ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] - - ldr fiq_rtmp, fiq_tx_irq_ack - str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] - - ldrb fiq_rtmp, [ fiq_rtx ], #1 - strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] - - subs fiq_rcount, fiq_rcount, #1 - subsne pc, lr, #4 @@ return, still have work to do - - mov fiq_rtmp, #0 - str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] - subs pc, lr, #4 - -fiq_tx_irq_ack: - .word 0 - -fiq_tx_end: - - .end diff --git a/arch/arm/mach-s3c/irq-s3c24xx.c b/arch/arm/mach-s3c/irq-s3c24xx.c deleted file mode 100644 index 088cc04b7431..000000000000 --- a/arch/arm/mach-s3c/irq-s3c24xx.c +++ /dev/null @@ -1,1352 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * S3C24XX IRQ handling - * - * Copyright (c) 2003-2004 Simtec Electronics - * Ben Dooks - * Copyright (c) 2012 Heiko Stuebner -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "irqs.h" -#include "regs-irq.h" -#include "regs-gpio.h" - -#include "cpu.h" -#include "regs-irqtype.h" -#include "pm.h" -#include "s3c24xx.h" - -#define S3C_IRQTYPE_NONE 0 -#define S3C_IRQTYPE_EINT 1 -#define S3C_IRQTYPE_EDGE 2 -#define S3C_IRQTYPE_LEVEL 3 - -struct s3c_irq_data { - unsigned int type; - unsigned long offset; - unsigned long parent_irq; - - /* data gets filled during init */ - struct s3c_irq_intc *intc; - unsigned long sub_bits; - struct s3c_irq_intc *sub_intc; -}; - -/* - * Structure holding the controller data - * @reg_pending register holding pending irqs - * @reg_intpnd special register intpnd in main intc - * @reg_mask mask register - * @domain irq_domain of the controller - * @parent parent controller for ext and sub irqs - * @irqs irq-data, always s3c_irq_data[32] - */ -struct s3c_irq_intc { - void __iomem *reg_pending; - void __iomem *reg_intpnd; - void __iomem *reg_mask; - struct irq_domain *domain; - struct s3c_irq_intc *parent; - struct s3c_irq_data *irqs; -}; - -/* - * Array holding pointers to the global controller structs - * [0] ... main_intc - * [1] ... sub_intc - * [2] ... main_intc2 on s3c2416 - */ -static struct s3c_irq_intc *s3c_intc[3]; - -static void s3c_irq_mask(struct irq_data *data) -{ - struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); - struct s3c_irq_intc *intc = irq_data->intc; - struct s3c_irq_intc *parent_intc = intc->parent; - struct s3c_irq_data *parent_data; - unsigned long mask; - unsigned int irqno; - - mask = readl_relaxed(intc->reg_mask); - mask |= (1UL << irq_data->offset); - writel_relaxed(mask, intc->reg_mask); - - if (parent_intc) { - parent_data = &parent_intc->irqs[irq_data->parent_irq]; - - /* check to see if we need to mask the parent IRQ - * The parent_irq is always in main_intc, so the hwirq - * for find_mapping does not need an offset in any case. - */ - if ((mask & parent_data->sub_bits) == parent_data->sub_bits) { - irqno = irq_find_mapping(parent_intc->domain, - irq_data->parent_irq); - s3c_irq_mask(irq_get_irq_data(irqno)); - } - } -} - -static void s3c_irq_unmask(struct irq_data *data) -{ - struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); - struct s3c_irq_intc *intc = irq_data->intc; - struct s3c_irq_intc *parent_intc = intc->parent; - unsigned long mask; - unsigned int irqno; - - mask = readl_relaxed(intc->reg_mask); - mask &= ~(1UL << irq_data->offset); - writel_relaxed(mask, intc->reg_mask); - - if (parent_intc) { - irqno = irq_find_mapping(parent_intc->domain, - irq_data->parent_irq); - s3c_irq_unmask(irq_get_irq_data(irqno)); - } -} - -static inline void s3c_irq_ack(struct irq_data *data) -{ - struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); - struct s3c_irq_intc *intc = irq_data->intc; - unsigned long bitval = 1UL << irq_data->offset; - - writel_relaxed(bitval, intc->reg_pending); - if (intc->reg_intpnd) - writel_relaxed(bitval, intc->reg_intpnd); -} - -static int s3c_irq_type(struct irq_data *data, unsigned int type) -{ - switch (type) { - case IRQ_TYPE_NONE: - break; - case IRQ_TYPE_EDGE_RISING: - case IRQ_TYPE_EDGE_FALLING: - case IRQ_TYPE_EDGE_BOTH: - irq_set_handler(data->irq, handle_edge_irq); - break; - case IRQ_TYPE_LEVEL_LOW: - case IRQ_TYPE_LEVEL_HIGH: - irq_set_handler(data->irq, handle_level_irq); - break; - default: - pr_err("No such irq type %d\n", type); - return -EINVAL; - } - - return 0; -} - -static int s3c_irqext_type_set(void __iomem *gpcon_reg, - void __iomem *extint_reg, - unsigned long gpcon_offset, - unsigned long extint_offset, - unsigned int type) -{ - unsigned long newvalue = 0, value; - - /* Set the GPIO to external interrupt mode */ - value = readl_relaxed(gpcon_reg); - value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); - writel_relaxed(value, gpcon_reg); - - /* Set the external interrupt to pointed trigger type */ - switch (type) - { - case IRQ_TYPE_NONE: - pr_warn("No edge setting!\n"); - break; - - case IRQ_TYPE_EDGE_RISING: - newvalue = S3C2410_EXTINT_RISEEDGE; - break; - - case IRQ_TYPE_EDGE_FALLING: - newvalue = S3C2410_EXTINT_FALLEDGE; - break; - - case IRQ_TYPE_EDGE_BOTH: - newvalue = S3C2410_EXTINT_BOTHEDGE; - break; - - case IRQ_TYPE_LEVEL_LOW: - newvalue = S3C2410_EXTINT_LOWLEV; - break; - - case IRQ_TYPE_LEVEL_HIGH: - newvalue = S3C2410_EXTINT_HILEV; - break; - - default: - pr_err("No such irq type %d\n", type); - return -EINVAL; - } - - value = readl_relaxed(extint_reg); - value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); - writel_relaxed(value, extint_reg); - - return 0; -} - -static int s3c_irqext_type(struct irq_data *data, unsigned int type) -{ - void __iomem *extint_reg; - void __iomem *gpcon_reg; - unsigned long gpcon_offset, extint_offset; - - if ((data->hwirq >= 4) && (data->hwirq <= 7)) { - gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C24XX_EXTINT0; - gpcon_offset = (data->hwirq) * 2; - extint_offset = (data->hwirq) * 4; - } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) { - gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C24XX_EXTINT1; - gpcon_offset = (data->hwirq - 8) * 2; - extint_offset = (data->hwirq - 8) * 4; - } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) { - gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C24XX_EXTINT2; - gpcon_offset = (data->hwirq - 8) * 2; - extint_offset = (data->hwirq - 16) * 4; - } else { - return -EINVAL; - } - - return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset, - extint_offset, type); -} - -static int s3c_irqext0_type(struct irq_data *data, unsigned int type) -{ - void __iomem *extint_reg; - void __iomem *gpcon_reg; - unsigned long gpcon_offset, extint_offset; - - if (data->hwirq <= 3) { - gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C24XX_EXTINT0; - gpcon_offset = (data->hwirq) * 2; - extint_offset = (data->hwirq) * 4; - } else { - return -EINVAL; - } - - return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset, - extint_offset, type); -} - -static struct irq_chip s3c_irq_chip = { - .name = "s3c", - .irq_ack = s3c_irq_ack, - .irq_mask = s3c_irq_mask, - .irq_unmask = s3c_irq_unmask, - .irq_set_type = s3c_irq_type, - .irq_set_wake = s3c_irq_wake -}; - -static struct irq_chip s3c_irq_level_chip = { - .name = "s3c-level", - .irq_mask = s3c_irq_mask, - .irq_unmask = s3c_irq_unmask, - .irq_ack = s3c_irq_ack, - .irq_set_type = s3c_irq_type, -}; - -static struct irq_chip s3c_irqext_chip = { - .name = "s3c-ext", - .irq_mask = s3c_irq_mask, - .irq_unmask = s3c_irq_unmask, - .irq_ack = s3c_irq_ack, - .irq_set_type = s3c_irqext_type, - .irq_set_wake = s3c_irqext_wake -}; - -static struct irq_chip s3c_irq_eint0t4 = { - .name = "s3c-ext0", - .irq_ack = s3c_irq_ack, - .irq_mask = s3c_irq_mask, - .irq_unmask = s3c_irq_unmask, - .irq_set_wake = s3c_irq_wake, - .irq_set_type = s3c_irqext0_type, -}; - -static void s3c_irq_demux(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc); - struct s3c_irq_intc *intc = irq_data->intc; - struct s3c_irq_intc *sub_intc = irq_data->sub_intc; - unsigned int n, offset; - unsigned long src, msk; - - /* we're using individual domains for the non-dt case - * and one big domain for the dt case where the subintc - * starts at hwirq number 32. - */ - offset = irq_domain_get_of_node(intc->domain) ? 32 : 0; - - chained_irq_enter(chip, desc); - - src = readl_relaxed(sub_intc->reg_pending); - msk = readl_relaxed(sub_intc->reg_mask); - - src &= ~msk; - src &= irq_data->sub_bits; - - while (src) { - n = __ffs(src); - src &= ~(1 << n); - generic_handle_domain_irq(sub_intc->domain, offset + n); - } - - chained_irq_exit(chip, desc); -} - -static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc, - struct pt_regs *regs, int intc_offset) -{ - int pnd; - int offset; - - pnd = readl_relaxed(intc->reg_intpnd); - if (!pnd) - return false; - - /* non-dt machines use individual domains */ - if (!irq_domain_get_of_node(intc->domain)) - intc_offset = 0; - - /* We have a problem that the INTOFFSET register does not always - * show one interrupt. Occasionally we get two interrupts through - * the prioritiser, and this causes the INTOFFSET register to show - * what looks like the logical-or of the two interrupt numbers. - * - * Thanks to Klaus, Shannon, et al for helping to debug this problem - */ - offset = readl_relaxed(intc->reg_intpnd + 4); - - /* Find the bit manually, when the offset is wrong. - * The pending register only ever contains the one bit of the next - * interrupt to handle. - */ - if (!(pnd & (1 << offset))) - offset = __ffs(pnd); - - generic_handle_domain_irq(intc->domain, intc_offset + offset); - return true; -} - -static asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs) -{ - do { - /* - * For platform based machines, neither ERR nor NULL can happen here. - * The s3c24xx_handle_irq() will be set as IRQ handler iff this succeeds: - * - * s3c_intc[0] = s3c24xx_init_intc() - * - * If this fails, the next calls to s3c24xx_init_intc() won't be executed. - * - * For DT machine, s3c_init_intc_of() could set the IRQ handler without - * setting s3c_intc[0] only if it was called with num_ctrl=0. There is no - * such code path, so again the s3c_intc[0] will have a valid pointer if - * set_handle_irq() is called. - * - * Therefore in s3c24xx_handle_irq(), the s3c_intc[0] is always something. - */ - if (s3c24xx_handle_intc(s3c_intc[0], regs, 0)) - continue; - - if (!IS_ERR_OR_NULL(s3c_intc[2])) - if (s3c24xx_handle_intc(s3c_intc[2], regs, 64)) - continue; - - break; - } while (1); -} - -#ifdef CONFIG_FIQ -/** - * s3c24xx_set_fiq - set the FIQ routing - * @irq: IRQ number to route to FIQ on processor. - * @ack_ptr: pointer to a location for storing the bit mask - * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing. - * - * Change the state of the IRQ to FIQ routing depending on @irq and @on. If - * @on is true, the @irq is checked to see if it can be routed and the - * interrupt controller updated to route the IRQ. If @on is false, the FIQ - * routing is cleared, regardless of which @irq is specified. - * - * returns the mask value for the register. - */ -int s3c24xx_set_fiq(unsigned int irq, u32 *ack_ptr, bool on) -{ - u32 intmod; - unsigned offs; - - if (on) { - offs = irq - FIQ_START; - if (offs > 31) - return 0; - - intmod = 1 << offs; - } else { - intmod = 0; - } - - if (ack_ptr) - *ack_ptr = intmod; - writel_relaxed(intmod, S3C2410_INTMOD); - - return intmod; -} - -EXPORT_SYMBOL_GPL(s3c24xx_set_fiq); -#endif - -static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct s3c_irq_intc *intc = h->host_data; - struct s3c_irq_data *irq_data = &intc->irqs[hw]; - struct s3c_irq_intc *parent_intc; - struct s3c_irq_data *parent_irq_data; - unsigned int irqno; - - /* attach controller pointer to irq_data */ - irq_data->intc = intc; - irq_data->offset = hw; - - parent_intc = intc->parent; - - /* set handler and flags */ - switch (irq_data->type) { - case S3C_IRQTYPE_NONE: - return 0; - case S3C_IRQTYPE_EINT: - /* On the S3C2412, the EINT0to3 have a parent irq - * but need the s3c_irq_eint0t4 chip - */ - if (parent_intc && (!soc_is_s3c2412() || hw >= 4)) - irq_set_chip_and_handler(virq, &s3c_irqext_chip, - handle_edge_irq); - else - irq_set_chip_and_handler(virq, &s3c_irq_eint0t4, - handle_edge_irq); - break; - case S3C_IRQTYPE_EDGE: - if (parent_intc || intc->reg_pending == S3C2416_SRCPND2) - irq_set_chip_and_handler(virq, &s3c_irq_level_chip, - handle_edge_irq); - else - irq_set_chip_and_handler(virq, &s3c_irq_chip, - handle_edge_irq); - break; - case S3C_IRQTYPE_LEVEL: - if (parent_intc) - irq_set_chip_and_handler(virq, &s3c_irq_level_chip, - handle_level_irq); - else - irq_set_chip_and_handler(virq, &s3c_irq_chip, - handle_level_irq); - break; - default: - pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type); - return -EINVAL; - } - - irq_set_chip_data(virq, irq_data); - - if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) { - if (irq_data->parent_irq > 31) { - pr_err("irq-s3c24xx: parent irq %lu is out of range\n", - irq_data->parent_irq); - return -EINVAL; - } - - parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; - parent_irq_data->sub_intc = intc; - parent_irq_data->sub_bits |= (1UL << hw); - - /* attach the demuxer to the parent irq */ - irqno = irq_find_mapping(parent_intc->domain, - irq_data->parent_irq); - if (!irqno) { - pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n", - irq_data->parent_irq); - return -EINVAL; - } - irq_set_chained_handler(irqno, s3c_irq_demux); - } - - return 0; -} - -static const struct irq_domain_ops s3c24xx_irq_ops = { - .map = s3c24xx_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static void s3c24xx_clear_intc(struct s3c_irq_intc *intc) -{ - void __iomem *reg_source; - unsigned long pend; - unsigned long last; - int i; - - /* if intpnd is set, read the next pending irq from there */ - reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending; - - last = 0; - for (i = 0; i < 4; i++) { - pend = readl_relaxed(reg_source); - - if (pend == 0 || pend == last) - break; - - writel_relaxed(pend, intc->reg_pending); - if (intc->reg_intpnd) - writel_relaxed(pend, intc->reg_intpnd); - - pr_info("irq: clearing pending status %08x\n", (int)pend); - last = pend; - } -} - -static struct s3c_irq_intc * __init s3c24xx_init_intc(struct device_node *np, - struct s3c_irq_data *irq_data, - struct s3c_irq_intc *parent, - unsigned long address) -{ - struct s3c_irq_intc *intc; - void __iomem *base = (void *)0xf6000000; /* static mapping */ - int irq_num; - int irq_start; - int ret; - - intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); - if (!intc) - return ERR_PTR(-ENOMEM); - - intc->irqs = irq_data; - - if (parent) - intc->parent = parent; - - /* select the correct data for the controller. - * Need to hard code the irq num start and offset - * to preserve the static mapping for now - */ - switch (address) { - case 0x4a000000: - pr_debug("irq: found main intc\n"); - intc->reg_pending = base; - intc->reg_mask = base + 0x08; - intc->reg_intpnd = base + 0x10; - irq_num = 32; - irq_start = S3C2410_IRQ(0); - break; - case 0x4a000018: - pr_debug("irq: found subintc\n"); - intc->reg_pending = base + 0x18; - intc->reg_mask = base + 0x1c; - irq_num = 29; - irq_start = S3C2410_IRQSUB(0); - break; - case 0x4a000040: - pr_debug("irq: found intc2\n"); - intc->reg_pending = base + 0x40; - intc->reg_mask = base + 0x48; - intc->reg_intpnd = base + 0x50; - irq_num = 8; - irq_start = S3C2416_IRQ(0); - break; - case 0x560000a4: - pr_debug("irq: found eintc\n"); - base = (void *)0xfd000000; - - intc->reg_mask = base + 0xa4; - intc->reg_pending = base + 0xa8; - irq_num = 24; - irq_start = S3C2410_IRQ(32); - break; - default: - pr_err("irq: unsupported controller address\n"); - ret = -EINVAL; - goto err; - } - - /* now that all the data is complete, init the irq-domain */ - s3c24xx_clear_intc(intc); - intc->domain = irq_domain_add_legacy(np, irq_num, irq_start, - 0, &s3c24xx_irq_ops, - intc); - if (!intc->domain) { - pr_err("irq: could not create irq-domain\n"); - ret = -EINVAL; - goto err; - } - - set_handle_irq(s3c24xx_handle_irq); - - return intc; - -err: - kfree(intc); - return ERR_PTR(ret); -} - -static struct s3c_irq_data __maybe_unused init_eint[32] = { - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */ -}; - -#ifdef CONFIG_CPU_S3C2410 -static struct s3c_irq_data init_s3c2410base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2410subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ -}; - -void __init s3c2410_init_irq(void) -{ -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2410base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2410subint[0], - s3c_intc[0], 0x4a000018); - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); -} -#endif - -#ifdef CONFIG_CPU_S3C2412 -static struct s3c_irq_data init_s3c2412base[32] = { - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT1 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT2 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* SDI/CF */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2412eint[32] = { - { .type = S3C_IRQTYPE_EINT, .parent_irq = 0 }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 1 }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 2 }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 3 }, /* EINT3 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */ -}; - -static struct s3c_irq_data init_s3c2412subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_NONE, }, - { .type = S3C_IRQTYPE_NONE, }, - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* SDI */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* CF */ -}; - -void __init s3c2412_init_irq(void) -{ - pr_info("S3C2412: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_s3c2412eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2412subint[0], - s3c_intc[0], 0x4a000018); -} -#endif - -#ifdef CONFIG_CPU_S3C2416 -static struct s3c_irq_data init_s3c2416base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */ - { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* NAND */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_NONE, }, - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2416subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ -}; - -static struct s3c_irq_data init_s3c2416_second[32] = { - { .type = S3C_IRQTYPE_EDGE }, /* 2D */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */ -}; - -void __init s3c2416_init_irq(void) -{ - pr_info("S3C2416: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2416subint[0], - s3c_intc[0], 0x4a000018); - - s3c_intc[2] = s3c24xx_init_intc(NULL, &init_s3c2416_second[0], - NULL, 0x4a000040); -} - -#endif - -#ifdef CONFIG_CPU_S3C2440 -static struct s3c_irq_data init_s3c2440base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2440subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ -}; - -void __init s3c2440_init_irq(void) -{ - pr_info("S3C2440: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0], - s3c_intc[0], 0x4a000018); -} -#endif - -#ifdef CONFIG_CPU_S3C2442 -static struct s3c_irq_data init_s3c2442base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2442subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ -}; - -void __init s3c2442_init_irq(void) -{ - pr_info("S3C2442: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2442subint[0], - s3c_intc[0], 0x4a000018); -} -#endif - -#ifdef CONFIG_CPU_S3C2443 -static struct s3c_irq_data init_s3c2443base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */ - { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* CFON */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* NAND */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - - -static struct s3c_irq_data init_s3c2443subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ -}; - -void __init s3c2443_init_irq(void) -{ - pr_info("S3C2443: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2443subint[0], - s3c_intc[0], 0x4a000018); -} -#endif - -#ifdef CONFIG_OF -static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - unsigned int ctrl_num = hw / 32; - unsigned int intc_hw = hw % 32; - struct s3c_irq_intc *intc = s3c_intc[ctrl_num]; - struct s3c_irq_intc *parent_intc = intc->parent; - struct s3c_irq_data *irq_data = &intc->irqs[intc_hw]; - - /* attach controller pointer to irq_data */ - irq_data->intc = intc; - irq_data->offset = intc_hw; - - if (!parent_intc) - irq_set_chip_and_handler(virq, &s3c_irq_chip, handle_edge_irq); - else - irq_set_chip_and_handler(virq, &s3c_irq_level_chip, - handle_edge_irq); - - irq_set_chip_data(virq, irq_data); - - return 0; -} - -/* Translate our of irq notation - * format: - */ -static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) -{ - struct s3c_irq_intc *intc; - struct s3c_irq_intc *parent_intc; - struct s3c_irq_data *irq_data; - struct s3c_irq_data *parent_irq_data; - int irqno; - - if (WARN_ON(intsize < 4)) - return -EINVAL; - - if (intspec[0] > 2 || !s3c_intc[intspec[0]]) { - pr_err("controller number %d invalid\n", intspec[0]); - return -EINVAL; - } - intc = s3c_intc[intspec[0]]; - - *out_hwirq = intspec[0] * 32 + intspec[2]; - *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; - - parent_intc = intc->parent; - if (parent_intc) { - irq_data = &intc->irqs[intspec[2]]; - irq_data->parent_irq = intspec[1]; - parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; - parent_irq_data->sub_intc = intc; - parent_irq_data->sub_bits |= (1UL << intspec[2]); - - /* parent_intc is always s3c_intc[0], so no offset */ - irqno = irq_create_mapping(parent_intc->domain, intspec[1]); - if (irqno < 0) { - pr_err("irq: could not map parent interrupt\n"); - return irqno; - } - - irq_set_chained_handler(irqno, s3c_irq_demux); - } - - return 0; -} - -static const struct irq_domain_ops s3c24xx_irq_ops_of = { - .map = s3c24xx_irq_map_of, - .xlate = s3c24xx_irq_xlate_of, -}; - -struct s3c24xx_irq_of_ctrl { - char *name; - unsigned long offset; - struct s3c_irq_intc **handle; - struct s3c_irq_intc **parent; - struct irq_domain_ops *ops; -}; - -static int __init s3c_init_intc_of(struct device_node *np, - struct device_node *interrupt_parent, - struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl) -{ - struct s3c_irq_intc *intc; - struct s3c24xx_irq_of_ctrl *ctrl; - struct irq_domain *domain; - void __iomem *reg_base; - int i; - - reg_base = of_iomap(np, 0); - if (!reg_base) { - pr_err("irq-s3c24xx: could not map irq registers\n"); - return -EINVAL; - } - - domain = irq_domain_add_linear(np, num_ctrl * 32, - &s3c24xx_irq_ops_of, NULL); - if (!domain) { - pr_err("irq: could not create irq-domain\n"); - return -EINVAL; - } - - for (i = 0; i < num_ctrl; i++) { - ctrl = &s3c_ctrl[i]; - - pr_debug("irq: found controller %s\n", ctrl->name); - - intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); - if (!intc) - return -ENOMEM; - - intc->domain = domain; - intc->irqs = kcalloc(32, sizeof(struct s3c_irq_data), - GFP_KERNEL); - if (!intc->irqs) { - kfree(intc); - return -ENOMEM; - } - - if (ctrl->parent) { - intc->reg_pending = reg_base + ctrl->offset; - intc->reg_mask = reg_base + ctrl->offset + 0x4; - - if (*(ctrl->parent)) { - intc->parent = *(ctrl->parent); - } else { - pr_warn("irq: parent of %s missing\n", - ctrl->name); - kfree(intc->irqs); - kfree(intc); - continue; - } - } else { - intc->reg_pending = reg_base + ctrl->offset; - intc->reg_mask = reg_base + ctrl->offset + 0x08; - intc->reg_intpnd = reg_base + ctrl->offset + 0x10; - } - - s3c24xx_clear_intc(intc); - s3c_intc[i] = intc; - } - - set_handle_irq(s3c24xx_handle_irq); - - return 0; -} - -static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = { - { - .name = "intc", - .offset = 0, - }, { - .name = "subintc", - .offset = 0x18, - .parent = &s3c_intc[0], - } -}; - -static int __init s3c2410_init_intc_of(struct device_node *np, - struct device_node *interrupt_parent) -{ - return s3c_init_intc_of(np, interrupt_parent, - s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl)); -} -IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of); - -static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = { - { - .name = "intc", - .offset = 0, - }, { - .name = "subintc", - .offset = 0x18, - .parent = &s3c_intc[0], - }, { - .name = "intc2", - .offset = 0x40, - } -}; - -static int __init s3c2416_init_intc_of(struct device_node *np, - struct device_node *interrupt_parent) -{ - return s3c_init_intc_of(np, interrupt_parent, - s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl)); -} -IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of); -#endif diff --git a/arch/arm/mach-s3c/irqs-s3c24xx.h b/arch/arm/mach-s3c/irqs-s3c24xx.h deleted file mode 100644 index fecbf7e440c6..000000000000 --- a/arch/arm/mach-s3c/irqs-s3c24xx.h +++ /dev/null @@ -1,219 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2003-2005 Simtec Electronics - * Ben Dooks - */ - - -#ifndef __ASM_ARCH_IRQS_H -#define __ASM_ARCH_IRQS_H __FILE__ - -/* we keep the first set of CPU IRQs out of the range of - * the ISA space, so that the PC104 has them to itself - * and we don't end up having to do horrible things to the - * standard ISA drivers.... - */ - -#define S3C2410_CPUIRQ_OFFSET (16) - -#define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET) - -/* main cpu interrupts */ -#define IRQ_EINT0 S3C2410_IRQ(0) /* 16 */ -#define IRQ_EINT1 S3C2410_IRQ(1) -#define IRQ_EINT2 S3C2410_IRQ(2) -#define IRQ_EINT3 S3C2410_IRQ(3) -#define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */ -#define IRQ_EINT8t23 S3C2410_IRQ(5) -#define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */ -#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440,s3c2443 */ -#define IRQ_BATT_FLT S3C2410_IRQ(7) -#define IRQ_TICK S3C2410_IRQ(8) /* 24 */ -#define IRQ_WDT S3C2410_IRQ(9) /* WDT/AC97 for s3c2443 */ -#define IRQ_TIMER0 S3C2410_IRQ(10) -#define IRQ_TIMER1 S3C2410_IRQ(11) -#define IRQ_TIMER2 S3C2410_IRQ(12) -#define IRQ_TIMER3 S3C2410_IRQ(13) -#define IRQ_TIMER4 S3C2410_IRQ(14) -#define IRQ_UART2 S3C2410_IRQ(15) -#define IRQ_LCD S3C2410_IRQ(16) /* 32 */ -#define IRQ_DMA0 S3C2410_IRQ(17) /* IRQ_DMA for s3c2443 */ -#define IRQ_DMA1 S3C2410_IRQ(18) -#define IRQ_DMA2 S3C2410_IRQ(19) -#define IRQ_DMA3 S3C2410_IRQ(20) -#define IRQ_SDI S3C2410_IRQ(21) -#define IRQ_SPI0 S3C2410_IRQ(22) -#define IRQ_UART1 S3C2410_IRQ(23) -#define IRQ_RESERVED24 S3C2410_IRQ(24) /* 40 */ -#define IRQ_NFCON S3C2410_IRQ(24) /* for s3c2440 */ -#define IRQ_USBD S3C2410_IRQ(25) -#define IRQ_USBH S3C2410_IRQ(26) -#define IRQ_IIC S3C2410_IRQ(27) -#define IRQ_UART0 S3C2410_IRQ(28) /* 44 */ -#define IRQ_SPI1 S3C2410_IRQ(29) -#define IRQ_RTC S3C2410_IRQ(30) -#define IRQ_ADCPARENT S3C2410_IRQ(31) - -/* interrupts generated from the external interrupts sources */ -#define IRQ_EINT0_2412 S3C2410_IRQ(32) -#define IRQ_EINT1_2412 S3C2410_IRQ(33) -#define IRQ_EINT2_2412 S3C2410_IRQ(34) -#define IRQ_EINT3_2412 S3C2410_IRQ(35) -#define IRQ_EINT4 S3C2410_IRQ(36) /* 52 */ -#define IRQ_EINT5 S3C2410_IRQ(37) -#define IRQ_EINT6 S3C2410_IRQ(38) -#define IRQ_EINT7 S3C2410_IRQ(39) -#define IRQ_EINT8 S3C2410_IRQ(40) -#define IRQ_EINT9 S3C2410_IRQ(41) -#define IRQ_EINT10 S3C2410_IRQ(42) -#define IRQ_EINT11 S3C2410_IRQ(43) -#define IRQ_EINT12 S3C2410_IRQ(44) -#define IRQ_EINT13 S3C2410_IRQ(45) -#define IRQ_EINT14 S3C2410_IRQ(46) -#define IRQ_EINT15 S3C2410_IRQ(47) -#define IRQ_EINT16 S3C2410_IRQ(48) -#define IRQ_EINT17 S3C2410_IRQ(49) -#define IRQ_EINT18 S3C2410_IRQ(50) -#define IRQ_EINT19 S3C2410_IRQ(51) -#define IRQ_EINT20 S3C2410_IRQ(52) /* 68 */ -#define IRQ_EINT21 S3C2410_IRQ(53) -#define IRQ_EINT22 S3C2410_IRQ(54) -#define IRQ_EINT23 S3C2410_IRQ(55) - -#define IRQ_EINT_BIT(x) ((x) - IRQ_EINT4 + 4) -#define IRQ_EINT(x) (((x) >= 4) ? (IRQ_EINT4 + (x) - 4) : (IRQ_EINT0 + (x))) - -#define IRQ_LCD_FIFO S3C2410_IRQ(56) -#define IRQ_LCD_FRAME S3C2410_IRQ(57) - -/* IRQs for the interal UARTs, and ADC - * these need to be ordered in number of appearance in the - * SUBSRC mask register -*/ - -#define S3C2410_IRQSUB(x) S3C2410_IRQ((x)+58) - -#define IRQ_S3CUART_RX0 S3C2410_IRQSUB(0) /* 74 */ -#define IRQ_S3CUART_TX0 S3C2410_IRQSUB(1) -#define IRQ_S3CUART_ERR0 S3C2410_IRQSUB(2) - -#define IRQ_S3CUART_RX1 S3C2410_IRQSUB(3) /* 77 */ -#define IRQ_S3CUART_TX1 S3C2410_IRQSUB(4) -#define IRQ_S3CUART_ERR1 S3C2410_IRQSUB(5) - -#define IRQ_S3CUART_RX2 S3C2410_IRQSUB(6) /* 80 */ -#define IRQ_S3CUART_TX2 S3C2410_IRQSUB(7) -#define IRQ_S3CUART_ERR2 S3C2410_IRQSUB(8) - -#define IRQ_TC S3C2410_IRQSUB(9) -#define IRQ_ADC S3C2410_IRQSUB(10) - -#define NR_IRQS_S3C2410 (S3C2410_IRQSUB(10) + 1) - -/* extra irqs for s3c2412 */ - -#define IRQ_S3C2412_CFSDI S3C2410_IRQ(21) - -#define IRQ_S3C2412_SDI S3C2410_IRQSUB(13) -#define IRQ_S3C2412_CF S3C2410_IRQSUB(14) - -#define NR_IRQS_S3C2412 (S3C2410_IRQSUB(14) + 1) - -#define IRQ_S3C2416_EINT8t15 S3C2410_IRQ(5) -#define IRQ_S3C2416_DMA S3C2410_IRQ(17) -#define IRQ_S3C2416_UART3 S3C2410_IRQ(18) -#define IRQ_S3C2416_SDI1 S3C2410_IRQ(20) -#define IRQ_S3C2416_SDI0 S3C2410_IRQ(21) - -#define IRQ_S3C2416_LCD2 S3C2410_IRQSUB(15) -#define IRQ_S3C2416_LCD3 S3C2410_IRQSUB(16) -#define IRQ_S3C2416_LCD4 S3C2410_IRQSUB(17) -#define IRQ_S3C2416_DMA0 S3C2410_IRQSUB(18) -#define IRQ_S3C2416_DMA1 S3C2410_IRQSUB(19) -#define IRQ_S3C2416_DMA2 S3C2410_IRQSUB(20) -#define IRQ_S3C2416_DMA3 S3C2410_IRQSUB(21) -#define IRQ_S3C2416_DMA4 S3C2410_IRQSUB(22) -#define IRQ_S3C2416_DMA5 S3C2410_IRQSUB(23) -#define IRQ_S32416_WDT S3C2410_IRQSUB(27) -#define IRQ_S32416_AC97 S3C2410_IRQSUB(28) - -/* second interrupt-register of s3c2416/s3c2450 */ - -#define S3C2416_IRQ(x) S3C2410_IRQ((x) + 58 + 29) -#define IRQ_S3C2416_2D S3C2416_IRQ(0) -#define IRQ_S3C2416_IIC1 S3C2416_IRQ(1) -#define IRQ_S3C2416_RESERVED2 S3C2416_IRQ(2) -#define IRQ_S3C2416_RESERVED3 S3C2416_IRQ(3) -#define IRQ_S3C2416_PCM0 S3C2416_IRQ(4) -#define IRQ_S3C2416_PCM1 S3C2416_IRQ(5) -#define IRQ_S3C2416_I2S0 S3C2416_IRQ(6) -#define IRQ_S3C2416_I2S1 S3C2416_IRQ(7) - -#define NR_IRQS_S3C2416 (S3C2416_IRQ(7) + 1) - -/* extra irqs for s3c2440/s3c2442 */ - -#define IRQ_S3C2440_CAM_C S3C2410_IRQSUB(11) /* S3C2443 too */ -#define IRQ_S3C2440_CAM_P S3C2410_IRQSUB(12) /* S3C2443 too */ - -#define NR_IRQS_S3C2442 (S3C2410_IRQSUB(12) + 1) - -#define IRQ_S3C2440_WDT S3C2410_IRQSUB(13) -#define IRQ_S3C2440_AC97 S3C2410_IRQSUB(14) - -#define NR_IRQS_S3C2440 (S3C2410_IRQSUB(14) + 1) - -/* irqs for s3c2443 */ - -#define IRQ_S3C2443_DMA S3C2410_IRQ(17) /* IRQ_DMA1 */ -#define IRQ_S3C2443_UART3 S3C2410_IRQ(18) /* IRQ_DMA2 */ -#define IRQ_S3C2443_CFCON S3C2410_IRQ(19) /* IRQ_DMA3 */ -#define IRQ_S3C2443_HSMMC S3C2410_IRQ(20) /* IRQ_SDI */ -#define IRQ_S3C2443_NAND S3C2410_IRQ(24) /* reserved */ - -#define IRQ_S3C2416_HSMMC0 S3C2410_IRQ(21) /* S3C2416/S3C2450 */ - -#define IRQ_HSMMC0 IRQ_S3C2416_HSMMC0 -#define IRQ_HSMMC1 IRQ_S3C2443_HSMMC - -#define IRQ_S3C2443_LCD1 S3C2410_IRQSUB(14) -#define IRQ_S3C2443_LCD2 S3C2410_IRQSUB(15) -#define IRQ_S3C2443_LCD3 S3C2410_IRQSUB(16) -#define IRQ_S3C2443_LCD4 S3C2410_IRQSUB(17) - -#define IRQ_S3C2443_DMA0 S3C2410_IRQSUB(18) -#define IRQ_S3C2443_DMA1 S3C2410_IRQSUB(19) -#define IRQ_S3C2443_DMA2 S3C2410_IRQSUB(20) -#define IRQ_S3C2443_DMA3 S3C2410_IRQSUB(21) -#define IRQ_S3C2443_DMA4 S3C2410_IRQSUB(22) -#define IRQ_S3C2443_DMA5 S3C2410_IRQSUB(23) - -/* UART3 */ -#define IRQ_S3C2443_RX3 S3C2410_IRQSUB(24) -#define IRQ_S3C2443_TX3 S3C2410_IRQSUB(25) -#define IRQ_S3C2443_ERR3 S3C2410_IRQSUB(26) - -#define IRQ_S3C2443_WDT S3C2410_IRQSUB(27) -#define IRQ_S3C2443_AC97 S3C2410_IRQSUB(28) - -#define NR_IRQS_S3C2443 (S3C2410_IRQSUB(28) + 1) - -/* compatibility define. */ -#define IRQ_UART3 IRQ_S3C2443_UART3 -#define IRQ_S3CUART_RX3 IRQ_S3C2443_RX3 -#define IRQ_S3CUART_TX3 IRQ_S3C2443_TX3 -#define IRQ_S3CUART_ERR3 IRQ_S3C2443_ERR3 - -#define IRQ_LCD_VSYNC IRQ_S3C2443_LCD3 -#define IRQ_LCD_SYSTEM IRQ_S3C2443_LCD2 - -#ifdef CONFIG_CPU_S3C2440 -#define IRQ_S3C244X_AC97 IRQ_S3C2440_AC97 -#else -#define IRQ_S3C244X_AC97 IRQ_S3C2443_AC97 -#endif - -/* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */ -#define FIQ_START IRQ_EINT0 - -#endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/mach-s3c/mach-amlm5900.c b/arch/arm/mach-s3c/mach-amlm5900.c deleted file mode 100644 index f85e5885e9b4..000000000000 --- a/arch/arm/mach-s3c/mach-amlm5900.c +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// Copyright (c) 2006 American Microsystems Limited -// David Anders -// -// @History: -// derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by -// Ben Dooks - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "regs-gpio.h" -#include "gpio-samsung.h" - -#include -#include "devs.h" -#include "cpu.h" -#include "gpio-cfg.h" - -#include -#include -#include -#include - -#include "s3c24xx.h" - -static struct resource amlm5900_nor_resource = - DEFINE_RES_MEM(0x00000000, SZ_16M); - -static struct mtd_partition amlm5900_mtd_partitions[] = { - { - .name = "System", - .size = 0x240000, - .offset = 0, - .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { - .name = "Kernel", - .size = 0x100000, - .offset = MTDPART_OFS_APPEND, - }, { - .name = "Ramdisk", - .size = 0x300000, - .offset = MTDPART_OFS_APPEND, - }, { - .name = "JFFS2", - .size = 0x9A0000, - .offset = MTDPART_OFS_APPEND, - }, { - .name = "Settings", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; - -static struct physmap_flash_data amlm5900_flash_data = { - .width = 2, - .parts = amlm5900_mtd_partitions, - .nr_parts = ARRAY_SIZE(amlm5900_mtd_partitions), -}; - -static struct platform_device amlm5900_device_nor = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = &amlm5900_flash_data, - }, - .num_resources = 1, - .resource = &amlm5900_nor_resource, -}; - -static struct map_desc amlm5900_iodesc[] __initdata = { -}; - -#define UCON S3C2410_UCON_DEFAULT -#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB -#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE - -static struct s3c2410_uartcfg amlm5900_uartcfgs[] = { - [0] = { - .hwport = 0, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, - [1] = { - .hwport = 1, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, - [2] = { - .hwport = 2, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - } -}; - -static struct gpiod_lookup_table amlm5900_mmc_gpio_table = { - .dev_id = "s3c2410-sdi", - .table = { - /* bus pins */ - GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), - { }, - }, -}; - -static struct platform_device *amlm5900_devices[] __initdata = { -#ifdef CONFIG_FB_S3C2410 - &s3c_device_lcd, -#endif - &s3c_device_adc, - &s3c_device_wdt, - &s3c_device_i2c0, - &s3c_device_ohci, - &s3c_device_rtc, - &s3c_device_usbgadget, - &s3c_device_sdi, - &amlm5900_device_nor, -}; - -static void __init amlm5900_map_io(void) -{ - s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc)); - s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs)); - s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); -} - -static void __init amlm5900_init_time(void) -{ - s3c2410_init_clocks(12000000); - s3c24xx_timer_init(); -} - -#ifdef CONFIG_FB_S3C2410 -static struct s3c2410fb_display __initdata amlm5900_lcd_info = { - .width = 160, - .height = 160, - - .type = S3C2410_LCDCON1_STN4, - - .pixclock = 680000, /* HCLK = 100MHz */ - .xres = 160, - .yres = 160, - .bpp = 4, - .left_margin = 1 << (4 + 3), - .right_margin = 8 << 3, - .hsync_len = 48, - .upper_margin = 0, - .lower_margin = 0, - - .lcdcon5 = 0x00000001, -}; - -static struct s3c2410fb_mach_info __initdata amlm5900_fb_info = { - - .displays = &amlm5900_lcd_info, - .num_displays = 1, - .default_display = 0, - - .gpccon = 0xaaaaaaaa, - .gpccon_mask = 0xffffffff, - .gpccon_reg = S3C2410_GPCCON, - .gpcup = 0x0000ffff, - .gpcup_mask = 0xffffffff, - .gpcup_reg = S3C2410_GPCUP, - - .gpdcon = 0xaaaaaaaa, - .gpdcon_mask = 0xffffffff, - .gpdcon_reg = S3C2410_GPDCON, - .gpdup = 0x0000ffff, - .gpdup_mask = 0xffffffff, - .gpdup_reg = S3C2410_GPDUP, -}; -#endif - -static irqreturn_t -amlm5900_wake_interrupt(int irq, void *ignored) -{ - return IRQ_HANDLED; -} - -static void amlm5900_init_pm(void) -{ - int ret = 0; - - ret = request_irq(IRQ_EINT9, &amlm5900_wake_interrupt, - IRQF_TRIGGER_RISING | IRQF_SHARED, - "amlm5900_wakeup", &amlm5900_wake_interrupt); - if (ret != 0) { - printk(KERN_ERR "AML-M5900: no wakeup irq, %d?\n", ret); - } else { - enable_irq_wake(IRQ_EINT9); - /* configure the suspend/resume status pin */ - s3c_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT); - s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_UP); - } -} -static void __init amlm5900_init(void) -{ - amlm5900_init_pm(); -#ifdef CONFIG_FB_S3C2410 - s3c24xx_fb_set_platdata(&amlm5900_fb_info); -#endif - s3c_i2c0_set_platdata(NULL); - gpiod_add_lookup_table(&amlm5900_mmc_gpio_table); - platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices)); -} - -MACHINE_START(AML_M5900, "AML_M5900") - .atag_offset = 0x100, - .nr_irqs = NR_IRQS_S3C2410, - .map_io = amlm5900_map_io, - .nr_irqs = NR_IRQS_S3C2410, - .init_irq = s3c2410_init_irq, - .init_machine = amlm5900_init, - .init_time = amlm5900_init_time, -MACHINE_END diff --git a/arch/arm/mach-s3c/mach-anubis.c b/arch/arm/mach-s3c/mach-anubis.c deleted file mode 100644 index 4536f3e66e27..000000000000 --- a/arch/arm/mach-s3c/mach-anubis.c +++ /dev/null @@ -1,422 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright 2003-2009 Simtec Electronics -// http://armlinux.simtec.co.uk/ -// Ben Dooks - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "regs-gpio.h" -#include "gpio-samsung.h" -#include -#include - -#include -#include -#include -#include - -#include - -#include "devs.h" -#include "cpu.h" -#include - -#include "anubis.h" -#include "s3c24xx.h" -#include "simtec.h" - -#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics" - -static struct map_desc anubis_iodesc[] __initdata = { - /* ISA IO areas */ - - { - .virtual = (u32)S3C24XX_VA_ISA_BYTE, - .pfn = __phys_to_pfn(0x0), - .length = SZ_4M, - .type = MT_DEVICE, - }, - - /* we could possibly compress the next set down into a set of smaller tables - * pagetables, but that would mean using an L2 section, and it still means - * we cannot actually feed the same register to an LDR due to 16K spacing - */ - - /* CPLD control registers */ - - { - .virtual = (u32)ANUBIS_VA_CTRL1, - .pfn = __phys_to_pfn(ANUBIS_PA_CTRL1), - .length = SZ_4K, - .type = MT_DEVICE, - }, { - .virtual = (u32)ANUBIS_VA_IDREG, - .pfn = __phys_to_pfn(ANUBIS_PA_IDREG), - .length = SZ_4K, - .type = MT_DEVICE, - }, -}; - -#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK -#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB -#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE - -static struct s3c2410_uartcfg anubis_uartcfgs[] __initdata = { - [0] = { - .hwport = 0, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - .clk_sel = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, - }, - [1] = { - .hwport = 2, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - .clk_sel = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, - }, -}; - -/* NAND Flash on Anubis board */ - -static int external_map[] = { 2 }; -static int chip0_map[] = { 0 }; -static int chip1_map[] = { 1 }; - -static struct mtd_partition __initdata anubis_default_nand_part[] = { - [0] = { - .name = "Boot Agent", - .size = SZ_16K, - .offset = 0, - }, - [1] = { - .name = "/boot", - .size = SZ_4M - SZ_16K, - .offset = SZ_16K, - }, - [2] = { - .name = "user1", - .offset = SZ_4M, - .size = SZ_32M - SZ_4M, - }, - [3] = { - .name = "user2", - .offset = SZ_32M, - .size = MTDPART_SIZ_FULL, - } -}; - -static struct mtd_partition __initdata anubis_default_nand_part_large[] = { - [0] = { - .name = "Boot Agent", - .size = SZ_128K, - .offset = 0, - }, - [1] = { - .name = "/boot", - .size = SZ_4M - SZ_128K, - .offset = SZ_128K, - }, - [2] = { - .name = "user1", - .offset = SZ_4M, - .size = SZ_32M - SZ_4M, - }, - [3] = { - .name = "user2", - .offset = SZ_32M, - .size = MTDPART_SIZ_FULL, - } -}; - -/* the Anubis has 3 selectable slots for nand-flash, the two - * on-board chip areas, as well as the external slot. - * - * Note, there is no current hot-plug support for the External - * socket. -*/ - -static struct s3c2410_nand_set __initdata anubis_nand_sets[] = { - [1] = { - .name = "External", - .nr_chips = 1, - .nr_map = external_map, - .nr_partitions = ARRAY_SIZE(anubis_default_nand_part), - .partitions = anubis_default_nand_part, - }, - [0] = { - .name = "chip0", - .nr_chips = 1, - .nr_map = chip0_map, - .nr_partitions = ARRAY_SIZE(anubis_default_nand_part), - .partitions = anubis_default_nand_part, - }, - [2] = { - .name = "chip1", - .nr_chips = 1, - .nr_map = chip1_map, - .nr_partitions = ARRAY_SIZE(anubis_default_nand_part), - .partitions = anubis_default_nand_part, - }, -}; - -static void anubis_nand_select(struct s3c2410_nand_set *set, int slot) -{ - unsigned int tmp; - - slot = set->nr_map[slot] & 3; - - pr_debug("anubis_nand: selecting slot %d (set %p,%p)\n", - slot, set, set->nr_map); - - tmp = __raw_readb(ANUBIS_VA_CTRL1); - tmp &= ~ANUBIS_CTRL1_NANDSEL; - tmp |= slot; - - pr_debug("anubis_nand: ctrl1 now %02x\n", tmp); - - __raw_writeb(tmp, ANUBIS_VA_CTRL1); -} - -static struct s3c2410_platform_nand __initdata anubis_nand_info = { - .tacls = 25, - .twrph0 = 55, - .twrph1 = 40, - .nr_sets = ARRAY_SIZE(anubis_nand_sets), - .sets = anubis_nand_sets, - .select_chip = anubis_nand_select, - .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, -}; - -/* IDE channels */ - -static struct pata_platform_info anubis_ide_platdata = { - .ioport_shift = 5, -}; - -static struct resource anubis_ide0_resource[] = { - [0] = DEFINE_RES_MEM(S3C2410_CS3, 8 * 32), - [2] = DEFINE_RES_MEM(S3C2410_CS3 + (1 << 26) + (6 * 32), 32), - [3] = DEFINE_RES_IRQ(ANUBIS_IRQ_IDE0), -}; - -static struct platform_device anubis_device_ide0 = { - .name = "pata_platform", - .id = 0, - .num_resources = ARRAY_SIZE(anubis_ide0_resource), - .resource = anubis_ide0_resource, - .dev = { - .platform_data = &anubis_ide_platdata, - .coherent_dma_mask = ~0, - }, -}; - -static struct resource anubis_ide1_resource[] = { - [0] = DEFINE_RES_MEM(S3C2410_CS4, 8 * 32), - [1] = DEFINE_RES_MEM(S3C2410_CS4 + (1 << 26) + (6 * 32), 32), - [2] = DEFINE_RES_IRQ(ANUBIS_IRQ_IDE0), -}; - -static struct platform_device anubis_device_ide1 = { - .name = "pata_platform", - .id = 1, - .num_resources = ARRAY_SIZE(anubis_ide1_resource), - .resource = anubis_ide1_resource, - .dev = { - .platform_data = &anubis_ide_platdata, - .coherent_dma_mask = ~0, - }, -}; - -/* Asix AX88796 10/100 ethernet controller */ - -static struct ax_plat_data anubis_asix_platdata = { - .flags = AXFLG_MAC_FROMDEV, - .wordlength = 2, - .dcr_val = 0x48, - .rcr_val = 0x40, -}; - -static struct resource anubis_asix_resource[] = { - [0] = DEFINE_RES_MEM(S3C2410_CS5, 0x20 * 0x20), - [1] = DEFINE_RES_IRQ(ANUBIS_IRQ_ASIX), -}; - -static struct platform_device anubis_device_asix = { - .name = "ax88796", - .id = 0, - .num_resources = ARRAY_SIZE(anubis_asix_resource), - .resource = anubis_asix_resource, - .dev = { - .platform_data = &anubis_asix_platdata, - } -}; - -/* SM501 */ - -static struct resource anubis_sm501_resource[] = { - [0] = DEFINE_RES_MEM(S3C2410_CS2, SZ_8M), - [1] = DEFINE_RES_MEM(S3C2410_CS2 + SZ_64M - SZ_2M, SZ_2M), - [2] = DEFINE_RES_IRQ(IRQ_EINT0), -}; - -static struct sm501_initdata anubis_sm501_initdata = { - .gpio_high = { - .set = 0x3F000000, /* 24bit panel */ - .mask = 0x0, - }, - .misc_timing = { - .set = 0x010100, /* SDRAM timing */ - .mask = 0x1F1F00, - }, - .misc_control = { - .set = SM501_MISC_PNL_24BIT, - .mask = 0, - }, - - .devices = SM501_USE_GPIO, - - /* set the SDRAM and bus clocks */ - .mclk = 72 * MHZ, - .m1xclk = 144 * MHZ, -}; - -static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = { - [0] = { - .bus_num = 1, - .pin_scl = 44, - .pin_sda = 45, - }, - [1] = { - .bus_num = 2, - .pin_scl = 40, - .pin_sda = 41, - }, -}; - -static struct sm501_platdata anubis_sm501_platdata = { - .init = &anubis_sm501_initdata, - .gpio_base = -1, - .gpio_i2c = anubis_sm501_gpio_i2c, - .gpio_i2c_nr = ARRAY_SIZE(anubis_sm501_gpio_i2c), -}; - -static struct platform_device anubis_device_sm501 = { - .name = "sm501", - .id = 0, - .num_resources = ARRAY_SIZE(anubis_sm501_resource), - .resource = anubis_sm501_resource, - .dev = { - .platform_data = &anubis_sm501_platdata, - }, -}; - -/* Standard Anubis devices */ - -static struct platform_device *anubis_devices[] __initdata = { - &s3c2410_device_dclk, - &s3c_device_ohci, - &s3c_device_wdt, - &s3c_device_adc, - &s3c_device_i2c0, - &s3c_device_rtc, - &s3c_device_nand, - &anubis_device_ide0, - &anubis_device_ide1, - &anubis_device_asix, - &anubis_device_sm501, -}; - -/* I2C devices. */ - -static struct i2c_board_info anubis_i2c_devs[] __initdata = { - { - I2C_BOARD_INFO("tps65011", 0x48), - .irq = IRQ_EINT20, - } -}; - -/* Audio setup */ -static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = { - .have_mic = 1, - .have_lout = 1, - .output_cdclk = 1, - .use_mpllin = 1, - .amp_gpio = S3C2410_GPB(2), - .amp_gain[0] = S3C2410_GPD(10), - .amp_gain[1] = S3C2410_GPD(11), -}; - -static void __init anubis_map_io(void) -{ - s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc)); - s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs)); - s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); - - /* check for the newer revision boards with large page nand */ - - if ((__raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK) >= 4) { - printk(KERN_INFO "ANUBIS-B detected (revision %d)\n", - __raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK); - anubis_nand_sets[0].partitions = anubis_default_nand_part_large; - anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large); - } else { - /* ensure that the GPIO is setup */ - gpio_request_one(S3C2410_GPA(0), GPIOF_OUT_INIT_HIGH, NULL); - gpio_free(S3C2410_GPA(0)); - } -} - -static void __init anubis_init_time(void) -{ - s3c2440_init_clocks(12000000); - s3c24xx_timer_init(); -} - -static void __init anubis_init(void) -{ - s3c_i2c0_set_platdata(NULL); - s3c_nand_set_platdata(&anubis_nand_info); - simtec_audio_add(NULL, false, &anubis_audio); - - platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices)); - - i2c_register_board_info(0, anubis_i2c_devs, - ARRAY_SIZE(anubis_i2c_devs)); -} - - -MACHINE_START(ANUBIS, "Simtec-Anubis") - /* Maintainer: Ben Dooks */ - .atag_offset = 0x100, - .nr_irqs = NR_IRQS_S3C2440, - .map_io = anubis_map_io, - .init_machine = anubis_init, - .init_irq = s3c2440_init_irq, - .init_time = anubis_init_time, -MACHINE_END diff --git a/arch/arm/mach-s3c/mach-at2440evb.c b/arch/arm/mach-s3c/mach-at2440evb.c deleted file mode 100644 index 743403d873e0..000000000000 --- a/arch/arm/mach-s3c/mach-at2440evb.c +++ /dev/null @@ -1,233 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (c) 2008 Ramax Lo -// Based on mach-anubis.c by Ben Dooks -// and modifications by SBZ and -// Weibing -// -// For product information, visit http://www.arm.com/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "regs-gpio.h" -#include "gpio-samsung.h" -#include -#include - -#include -#include -#include -#include - -#include "devs.h" -#include "cpu.h" -#include - -#include "s3c24xx.h" - -static struct map_desc at2440evb_iodesc[] __initdata = { - /* Nothing here */ -}; - -#define UCON S3C2410_UCON_DEFAULT -#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE) -#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) - -static struct s3c2410_uartcfg at2440evb_uartcfgs[] __initdata = { - [0] = { - .hwport = 0, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - .clk_sel = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, - }, - [1] = { - .hwport = 1, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - .clk_sel = S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, - }, -}; - -/* NAND Flash on AT2440EVB board */ - -static struct mtd_partition __initdata at2440evb_default_nand_part[] = { - [0] = { - .name = "Boot Agent", - .size = SZ_256K, - .offset = 0, - }, - [1] = { - .name = "Kernel", - .size = SZ_2M, - .offset = SZ_256K, - }, - [2] = { - .name = "Root", - .offset = SZ_256K + SZ_2M, - .size = MTDPART_SIZ_FULL, - }, -}; - -static struct s3c2410_nand_set __initdata at2440evb_nand_sets[] = { - [0] = { - .name = "nand", - .nr_chips = 1, - .nr_partitions = ARRAY_SIZE(at2440evb_default_nand_part), - .partitions = at2440evb_default_nand_part, - }, -}; - -static struct s3c2410_platform_nand __initdata at2440evb_nand_info = { - .tacls = 25, - .twrph0 = 55, - .twrph1 = 40, - .nr_sets = ARRAY_SIZE(at2440evb_nand_sets), - .sets = at2440evb_nand_sets, - .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, -}; - -/* DM9000AEP 10/100 ethernet controller */ - -static struct resource at2440evb_dm9k_resource[] = { - [0] = DEFINE_RES_MEM(S3C2410_CS3, 4), - [1] = DEFINE_RES_MEM(S3C2410_CS3 + 4, 4), - [2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ \ - | IORESOURCE_IRQ_HIGHEDGE), -}; - -static struct dm9000_plat_data at2440evb_dm9k_pdata = { - .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), -}; - -static struct platform_device at2440evb_device_eth = { - .name = "dm9000", - .id = -1, - .num_resources = ARRAY_SIZE(at2440evb_dm9k_resource), - .resource = at2440evb_dm9k_resource, - .dev = { - .platform_data = &at2440evb_dm9k_pdata, - }, -}; - -static struct s3c24xx_mci_pdata at2440evb_mci_pdata __initdata = { - .set_power = s3c24xx_mci_def_set_power, -}; - -static struct gpiod_lookup_table at2440evb_mci_gpio_table = { - .dev_id = "s3c2410-sdi", - .table = { - /* Card detect S3C2410_GPG(10) */ - GPIO_LOOKUP("GPIOG", 10, "cd", GPIO_ACTIVE_LOW), - /* bus pins */ - GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), - { }, - }, -}; - - -/* 7" LCD panel */ - -static struct s3c2410fb_display at2440evb_lcd_cfg __initdata = { - - .lcdcon5 = S3C2410_LCDCON5_FRM565 | - S3C2410_LCDCON5_INVVLINE | - S3C2410_LCDCON5_INVVFRAME | - S3C2410_LCDCON5_PWREN | - S3C2410_LCDCON5_HWSWP, - - .type = S3C2410_LCDCON1_TFT, - - .width = 800, - .height = 480, - - .pixclock = 33333, /* HCLK 60 MHz, divisor 2 */ - .xres = 800, - .yres = 480, - .bpp = 16, - .left_margin = 88, - .right_margin = 40, - .hsync_len = 128, - .upper_margin = 32, - .lower_margin = 11, - .vsync_len = 2, -}; - -static struct s3c2410fb_mach_info at2440evb_fb_info __initdata = { - .displays = &at2440evb_lcd_cfg, - .num_displays = 1, - .default_display = 0, -}; - -static struct platform_device *at2440evb_devices[] __initdata = { - &s3c_device_ohci, - &s3c_device_wdt, - &s3c_device_adc, - &s3c_device_i2c0, - &s3c_device_rtc, - &s3c_device_nand, - &s3c_device_sdi, - &s3c_device_lcd, - &at2440evb_device_eth, -}; - -static void __init at2440evb_map_io(void) -{ - s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc)); - s3c24xx_init_uarts(at2440evb_uartcfgs, ARRAY_SIZE(at2440evb_uartcfgs)); - s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); -} - -static void __init at2440evb_init_time(void) -{ - s3c2440_init_clocks(16934400); - s3c24xx_timer_init(); -} - -static void __init at2440evb_init(void) -{ - s3c24xx_fb_set_platdata(&at2440evb_fb_info); - gpiod_add_lookup_table(&at2440evb_mci_gpio_table); - s3c24xx_mci_set_platdata(&at2440evb_mci_pdata); - s3c_nand_set_platdata(&at2440evb_nand_info); - s3c_i2c0_set_platdata(NULL); - - platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices)); -} - - -MACHINE_START(AT2440EVB, "AT2440EVB") - .atag_offset = 0x100, - .nr_irqs = NR_IRQS_S3C2440, - .map_io = at2440evb_map_io, - .init_machine = at2440evb_init, - .init_irq = s3c2440_init_irq, - .init_time = at2440evb_init_time, -MACHINE_END diff --git a/arch/arm/mach-s3c/mach-bast.c b/arch/arm/mach-s3c/mach-bast.c deleted file mode 100644 index a33ceab81e09..000000000000 --- a/arch/arm/mach-s3c/mach-bast.c +++ /dev/null @@ -1,583 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright 2003-2008 Simtec Electronics -// Ben Dooks -// -// http://www.simtec.co.uk/products/EB2410ITX/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include "regs-gpio.h" -#include "gpio-samsung.h" - -#include "cpu.h" -#include -#include "devs.h" -#include "gpio-cfg.h" - -#include "bast.h" -#include "s3c24xx.h" -#include "simtec.h" - -#define COPYRIGHT ", Copyright 2004-2008 Simtec Electronics" - -/* macros for virtual address mods for the io space entries */ -#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5) -#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4) -#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3) -#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2) - -/* macros to modify the physical addresses for io space */ - -#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2)) -#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3)) -#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4)) -#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5)) - -static struct map_desc bast_iodesc[] __initdata = { - /* ISA IO areas */ - { - .virtual = (u32)S3C24XX_VA_ISA_BYTE, - .pfn = PA_CS2(BAST_PA_ISAIO), - .length = SZ_16M, - .type = MT_DEVICE, - }, - /* bast CPLD control registers, and external interrupt controls */ - { - .virtual = (u32)BAST_VA_CTRL1, - .pfn = __phys_to_pfn(BAST_PA_CTRL1), - .length = SZ_1M, - .type = MT_DEVICE, - }, { - .virtual = (u32)BAST_VA_CTRL2, - .pfn = __phys_to_pfn(BAST_PA_CTRL2), - .length = SZ_1M, - .type = MT_DEVICE, - }, { - .virtual = (u32)BAST_VA_CTRL3, - .pfn = __phys_to_pfn(BAST_PA_CTRL3), - .length = SZ_1M, - .type = MT_DEVICE, - }, { - .virtual = (u32)BAST_VA_CTRL4, - .pfn = __phys_to_pfn(BAST_PA_CTRL4), - .length = SZ_1M, - .type = MT_DEVICE, - }, - /* PC104 IRQ mux */ - { - .virtual = (u32)BAST_VA_PC104_IRQREQ, - .pfn = __phys_to_pfn(BAST_PA_PC104_IRQREQ), - .length = SZ_1M, - .type = MT_DEVICE, - }, { - .virtual = (u32)BAST_VA_PC104_IRQRAW, - .pfn = __phys_to_pfn(BAST_PA_PC104_IRQRAW), - .length = SZ_1M, - .type = MT_DEVICE, - }, { - .virtual = (u32)BAST_VA_PC104_IRQMASK, - .pfn = __phys_to_pfn(BAST_PA_PC104_IRQMASK), - .length = SZ_1M, - .type = MT_DEVICE, - }, - - /* peripheral space... one for each of fast/slow/byte/16bit */ - /* note, ide is only decoded in word space, even though some registers - * are only 8bit */ - - /* slow, byte */ - { VA_C2(BAST_VA_ISAIO), PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - { VA_C2(BAST_VA_ISAMEM), PA_CS2(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE }, - { VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE }, - - /* slow, word */ - { VA_C3(BAST_VA_ISAIO), PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - { VA_C3(BAST_VA_ISAMEM), PA_CS3(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE }, - { VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE }, - - /* fast, byte */ - { VA_C4(BAST_VA_ISAIO), PA_CS4(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - { VA_C4(BAST_VA_ISAMEM), PA_CS4(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE }, - { VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE }, - - /* fast, word */ - { VA_C5(BAST_VA_ISAIO), PA_CS5(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - { VA_C5(BAST_VA_ISAMEM), PA_CS5(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE }, - { VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE }, -}; - -#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK -#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB -#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE - -static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = { - [0] = { - .hwport = 0, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, - [1] = { - .hwport = 1, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, - /* port 2 is not actually used */ - [2] = { - .hwport = 2, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - } -}; - -/* NAND Flash on BAST board */ - -#ifdef CONFIG_PM -static int bast_pm_suspend(void) -{ - /* ensure that an nRESET is not generated on resume. */ - gpio_direction_output(S3C2410_GPA(21), 1); - return 0; -} - -static void bast_pm_resume(void) -{ - s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT); -} - -#else -#define bast_pm_suspend NULL -#define bast_pm_resume NULL -#endif - -static struct syscore_ops bast_pm_syscore_ops = { - .suspend = bast_pm_suspend, - .resume = bast_pm_resume, -}; - -static int smartmedia_map[] = { 0 }; -static int chip0_map[] = { 1 }; -static int chip1_map[] = { 2 }; -static int chip2_map[] = { 3 }; - -static struct mtd_partition __initdata bast_default_nand_part[] = { - [0] = { - .name = "Boot Agent", - .size = SZ_16K, - .offset = 0, - }, - [1] = { - .name = "/boot", - .size = SZ_4M - SZ_16K, - .offset = SZ_16K, - }, - [2] = { - .name = "user", - .offset = SZ_4M, - .size = MTDPART_SIZ_FULL, - } -}; - -/* the bast has 4 selectable slots for nand-flash, the three - * on-board chip areas, as well as the external SmartMedia - * slot. - * - * Note, there is no current hot-plug support for the SmartMedia - * socket. -*/ - -static struct s3c2410_nand_set __initdata bast_nand_sets[] = { - [0] = { - .name = "SmartMedia", - .nr_chips = 1, - .nr_map = smartmedia_map, - .options = NAND_SCAN_SILENT_NODEV, - .nr_partitions = ARRAY_SIZE(bast_default_nand_part), - .partitions = bast_default_nand_part, - }, - [1] = { - .name = "chip0", - .nr_chips = 1, - .nr_map = chip0_map, - .nr_partitions = ARRAY_SIZE(bast_default_nand_part), - .partitions = bast_default_nand_part, - }, - [2] = { - .name = "chip1", - .nr_chips = 1, - .nr_map = chip1_map, - .options = NAND_SCAN_SILENT_NODEV, - .nr_partitions = ARRAY_SIZE(bast_default_nand_part), - .partitions = bast_default_nand_part, - }, - [3] = { - .name = "chip2", - .nr_chips = 1, - .nr_map = chip2_map, - .options = NAND_SCAN_SILENT_NODEV, - .nr_partitions = ARRAY_SIZE(bast_default_nand_part), - .partitions = bast_default_nand_part, - } -}; - -static void bast_nand_select(struct s3c2410_nand_set *set, int slot) -{ - unsigned int tmp; - - slot = set->nr_map[slot] & 3; - - pr_debug("bast_nand: selecting slot %d (set %p,%p)\n", - slot, set, set->nr_map); - - tmp = __raw_readb(BAST_VA_CTRL2); - tmp &= BAST_CPLD_CTLR2_IDERST; - tmp |= slot; - tmp |= BAST_CPLD_CTRL2_WNAND; - - pr_debug("bast_nand: ctrl2 now %02x\n", tmp); - - __raw_writeb(tmp, BAST_VA_CTRL2); -} - -static struct s3c2410_platform_nand __initdata bast_nand_info = { - .tacls = 30, - .twrph0 = 60, - .twrph1 = 60, - .nr_sets = ARRAY_SIZE(bast_nand_sets), - .sets = bast_nand_sets, - .select_chip = bast_nand_select, - .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, -}; - -/* DM9000 */ - -static struct resource bast_dm9k_resource[] = { - [0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000, 4), - [1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000 + 0x40, 0x40), - [2] = DEFINE_RES_NAMED(BAST_IRQ_DM9000 , 1, NULL, IORESOURCE_IRQ \ - | IORESOURCE_IRQ_HIGHLEVEL), -}; - -/* for the moment we limit ourselves to 16bit IO until some - * better IO routines can be written and tested -*/ - -static struct dm9000_plat_data bast_dm9k_platdata = { - .flags = DM9000_PLATF_16BITONLY, -}; - -static struct platform_device bast_device_dm9k = { - .name = "dm9000", - .id = 0, - .num_resources = ARRAY_SIZE(bast_dm9k_resource), - .resource = bast_dm9k_resource, - .dev = { - .platform_data = &bast_dm9k_platdata, - } -}; - -/* serial devices */ - -#define SERIAL_BASE (S3C2410_CS2 + BAST_PA_SUPERIO) -#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SHARE_IRQ) -#define SERIAL_CLK (1843200) - -static struct plat_serial8250_port bast_sio_data[] = { - [0] = { - .mapbase = SERIAL_BASE + 0x2f8, - .irq = BAST_IRQ_PCSERIAL1, - .flags = SERIAL_FLAGS, - .iotype = UPIO_MEM, - .regshift = 0, - .uartclk = SERIAL_CLK, - }, - [1] = { - .mapbase = SERIAL_BASE + 0x3f8, - .irq = BAST_IRQ_PCSERIAL2, - .flags = SERIAL_FLAGS, - .iotype = UPIO_MEM, - .regshift = 0, - .uartclk = SERIAL_CLK, - }, - { } -}; - -static struct platform_device bast_sio = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = &bast_sio_data, - }, -}; - -/* we have devices on the bus which cannot work much over the - * standard 100KHz i2c bus frequency -*/ - -static struct s3c2410_platform_i2c __initdata bast_i2c_info = { - .flags = 0, - .slave_addr = 0x10, - .frequency = 100*1000, -}; - -/* Asix AX88796 10/100 ethernet controller */ - -static struct ax_plat_data bast_asix_platdata = { - .flags = AXFLG_MAC_FROMDEV, - .wordlength = 2, - .dcr_val = 0x48, - .rcr_val = 0x40, -}; - -static struct resource bast_asix_resource[] = { - [0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET, 0x18 * 0x20), - [1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20), 1), - [2] = DEFINE_RES_IRQ(BAST_IRQ_ASIX), -}; - -static struct platform_device bast_device_asix = { - .name = "ax88796", - .id = 0, - .num_resources = ARRAY_SIZE(bast_asix_resource), - .resource = bast_asix_resource, - .dev = { - .platform_data = &bast_asix_platdata - } -}; - -/* Asix AX88796 10/100 ethernet controller parallel port */ - -static struct resource bast_asixpp_resource[] = { - [0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20), \ - 0x30 * 0x20), -}; - -static struct platform_device bast_device_axpp = { - .name = "ax88796-pp", - .id = 0, - .num_resources = ARRAY_SIZE(bast_asixpp_resource), - .resource = bast_asixpp_resource, -}; - -/* LCD/VGA controller */ - -static struct s3c2410fb_display __initdata bast_lcd_info[] = { - { - .type = S3C2410_LCDCON1_TFT, - .width = 640, - .height = 480, - - .pixclock = 33333, - .xres = 640, - .yres = 480, - .bpp = 4, - .left_margin = 40, - .right_margin = 20, - .hsync_len = 88, - .upper_margin = 30, - .lower_margin = 32, - .vsync_len = 3, - - .lcdcon5 = 0x00014b02, - }, - { - .type = S3C2410_LCDCON1_TFT, - .width = 640, - .height = 480, - - .pixclock = 33333, - .xres = 640, - .yres = 480, - .bpp = 8, - .left_margin = 40, - .right_margin = 20, - .hsync_len = 88, - .upper_margin = 30, - .lower_margin = 32, - .vsync_len = 3, - - .lcdcon5 = 0x00014b02, - }, - { - .type = S3C2410_LCDCON1_TFT, - .width = 640, - .height = 480, - - .pixclock = 33333, - .xres = 640, - .yres = 480, - .bpp = 16, - .left_margin = 40, - .right_margin = 20, - .hsync_len = 88, - .upper_margin = 30, - .lower_margin = 32, - .vsync_len = 3, - - .lcdcon5 = 0x00014b02, - }, -}; - -/* LCD/VGA controller */ - -static struct s3c2410fb_mach_info __initdata bast_fb_info = { - - .displays = bast_lcd_info, - .num_displays = ARRAY_SIZE(bast_lcd_info), - .default_display = 1, -}; - -/* I2C devices fitted. */ - -static struct i2c_board_info bast_i2c_devs[] __initdata = { - { - I2C_BOARD_INFO("tlv320aic23", 0x1a), - }, { - I2C_BOARD_INFO("simtec-pmu", 0x6b), - }, { - I2C_BOARD_INFO("ch7013", 0x75), - }, -}; - -static struct s3c_hwmon_pdata bast_hwmon_info = { - /* LCD contrast (0-6.6V) */ - .in[0] = &(struct s3c_hwmon_chcfg) { - .name = "lcd-contrast", - .mult = 3300, - .div = 512, - }, - /* LED current feedback */ - .in[1] = &(struct s3c_hwmon_chcfg) { - .name = "led-feedback", - .mult = 3300, - .div = 1024, - }, - /* LCD feedback (0-6.6V) */ - .in[2] = &(struct s3c_hwmon_chcfg) { - .name = "lcd-feedback", - .mult = 3300, - .div = 512, - }, - /* Vcore (1.8-2.0V), Vref 3.3V */ - .in[3] = &(struct s3c_hwmon_chcfg) { - .name = "vcore", - .mult = 3300, - .div = 1024, - }, -}; - -/* Standard BAST devices */ -// cat /sys/devices/platform/s3c24xx-adc/s3c-hwmon/in_0 - -static struct platform_device *bast_devices[] __initdata = { - &s3c2410_device_dclk, - &s3c_device_ohci, - &s3c_device_lcd, - &s3c_device_wdt, - &s3c_device_i2c0, - &s3c_device_rtc, - &s3c_device_nand, - &s3c_device_adc, - &s3c_device_hwmon, - &bast_device_dm9k, - &bast_device_asix, - &bast_device_axpp, - &bast_sio, -}; - -static struct s3c_cpufreq_board __initdata bast_cpufreq = { - .refresh = 7800, /* 7.8usec */ - .auto_io = 1, - .need_io = 1, -}; - -static struct s3c24xx_audio_simtec_pdata __initdata bast_audio = { - .have_mic = 1, - .have_lout = 1, -}; - -static void __init bast_map_io(void) -{ - s3c_hwmon_set_platdata(&bast_hwmon_info); - - s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); - s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs)); - s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); -} - -static void __init bast_init_time(void) -{ - s3c2410_init_clocks(12000000); - s3c24xx_timer_init(); -} - -static void __init bast_init(void) -{ - register_syscore_ops(&bast_pm_syscore_ops); - - s3c_i2c0_set_platdata(&bast_i2c_info); - s3c_nand_set_platdata(&bast_nand_info); - s3c24xx_fb_set_platdata(&bast_fb_info); - platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices)); - - i2c_register_board_info(0, bast_i2c_devs, - ARRAY_SIZE(bast_i2c_devs)); - - usb_simtec_init(); - nor_simtec_init(); - simtec_audio_add(NULL, true, &bast_audio); - - WARN_ON(gpio_request(S3C2410_GPA(21), "bast nreset")); - - s3c_cpufreq_setboard(&bast_cpufreq); -} - -MACHINE_START(BAST, "Simtec-BAST") - /* Maintainer: Ben Dooks */ - .atag_offset = 0x100, - .nr_irqs = NR_IRQS_S3C2410, - .map_io = bast_map_io, - .init_irq = s3c2410_init_irq, - .init_machine = bast_init, - .init_time = bast_init_time, -MACHINE_END diff --git a/arch/arm/mach-s3c/mach-gta02.c b/arch/arm/mach-s3c/mach-gta02.c deleted file mode 100644 index d50a81d85ae1..000000000000 --- a/arch/arm/mach-s3c/mach-gta02.c +++ /dev/null @@ -1,588 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// S3C2442 Machine Support for Openmoko GTA02 / FreeRunner. -// -// Copyright (C) 2006-2009 by Openmoko, Inc. -// Authors: Harald Welte -// Andy Green -// Werner Almesberger -// All rights reserved. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "regs-gpio.h" -#include "regs-irq.h" -#include "gpio-samsung.h" - -#include "cpu.h" -#include "devs.h" -#include "gpio-cfg.h" -#include "pm.h" - -#include "s3c24xx.h" -#include "gta02.h" - -static struct pcf50633 *gta02_pcf; - -/* - * This gets called frequently when we paniced. - */ - -static long gta02_panic_blink(int state) -{ - char led; - - led = (state) ? 1 : 0; - gpio_direction_output(GTA02_GPIO_AUX_LED, led); - - return 0; -} - - -static struct map_desc gta02_iodesc[] __initdata = { - { - .virtual = 0xe0000000, - .pfn = __phys_to_pfn(S3C2410_CS3 + 0x01000000), - .length = SZ_1M, - .type = MT_DEVICE - }, -}; - -#define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN) -#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) -#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) - -static struct s3c2410_uartcfg gta02_uartcfgs[] = { - [0] = { - .hwport = 0, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, - [1] = { - .hwport = 1, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, - [2] = { - .hwport = 2, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, -}; - -#ifdef CONFIG_CHARGER_PCF50633 -/* - * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin. - * We use this to recognize that we can pull 1A from the USB socket. - * - * These constants are the measured pcf50633 ADC levels with the 1A - * charger / 48K resistor, and with no pulldown resistor. - */ - -#define ADC_NOM_CHG_DETECT_1A 6 -#define ADC_NOM_CHG_DETECT_USB 43 - -#ifdef CONFIG_PCF50633_ADC -static void -gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res) -{ - int ma; - - /* Interpret charger type */ - if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) { - - /* - * Sanity - stop GPO driving out now that we have a 1A charger - * GPO controls USB Host power generation on GTA02 - */ - pcf50633_gpio_set(pcf, PCF50633_GPO, 0); - - ma = 1000; - } else - ma = 100; - - pcf50633_mbc_usb_curlim_set(pcf, ma); -} -#endif - -static struct delayed_work gta02_charger_work; -static int gta02_usb_vbus_draw; - -static void gta02_charger_worker(struct work_struct *work) -{ - if (gta02_usb_vbus_draw) { - pcf50633_mbc_usb_curlim_set(gta02_pcf, gta02_usb_vbus_draw); - return; - } - -#ifdef CONFIG_PCF50633_ADC - pcf50633_adc_async_read(gta02_pcf, - PCF50633_ADCC1_MUX_ADCIN1, - PCF50633_ADCC1_AVERAGE_16, - gta02_configure_pmu_for_charger, - NULL); -#else - /* - * If the PCF50633 ADC is disabled we fallback to a - * 100mA limit for safety. - */ - pcf50633_mbc_usb_curlim_set(gta02_pcf, 100); -#endif -} - -#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000) - -static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq) -{ - if (irq == PCF50633_IRQ_USBINS) { - schedule_delayed_work(>a02_charger_work, - GTA02_CHARGER_CONFIGURE_TIMEOUT); - - return; - } - - if (irq == PCF50633_IRQ_USBREM) { - cancel_delayed_work_sync(>a02_charger_work); - gta02_usb_vbus_draw = 0; - } -} - -static void gta02_udc_vbus_draw(unsigned int ma) -{ - if (!gta02_pcf) - return; - - gta02_usb_vbus_draw = ma; - - schedule_delayed_work(>a02_charger_work, - GTA02_CHARGER_CONFIGURE_TIMEOUT); -} -#else /* !CONFIG_CHARGER_PCF50633 */ -#define gta02_pmu_event_callback NULL -#define gta02_udc_vbus_draw NULL -#endif - -static char *gta02_batteries[] = { - "battery", -}; - -static struct pcf50633_bl_platform_data gta02_backlight_data = { - .default_brightness = 0x3f, - .default_brightness_limit = 0, - .ramp_time = 5, -}; - -static struct pcf50633_platform_data gta02_pcf_pdata = { - .resumers = { - [0] = PCF50633_INT1_USBINS | - PCF50633_INT1_USBREM | - PCF50633_INT1_ALARM, - [1] = PCF50633_INT2_ONKEYF, - [2] = PCF50633_INT3_ONKEY1S, - [3] = PCF50633_INT4_LOWSYS | - PCF50633_INT4_LOWBAT | - PCF50633_INT4_HIGHTMP, - }, - - .batteries = gta02_batteries, - .num_batteries = ARRAY_SIZE(gta02_batteries), - - .charger_reference_current_ma = 1000, - - .backlight_data = >a02_backlight_data, - - .reg_init_data = { - [PCF50633_REGULATOR_AUTO] = { - .constraints = { - .min_uV = 3300000, - .max_uV = 3300000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .always_on = 1, - .apply_uV = 1, - }, - }, - [PCF50633_REGULATOR_DOWN1] = { - .constraints = { - .min_uV = 1300000, - .max_uV = 1600000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .always_on = 1, - .apply_uV = 1, - }, - }, - [PCF50633_REGULATOR_DOWN2] = { - .constraints = { - .min_uV = 1800000, - .max_uV = 1800000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .apply_uV = 1, - .always_on = 1, - }, - }, - [PCF50633_REGULATOR_HCLDO] = { - .constraints = { - .min_uV = 2000000, - .max_uV = 3300000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | - REGULATOR_CHANGE_STATUS, - }, - }, - [PCF50633_REGULATOR_LDO1] = { - .constraints = { - .min_uV = 3300000, - .max_uV = 3300000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - .apply_uV = 1, - }, - }, - [PCF50633_REGULATOR_LDO2] = { - .constraints = { - .min_uV = 3300000, - .max_uV = 3300000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .apply_uV = 1, - }, - }, - [PCF50633_REGULATOR_LDO3] = { - .constraints = { - .min_uV = 3000000, - .max_uV = 3000000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .apply_uV = 1, - }, - }, - [PCF50633_REGULATOR_LDO4] = { - .constraints = { - .min_uV = 3200000, - .max_uV = 3200000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - .apply_uV = 1, - }, - }, - [PCF50633_REGULATOR_LDO5] = { - .constraints = { - .min_uV = 3000000, - .max_uV = 3000000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - .valid_ops_mask = REGULATOR_CHANGE_STATUS, - .apply_uV = 1, - }, - }, - [PCF50633_REGULATOR_LDO6] = { - .constraints = { - .min_uV = 3000000, - .max_uV = 3000000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - }, - }, - [PCF50633_REGULATOR_MEMLDO] = { - .constraints = { - .min_uV = 1800000, - .max_uV = 1800000, - .valid_modes_mask = REGULATOR_MODE_NORMAL, - }, - }, - - }, - .mbc_event_callback = gta02_pmu_event_callback, -}; - - -/* NOR Flash. */ - -#define GTA02_FLASH_BASE 0x18000000 /* GCS3 */ -#define GTA02_FLASH_SIZE 0x200000 /* 2MBytes */ - -static struct physmap_flash_data gta02_nor_flash_data = { - .width = 2, -}; - -static struct resource gta02_nor_flash_resource = - DEFINE_RES_MEM(GTA02_FLASH_BASE, GTA02_FLASH_SIZE); - -static struct platform_device gta02_nor_flash = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = >a02_nor_flash_data, - }, - .resource = >a02_nor_flash_resource, - .num_resources = 1, -}; - - -static struct platform_device s3c24xx_pwm_device = { - .name = "s3c24xx_pwm", - .num_resources = 0, -}; - -static struct platform_device gta02_dfbmcs320_device = { - .name = "dfbmcs320", -}; - -static struct i2c_board_info gta02_i2c_devs[] __initdata = { - { - I2C_BOARD_INFO("pcf50633", 0x73), - .irq = GTA02_IRQ_PCF50633, - .platform_data = >a02_pcf_pdata, - }, - { - I2C_BOARD_INFO("wm8753", 0x1a), - }, -}; - -static struct s3c2410_nand_set __initdata gta02_nand_sets[] = { - [0] = { - /* - * This name is also hard-coded in the boot loaders, so - * changing it would would require all users to upgrade - * their boot loaders, some of which are stored in a NOR - * that is considered to be immutable. - */ - .name = "neo1973-nand", - .nr_chips = 1, - .flash_bbt = 1, - }, -}; - -/* - * Choose a set of timings derived from S3C@2442B MCP54 - * data sheet (K5D2G13ACM-D075 MCP Memory). - */ - -static struct s3c2410_platform_nand __initdata gta02_nand_info = { - .tacls = 0, - .twrph0 = 25, - .twrph1 = 15, - .nr_sets = ARRAY_SIZE(gta02_nand_sets), - .sets = gta02_nand_sets, - .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, -}; - - -/* Get PMU to set USB current limit accordingly. */ -static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = { - .vbus_draw = gta02_udc_vbus_draw, -}; - -static struct gpiod_lookup_table gta02_udc_gpio_table = { - .dev_id = "s3c2410-usbgadget", - .table = { - GPIO_LOOKUP("GPIOB", 9, "pullup", GPIO_ACTIVE_HIGH), - { }, - }, -}; - -/* USB */ -static struct s3c2410_hcd_info gta02_usb_info __initdata = { - .port[0] = { - .flags = S3C_HCDFLG_USED, - }, - .port[1] = { - .flags = 0, - }, -}; - -/* Touchscreen */ -static struct s3c2410_ts_mach_info gta02_ts_info = { - .delay = 10000, - .presc = 0xff, /* slow as we can go */ - .oversampling_shift = 2, -}; - -/* Buttons */ -static struct gpio_keys_button gta02_buttons[] = { - { - .gpio = GTA02_GPIO_AUX_KEY, - .code = KEY_PHONE, - .desc = "Aux", - .type = EV_KEY, - .debounce_interval = 100, - }, - { - .gpio = GTA02_GPIO_HOLD_KEY, - .code = KEY_PAUSE, - .desc = "Hold", - .type = EV_KEY, - .debounce_interval = 100, - }, -}; - -static struct gpio_keys_platform_data gta02_buttons_pdata = { - .buttons = gta02_buttons, - .nbuttons = ARRAY_SIZE(gta02_buttons), -}; - -static struct platform_device gta02_buttons_device = { - .name = "gpio-keys", - .id = -1, - .dev = { - .platform_data = >a02_buttons_pdata, - }, -}; - -static struct gpiod_lookup_table gta02_audio_gpio_table = { - .dev_id = "neo1973-audio", - .table = { - GPIO_LOOKUP("GPIOJ", 2, "amp-shut", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("GPIOJ", 1, "hp", GPIO_ACTIVE_HIGH), - { }, - }, -}; - -static struct platform_device gta02_audio = { - .name = "neo1973-audio", - .id = -1, -}; - -static struct gpiod_lookup_table gta02_mmc_gpio_table = { - .dev_id = "s3c2410-sdi", - .table = { - /* bus pins */ - GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), - { }, - }, -}; - -static void __init gta02_map_io(void) -{ - s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc)); - s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs)); - s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); -} - - -/* These are the guys that don't need to be children of PMU. */ - -static struct platform_device *gta02_devices[] __initdata = { - &s3c_device_ohci, - &s3c_device_wdt, - &s3c_device_sdi, - &s3c_device_usbgadget, - &s3c_device_nand, - >a02_nor_flash, - &s3c24xx_pwm_device, - &s3c_device_iis, - &s3c_device_i2c0, - >a02_dfbmcs320_device, - >a02_buttons_device, - &s3c_device_adc, - &s3c_device_ts, - >a02_audio, -}; - -static void gta02_poweroff(void) -{ - pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1); -} - -static void __init gta02_machine_init(void) -{ - /* Set the panic callback to turn AUX LED on or off. */ - panic_blink = gta02_panic_blink; - - s3c_pm_init(); - -#ifdef CONFIG_CHARGER_PCF50633 - INIT_DELAYED_WORK(>a02_charger_work, gta02_charger_worker); -#endif - - s3c24xx_udc_set_platdata(>a02_udc_cfg); - s3c24xx_ts_set_platdata(>a02_ts_info); - s3c_ohci_set_platdata(>a02_usb_info); - s3c_nand_set_platdata(>a02_nand_info); - s3c_i2c0_set_platdata(NULL); - - i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs)); - - /* Configure the I2S pins (GPE0...GPE4) in correct mode */ - s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), - S3C_GPIO_PULL_NONE); - - gpiod_add_lookup_table(>a02_udc_gpio_table); - gpiod_add_lookup_table(>a02_audio_gpio_table); - gpiod_add_lookup_table(>a02_mmc_gpio_table); - platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices)); - pm_power_off = gta02_poweroff; - - regulator_has_full_constraints(); -} - -static void __init gta02_init_time(void) -{ - s3c2442_init_clocks(12000000); - s3c24xx_timer_init(); -} - -MACHINE_START(NEO1973_GTA02, "GTA02") - /* Maintainer: Nelson Castillo */ - .atag_offset = 0x100, - .nr_irqs = NR_IRQS_S3C2442, - .map_io = gta02_map_io, - .init_irq = s3c2442_init_irq, - .init_machine = gta02_machine_init, - .init_time = gta02_init_time, -MACHINE_END diff --git a/arch/arm/mach-s3c/mach-h1940.c b/arch/arm/mach-s3c/mach-h1940.c deleted file mode 100644 index 83ac6cfdb1d8..000000000000 --- a/arch/arm/mach-s3c/mach-h1940.c +++ /dev/null @@ -1,809 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Copyright (c) 2003-2005 Simtec Electronics -// Ben Dooks -// -// https://www.handhelds.org/projects/h1940.html - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include