How does Nvidia graphic driver worked?

First go to Nvidia website and download the graphic card drivers for Linux. Untar it (via the “-x” command):

NVIDIA-Linux-x86-256.35.run -x
Creating directory NVIDIA-Linux-x86-256.35
Verifying archive integrity… OK
Uncompressing NVIDIA Accelerated Graphics Driver for Linux-x86 256.35/tmp/NVIDIA-Linux-x86-256.35
…………………………………………………………………………………………………………….

Then “cd kernel” to view the files:

wc *.c |sort -n
97 240 2397 os-registry.c
151 355 3441 nv_gvi.c
272 1192 9077 gcc-version-check.c
328 853 9359 os-agp.c
346 827 10174 nv-i2c.c
770 2466 23481 nv-vm.c
1200 3042 33949 nvacpi.c
1403 3594 33035 os-interface.c
5171 14259 148873 nv.c
9738 26828 273786 total

Wow….a lot of the logic is behind nv.c, and so looking for “probe” symbol:

grep -i probe *.c
nv.c:static NvU32 num_probed_nv_devices = 0;
nv.c:int nv_kern_probe(struct pci_dev *, const struct pci_device_id *);
nv.c:int nv_kern_smu_probe(struct pci_dev *);
nv.c: .probe = nv_kern_probe,
nv.c: if (num_probed_nv_devices != count)
nv.c: “NVRM: The NVIDIA probe routine was not called for %d device(s).\n”,
nv.c: count – num_probed_nv_devices);
nv.c: if (num_probed_nv_devices == 0)
nv.c: nv_printf(NV_DBG_ERRORS, “NVRM: No NVIDIA graphics adapter probed!\n”);
nv.c: if (num_probed_nv_devices != num_nv_devices)
nv.c: “NVRM: The NVIDIA probe routine failed for %d device(s).\n”,
nv.c: num_probed_nv_devices – num_nv_devices);
nv.c:/* make sure the pci_driver called probe for all of our devices.
nv.c:nv_kern_probe
nv.c: return nv_kern_smu_probe(dev);
nv.c: num_probed_nv_devices++;
nv.c: if (nv_ext_kern_probe(num_nv_devices))
nv.c: nv_printf(NV_DBG_ERRORS, “NVRM: failed extended probe!!\n”);
nv.c:nv_kern_smu_probe

Who called nv_kern_probe():

It is called during the PCI setup phase:

static struct pci_driver nv_pci_driver = {
.name = “nvidia”,
.id_table = nv_pci_table,
.probe = nv_kern_probe,
#if defined(NV_PM_SUPPORT_DEVICE_DRIVER_MODEL)
.suspend = nv_kern_suspend,
.resume = nv_kern_resume,
#endif
};

and nv_pci_driver is registered during the module initialization:

static int __init nvidia_init_module(void)
{
<……>
if (pci_register_driver(&nv_pci_driver) < 0)
{
rc = -ENODEV;
nv_printf(NV_DBG_ERRORS, “NVRM: No NVIDIA graphics adapter found!\n”);
goto failed2;
}

A list of some other functions in nv.c are:

static void nv_kern_vma_open(struct vm_area_struct *);
static void nv_kern_vma_release(struct vm_area_struct *);
int nv_kern_open(struct inode *, struct file *);
int nv_kern_close(struct inode *, struct file *);
int nv_kern_mmap(struct file *, struct vm_area_struct *);
unsigned int nv_kern_poll(struct file *, poll_table *);
int nv_kern_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
long nv_kern_unlocked_ioctl(struct file *, unsigned int, unsigned long);
long nv_kern_compat_ioctl(struct file *, unsigned int, unsigned long);
void nv_kern_isr_bh(unsigned long);
#if !defined(NV_IRQ_HANDLER_T_PRESENT) || (NV_IRQ_HANDLER_T_ARGUMENT_COUNT == 3)
irqreturn_t nv_kern_isr(int, void *, struct pt_regs *);
#else
irqreturn_t nv_kern_isr(int, void *);
#endif
void nv_kern_rc_timer(unsigned long);

static int nv_kern_apm_event(struct pm_dev *, pm_request_t, void *);
static int nv_kern_read_cardinfo(char *, char **, off_t off, int, int *, void *);
static int nv_kern_read_status(char *, char **, off_t off, int, int *, void *);
static int nv_kern_read_registry(char *, char **, off_t off, int, int *, void *);
static int nv_kern_read_agpinfo(char *, char **, off_t off, int, int *, void *);
static int nv_kern_read_version(char *, char **, off_t off, int, int *, void *);
static int nv_kern_read_text_file(char *, char **, off_t off, int, int *, void *);

int nv_kern_ctl_open(struct inode *, struct file *);
int nv_kern_ctl_close(struct inode *, struct file *);

int nv_kern_probe(struct pci_dev *, const struct pci_device_id *);
int nv_kern_smu_probe(struct pci_dev *);

static int nv_kern_suspend(struct pci_dev *, pm_message_t);
static int nv_kern_smu_suspend(void);
static int nv_kern_resume(struct pci_dev *);
static int nv_kern_smu_resume(void);

The above functions – in particular – nv_kern_read_cardinfo() will call the rm_* (for Resource Manager) functions to get the details:

BOOL NV_API_CALL rm_init_rm (nv_stack_t *);
BOOL NV_API_CALL rm_shutdown_rm (nv_stack_t *);
BOOL NV_API_CALL rm_init_private_state (nv_stack_t *, nv_state_t *);
BOOL NV_API_CALL rm_free_private_state (nv_stack_t *, nv_state_t *);
BOOL NV_API_CALL rm_init_adapter (nv_stack_t *, nv_state_t *);
BOOL NV_API_CALL rm_disable_adapter (nv_stack_t *, nv_state_t *);
BOOL NV_API_CALL rm_shutdown_adapter (nv_stack_t *, nv_state_t *);
void NV_API_CALL rm_set_interrupts (nv_stack_t *, BOOL);
BOOL NV_API_CALL rm_ioctl (nv_stack_t *, nv_state_t *, void *, NvU32, void *);
BOOL NV_API_CALL rm_isr (nv_stack_t *, nv_state_t *, NvU32 *);
void NV_API_CALL rm_isr_bh (nv_stack_t *, nv_state_t *);
RM_STATUS NV_API_CALL rm_power_management (nv_stack_t *, nv_state_t *, NvU32, NvU32);
RM_STATUS NV_API_CALL rm_save_low_res_mode (nv_stack_t *, nv_state_t *);
NvU32 NV_API_CALL rm_get_vbios_version (nv_stack_t *, nv_state_t *, NvU32 *, NvU32 *, NvU32 *, NvU32 *, NvU32 *);
void NV_API_CALL rm_free_unused_clients (nv_stack_t *, nv_state_t *, void *);

void NV_API_CALL rm_update_agp_config (nv_stack_t *, nv_state_t *);
RM_STATUS NV_API_CALL rm_init_agp (nv_stack_t *, nv_state_t *, NvU64 *, NvU64 *);
RM_STATUS NV_API_CALL rm_teardown_agp (nv_stack_t *, nv_state_t *);

RM_STATUS NV_API_CALL rm_alloc_agp_pages (nv_stack_t *, nv_state_t *, NvU32, void **, NvU32 *);
RM_STATUS NV_API_CALL rm_free_agp_pages (nv_stack_t *, nv_state_t *, void *);

RM_STATUS NV_API_CALL rm_alloc_agp_bitmap (nv_stack_t *, nv_state_t *, NvU32, NvU32 *);
RM_STATUS NV_API_CALL rm_free_agp_bitmap (nv_stack_t *, nv_state_t *, NvU32, NvU32);
RM_STATUS NV_API_CALL rm_set_agp_bitmap (nv_stack_t *, nv_state_t *, void *);
RM_STATUS NV_API_CALL rm_clear_agp_bitmap (nv_stack_t *, nv_state_t *, void **);

RM_STATUS NV_API_CALL rm_read_registry_dword (nv_stack_t *, nv_state_t *, NvU8 *, NvU8 *, NvU32 *);
RM_STATUS NV_API_CALL rm_write_registry_dword (nv_stack_t *, nv_state_t *, NvU8 *, NvU8 *, NvU32);
RM_STATUS NV_API_CALL rm_read_registry_binary (nv_stack_t *, nv_state_t *, NvU8 *, NvU8 *, NvU8 *, NvU32 *);
RM_STATUS NV_API_CALL rm_write_registry_binary (nv_stack_t *, nv_state_t *, NvU8 *, NvU8 *, NvU8 *, NvU32);

RM_STATUS NV_API_CALL rm_run_rc_callback (nv_stack_t *, nv_state_t *);
RM_STATUS NV_API_CALL rm_get_device_name (nv_stack_t *, nv_state_t *, NvU16, NvU32, NvU8*);

NvU64 NV_API_CALL nv_rdtsc (void);

void NV_API_CALL rm_register_compatible_ioctls (nv_stack_t *);
void NV_API_CALL rm_unregister_compatible_ioctls (nv_stack_t *);

BOOL NV_API_CALL rm_is_legacy_device (nv_stack_t *, NvU16, BOOL);
BOOL NV_API_CALL rm_is_supported_device (nv_stack_t *, nv_state_t *);

RM_STATUS NV_API_CALL rm_i2c_read_buffer (nv_stack_t *, nv_state_t *, void *, NvU8, NvU32, NvU8 *);
RM_STATUS NV_API_CALL rm_i2c_write_buffer (nv_stack_t *, nv_state_t *, void *, NvU8, NvU32, NvU8 *);
RM_STATUS NV_API_CALL rm_i2c_smbus_write_quick (nv_stack_t *, nv_state_t *, void *, NvU8, NvU8);
RM_STATUS NV_API_CALL rm_i2c_smbus_read_buffer (nv_stack_t *, nv_state_t *, void *, NvU8, NvU8, NvU32, NvU8 *);
RM_STATUS NV_API_CALL rm_i2c_smbus_write_buffer (nv_stack_t *, nv_state_t *, void *, NvU8, NvU8, NvU32, NvU8 *);

void NV_API_CALL rm_check_pci_config_space (nv_stack_t *, nv_state_t *nv, BOOL, BOOL, BOOL);

where are all these functions implemented? In the same directory comes a pre-compiled object files: nv-kernel.o:

objdump -t nv-kernel.o |grep rm_
00493da1 g F .text 000000a4 rm_resume_smu
004921ec g F .text 0000010b rm_free_agp_bitmap
0049198e g F .text 000000aa rm_change_res_mode
004936dd g F .text 0000027c rm_i2c_smbus_write_buffer
00493e45 g F .text 000008cf rm_check_pci_config_space
00491589 g F .text 0000022a rm_power_management
00493a3f g F .text 00000063 rm_save_low_res_mode
00492d0f g F .text 00000272 rm_i2c_read_buffer
00496654 g F .text 0000007d rm_gvi_detach_device
00492024 g F .text 00000103 rm_free_agp_pages
00491156 g F .text 000000ab rm_shutdown_adapter
00493af7 g F .text 000000b0 rm_system_event
004918a4 g F .text 0000007d rm_isr_bh
004931f3 g F .text 0000026e rm_i2c_smbus_write_quick
00491c61 g F .text 00000047 rm_purge_os_event_list
0049261b g F .text 000000e5 rm_write_registry_dword
00491475 g F .text 00000082 rm_io_flush
00493c52 g F .text 000000ab rm_shutdown_smu
00497555 g F .text 0000007b rm_gvi_get_device_name
00492540 g F .text 000000db rm_read_registry_binary
00491201 g F .text 00000052 rm_get_adapter_status
00491921 g F .text 0000006d rm_ioctl
00497699 g F .text 00000069 rm_shutdown_gvi_device
00491f4e g F .text 000000d6 rm_alloc_agp_pages
004966d1 g F .text 0000006d rm_gvi_attach_device
004922f7 g F .text 000000ac rm_set_agp_bitmap
00492127 g F .text 000000c5 rm_alloc_agp_bitmap
00493aa2 g F .text 00000055 rm_perform_version_check
00491c0c g F .text 00000055 rm_free_os_event
004975d0 g F .text 000000c9 rm_gvi_get_firmware_version
0049739f g F .text 00000098 rm_gvi_isr
00494714 g F .text 00000084 rm_disable_gpu_state_persistence
00492855 g F .text 00000166 rm_get_device_name
00491ca8 g F .text 0000005d rm_get_event_data
00493ba7 g F .text 000000ab rm_init_smu
00492f81 g F .text 00000272 rm_i2c_write_buffer
004914f7 g F .text 00000092 rm_get_vbios_version
0049727b g F .text 00000124 rm_gvi_bh
00497437 g F .text 00000088 rm_gvi_suspend
00492bc4 g F .text 0000014b rm_is_supported_device
004910ab g F .text 000000ab rm_disable_adapter
004912ef g F .text 00000186 rm_set_interrupts
00492adb g F .text 00000042 rm_unregister_compatible_ioctls
0049719c g F .text 000000df rm_gvi_free_private_state
00493461 g F .text 0000027c rm_i2c_smbus_read_buffer
004923a3 g F .text 000000b8 rm_clear_agp_bitmap
004912a1 g F .text 0000004e rm_shutdown_rm
00490f25 g F .text 00000055 rm_init_private_state
00491e9d g F .text 000000b1 rm_update_agp_config
004974bf g F .text 00000096 rm_gvi_resume
00491d05 g F .text 000000e3 rm_init_agp
00492b1d g F .text 000000a7 rm_is_legacy_device
00491baf g F .text 0000005d rm_alloc_os_event
00492a3c g F .text 0000005d rm_update_device_mapping_info
00490f7a g F .text 00000055 rm_free_private_state
004927db g F .text 0000007a rm_run_rc_callback
00491253 g F .text 0000004e rm_init_rm
004917b3 g F .text 000000f1 rm_isr
00491de8 g F .text 000000b5 rm_teardown_agp
004929bb g F .text 00000081 rm_access_registry
00496f31 g F .text 00000006 rm_init_gvi_device
00490fcf g F .text 000000dc rm_init_adapter
00493cfd g F .text 000000a4 rm_suspend_smu
00492700 g F .text 000000db rm_write_registry_binary
00496f37 g F .text 00000265 rm_gvi_init_private_state
00491a38 g F .text 00000057 rm_save_client
0049245b g F .text 000000e5 rm_read_registry_dword
00491ad8 g F .text 000000d7 rm_free_unused_clients
004939d6 g F .text 00000069 rm_i2c_remove_adapters
00492a99 g F .text 00000042 rm_register_compatible_ioctls
00491a8f g F .text 00000049 rm_release_client

Hm….so they don’t come as source codes. Have to stop here :-).

 

Advertisements

2 responses to this post.

  1. hello,

    I am trying to implement suspend/resume for GPU explicitly on demand.
    I have a GeForce GT 430 GPU connected to PCIe bus on Intel® Atom™ Processor D510 machine running on 2.6.31-15 kernel.
    The nvidia driver used is NVIDIA-Linux-x86-270.41.19

    I understood that the runtime resume/suspend is done by th call backs defined in the driver nv_kern_suspend and nv_kern_resume.

    static struct pci_driver nv_pci_driver = {
    .name = “nvidia”,
    .id_table = nv_pci_table,
    .probe = nv_kern_probe,
    #if defined(NV_PM_SUPPORT_DEVICE_DRIVER_MODEL)
    .suspend = nv_kern_suspend,
    .resume = nv_kern_resume,
    #endif
    };

    Now my poroblem is how do i call those functions from my program.It needs the pointer to struct pci_dev .But how do i get it in my program.

    I am not familiar with interfacing with PCIe device from user space programs.I am only familiar with basic operation of a char device like open/read/ioctl/close.Could you please provide me some pointers on how to initiate suspend for GPU.

    Thanks in advance
    Don

    Reply

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: