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() 228