tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
take 2: MI overrides of bus_dma(9), bus_space(9), pci(9)
I would like for MI drivers to be able to override pci(9), bus_space(9),
and bus_dma(9) behavior for the purpose of handling exceptions, managing
bus resources, creating test harnesses, and counting events.
Matt Thomas nudged me in some private discussions to leave MD the
bus_space_tag_t and pci_chipset_tag_t, instead of embedding an MI tag,
and to let each architecture provide its own implementation of an
MI override functions for bus_space(9) and pci(9). Matt powerfully
influenced the look of the override API.
I will describe the overrides API for pci(9), first:
/* This is part of the ABI. Do not re-assign bits to names. */
enum pci_override_idx {
PCI_OVERRIDE_CONF_READ = __BIT(0)
, PCI_OVERRIDE_CONF_WRITE = __BIT(1)
, PCI_OVERRIDE_INTR_MAP = __BIT(2)
, PCI_OVERRIDE_INTR_STRING = __BIT(3)
, PCI_OVERRIDE_INTR_EVCNT = __BIT(4)
, PCI_OVERRIDE_INTR_ESTABLISH = __BIT(5)
, PCI_OVERRIDE_INTR_DISESTABLISH = __BIT(6)
, PCI_OVERRIDE_MAKE_TAG = __BIT(7)
, PCI_OVERRIDE_DECOMPOSE_TAG = __BIT(8)
};
/* This is part of the ABI. Only add new fields to the end of this
* structure!
*/
struct pci_overrides {
pcireg_t (*ov_conf_read)(void *, pci_chipset_tag_t, pcitag_t, int);
void (*ov_conf_write)(void *, pci_chipset_tag_t, pcitag_t, int,
pcireg_t);
int (*ov_intr_map)(void *, struct pci_attach_args *,
pci_intr_handle_t *);
const char *(*ov_intr_string)(void *, pci_chipset_tag_t,
pci_intr_handle_t);
const struct evcnt *(*ov_intr_evcnt)(void *, pci_chipset_tag_t,
pci_intr_handle_t);
void *(*ov_intr_establish)(void *, pci_chipset_tag_t, pci_intr_handle_t,
int, int (*)(void *), void *);
void (*ov_intr_disestablish)(void *, pci_chipset_tag_t, void *);
pcitag_t (*ov_make_tag)(void *, pci_chipset_tag_t, int, int, int);
void (*ov_decompose_tag)(void *, pci_chipset_tag_t, pcitag_t,
int *, int *, int *);
};
int pci_chipset_tag_create(pci_chipset_tag_t opc, uint64_t present,
const struct pci_overrides *ov,
void *ctx, pci_chipset_tag_t *pcp);
Create a copy of the tag opc at *pcp. Except for the
behavior overridden by ov, *pcp inherits opc's behavior
under pci(9) calls.
ov contains function pointers corresponding to pci(9)
routines. Each function pointer has a corresponding bit
in `present', and if that bit is 1, the function pointer
overrides the corresponding pci(9) call for the new tag.
pci_chipset_tag_create(9) does not copy ov. After a new
tag is created by pci_chipset_tag_create(9), ov must not
be destroyed until after the tag is destroyed by
pci_chipset_tag_destroy(9).
The first argument of every override-function is a void *,
and ctx is passed in that argument.
Return 0 if the call succeeds. Return EOPNOTSUPP if the
architecture does not support overrides. Return EINVAL if
`present' is 0, if `ov' is NULL, or if `present' indicates
that an override is present, but the corresponding override
in `ov' is NULL.
If the call does not succeed, *pcp is undefined.
void pci_chipset_tag_destroy(pci_chipset_tag_t pc);
Destroy a tag created by a prior call to pci_chipset_tag_create(9).
If a tag that was not created by pci_chipset_tag_create(9)
is destroyed, results are undefined. If a tag that was
already destroyed is a destroyed a second time, results
are undefined.
Both of those routines and the types are declared in sys/dev/pci/pcivar.h.
A weak alias for eopnotsupp, pci_chipset_tag_create, and a weak
alias for voidop, pci_chipset_tag_destroy, provide every architecture
with a default implementation.
I have implemented this API on i386 and used it to override
pci_intr_string(9), pci_intr_map(9), pci_conf_read(9),
pci_intr_establish(9), and pci_intr_disestablish(9) in cbb(4). I was
subsequently able to reduce the differences between if_ath_pci.c and
if_ath_cardbus.c to these:
- if (Cardbus_mapreg_map(ct, ATH_PCI_MMBA, mem_type, 0, &psc->sc_iot,
+ if (pci_mapreg_map(pa, ATH_PCI_MMBA, mem_type, 0, &psc->sc_iot,
bad1:
- Cardbus_mapreg_unmap(psc->sc_ct, ATH_PCI_MMBA, psc->sc_iot, psc->sc_ioh,
- psc->sc_mapsz);
+ bus_space_unmap(psc->sc_iot, psc->sc_ioh, psc->sc_mapsz);
- Cardbus_mapreg_unmap(psc->sc_ct, ATH_PCI_MMBA, psc->sc_iot, psc->sc_ioh,
- psc->sc_mapsz);
+ bus_space_unmap(psc->sc_iot, psc->sc_ioh, psc->sc_mapsz);
return 0;
To eliminate the remaining differences, I need either to override
pci_mapreg_map(9), or to revamp CardBus resource management, and I need
to override bus_space_unmap(9). That brings me to the bus_space(9)
overrides:
enum bus_space_override_idx {
BUS_SPACE_OVERRIDE_SPACE_MAP = __BIT(0)
, BUS_SPACE_OVERRIDE_SPACE_UNMAP = __BIT(1)
, BUS_SPACE_OVERRIDE_SPACE_ALLOC = __BIT(2)
, BUS_SPACE_OVERRIDE_SPACE_FREE = __BIT(3)
, BUS_SPACE_OVERRIDE_SPACE_EXTEND = __BIT(4)
, BUS_SPACE_OVERRIDE_SPACE_TRIM = __BIT(5)
};
/* Only add new members at the end of this struct! */
struct bus_space_overrides {
int (*bs_space_map)(void *, bus_space_tag_t, bus_addr_t, bus_size_t,
int, bus_space_handle_t *);
void (*bs_space_unmap)(void *, bus_space_tag_t, bus_space_handle_t,
bus_size_t);
int (*bs_space_alloc)(void *, bus_space_tag_t, bus_addr_t, bus_addr_t,
bus_size_t, bus_size_t, bus_size_t, int, bus_addr_t *,
bus_space_handle_t *);
void (*bs_space_free)(void *, bus_space_tag_t, bus_space_handle_t,
bus_size_t);
};
int bus_space_tag_create(bus_space_tag_t, uint64_t,
const struct bus_space_overrides *, void *,
bus_space_tag_t *);
void bus_space_tag_destroy(bus_space_tag_t);
Those overrides work by analogy to the pci(9) overrides.
Finally, here are extensions to bus_space(9) that remain a
work-in-progress:
/* Return true iff the two tags correspond to the same bus space.
* The default implementation memcmp()'s the two tags.
*/
bool bus_space_is_equal(bus_space_tag_t, bus_space_tag_t);
/*
* Routines for reserving regions of bus space without mapping them,
* and for extending/reducing existing reservations.
*/
/* Reserve a region of bus space. Reserved bus space cannot be allocated
* with bus_space_alloc(). Unlike bus_space_alloc()'d space, reserved
* space is not bus_space_map()'d.
*/
int bus_space_reserve(bus_space_tag_t, bus_addr_t, bus_size_t,
bus_space_reservation_t *);
/* Cancel a reservation. */
void bus_space_release(bus_space_tag_t, bus_space_reservation_t);
/* Extend a reservation to the left and/or to the right. The extension
* will not be bus_space_map()'d.
*/
int bus_space_extend(bus_space_tag_t, bus_space_reservation_t, bus_size_t,
bus_size_t);
/* Trim bus space from a reservation on the left and/or on the right.
* The trimmed region must not be currently bus_space_map()'d.
*/
void bus_space_trim(bus_space_tag_t, bus_space_reservation_t, bus_size_t,
bus_size_t);
Dave
--
David Young OJC Technologies
dyoung%ojctech.com@localhost Urbana, IL * (217) 278-3933
Home |
Main Index |
Thread Index |
Old Index