The kernel driver can write directly to registers and/or memory on the card. It also handles command packets generated by the userspace drivers and passes them to the hardware after checking the contents. Two types of packets are most commonly used -- type 0 packets are used to write registers from userspace (this is why the kernel driver checks 'em) and type 3 packets tell the chips to perform more complex commands.
Here's a subset of the commands supported on Evergreen -- dispatch commands are for compute, draw commands for graphics.
Example taken from : http://cgit.freedesktop.org/~airlied...d.h?h=drm-next
For more info about how packets get to the hardware (via a ring buffer in memory that CPU and GPU can both access) take a look at pages 18-20 of :/* Packet 3 types */
#define PACKET3_NOP 0x10
#define PACKET3_SET_BASE 0x11
#define PACKET3_CLEAR_STATE 0x12
#define PACKET3_INDEX_BUFFER_SIZE 0x13
#define PACKET3_DISPATCH_DIRECT 0x15
#define PACKET3_DISPATCH_INDIRECT 0x16
#define PACKET3_INDIRECT_BUFFER_END 0x17
#define PACKET3_MODE_CONTROL 0x18
#define PACKET3_SET_PREDICATION 0x20
#define PACKET3_REG_RMW 0x21
#define PACKET3_COND_EXEC 0x22
#define PACKET3_PRED_EXEC 0x23
#define PACKET3_DRAW_INDIRECT 0x24
#define PACKET3_DRAW_INDEX_INDIRECT 0x25
Edit -- originally linked to 6xx/7xx 3D doc but the 3xx-5xx doc has more details.