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