Overhaul of CIS parsing, next step: keep a cached copy of the CIS,

read before we configure the card, so we can implement
/dev/cardbus*.cis.  Also, do this on a per-child basis, so we now have
a different name than before.  I think i'll have to fix that for some
legacy tools to keep working.

I can now do a dumpcis on my running atheros card and have it still work!
This commit is contained in:
Warner Losh 2008-11-17 01:32:29 +00:00
parent 30dda99b96
commit a7de0b74a7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=185015
4 changed files with 68 additions and 73 deletions

View file

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2003 M. Warner Losh. All Rights Reserved.
* Copyright (c) 2003-2008 M. Warner Losh. All Rights Reserved.
* Copyright (c) 2000,2001 Jonathan Chen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -99,20 +99,18 @@ cardbus_probe(device_t cbdev)
static int
cardbus_attach(device_t cbdev)
{
struct cardbus_softc *sc = device_get_softc(cbdev);
struct cardbus_softc *sc;
sc = device_get_softc(cbdev);
sc->sc_dev = cbdev;
cardbus_device_create(sc);
return (0);
}
static int
cardbus_detach(device_t cbdev)
{
struct cardbus_softc *sc = device_get_softc(cbdev);
cardbus_detach_card(cbdev);
cardbus_device_destroy(sc);
return (0);
}
@ -165,7 +163,9 @@ cardbus_attach_card(device_t cbdev)
int bus, domain, slot, func;
int cardattached = 0;
int cardbusfunchigh = 0;
struct cardbus_softc *sc;
sc = device_get_softc(cbdev);
cardbus_detach_card(cbdev); /* detach existing cards */
POWER_ENABLE_SOCKET(brdev, cbdev);
domain = pcib_get_domain(cbdev);
@ -192,6 +192,7 @@ cardbus_attach_card(device_t cbdev)
dinfo->pci.cfg.dev = child;
resource_list_init(&dinfo->pci.resources);
device_set_ivars(child, dinfo);
cardbus_device_create(sc, dinfo, cbdev, child);
if (cardbus_do_cis(cbdev, child) != 0)
DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n"));
pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0);
@ -235,6 +236,7 @@ cardbus_detach_card(device_t cbdev)
if (status == DS_ATTACHED || status == DS_BUSY)
device_detach(devlist[tmp]);
cardbus_release_all_resources(cbdev, dinfo);
cardbus_device_destroy(dinfo);
device_delete_child(cbdev, devlist[tmp]);
pci_freecfg((struct pci_devinfo *)dinfo);
}

View file

@ -1,4 +1,5 @@
/*-
* Copyright (c) 2005-2008, M. Warner Losh
* Copyright (c) 2000,2001 Jonathan Chen.
* All rights reserved.
*

View file

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2005, M. Warner Losh
* Copyright (c) 2005-2008, M. Warner Losh
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -63,26 +63,6 @@ static struct cdevsw cardbus_cdevsw = {
.d_name = "cardbus"
};
int
cardbus_device_create(struct cardbus_softc *sc)
{
uint32_t minor;
minor = device_get_unit(sc->sc_dev) << 16;
sc->sc_cisdev = make_dev(&cardbus_cdevsw, minor, 0, 0, 0666,
"cardbus%u.cis", device_get_unit(sc->sc_dev));
sc->sc_cisdev->si_drv1 = sc;
return (0);
}
int
cardbus_device_destroy(struct cardbus_softc *sc)
{
if (sc->sc_cisdev)
destroy_dev(sc->sc_cisdev);
return (0);
}
static int
cardbus_build_cis(device_t cbdev, device_t child, int id,
int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
@ -115,7 +95,8 @@ cardbus_build_cis(device_t cbdev, device_t child, int id,
}
static int
cardbus_device_buffer_cis(device_t parent, device_t child)
cardbus_device_buffer_cis(device_t parent, device_t child,
struct cis_buffer *cbp)
{
struct cardbus_softc *sc;
struct tuple_callbacks cb[] = {
@ -123,46 +104,44 @@ cardbus_device_buffer_cis(device_t parent, device_t child)
};
sc = device_get_softc(parent);
return (cardbus_parse_cis(parent, child, cb, &sc->sc_cis));
return (cardbus_parse_cis(parent, child, cb, cbp));
}
int
cardbus_device_create(struct cardbus_softc *sc, struct cardbus_devinfo *devi,
device_t parent, device_t child)
{
uint32_t minor;
cardbus_device_buffer_cis(parent, child, &devi->sc_cis);
minor = (device_get_unit(sc->sc_dev) << 8) + devi->pci.cfg.func;
devi->sc_cisdev = make_dev(&cardbus_cdevsw, minor, 0, 0, 0666,
"cardbus%d.%d.cis", device_get_unit(sc->sc_dev),
devi->pci.cfg.func);
/* XXX need cardbus%d.cis compat layer here ? */
devi->sc_cisdev->si_drv1 = devi;
return (0);
}
int
cardbus_device_destroy(struct cardbus_devinfo *devi)
{
if (devi->sc_cisdev)
destroy_dev(devi->sc_cisdev);
return (0);
}
static int
cardbus_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
device_t parent, child;
device_t *kids;
int cnt, err;
struct cardbus_softc *sc;
sc = dev->si_drv1;
if (sc->sc_cis_open)
return (EBUSY);
parent = sc->sc_dev;
err = device_get_children(parent, &kids, &cnt);
if (err)
return err;
sc->sc_cis.len = 0;
if (cnt == 0) {
free(kids, M_TEMP);
sc->sc_cis_open++;
return (0);
}
child = kids[0];
free(kids, M_TEMP);
err = cardbus_device_buffer_cis(parent, child);
if (err)
return (err);
sc->sc_cis_open++;
return (0);
}
static int
cardbus_close(struct cdev *dev, int fflags, int devtype, struct thread *td)
{
struct cardbus_softc *sc;
sc = dev->si_drv1;
sc->sc_cis_open = 0;
return (0);
}
@ -176,12 +155,12 @@ cardbus_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
static int
cardbus_read(struct cdev *dev, struct uio *uio, int ioflag)
{
struct cardbus_softc *sc;
struct cardbus_devinfo *devi;
sc = dev->si_drv1;
devi = dev->si_drv1;
/* EOF */
if (uio->uio_offset >= sc->sc_cis.len)
if (uio->uio_offset >= devi->sc_cis.len)
return (0);
return (uiomove(sc->sc_cis.buffer + uio->uio_offset,
MIN(uio->uio_resid, sc->sc_cis.len - uio->uio_offset), uio));
return (uiomove(devi->sc_cis.buffer + uio->uio_offset,
MIN(uio->uio_resid, devi->sc_cis.len - uio->uio_offset), uio));
}

View file

@ -1,4 +1,5 @@
/*-
* Copyright (c) 2008, M. Warner Losh
* Copyright (c) 2000,2001 Jonathan Chen.
* All rights reserved.
*
@ -29,6 +30,21 @@
/*
* Structure definitions for the Cardbus Bus driver
*/
/*
* Static copy of the CIS buffer. Technically, you aren't supposed
* to do this. In practice, however, it works well.
*/
struct cis_buffer
{
size_t len; /* Actual length of the CIS */
uint8_t buffer[2040]; /* small enough to be 2k */
};
/*
* Per child information for the PCI device. Cardbus layers on some
* additional data.
*/
struct cardbus_devinfo
{
struct pci_devinfo pci;
@ -43,36 +59,33 @@ struct cardbus_devinfo
} lan;
} funce;
uint32_t fepresent; /* bit mask of funce values present */
struct cdev *sc_cisdev;
struct cis_buffer sc_cis;
};
struct cis_buffer
{
size_t len; /* Actual length of the CIS */
uint8_t buffer[2040]; /* small enough to be 2k */
};
/*
* Per cardbus soft info. Not sure why we even keep this around...
*/
struct cardbus_softc
{
device_t sc_dev;
/* The following fields should in be in struct cardbus_devinfo */
struct cdev *sc_cisdev;
struct cis_buffer sc_cis;
int sc_cis_open;
};
/*
* Per node callback structures.
*/
struct tuple_callbacks;
typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
uint8_t *tupledata, uint32_t start, uint32_t *off,
struct tuple_callbacks *info, void *);
struct tuple_callbacks {
int id;
char *name;
tuple_cb *func;
};
int cardbus_device_create(struct cardbus_softc *);
int cardbus_device_destroy(struct cardbus_softc *);
int cardbus_device_create(struct cardbus_softc *sc,
struct cardbus_devinfo *devi, device_t parent, device_t child);
int cardbus_device_destroy(struct cardbus_devinfo *devi);
int cardbus_parse_cis(device_t cbdev, device_t child,
struct tuple_callbacks *callbacks, void *);