A Review of NEWCARD Warner Losh imp@FreeBSD.org Timing Solutions, Inc Abstract NEWCARD is a port of NetBSD pcmcia code to FreeBSD. A review of the architecture and history of NEWCARD is presented. NEWCARD is compared to FreeBSD's OLDCARD pccard code and NetBSD pcmcia code. Design decisions are discussed. Driver migration from OLDCARD to NEWCARD are discussed. Future directions, including CardBus, are outlined. What Is NEWCARD? NEWCARD is the name for the effort to port the NetBSD's pcmcia system to FreeBSD. There are a number of kernel differences between FreeBSD and NetBSD that required work, for example, FreeBSD's resource allocation and device configuration differ somewhat from NetBSD's. NEWCARD implements the entire pccard stack inside the kernel, unlike OLDCARD, FreeBSD's previous implementation. It parsed each card's CIS from a userland daemon. These userland/kernel boundary crossings slowed processing of the insertion and removal of cards and caused other problems for the system. NetBSD's integration of all processing into the kernel solves these problems. In addition to pccard functionality, the code has been converted to use FreeBSD's newbus device configuration architecture. A few defaults have changed. NEWCARD implements a simplified driver interface. NEWCARD builds on the experiences with the plain FreeBSD OLDCARD and PAO's version. NEWCARD brings additional functionality not present in OLDCARD or PAO. Porting Base Selection When the author began his search for an improved pccard system for FreeBSD, he had many choices. He wanted one that would support 16 bit and 32 bit cards and move all the resource configuration into the kernel. First, he could have expanded the OLDCARD system. After the author's experiences in porting OLDCARD to the newbus framework, the author quickly discarded this option. Second, he could have rewritten the entire thing from scratch. While it would be fun to do that, such an effort was beyond the time constraints that the author had to work with. Thus the author was left with the option of evaluating existing code bases to see which ones would be suitable for FreeBSD's pccard needs. The author identified several code bases while working on the project. The newconfig project had code running on FreeBSD. NetBSD had a working 16-bit system, as did OpenBSD. Linux had supported pccards for a long time as well. The author also heard about something called Wildboar, which had produced code which was later integrated into BSD/OS. At the time the project started, the author found nothing useful on the Wildboar code. All the other code bases had information available to allow to evaluate them. The newconfig project, based in Japan, ported NetBSD pcmcia code to FreeBSD. At the time the author started work on this project, FreeBSD's core had decided to migrate all FreeBSD drivers away from the old config(8) interface to newbus. The newconfig project had ported the config.new(8) present in 4.4 BSD to FreeBSD using NetBSD as a base. The workers on the newconfig project resented core's decision and were disinclined to port newconfig to newbus. Since newbus and newconfig are incompatible, much work was lost due to this change. Since this code appeared to be the most mature, and in an effort to salvage their work, the author chose NetBSD's code, with the newconfig tweaks, as the basis for his work. OpenBSD derived its code from the NetBSD code, so the effort to port it would be about the same. A few good ideas are in this code, and once NEWCARD settles down they will likely be integrated into NEWCARD. The author also evaluated the Linux card services code. Like everything else in the Linux kernel, this code has a GPL license. The author rejected using this code because FreeBSD has a strong policy of avoiding GPL code in the kernel. The Linux code isn't bad, but suffers from implementing the standard too closely. Socket services and card services based systems gives the driver writer great control over everything, but this control comes at the price of increased driver complexity. Late in the development cycle of NEWCARD, BSDi purchased Walnut Creek CDROM. With this purchase, most of the BSD/OS source base became available for use with FreeBSD. Wildboar, BSD/OS's pccard implementation, became available. It implements 16-bit pccard functionality very cleanly. Coincidentally, it too had been developed in Japan a number of years ago. Had the code been available at the start of the development process, the author would have chosen to port that and expand it for 32bit CardBus support. While Wildboar may prove useful in the future, the author decided to finish the NEWCARD effort without using it. Differences from OLDCARD The code bases for OLDCARD and NEWCARD are unrelated. Nearly every major detail of implementation differs. OLDCARD used a mixture of userland code and kernel code to activate the card. It required a running daemon to configure the cards. In addition, a fair amount of system level configuration information resided in /etc/pccard.conf so pccardd could manage resources for pccards. These requirements made OLDCARD difficult to configure and hard to use on some machines. The kernel portion of OLDCARD did much in an interrupt context, which resulted in some interesting deadlocks and other problems. The pccardd daemon also chose which device driver to assign to the inserted card. The device drivers themselves had only veto power over this choice. In contrast, NEWCARD implements everything in the kernel. The kernel handles all card configuration and power management. Its infrastructure allows a larger class of cards than OLDCARD. NEWCARD supports both kinds of multifunction cards, the true multifunction cards and pseudo multifunction cards. Both types of multifunction cards have more than one function, like a combination modem and Ethernet card. A true multifunction card lists each discrete function in its CIS. A pseudo multifunction card lists only one function in the CIS and expects the driver writer to separate out the functions in their code. In addition, it queues insertion and deletion events so that it can run the card detach in a safer context. It requires that drivers claim devices that they support, in contrast to OLDCARD which told the driver to take a device. As with any two bases of code that implement the same sort of thing, there are a number of other differences as well. These are differences in external API, internal structure and the like. Most of these differences are uninteresting and will not be covered in this paper. Differences in OLDCARD and NEWCARD Driver Interface The author designed NEWCARD's driver interface to have minimal impact on the existing OLDCARD drivers. When the author converted the OLDCARD code to newbus, the radical changes to the device API obsoleted many pccard drivers. These change has proven to be a large burdon on driver writers, many of whom still haven't updated their drivers to newbus. The author wished to avoid a similar experience when FreeBSD moved from OLDCARD to NEWCARD. The NEWCARD driver interface allows easy migration from OLDCARD. In addition, the author has attempted to allow the same source and object to be used for both OLDCARD and NEWCARD drivers. While the NEWCARD driver interface was written to allow easy porting of OLDCARD drivers, it isn't a drop in replacement. OLDCARD drivers require a few modifications to work. At a minimum, the table of supported cards must be moved into the driver and matching routines must be called. OLDCARD has augmented include these routines, but as driver selection is done in pccardd, these functions always return "yes, this matches." Most unconverted OLDCARD drivers in the FreeBSD tree just need this functionality. NEWCARD drivers are free to use this table to support additional "quirk" information about each card, but those drivers doing so will not work with the OLDCARD framework as the OLDCARD framework lacks the infrastructure necessary to support this. OLDCARD drivers could assume that probe always succeeded. However, many chose to poke at the purported hardware to make sure that it really was there. NEWCARD drivers should just match on the CIS information provided by the kernel. Each NEWCARD driver is expected to have a table of n-tuples made up of card-name, OEM-number, product-number, manufacturer-string, version-string, and function-number. A common routine for looking for matches is provided. Any of these items may be unspecified, which means that item matches all cards. This is an expansion of NetBSD's lookup routine which doesn't provide for CIS string matching. FreeBSD's current /etc/defaults/pccard.conf has over 250 entries in it by CIS string alone, so some transition mechanism was necessary. The probe code may also match on card function type. This maps the the wild card entries in PAO and later versions of FreeBSD's pccardd. Since the kernel now manages the power for pccards, drivers can now be made smarter about powering card functions up and down as needed. The first prototype implementation does not provide cards with an easy way to do this. This deficiency will be corrected over time. After configuration, NEWCARD powers up all functions of the card at all times. Driver simplification is traded for additional power consumption. Given that most 16bit cards draw on the order of a few hundred milliamps, the ability to selectively power functions up and down is highly desirable. The CIS parsing engine in the NEWCARD code understands multifunction cards. It automatically will enable each function that it finds in a card as a separate device node in the newbus tree. Most multifunction cards list each individual function in the CIS, so the NEWCARD framework ensures that each function of the card works properly without needing a special driver. However, an interesting number of pccards list only one function in their CIS table, but which none the less provide multiple devices. For these cards, special drivers are needed, but NEWCARD allows them to be constructed with a minimum of effort. In addition to the driver API, users will notice several differences. First, cards are usable much faster than with OLDCARD. NEWCARD configures cards in a couple of seconds rather than the 30 seconds that pccardd required. Second, pccardd is now gone (or at least is currently broken). Cards will configure without it, but no automatic execution of arbitrary commands on insertion or removal is performed. The author anticipates a new daemon will be written to provide this functionality. The new daemon will likely support all hot pluggable busses (usb, pccard, cardbus, firewire, compact pci, etc) so once it is done for one, all busses will be able to leverage off of it. Differences from NetBSD There are a number of minor and major differences between the NetBSD pcmcia code and the FreeBSD NEWCARD code. Major differences include automatic function activation, automatic power management, pccard to bridge interface and kernel interface usage. In NetBSD's code, each driver is responsible for activating the card's function and powering it up. This works well in practice, but has the effect of requiring duplicated code in nearly all of the drivers. The author desired to simplify the basic bus code for each driver. Likewise, FreeBSD's general bus configuration interfaces generally do not impose the requirement to specifically activate the card in order to use it. Finally, FreeBSD's OLDCARD drivers expect to have external agents configure and power up the card. These three reasons caused the author to chose to make things more automatic. It allows OLDCARD drivers to be reused with a minimum of rework. NetBSD's pcmcia to pcmcia-bridge interface was done via a table of function pointers. Many of these functions controlled resource allocation and activation. FreeBSD's kobj and newbus infrastructure handled these for other busses, so the author decided to convert the function pointer table to use more native methods. This allows the OLDCARD FreeBSD drivers to behave much the same way that they have always behaved and reduced the porting load when NEWCARD is activated. NetBSD and FreeBSD's bus space interfaces have diverged somewhat since FreeBSD incorporated a snapshot of the bus space code into the tree with CAM. The functional changes in NetBSD were the same as many of the newbus device interfaces. Rather than try to incorporate them into FreeBSD, their usage has been rewritten. Incorporating them into FreeBSD made the bus_space_handle_t a complex structure rather than a simple one. Feedback from the developer community indicated that this was undesirable for the small gains that having a unified API would bring us, so this line of attack was dropped. As noted above, FreeBSD provides the ability to match cards based on the version 1 info structure that most pccards possess. NetBSD provides access to this information, but doesn't provide a common routine to do the matching. In NetBSD, when cards are ejected, NetBSD doesn't really remove them from the system. NetBSD caches information about the cards so that it might make educated guesses about those devices that go away and return. This works well for stateless cards, such as Ethernet devices and modems, but less well for cards that store state, such as disk controllers and compact flash cards. FreeBSD takes a more conservative approach of saying that once a card is ejected, the device is gone from the system, never to return. Both approaches have their advantages and disadvantages. Unlike USB, which provides an explicit powered down, but state retaining mode of operation, pccards can be on or off which makes it impossible to know, in the general case, if the card you see inserted is the same as or different from an earlier card that was in the system. NetBSD calls things pcmcia, while FreeBSD uses pccard. All references to pcmcia were changed to pccard in the code. Others have suggested this change is a silly thing to have done and will make a future merge harder. The author agrees that it might have been wise to retain the NetBSD names, but maintains it will be difficult to produce a merged code base and the name will be the least of the issues there. Future directions A number of items remain for future consideration. A daemon needs to be written to handle card events at the user level. Additional testing and debugging of the infrastructure is needed. Drivers should be migrated from using CIS strings to match cards to using the OEM number and card id. CIS matching routines likely should be done as regular expressions, not simple strings. 32bit cardbus support should be added. In addition, the author would love to see a wider participation of the developer community in the NEWCARD work. He hopes that some readers of this paper will learn enough to start making useful contributions to the project. A Note on CardBus Work on the CardBus side of things is on going at the time this paper was written. Due to time constraints for publication in the BSDcon 2000 proceedings, this section on cardbus has been omitted. The author will update the paper and make a more complete version available at http://people.freebsd.org/~imp/bsdcon2000/paper.html before BSDCon 2000.