Merge branch 'vendor/LESS'
[dragonfly.git] / doc / porting_drivers.txt
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), "-"));