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* UMA conversion - generally speaking UMA should be converted to a standard 107 kmalloc. 108 109 Note however that in FreeBSD M_NOWAIT is often used in cases where, in fact, 110 the kmalloc cannot fail without blowing something up or causing a fatal 111 (and very unexpected) I/O error. M_INTWAIT should be used for these cases. 112 113* CDEVSW conversion - see other devices. Generally speaking a major number 114 is needed and a function map needs to be specified more explicitly. 115 116 Most calls passing struct cdev pointers are dev_t's in DragonFly. 117 118 All device vectors in DragonFly pass a dev_<name>_args structure pointer 119 instead of explicit arguments. 120 121 Strategy calls - we pass BIO's and a lot of BUF fields are in the BIO 122 in FreeBSD, but left in the BUF in DragonFly. FreeBSD for some reason 123 names its struct bio pointers 'bp', its a good idea to rename them to 'bio' 124 to avoid confusion and have a struct buf *bp = bio->bio_buf; pointer to 125 access the buf. 126 127* MSLEEP/TSLEEP conversion. The DragonFly msleep/tsleep do not have 'PRI' 128 priorities. 0 should be used. 129 130* BUS_* FUNCTIONS 131 132 bus_setup_intr() - replace INTR_TYPE_* flags with 0. There is an extra 133 argument for an interrupt interlock using the sys/serializer.h interface. 134 This can either be left NULL or you can convert the spinlock(s) for 135 the driver into serializer locks and integrate the interrupt service 136 routine with a serializer. 137 138* CAM CODE - cam_simq* code refcounts, so shared device queues (raid and 139 multi-channel devices) are not freed before all references have gone 140 away. 141 142* callout_drain() should be replaced by callout_stop_sync() 143 144* UNRHDR functions - DragonFly uses a more generic idr(9) subsystem 145 compatible with the Linux API of the same name 146 147 This LWN article describes it in details: http://lwn.net/Articles/103209/ 148 149 A typical conversion looks like this: 150 151 #include <sys/idr.h> 152 153 free_unr() has to be replaced by idr_remove() 154 155 alloc_unr() has to be replaced by a code sequence using idr_pre_get and 156 idr_get_new such as this one: 157 158 retry: 159 if (idr_pre_get(xxx) ==0) { 160 kprintf("Memory allocation error\n"); 161 return error; 162 } 163 spin_lock(xxx); 164 ret = idr_get_new(xxx); 165 spin_unlock(xxx); 166 if (ret == EAGAIN) 167 goto retry; 168 169* MPASS macro - Replace it with KKASSERT 170 171* In DragonFly 3.3 format specifier %D was removed from kprintf. As a 172 replacement functions kether_ntoa() and hexncpy() were added. 173 174 - Ethernet address (MAC) to its hexadecimal form: 175 176 char ethstr[ETHER_ADDRSTRLEN + 1]; 177 u_char hwaddr[6]; 178 179 kprintf("MAC address %s\n", kether_ntoa(hwaddr, ethstr) 180 181 - Generic conversion (block of bytes to hexadecimal form): 182 183 char hexstr[18]; 184 u_char mydata[6] = {1, 2, 3, 4, 5 ,6}; 185 186 /* 187 * Below statement would print: 188 * 189 * 01-02-03-04-05-06 190 */ 191 kprintf("%s\n", hexncpy(mydata, 6, hexstr, HEX_NCPYLEN(6), "-")); 192