pci_init_capabilities 中的pci_msi_setup_pci_dev初始化
static void pci_msi_setup_pci_dev(struct pci_dev *dev)
{
/*
* Disable the MSI hardware to avoid screaming interrupts
* during boot. This is the power on reset default so
* usually this should be a noop.
*/
dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (dev->msi_cap)
pci_msi_set_enable(dev, 0);
dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (dev->msix_cap)
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
}
在pci_msi_setup_pci_dev 中首先通过pci_find_capability 来查询是否支持PCI_CAP_ID_MSI。如果支持的哈,调用pci_msi_set_enable disable掉
static inline void pci_msi_set_enable(struct pci_dev *dev, int enable)
{
u16 control;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
pci_msi_set_enable的实现比较简单,直接通过pci_read_config_word 来写寄存器,在pci子系统这边读写硬件都是通过pci_read_config_XXX 这样的接口进行,这个接口的第一个参数是dev,第二个是要写的位置,第三个就是要写的值.
通过判断是否支持PCI_CAP_ID_MSIX,如果支持的话,调用pci_msix_clear_and_set_ctrl 清零并enable
static inline void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
{
u16 ctrl;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
ctrl &= ~clear;
ctrl |= set;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
}
pci_msix_clear_and_set_ctrl和pci_msi_set_enable的实现一样只是要写的寄存器的pos和值不一样.
pci_allocate_cap_save_buffers 中总共问五种capbility 预留buffer
void pci_allocate_cap_save_buffers(struct pci_dev *dev)
{
int error;
error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP,
PCI_EXP_SAVE_REGS * sizeof(u16));
if (error)
dev_err(&dev->dev,
"unable to preallocate PCI Express save buffer\n");
error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_PCIX, sizeof(u16));
if (error)
dev_err(&dev->dev,
"unable to preallocate PCI-X save buffer\n");
pci_allocate_vc_save_buffers(dev);
}
这五种capbility 分别是PCI_CAP_ID_EXP/PCI_CAP_ID_PCIX/PCI_EXT_CAP_ID_MFVC/PCI_EXT_CAP_ID_VC/PCI_EXT_CAP_ID_VC9
这里以PCI_CAP_ID_EXP 为例
int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size)
{
return _pci_add_cap_save_buffer(dev, cap, false, size);
}
static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap,
bool extended, unsigned int size)
{
int pos;
struct pci_cap_saved_state *save_state;
//首先查看是否有这个cap
if (extended)
pos = pci_find_ext_capability(dev, cap);
else
pos = pci_find_capability(dev, cap);
if (!pos)
return 0;
//申请一个struct pci_cap_saved_state *save_state;
save_state = kzalloc(sizeof(*save_state) + size, GFP_KERNEL);
if (!save_state)
return -ENOMEM;
save_state->cap.cap_nr = cap;
save_state->cap.cap_extended = extended;
save_state->cap.size = size;
//将save_state 添加到pci_dev->saved_cap_space
pci_add_saved_cap(dev, save_state);
return 0;
}
static void pci_add_saved_cap(struct pci_dev *pci_dev,
struct pci_cap_saved_state *new_cap)
{
hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
}
static void pci_msi_setup_pci_dev(struct pci_dev *dev)
{
/*
* Disable the MSI hardware to avoid screaming interrupts
* during boot. This is the power on reset default so
* usually this should be a noop.
*/
dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (dev->msi_cap)
pci_msi_set_enable(dev, 0);
dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (dev->msix_cap)
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
}
在pci_msi_setup_pci_dev 中首先通过pci_find_capability 来查询是否支持PCI_CAP_ID_MSI。如果支持的哈,调用pci_msi_set_enable disable掉
static inline void pci_msi_set_enable(struct pci_dev *dev, int enable)
{
u16 control;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
pci_msi_set_enable的实现比较简单,直接通过pci_read_config_word 来写寄存器,在pci子系统这边读写硬件都是通过pci_read_config_XXX 这样的接口进行,这个接口的第一个参数是dev,第二个是要写的位置,第三个就是要写的值.
通过判断是否支持PCI_CAP_ID_MSIX,如果支持的话,调用pci_msix_clear_and_set_ctrl 清零并enable
static inline void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
{
u16 ctrl;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
ctrl &= ~clear;
ctrl |= set;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
}
pci_msix_clear_and_set_ctrl和pci_msi_set_enable的实现一样只是要写的寄存器的pos和值不一样.
pci_allocate_cap_save_buffers 中总共问五种capbility 预留buffer
void pci_allocate_cap_save_buffers(struct pci_dev *dev)
{
int error;
error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP,
PCI_EXP_SAVE_REGS * sizeof(u16));
if (error)
dev_err(&dev->dev,
"unable to preallocate PCI Express save buffer\n");
error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_PCIX, sizeof(u16));
if (error)
dev_err(&dev->dev,
"unable to preallocate PCI-X save buffer\n");
pci_allocate_vc_save_buffers(dev);
}
这五种capbility 分别是PCI_CAP_ID_EXP/PCI_CAP_ID_PCIX/PCI_EXT_CAP_ID_MFVC/PCI_EXT_CAP_ID_VC/PCI_EXT_CAP_ID_VC9
这里以PCI_CAP_ID_EXP 为例
int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size)
{
return _pci_add_cap_save_buffer(dev, cap, false, size);
}
static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap,
bool extended, unsigned int size)
{
int pos;
struct pci_cap_saved_state *save_state;
//首先查看是否有这个cap
if (extended)
pos = pci_find_ext_capability(dev, cap);
else
pos = pci_find_capability(dev, cap);
if (!pos)
return 0;
//申请一个struct pci_cap_saved_state *save_state;
save_state = kzalloc(sizeof(*save_state) + size, GFP_KERNEL);
if (!save_state)
return -ENOMEM;
save_state->cap.cap_nr = cap;
save_state->cap.cap_extended = extended;
save_state->cap.size = size;
//将save_state 添加到pci_dev->saved_cap_space
pci_add_saved_cap(dev, save_state);
return 0;
}
static void pci_add_saved_cap(struct pci_dev *pci_dev,
struct pci_cap_saved_state *new_cap)
{
hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
}