| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: xmm7360.c,v 1.15 2022/02/12 15:51:29 thorpej Exp $ */ | | 1 | /* $NetBSD: xmm7360.c,v 1.16 2022/02/12 16:21:27 thorpej Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Device driver for Intel XMM7360 LTE modems, eg. Fibocom L850-GL. | | 4 | * Device driver for Intel XMM7360 LTE modems, eg. Fibocom L850-GL. |
5 | * Written by James Wah | | 5 | * Written by James Wah |
6 | * james@laird-wah.net | | 6 | * james@laird-wah.net |
7 | * | | 7 | * |
8 | * Development of this driver was supported by genua GmbH | | 8 | * Development of this driver was supported by genua GmbH |
9 | * | | 9 | * |
10 | * Copyright (c) 2020 genua GmbH <info@genua.de> | | 10 | * Copyright (c) 2020 genua GmbH <info@genua.de> |
11 | * Copyright (c) 2020 James Wah <james@laird-wah.net> | | 11 | * Copyright (c) 2020 James Wah <james@laird-wah.net> |
12 | * | | 12 | * |
13 | * The OpenBSD and NetBSD support was written by Jaromir Dolecek for | | 13 | * The OpenBSD and NetBSD support was written by Jaromir Dolecek for |
14 | * Moritz Systems Technology Company Sp. z o.o. | | 14 | * Moritz Systems Technology Company Sp. z o.o. |
| @@ -65,27 +65,27 @@ MODULE_DEVICE_TABLE(pci, xmm7360_ids); | | | @@ -65,27 +65,27 @@ MODULE_DEVICE_TABLE(pci, xmm7360_ids); |
65 | | | 65 | |
66 | #endif | | 66 | #endif |
67 | | | 67 | |
68 | #if defined(__OpenBSD__) || defined(__NetBSD__) | | 68 | #if defined(__OpenBSD__) || defined(__NetBSD__) |
69 | | | 69 | |
70 | #ifdef __OpenBSD__ | | 70 | #ifdef __OpenBSD__ |
71 | #include "bpfilter.h" | | 71 | #include "bpfilter.h" |
72 | #endif | | 72 | #endif |
73 | #ifdef __NetBSD__ | | 73 | #ifdef __NetBSD__ |
74 | #include "opt_inet.h" | | 74 | #include "opt_inet.h" |
75 | #include "opt_gateway.h" | | 75 | #include "opt_gateway.h" |
76 | | | 76 | |
77 | #include <sys/cdefs.h> | | 77 | #include <sys/cdefs.h> |
78 | __KERNEL_RCSID(0, "$NetBSD: xmm7360.c,v 1.15 2022/02/12 15:51:29 thorpej Exp $"); | | 78 | __KERNEL_RCSID(0, "$NetBSD: xmm7360.c,v 1.16 2022/02/12 16:21:27 thorpej Exp $"); |
79 | #endif | | 79 | #endif |
80 | | | 80 | |
81 | #include <sys/param.h> | | 81 | #include <sys/param.h> |
82 | #include <sys/systm.h> | | 82 | #include <sys/systm.h> |
83 | #include <sys/sockio.h> | | 83 | #include <sys/sockio.h> |
84 | #include <sys/mbuf.h> | | 84 | #include <sys/mbuf.h> |
85 | #include <sys/kernel.h> | | 85 | #include <sys/kernel.h> |
86 | #include <sys/device.h> | | 86 | #include <sys/device.h> |
87 | #include <sys/socket.h> | | 87 | #include <sys/socket.h> |
88 | #include <sys/mutex.h> | | 88 | #include <sys/mutex.h> |
89 | #include <sys/tty.h> | | 89 | #include <sys/tty.h> |
90 | #include <sys/conf.h> | | 90 | #include <sys/conf.h> |
91 | #include <sys/kthread.h> | | 91 | #include <sys/kthread.h> |
| @@ -193,26 +193,31 @@ typedef struct mutex spinlock_t; | | | @@ -193,26 +193,31 @@ typedef struct mutex spinlock_t; |
193 | #define __UNVOLATILE(a) ((void *)(unsigned long)(volatile void *)(a)) | | 193 | #define __UNVOLATILE(a) ((void *)(unsigned long)(volatile void *)(a)) |
194 | | | 194 | |
195 | #if OpenBSD <= 201911 | | 195 | #if OpenBSD <= 201911 |
196 | /* Backward compat with OpenBSD 6.6 */ | | 196 | /* Backward compat with OpenBSD 6.6 */ |
197 | #define klist_insert(klist, kn) \ | | 197 | #define klist_insert(klist, kn) \ |
198 | SLIST_INSERT_HEAD(klist, kn, kn_selnext) | | 198 | SLIST_INSERT_HEAD(klist, kn, kn_selnext) |
199 | #define klist_remove(klist, kn) \ | | 199 | #define klist_remove(klist, kn) \ |
200 | SLIST_REMOVE(klist, kn, knote, kn_selnext) | | 200 | SLIST_REMOVE(klist, kn, knote, kn_selnext) |
201 | #define XMM_KQ_ISFD_INITIALIZER .f_isfd = 1 | | 201 | #define XMM_KQ_ISFD_INITIALIZER .f_isfd = 1 |
202 | #else | | 202 | #else |
203 | #define XMM_KQ_ISFD_INITIALIZER .f_flags = FILTEROP_ISFD | | 203 | #define XMM_KQ_ISFD_INITIALIZER .f_flags = FILTEROP_ISFD |
204 | #endif /* OpenBSD <= 201911 */ | | 204 | #endif /* OpenBSD <= 201911 */ |
205 | | | 205 | |
| | | 206 | #define selrecord_knote(si, kn) \ |
| | | 207 | klist_insert(&(si)->si_note, (kn)) |
| | | 208 | #define selremove_knote(si, kn) \ |
| | | 209 | klist_remove(&(si)->si_note, (kn)) |
| | | 210 | |
206 | #endif | | 211 | #endif |
207 | | | 212 | |
208 | #ifdef __NetBSD__ | | 213 | #ifdef __NetBSD__ |
209 | typedef struct kmutex spinlock_t; | | 214 | typedef struct kmutex spinlock_t; |
210 | #define dev_err aprint_error_dev | | 215 | #define dev_err aprint_error_dev |
211 | #define dev_info aprint_normal_dev | | 216 | #define dev_info aprint_normal_dev |
212 | #define mutex kmutex | | 217 | #define mutex kmutex |
213 | #define kzalloc(size, flags) malloc(size, M_DEVBUF, M_WAITOK | M_ZERO) | | 218 | #define kzalloc(size, flags) malloc(size, M_DEVBUF, M_WAITOK | M_ZERO) |
214 | #define kfree(addr) free(addr, M_DEVBUF) | | 219 | #define kfree(addr) free(addr, M_DEVBUF) |
215 | #define mutex_init(lock) mutex_init(lock, MUTEX_DEFAULT, IPL_TTY) | | 220 | #define mutex_init(lock) mutex_init(lock, MUTEX_DEFAULT, IPL_TTY) |
216 | #define mutex_lock(lock) mutex_enter(lock) | | 221 | #define mutex_lock(lock) mutex_enter(lock) |
217 | #define mutex_unlock(lock) mutex_exit(lock) | | 222 | #define mutex_unlock(lock) mutex_exit(lock) |
218 | #define spin_lock_irqsave(lock, flags) mutex_enter(lock) | | 223 | #define spin_lock_irqsave(lock, flags) mutex_enter(lock) |
| @@ -247,27 +252,26 @@ typedef struct kmutex spinlock_t; | | | @@ -247,27 +252,26 @@ typedef struct kmutex spinlock_t; |
247 | m0; \ | | 252 | m0; \ |
248 | }) | | 253 | }) |
249 | #define ifq_deq_rollback(ifq, m) m_freem(m) | | 254 | #define ifq_deq_rollback(ifq, m) m_freem(m) |
250 | #define ifq_deq_commit(ifq, m) /* nothing to do */ | | 255 | #define ifq_deq_commit(ifq, m) /* nothing to do */ |
251 | #define ifq_is_oactive(ifq) true /* always restart queue */ | | 256 | #define ifq_is_oactive(ifq) true /* always restart queue */ |
252 | #define ifq_clr_oactive(ifq) /* nothing to do */ | | 257 | #define ifq_clr_oactive(ifq) /* nothing to do */ |
253 | #define ifq_empty(ifq) IFQ_IS_EMPTY(ifq) | | 258 | #define ifq_empty(ifq) IFQ_IS_EMPTY(ifq) |
254 | #define ifq_purge(ifq) IF_PURGE(ifq) | | 259 | #define ifq_purge(ifq) IF_PURGE(ifq) |
255 | #define if_enqueue(ifp, m) ifq_enqueue(ifp, m) | | 260 | #define if_enqueue(ifp, m) ifq_enqueue(ifp, m) |
256 | #define if_ih_insert(ifp, func, arg) (ifp)->_if_input = (func) | | 261 | #define if_ih_insert(ifp, func, arg) (ifp)->_if_input = (func) |
257 | #define if_ih_remove(ifp, func, arg) /* nothing to do */ | | 262 | #define if_ih_remove(ifp, func, arg) /* nothing to do */ |
258 | #define if_hardmtu if_mtu | | 263 | #define if_hardmtu if_mtu |
259 | #define IF_OUTPUT_CONST const | | 264 | #define IF_OUTPUT_CONST const |
260 | #define si_note sel_klist | | | |
261 | #define XMM_KQ_ISFD_INITIALIZER .f_flags = FILTEROP_ISFD | | 265 | #define XMM_KQ_ISFD_INITIALIZER .f_flags = FILTEROP_ISFD |
262 | #define tty_lock() mutex_spin_enter(&tty_lock) | | 266 | #define tty_lock() mutex_spin_enter(&tty_lock) |
263 | #define tty_unlock() mutex_spin_exit(&tty_lock) | | 267 | #define tty_unlock() mutex_spin_exit(&tty_lock) |
264 | #define tty_locked() KASSERT(mutex_owned(&tty_lock)) | | 268 | #define tty_locked() KASSERT(mutex_owned(&tty_lock)) |
265 | #define bpfattach(bpf, ifp, dlt, sz) bpf_attach(ifp, dlt, sz) | | 269 | #define bpfattach(bpf, ifp, dlt, sz) bpf_attach(ifp, dlt, sz) |
266 | #define NBPFILTER 1 | | 270 | #define NBPFILTER 1 |
267 | #define BPF_MTAP_OUT(ifp, m) bpf_mtap(ifp, m, BPF_D_OUT) | | 271 | #define BPF_MTAP_OUT(ifp, m) bpf_mtap(ifp, m, BPF_D_OUT) |
268 | #endif /* __NetBSD__ */ | | 272 | #endif /* __NetBSD__ */ |
269 | | | 273 | |
270 | #define __user /* nothing */ | | 274 | #define __user /* nothing */ |
271 | #define copy_from_user(kbuf, userbuf, sz) \ | | 275 | #define copy_from_user(kbuf, userbuf, sz) \ |
272 | ({ \ | | 276 | ({ \ |
273 | int __ret = 0; \ | | 277 | int __ret = 0; \ |
| @@ -2740,54 +2744,54 @@ out: | | | @@ -2740,54 +2744,54 @@ out: |
2740 | if (events & (POLLOUT | POLLWRNORM)) | | 2744 | if (events & (POLLOUT | POLLWRNORM)) |
2741 | selrecord(p, &sc->sc_selw); | | 2745 | selrecord(p, &sc->sc_selw); |
2742 | } | | 2746 | } |
2743 | | | 2747 | |
2744 | return mask & events; | | 2748 | return mask & events; |
2745 | } | | 2749 | } |
2746 | | | 2750 | |
2747 | static void | | 2751 | static void |
2748 | filt_wwancrdetach(struct knote *kn) | | 2752 | filt_wwancrdetach(struct knote *kn) |
2749 | { | | 2753 | { |
2750 | struct queue_pair *qp = (struct queue_pair *)kn->kn_hook; | | 2754 | struct queue_pair *qp = (struct queue_pair *)kn->kn_hook; |
2751 | | | 2755 | |
2752 | tty_lock(); | | 2756 | tty_lock(); |
2753 | klist_remove(&qp->selr.si_note, kn); | | 2757 | selremove_knote(&qp->selr, kn); |
2754 | tty_unlock(); | | 2758 | tty_unlock(); |
2755 | } | | 2759 | } |
2756 | | | 2760 | |
2757 | static int | | 2761 | static int |
2758 | filt_wwancread(struct knote *kn, long hint) | | 2762 | filt_wwancread(struct knote *kn, long hint) |
2759 | { | | 2763 | { |
2760 | struct queue_pair *qp = (struct queue_pair *)kn->kn_hook; | | 2764 | struct queue_pair *qp = (struct queue_pair *)kn->kn_hook; |
2761 | | | 2765 | |
2762 | kn->kn_data = 0; | | 2766 | kn->kn_data = 0; |
2763 | | | 2767 | |
2764 | if (!qp->open) { | | 2768 | if (!qp->open) { |
2765 | knote_set_eof(kn, 0); | | 2769 | knote_set_eof(kn, 0); |
2766 | return (1); | | 2770 | return (1); |
2767 | } else { | | 2771 | } else { |
2768 | kn->kn_data = xmm7360_qp_has_data(qp) ? 1 : 0; | | 2772 | kn->kn_data = xmm7360_qp_has_data(qp) ? 1 : 0; |
2769 | } | | 2773 | } |
2770 | | | 2774 | |
2771 | return (kn->kn_data > 0); | | 2775 | return (kn->kn_data > 0); |
2772 | } | | 2776 | } |
2773 | | | 2777 | |
2774 | static void | | 2778 | static void |
2775 | filt_wwancwdetach(struct knote *kn) | | 2779 | filt_wwancwdetach(struct knote *kn) |
2776 | { | | 2780 | { |
2777 | struct queue_pair *qp = (struct queue_pair *)kn->kn_hook; | | 2781 | struct queue_pair *qp = (struct queue_pair *)kn->kn_hook; |
2778 | | | 2782 | |
2779 | tty_lock(); | | 2783 | tty_lock(); |
2780 | klist_remove(&qp->selw.si_note, kn); | | 2784 | selremove_knote(&qp->selw, kn); |
2781 | tty_unlock(); | | 2785 | tty_unlock(); |
2782 | } | | 2786 | } |
2783 | | | 2787 | |
2784 | static int | | 2788 | static int |
2785 | filt_wwancwrite(struct knote *kn, long hint) | | 2789 | filt_wwancwrite(struct knote *kn, long hint) |
2786 | { | | 2790 | { |
2787 | struct queue_pair *qp = (struct queue_pair *)kn->kn_hook; | | 2791 | struct queue_pair *qp = (struct queue_pair *)kn->kn_hook; |
2788 | | | 2792 | |
2789 | kn->kn_data = 0; | | 2793 | kn->kn_data = 0; |
2790 | | | 2794 | |
2791 | if (qp->open) { | | 2795 | if (qp->open) { |
2792 | if (xmm7360_qp_can_write(qp)) | | 2796 | if (xmm7360_qp_can_write(qp)) |
2793 | kn->kn_data = qp->page_size; | | 2797 | kn->kn_data = qp->page_size; |
| @@ -2806,50 +2810,50 @@ static const struct filterops wwancread_ | | | @@ -2806,50 +2810,50 @@ static const struct filterops wwancread_ |
2806 | static const struct filterops wwancwrite_filtops = { | | 2810 | static const struct filterops wwancwrite_filtops = { |
2807 | XMM_KQ_ISFD_INITIALIZER, | | 2811 | XMM_KQ_ISFD_INITIALIZER, |
2808 | .f_attach = NULL, | | 2812 | .f_attach = NULL, |
2809 | .f_detach = filt_wwancwdetach, | | 2813 | .f_detach = filt_wwancwdetach, |
2810 | .f_event = filt_wwancwrite, | | 2814 | .f_event = filt_wwancwrite, |
2811 | }; | | 2815 | }; |
2812 | | | 2816 | |
2813 | int | | 2817 | int |
2814 | wwanckqfilter(dev_t dev, struct knote *kn) | | 2818 | wwanckqfilter(dev_t dev, struct knote *kn) |
2815 | { | | 2819 | { |
2816 | struct wwanc_softc *sc = device_lookup_private(&wwanc_cd, DEVUNIT(dev)); | | 2820 | struct wwanc_softc *sc = device_lookup_private(&wwanc_cd, DEVUNIT(dev)); |
2817 | int func = DEVFUNC(dev); | | 2821 | int func = DEVFUNC(dev); |
2818 | struct queue_pair *qp = &sc->sc_xmm.qp[func]; | | 2822 | struct queue_pair *qp = &sc->sc_xmm.qp[func]; |
2819 | struct klist *klist; | | 2823 | struct selinfo *si; |
2820 | | | 2824 | |
2821 | if (DEV_IS_TTY(func)) | | 2825 | if (DEV_IS_TTY(func)) |
2822 | return ttkqfilter(dev, kn); | | 2826 | return ttkqfilter(dev, kn); |
2823 | | | 2827 | |
2824 | KASSERT(!DEV_IS_TTY(func)); | | 2828 | KASSERT(!DEV_IS_TTY(func)); |
2825 | | | 2829 | |
2826 | switch (kn->kn_filter) { | | 2830 | switch (kn->kn_filter) { |
2827 | case EVFILT_READ: | | 2831 | case EVFILT_READ: |
2828 | klist = &qp->selr.si_note; | | 2832 | si = &qp->selr; |
2829 | kn->kn_fop = &wwancread_filtops; | | 2833 | kn->kn_fop = &wwancread_filtops; |
2830 | break; | | 2834 | break; |
2831 | case EVFILT_WRITE: | | 2835 | case EVFILT_WRITE: |
2832 | klist = &qp->selw.si_note; | | 2836 | si = &qp->selw; |
2833 | kn->kn_fop = &wwancwrite_filtops; | | 2837 | kn->kn_fop = &wwancwrite_filtops; |
2834 | break; | | 2838 | break; |
2835 | default: | | 2839 | default: |
2836 | return (EINVAL); | | 2840 | return (EINVAL); |
2837 | } | | 2841 | } |
2838 | | | 2842 | |
2839 | kn->kn_hook = (void *)qp; | | 2843 | kn->kn_hook = (void *)qp; |
2840 | | | 2844 | |
2841 | tty_lock(); | | 2845 | tty_lock(); |
2842 | klist_insert(klist, kn); | | 2846 | selrecord_knote(si, kn); |
2843 | tty_unlock(); | | 2847 | tty_unlock(); |
2844 | | | 2848 | |
2845 | return (0); | | 2849 | return (0); |
2846 | } | | 2850 | } |
2847 | | | 2851 | |
2848 | static void * | | 2852 | static void * |
2849 | dma_alloc_coherent(struct device *self, size_t sz, dma_addr_t *physp, int flags) | | 2853 | dma_alloc_coherent(struct device *self, size_t sz, dma_addr_t *physp, int flags) |
2850 | { | | 2854 | { |
2851 | struct wwanc_softc *sc = device_private(self); | | 2855 | struct wwanc_softc *sc = device_private(self); |
2852 | bus_dma_segment_t seg; | | 2856 | bus_dma_segment_t seg; |
2853 | int nsegs; | | 2857 | int nsegs; |
2854 | int error; | | 2858 | int error; |
2855 | caddr_t kva; | | 2859 | caddr_t kva; |