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