$DragonFly: doc/notes/porting_drivers.txt,v 1.4 2008/04/06 19:08:30 pavalos Exp $ PORTING FREEBSD DRIVERS TO DRAGONFLY * Copy the driver code to the appropriate DragonFly directory. For example, a disk driver /usr/src/sys/dev/blah in FreeBSD would likely be /usr/src/sys/dev/disk/blah in DragonFly. * Keep all the CVS ids in the files for future reference point. If the files don't have it, please add it to them. You can find them out from CVSWeb repository or by checking out the specific source files with the FreeBSD SVN client. This could be automated in the case pkgsrc's SVN client had the set of patches that provide this functionality. * Remove FBSDID declaration and '#include ' as well. * Driver local #include's probably use a path. These need to be changed to "blah.h". '.' is not included in the #include path in FreeBSD builds, but it is in DragonFly builds. * Other #include's may reference things in which in DragonFly reside in . In particular, dev/pccard becomes bus/pccard. Note that defines in FreeBSD's pccard_cis.h reside in DragonFly's pccardreg.h . * The following kernel functions have been renamed in DragonFly: malloc(), free() etc. -> kmalloc(), kfree() etc. printf() etc. -> kprintf() etc. psignal() -> ksignal() random() -> krandom() * MUTEX conversion - mutexes are generally replaced by spinlocks. However, DragonFly spinlocks are more restrictive than FreeBSD mutexes so a direct replacement is not necessarily appropriate in all cases. A lockmgr lock should be used when a direct replacement is not appropriate. In particular, DragonFly does not allow recursive exclusive spinlocks and does not allow multiple exclusive spinlocks to be held by any given thread. Instances of should be replaced with . When replacing mutexes with spinlocks it is a good idea to rename the structural field (typically 'mtx') to something else (typically 'spin'). The &Giant mutex is typically converted to get_mplock() and rel_mplock(). However, there are places where FreeBSD unlocks giant around some code and then relocks giant... those should simply be removed. FreeBSD has weird callout + mutex functions. DragonFly does not integrate the two. Instead, the driver in DragonFly must obtain the spinlocks in question in the callback routine. As a rule of thumb, MTX_DEF mutexes should be replaced with exclusive, recursive lockmgr locks. So, suppose the original code is using struct mtx my_mtx; you'd normally rename it to struct lock my_lock; and change the initialization from something like mtx_init(&my_mtx, "mymtx", "whatever", MTX_DEF); to lockinit(&my_lock, "mylock", 0, LK_CANRECURSE); Destroying it is trivial, mtx_destroy(&my_mtx); becomes lockuninit(&my_lock); You use the same function for locking and unlocking a lockmgr lock, so exchange mtx_lock(&my_mtx); with lockmgr(&my_lock, LK_EXCLUSIVE); and mtx_unlock(&my_mtx); with lockmgr(&my_lock, LK_RELEASE); For testing the lock status, one would use lockstatus(&my_lock, curthread); in place of mtx_owned(&my_mtx); An mtx_trylock(&my_mtx); call is replaced with lockmgr(&my_lock, LK_EXCLUSIVE|LK_NOWAIT); As for mtx_assert() calls, translate them like this: mtx_assert(&my_mtx, MA_OWNED) -> KKASSERT(lockstatus(&my_lock, curthread) != 0) mtx_assert(&my_mtx, MA_NOTOWNED) -> KKASSERT(lockstatus(&my_lock, curthread) == 0) In DragonFly, lockstatus() does not return information about whether there have been recursive lock acquisitions, so there is no generic way to emulate the mtx_assert(&my_mtx, MA_OWNED|MA_RECURSED); mtx_assert(&my_mtx, MA_OWNED|MA_NOTRECURSED); calls. * UMA conversion - generally speaking UMA should be converted to a standard kmalloc. Note however that in FreeBSD M_NOWAIT is often used in cases where, in fact, the kmalloc cannot fail without blowing something up or causing a fatal (and very unexpected) I/O error. M_INTWAIT should be used for these cases. * CDEVSW conversion - see other devices. Generally speaking a major number is needed and a function map needs to be specified more explicitly. Most calls passing struct cdev pointers are dev_t's in DragonFly. All device vectors in DragonFly pass a dev__args structure pointer instead of explicit arguments. Strategy calls - we pass BIO's and a lot of BUF fields are in the BIO in FreeBSD, but left in the BUF in DragonFly. FreeBSD for some reason names its struct bio pointers 'bp', its a good idea to rename them to 'bio' to avoid confusion and have a struct buf *bp = bio->bio_buf; pointer to access the buf. * MSLEEP/TSLEEP conversion. The DragonFly msleep/tsleep do not have 'PRI' priorities. 0 should be used. * BUS_* FUNCTIONS bus_setup_intr() - replace INTR_TYPE_* flags with 0. There is an extra argument for an interrupt interlock using the sys/serializer.h interface. This can either be left NULL or you can convert the spinlock(s) for the driver into serializer locks and integrate the interrupt service routine with a serializer. * CAM CODE - cam_simq* code refcounts, so shared device queues (raid and multi-channel devices) are not freed before all references have gone away. * callout_drain() should be replaced by callout_stop_sync() * UNRHDR functions - DragonFly uses a more generic idr(9) subsystem compatible with the Linux API of the same name This LWN article describes it in details: http://lwn.net/Articles/103209/ A typical conversion looks like this: #include free_unr() has to be replaced by idr_remove() alloc_unr() has to be replaced by a code sequence using idr_pre_get and idr_get_new such as this one: retry: if (idr_pre_get(xxx) ==0) { kprintf("Memory allocation error\n"); return error; } spin_lock(xxx); ret = idr_get_new(xxx); spin_unlock(xxx); if (ret == EAGAIN) goto retry; * MPASS macro - Replace it with KKASSERT * In DragonFly 3.3 format specifier %D was removed from kprintf. As a replacement functions kether_ntoa() and hexncpy() were added. - Ethernet address (MAC) to its hexadecimal form: char ethstr[ETHER_ADDRSTRLEN + 1]; u_char hwaddr[6]; kprintf("MAC address %s\n", kether_ntoa(hwaddr, ethstr) - Generic conversion (block of bytes to hexadecimal form): char hexstr[18]; u_char mydata[6] = {1, 2, 3, 4, 5 ,6}; /* * Below statement would print: * * 01-02-03-04-05-06 */ kprintf("%s\n", hexncpy(mydata, 6, hexstr, HEX_NCPYLEN(6), "-"));