[RFC Proposal] A mechanism to quirk all configuration access to a PCI device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Bjorn, List,

Sometimes we come across PCI devices that have an errata that require
special handling when accessing that device's configuration space.
(E.g. https://github.com/rajatxjain/public_shared/blob/main/OZ711LV2_appnote.pdf):
 - Some registers may only support access of a particular size.
 - Some registers may have a bad value, so need to return some other good value.
 - etc.

So I have been thinking about implementing a mechanism that allows a
PCI quirk for a device (VID/DID/ etc), such that all the PCI
configuration accesses to that device goes through that quirk (thus
giving it a chance to do any special handling). This includes access
from kernel, userspace and drivers. AFAIU, a reasonable central point
where all the PCI configuration accesses go through are:

pci_bus->ops->read()
pci_bus->ops->write()

thus making the macros

pci_bus_read_config_##size()
pci_user_read_config_##size()

good candidates for tapping configuration accesses. Here is a
proposal, I'd appreciate it if you could please let me know what you
think about this. I've tried this to be as less intrusive and as
efficient as possible.

BASIC IDEA:

(1) Provide macros that follow existing fixup macros:

#define DECLARE_PCI_FIXUP_CONFIG_READ(...)
              ....
#define DECLARE_PCI_FIXUP_CONFIG_WRITE(...)
              ....
These macros shall allow to place hooks for particular VIDs/DIDs in
special sections (.pci_fixup_config_read, .pci_fixup_config_write)

(2) Add the following data structures to the struct pci_bus, all of
them initialized with 0/NULL:

/*
 *  Bitmap with 1 bit for each devfn on this pci_bus.
 * Each bit, if set, means that config accesses to that
 * devfn needs to go through a quirk
 */
u32 bitmap_quirk;

/*
 * Array of 32 function pointers (config space quirk functions),
 * 1 for each devfn possible on this pci_bus.
 * ("quirk_function_ptr" is a typedef here)
 *
/
quirk_function_ptr config_read_quirk[32];
quirk_function_ptr config_write_quirk[32];

(3) When the config access is made, in the following macros:

pci_bus_read_config_##size
pci_bus_write_config_##size
pci_user_read_config_##size
pci_user_write_config_##size

Check and quirk if we need to:

if (bus->bitmap_quirk & (1 << devfn)) {    /* Does this devfn needs
config quirk? */
    bus->config_read_quirk[devfn](...)
} else {
     bus->ops->read(...)
}

(4) Somewhere during the pci_dev addition time (perhaps in pci_setup_device()):
     Do something like:
     pci_attach_config_fixup(pci_fixup_config_read, dev);
     pci_attach_config_fixup(pci_fixup_config_write, dev);
      - These functions shall be somewhat similar to pci_do_fixups()
in matching DID/VID etc and if there is a match:
      - Set the corresponding bit and function pointers in the parent pci_bus.

(5) Somewhere during the pci_dev removal time (perhaps in
pci_device_add() or  pci_setup_device()):
     Do something like:
     pci_attach_config_fixup(pci_fixup_config_read, dev);
     pci_attach_config_fixup(pci_fixup_config_write, dev);
      - These functions shall be somewhat similar to pci_do_fixups()
in matching DID/VID etc and if there is a match:
      - Set the corresponding bit in the bitmap and function pointer
in the parent pci_bus.

NOTES:

a. Since the device quirk, shall be called while holding the pci_lock,
it shall need to be fast (perhaps not allowed to do anything else
rather than dev->bus->ops->read() and perhaps massage values before
returning it).

b. Note that in step (4) and (5), we're changing the pci_bus fields
when we add or remove pci_dev. I think that should be OK to do without
a lock because we can choose to do it at a place where we are holding
the pci_bus_sem.

c. I think I might have to use a lock to protect the pci_bus new
fields anyway but I think it should be fast. Anyway, I think we can
think about the locking as a next step once I get some feedback.

This is something I came up with this morning, so of course there
might be gaps or things I didn't think of. Please let me know your
comments and / or thoughts.

Thanks & Best Regards,

Rajat



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux