1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2/*
3 * Copyright (C) 2005-2011, 2021-2022 Intel Corporation
4 */
5#include <linux/device.h>
6#include <linux/interrupt.h>
7#include <linux/export.h>
8#if defined(CONFIG_IWLWIFI_DEBUG)
9#include <linux/net.h>
10#endif
11#include "iwl-drv.h"
12#include "iwl-debug.h"
13#if defined(__FreeBSD__)
14#include "iwl-modparams.h"
15#endif
16#include "iwl-devtrace.h"
17
18#if defined(__FreeBSD__)
19#if defined(CONFIG_IWLWIFI_DEBUG)
20#include <sys/systm.h>		/* hexdump(9) */
21#include <linux/preempt.h>
22#endif
23#endif
24
25#if defined(__linux__)
26#define __iwl_fn(fn)						\
27void __iwl_ ##fn(struct device *dev, const char *fmt, ...)	\
28{								\
29	struct va_format vaf = {				\
30		.fmt = fmt,					\
31	};							\
32	va_list args;						\
33								\
34	va_start(args, fmt);					\
35	vaf.va = &args;						\
36	dev_ ##fn(dev, "%pV", &vaf);				\
37	trace_iwlwifi_ ##fn(&vaf);				\
38	va_end(args);						\
39}
40#elif defined(__FreeBSD__)
41#define __iwl_fn(fn)						\
42void __iwl_ ##fn(struct device *dev, const char *fmt, ...)	\
43{								\
44	struct va_format vaf = {				\
45		.fmt = fmt,					\
46	};							\
47	va_list args;						\
48	char *str;						\
49								\
50	va_start(args, fmt);					\
51	vaf.va = &args;						\
52	vasprintf(&str, M_KMALLOC, vaf.fmt, args);		\
53	dev_ ##fn(dev, "%s", str);				\
54	trace_iwlwifi_ ##fn(&vaf);				\
55	free(str, M_KMALLOC);					\
56	va_end(args);						\
57}
58#endif
59
60__iwl_fn(warn)
61IWL_EXPORT_SYMBOL(__iwl_warn);
62__iwl_fn(info)
63IWL_EXPORT_SYMBOL(__iwl_info);
64__iwl_fn(crit)
65IWL_EXPORT_SYMBOL(__iwl_crit);
66
67void __iwl_err(struct device *dev, enum iwl_err_mode mode, const char *fmt, ...)
68{
69	struct va_format vaf = {
70		.fmt = fmt,
71	};
72	va_list args, args2;
73
74	va_start(args, fmt);
75	switch (mode) {
76	case IWL_ERR_MODE_RATELIMIT:
77		if (net_ratelimit())
78			break;
79		fallthrough;
80	case IWL_ERR_MODE_REGULAR:
81	case IWL_ERR_MODE_RFKILL:
82		va_copy(args2, args);
83		vaf.va = &args2;
84#if defined(__linux_)
85		if (mode == IWL_ERR_MODE_RFKILL)
86			dev_err(dev, "(RFKILL) %pV", &vaf);
87		else
88			dev_err(dev, "%pV", &vaf);
89#elif defined(__FreeBSD__)
90		char *str;
91		vasprintf(&str, M_KMALLOC, vaf.fmt, args2);
92		dev_err(dev, "%s%s", (mode == IWL_ERR_MODE_RFKILL) ? "(RFKILL)" : "", str);
93		free(str, M_KMALLOC);
94#endif
95		va_end(args2);
96		break;
97	default:
98		break;
99	}
100	vaf.va = &args;
101	trace_iwlwifi_err(&vaf);
102	va_end(args);
103}
104IWL_EXPORT_SYMBOL(__iwl_err);
105
106#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
107
108#ifdef CONFIG_IWLWIFI_DEBUG
109bool
110iwl_have_debug_level(enum iwl_dl level)
111{
112
113	return (iwlwifi_mod_params.debug_level & level || level == IWL_DL_ANY);
114}
115
116/* Passing the iwl_drv * in seems pointless. */
117void
118iwl_print_hex_dump(void *drv __unused, enum iwl_dl level,
119#if defined(__linux__)
120    const char *prefix, uint8_t *data, size_t len)
121#elif defined(__FreeBSD__)
122    const char *prefix, const uint8_t *data, size_t len)
123#endif
124{
125
126	/* Given we have a level, check for it. */
127	if (!iwl_have_debug_level(level))
128		return;
129
130#if defined(__linux_)
131	/* XXX I am cluseless in my editor. pcie/trans.c to the rescue. */
132	print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
133	    32, 4, data, len, 0);
134#elif defined(__FreeBSD__)
135	hexdump(data, len, prefix, 0);
136#endif
137}
138#endif
139
140void __iwl_dbg(struct device *dev,
141	       u32 level, bool limit, const char *function,
142	       const char *fmt, ...)
143{
144	struct va_format vaf = {
145		.fmt = fmt,
146	};
147	va_list args;
148
149	va_start(args, fmt);
150	vaf.va = &args;
151#ifdef CONFIG_IWLWIFI_DEBUG
152	if (iwl_have_debug_level(level) &&
153	    (!limit || net_ratelimit())) {
154#if defined(__linux_)
155		dev_printk(KERN_DEBUG, dev, "%s %pV", function, &vaf);
156#elif defined(__FreeBSD__)
157		char *str;
158		vasprintf(&str, M_KMALLOC, vaf.fmt, args);
159		dev_printk(KERN_DEBUG, dev, "%d %u %s %s",
160		    curthread->td_tid, (unsigned int)ticks, function, str);
161		free(str, M_KMALLOC);
162#endif
163	}
164
165#endif
166	trace_iwlwifi_dbg(level, function, &vaf);
167	va_end(args);
168}
169IWL_EXPORT_SYMBOL(__iwl_dbg);
170#endif
171