xref: /dragonfly/doc/porting_drivers.txt (revision ac392440)
1		    PORTING FREEBSD DRIVERS TO DRAGONFLY
2
3* Copy the driver code to the appropriate DragonFly directory.  For example,
4  a disk driver /usr/src/sys/dev/blah in FreeBSD would likely be
5  /usr/src/sys/dev/disk/blah in DragonFly.
6
7* Keep all the SVN IDs in the files as a future reference point. dports' SVN
8  will do that by default. When using the FreeBSD git repo, please note the
9  files' IDs manually, either in the files themselves or in the commit message.
10  The general idea is that it must not get lost.
11
12* Driver local #include's probably use a <dev/blah/blah.h> path.  These
13  need to be changed to "blah.h".   '.' is not included in the #include
14  path in FreeBSD builds, but it is in DragonFly builds.
15
16* Other #include's may reference things in <dev/...> which in DragonFly
17  reside in <bus/...>.  In particular, dev/pccard becomes bus/pccard.
18  Note that defines in FreeBSD's pccard_cis.h reside in DragonFly's
19  pccardreg.h .
20
21* The following kernel functions have been renamed in DragonFly:
22
23  malloc(), free() etc.	->	kmalloc(), kfree() etc.
24  printf() etc.		->	kprintf() etc.
25  psignal()		->	ksignal()
26  random()		->	krandom()
27
28* MUTEX conversion - mutexes are generally replaced by spinlocks.  However,
29  DragonFly spinlocks are more restrictive than FreeBSD mutexes so a
30  direct replacement is not necessarily appropriate in all cases.  A lockmgr
31  lock should be used when a direct replacement is not appropriate.
32  In particular, DragonFly does not allow recursive exclusive spinlocks
33  and does not allow multiple exclusive spinlocks to be held by any given
34  thread.
35
36  Instances of <sys/mutex.h> should be replaced with <sys/spinlock.h>.
37
38  When replacing mutexes with spinlocks it is a good idea to rename
39  the structural field (typically 'mtx') to something else (typically 'spin').
40
41  The &Giant mutex is typically converted to get_mplock() and rel_mplock().
42  However, there are places where FreeBSD unlocks giant around some code and
43  then relocks giant... those should simply be removed.
44
45  FreeBSD has weird callout + mutex functions.  DragonFly does not integrate
46  the two.  Instead, the driver in DragonFly must obtain the spinlocks
47  in question in the callback routine.
48
49  As a rule of thumb, MTX_DEF mutexes should be replaced with exclusive,
50  recursive lockmgr locks.
51
52  So, suppose the original code is using
53	struct mtx my_mtx;
54  you'd normally rename it to
55	struct lock my_lock;
56
57  and change the initialization from something like
58	mtx_init(&my_mtx, "mymtx", "whatever", MTX_DEF);
59  to
60	lockinit(&my_lock, "mylock", 0, LK_CANRECURSE);
61
62  Destroying it is trivial,
63	mtx_destroy(&my_mtx);
64  becomes
65	lockuninit(&my_lock);
66
67  You use the same function for locking and unlocking a lockmgr lock,
68  so exchange
69	mtx_lock(&my_mtx);
70  with
71	lockmgr(&my_lock, LK_EXCLUSIVE);
72  and
73	mtx_unlock(&my_mtx);
74  with
75	lockmgr(&my_lock, LK_RELEASE);
76
77  For testing the lock status, one would use
78	lockstatus(&my_lock, curthread);
79  in place of
80	mtx_owned(&my_mtx);
81
82  An
83	mtx_trylock(&my_mtx);
84  call is replaced with
85	lockmgr_try(&my_lock, LK_EXCLUSIVE);
86
87  As for mtx_assert() calls, translate them like this:
88
89	mtx_assert(&my_mtx, MA_OWNED) -> KKASSERT(lockstatus(&my_lock, curthread) != 0)
90	mtx_assert(&my_mtx, MA_NOTOWNED) -> KKASSERT(lockstatus(&my_lock, curthread) == 0)
91
92  In DragonFly, lockstatus() does not return information about whether there have been
93  recursive lock acquisitions, so there is no generic way to emulate the
94
95	mtx_assert(&my_mtx, MA_OWNED|MA_RECURSED);
96	mtx_assert(&my_mtx, MA_OWNED|MA_NOTRECURSED);
97
98  calls.
99
100* rwlock conversion: Use lockmgr locks
101
102* UMA conversion - generally speaking UMA should be converted to a standard
103  kmalloc.
104
105  Note however that in FreeBSD M_NOWAIT is often used in cases where, in fact,
106  the kmalloc cannot fail without blowing something up or causing a fatal
107  (and very unexpected) I/O error.  M_INTWAIT should be used for these cases.
108
109* CDEVSW conversion - see other devices.  Generally speaking a major number
110  is needed and a function map needs to be specified more explicitly.
111
112  Most calls passing struct cdev pointers are dev_t's in DragonFly.
113
114  All device vectors in DragonFly pass a dev_<name>_args structure pointer
115  instead of explicit arguments.
116
117  Strategy calls - we pass BIO's and a lot of BUF fields are in the BIO
118  in FreeBSD, but left in the BUF in DragonFly.  FreeBSD for some reason
119  names its struct bio pointers 'bp', its a good idea to rename them to 'bio'
120  to avoid confusion and have a struct buf *bp = bio->bio_buf; pointer to
121  access the buf.
122
123* MSLEEP/TSLEEP conversion.  The DragonFly msleep/tsleep do not have 'PRI'
124  priorities.  0 should be used.
125
126* BUS_* FUNCTIONS
127
128  bus_setup_intr() - replace INTR_TYPE_* flags with 0.  There is an extra
129  argument for an interrupt interlock using the sys/serializer.h interface.
130  This can either be left NULL or you can convert the spinlock(s) for
131  the driver into serializer locks and integrate the interrupt service
132  routine with a serializer.
133
134* CAM CODE - cam_simq* code refcounts, so shared device queues (raid and
135  multi-channel devices) are not freed before all references have gone
136  away.
137
138* UNRHDR functions - DragonFly uses a more generic idr(9) subsystem
139  compatible with the Linux API of the same name
140
141  This LWN article describes it in details: http://lwn.net/Articles/103209/
142
143  A typical conversion looks like this:
144
145  #include <sys/idr.h>
146
147  free_unr() has to be replaced by idr_remove()
148
149  alloc_unr() has to be replaced by a code sequence using idr_pre_get and
150  idr_get_new such as this one:
151
152  retry:
153	if (idr_pre_get(xxx) ==0) {
154	kprintf("Memory allocation error\n");
155	    return error;
156	}
157	spin_lock(xxx);
158	ret = idr_get_new(xxx);
159	spin_unlock(xxx);
160	if (ret == EAGAIN)
161	    goto retry;
162
163* MPASS macro - Replace it with KKASSERT
164
165
166* PROC_LOCK / PROC_UNLOCK: to be determined on a case-by-case basis
167
168  Some of the time these macros can be removed entirely
169
170  In some cases, some locking must be done; lwkt_gettoken(&proc_token)
171  and the corresponding lwkt_reltoken() call should be good replacements
172
173  It is not a good idea to blindly implement these macros globally, some
174  particular proc subsystem locking semantics differ enough between FreeBSD
175  and DragonFly that this would cause problems
176
177* In DragonFly 5.1 format specifier %b was replaced by args safe "%pb%i" version
178  that only needs argument swapping. Replacement functions where not added.
179
180	kvcprintf("reg=%pb%i\n", "\10\2BITTWO\1BITONE\n", 3);
181
182* In DragonFly 5.1 format specifier %r was removed from kprintf. As a
183  replacement function makedev_unit_b32() was added.
184
185  - Unit suffix encoded as base32 for make_dev() device creation:
186
187	char tbuf[MAKEDEV_MINNBUF];
188
189	kbd->kb_dev = make_dev(&kbd_ops, kbd->kb_index,
190				UID_ROOT, GID_WHEEL, 0600, "kbd%s",
191				makedev_unit_b32(tbuf, kbd->kb_index));
192
193  - For single character case the hex2ascii() can be used to avoid buffers:
194
195	kprintf("%c\n", hex2ascii(n % base));
196
197* In DragonFly 3.3 format specifier %D was removed from kprintf. As a
198  replacement functions kether_ntoa() and hexncpy() were added.
199
200  - Ethernet address (MAC) to its hexadecimal form:
201
202	char ethstr[ETHER_ADDRSTRLEN + 1];
203	u_char hwaddr[6];
204
205	kprintf("MAC address %s\n", kether_ntoa(hwaddr, ethstr)
206
207  - Generic conversion (block of bytes to hexadecimal form):
208
209	char hexstr[18];
210	u_char mydata[6] = {1, 2, 3, 4, 5 ,6};
211
212	/*
213	 * Below statement would print:
214	 *
215	 * 01-02-03-04-05-06
216	 */
217	kprintf("%s\n", hexncpy(mydata, 6, hexstr, HEX_NCPYLEN(6), "-"));
218
219* TAILQ_XXX_SAFE
220
221  Use TAILQ_XXX_MUTABLE; the macros have the same effect, only the name is
222  different
223
224* kern_yield()
225
226  Replace by lwkt_yield()
227
228* vm_page_lock() and vm_page_unlock()
229
230  Not needed on DragonFly, remove these calls
231
232* vm_pager_get_pages()
233
234  Removed, use vm_pager_get_page() instead
235
236* VPO_BUSY
237
238  Replace by PG_BUSY
239
240* kern_psignal()
241
242  Replace by ksignal()
243