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