Commit | Line | Data |
---|---|---|
4993a92b MD |
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 | ||
efb850f9 | 7 | * Keep all the SVN IDs in the files as a future reference point. dports' SVN |
45fa0bf8 | 8 | will do that by default. When using the FreeBSD git repo, please note the |
efb850f9 SW |
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. | |
e732300c | 11 | |
4993a92b MD |
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 | ||
07d0d38c SW |
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() | |
d2da76f2 | 26 | random() -> krandom() |
07d0d38c | 27 | |
4993a92b | 28 | * MUTEX conversion - mutexes are generally replaced by spinlocks. However, |
72e64973 | 29 | DragonFly spinlocks are more restrictive than FreeBSD mutexes so a |
4993a92b MD |
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 | ||
72e64973 SW |
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 | |
60e7fae5 | 60 | lockinit(&my_lock, "mylock", 0, LK_CANRECURSE); |
72e64973 SW |
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(&my_lock, LK_EXCLUSIVE|LK_NOWAIT); | |
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. | |
4b3fb495 FT |
99 | |
100 | * rwlock conversion: Use lockmgr locks | |
72e64973 | 101 | |
07d0d38c SW |
102 | * UMA conversion - generally speaking UMA should be converted to a standard |
103 | kmalloc. | |
4993a92b MD |
104 | |
105 | Note however that in FreeBSD M_NOWAIT is often used in cases where, in fact, | |
07d0d38c | 106 | the kmalloc cannot fail without blowing something up or causing a fatal |
4993a92b MD |
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 | ||
d2da76f2 SW |
123 | * MSLEEP/TSLEEP conversion. The DragonFly msleep/tsleep do not have 'PRI' |
124 | priorities. 0 should be used. | |
4993a92b | 125 | |
4993a92b MD |
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. | |
60e7fae5 | 130 | This can either be left NULL or you can convert the spinlock(s) for |
4993a92b MD |
131 | the driver into serializer locks and integrate the interrupt service |
132 | routine with a serializer. | |
d2da76f2 SW |
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. | |
317f6748 FT |
137 | |
138 | * callout_drain() should be replaced by callout_stop_sync() | |
de612e47 FT |
139 | |
140 | * UNRHDR functions - DragonFly uses a more generic idr(9) subsystem | |
141 | compatible with the Linux API of the same name | |
142 | ||
143 | This LWN article describes it in details: http://lwn.net/Articles/103209/ | |
144 | ||
145 | A typical conversion looks like this: | |
146 | ||
147 | #include <sys/idr.h> | |
148 | ||
149 | free_unr() has to be replaced by idr_remove() | |
150 | ||
151 | alloc_unr() has to be replaced by a code sequence using idr_pre_get and | |
152 | idr_get_new such as this one: | |
153 | ||
154 | retry: | |
155 | if (idr_pre_get(xxx) ==0) { | |
156 | kprintf("Memory allocation error\n"); | |
157 | return error; | |
158 | } | |
159 | spin_lock(xxx); | |
160 | ret = idr_get_new(xxx); | |
161 | spin_unlock(xxx); | |
162 | if (ret == EAGAIN) | |
163 | goto retry; | |
164 | ||
4dd401bd | 165 | * MPASS macro - Replace it with KKASSERT |
2764c241 | 166 | |
cf396422 FT |
167 | |
168 | * PROC_LOCK / PROC_UNLOCK: to be determined on a case-by-case basis | |
169 | ||
170 | Some of the time these macros can be removed entirely | |
171 | ||
172 | In some cases, some locking must be done; lwkt_gettoken(&proc_token) | |
173 | and the corresponding lwkt_reltoken() call should be good replacements | |
174 | ||
175 | It is not a good idea to blindly implement these macros globally, some | |
176 | particular proc subsystem locking semantics differ enough between FreeBSD | |
177 | and DragonFly that this would cause problems | |
178 | ||
179 | ||
2764c241 AHJ |
180 | * In DragonFly 3.3 format specifier %D was removed from kprintf. As a |
181 | replacement functions kether_ntoa() and hexncpy() were added. | |
182 | ||
183 | - Ethernet address (MAC) to its hexadecimal form: | |
184 | ||
185 | char ethstr[ETHER_ADDRSTRLEN + 1]; | |
186 | u_char hwaddr[6]; | |
187 | ||
188 | kprintf("MAC address %s\n", kether_ntoa(hwaddr, ethstr) | |
189 | ||
190 | - Generic conversion (block of bytes to hexadecimal form): | |
191 | ||
192 | char hexstr[18]; | |
193 | u_char mydata[6] = {1, 2, 3, 4, 5 ,6}; | |
194 | ||
195 | /* | |
196 | * Below statement would print: | |
197 | * | |
198 | * 01-02-03-04-05-06 | |
199 | */ | |
200 | kprintf("%s\n", hexncpy(mydata, 6, hexstr, HEX_NCPYLEN(6), "-")); | |
4b3fb495 FT |
201 | |
202 | * TAILQ_XXX_SAFE | |
203 | ||
204 | Use TAILQ_XXX_MUTABLE; the macros have the same effect, only the name is | |
205 | different | |
206 | ||
207 | * kern_yield() | |
208 | ||
209 | Replace by lwkt_yield() | |
210 | ||
211 | * vm_page_lock() and vm_page_unlock() | |
212 | ||
213 | Not needed on DragonFly, remove these calls | |
214 | ||
215 | * vm_pager_get_pages() | |
216 | ||
217 | Removed, use vm_pager_get_page() instead | |
218 | ||
219 | * VPO_BUSY | |
220 | ||
221 | Replace by PG_BUSY | |
222 | ||
223 | * kern_psignal() | |
224 | ||
225 | Replace by ksignal() |