From owner-svn-src-stable-7@FreeBSD.ORG Wed Jun 10 19:21:23 2009 Return-Path: Delivered-To: svn-src-stable-7@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8C2CA106564A; Wed, 10 Jun 2009 19:21:23 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 7879A8FC13; Wed, 10 Jun 2009 19:21:23 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n5AJLN2v023481; Wed, 10 Jun 2009 19:21:23 GMT (envelope-from imp@svn.freebsd.org) Received: (from imp@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n5AJLNDe023477; Wed, 10 Jun 2009 19:21:23 GMT (envelope-from imp@svn.freebsd.org) Message-Id: <200906101921.n5AJLNDe023477@svn.freebsd.org> From: Warner Losh Date: Wed, 10 Jun 2009 19:21:23 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r193945 - stable/7/sys/dev/cardbus X-BeenThere: svn-src-stable-7@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 7-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 10 Jun 2009 19:21:24 -0000 Author: imp Date: Wed Jun 10 19:21:23 2009 New Revision: 193945 URL: http://svn.freebsd.org/changeset/base/193945 Log: MFC: r188216 | wkoszek | 2009-02-05 17:55:19 -0700 (Thu, 05 Feb 2009) | 5 lines r185545 | imp | 2008-12-01 21:54:31 -0700 (Mon, 01 Dec 2008) | 2 lines r185140 | imp | 2008-11-20 20:03:57 -0700 (Thu, 20 Nov 2008) | 4 lines r185015 | imp | 2008-11-16 18:32:29 -0700 (Sun, 16 Nov 2008) | 8 lines r184981 | imp | 2008-11-14 22:22:06 -0700 (Fri, 14 Nov 2008) | 5 lines These commits move all the parsing of the CIS to where the card is detected, rather than when the open call for the device happens. This means that we can now reliably get this info from cards. Atheros network cards in conjunction with the HAL were a primary motivator for this fix, although other applications benefit. Modified: stable/7/sys/dev/cardbus/cardbus.c stable/7/sys/dev/cardbus/cardbus_cis.c stable/7/sys/dev/cardbus/cardbus_device.c stable/7/sys/dev/cardbus/cardbusvar.h Modified: stable/7/sys/dev/cardbus/cardbus.c ============================================================================== --- stable/7/sys/dev/cardbus/cardbus.c Wed Jun 10 19:03:23 2009 (r193944) +++ stable/7/sys/dev/cardbus/cardbus.c Wed Jun 10 19:21:23 2009 (r193945) @@ -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); } Modified: stable/7/sys/dev/cardbus/cardbus_cis.c ============================================================================== --- stable/7/sys/dev/cardbus/cardbus_cis.c Wed Jun 10 19:03:23 2009 (r193944) +++ stable/7/sys/dev/cardbus/cardbus_cis.c Wed Jun 10 19:21:23 2009 (r193945) @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2005-2008, M. Warner Losh * Copyright (c) 2000,2001 Jonathan Chen. * All rights reserved. * @@ -318,29 +319,27 @@ decode_tuple_bar(device_t cbdev, device_ if (type == SYS_RES_MEMORY) { if (reg & TPL_BAR_REG_PREFETCHABLE) dinfo->mprefetchable |= (1 << PCI_RID2BAR(bar)); -#if 0 /* - * XXX: It appears from a careful reading of the spec - * that we're not supposed to honor this when the bridge - * is not on the main system bus. PCI spec doesn't appear - * to allow for memory ranges not listed in the bridge's - * decode range to be decoded. The PC Card spec seems to - * indicate that this should only be done on x86 based - * machines, which seems to imply that on non-x86 machines - * the adddresses can be anywhere. This further implies that - * since the hardware can do it on non-x86 machines, it should - * be able to do it on x86 machines. Therefore, we can and - * should ignore this hint. Furthermore, the PC Card spec - * recommends always allocating memory above 1MB, contradicting - * the other part of the PC Card spec. + * The PC Card spec says we're only supposed to honor this + * hint when the cardbus bridge is a child of pci0 (the main + * bus). The PC Card spec seems to indicate that this should + * only be done on x86 based machines, which suggests that on + * non-x86 machines the adddresses can be anywhere. Since the + * hardware can do it on non-x86 machines, it should be able + * to do it on x86 machines too. Therefore, we can and should + * ignore this hint. Furthermore, the PC Card spec recommends + * always allocating memory above 1MB, contradicting the other + * part of the PC Card spec, it seems. We make note of it, + * but otherwise don't use this information. * - * NetBSD ignores this bit, but it also ignores the - * prefetchable bit too, so that's not an indication of - * correctness. + * Some Realtek cards have this set in their CIS, but fail + * to actually work when mapped this way, and experience + * has shown ignoring this big to be a wise choice. + * + * XXX We should cite chapter and verse for standard refs. */ if (reg & TPL_BAR_REG_BELOW1MB) dinfo->mbelow1mb |= (1 << PCI_RID2BAR(bar)); -#endif } return (0); Modified: stable/7/sys/dev/cardbus/cardbus_device.c ============================================================================== --- stable/7/sys/dev/cardbus/cardbus_device.c Wed Jun 10 19:03:23 2009 (r193944) +++ stable/7/sys/dev/cardbus/cardbus_device.c Wed Jun 10 19:21:23 2009 (r193945) @@ -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, @@ -96,13 +76,17 @@ cardbus_build_cis(device_t cbdev, device * CISTPL_END is a special case, it has no length field. */ if (id == CISTPL_END) { - if (cis->len + 1 > sizeof(cis->buffer)) + if (cis->len + 1 > sizeof(cis->buffer)) { + cis->len = 0; return (ENOSPC); + } cis->buffer[cis->len++] = id; return (0); } - if (cis->len + 2 + len > sizeof(cis->buffer)) + if (cis->len + 2 + len > sizeof(cis->buffer)) { + cis->len = 0; return (ENOSPC); + } cis->buffer[cis->len++] = id; cis->buffer[cis->len++] = len; for (i = 0; i < len; i++) @@ -110,52 +94,54 @@ cardbus_build_cis(device_t cbdev, device return (0); } -static int -cardbus_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +static int +cardbus_device_buffer_cis(device_t parent, device_t child, + struct cis_buffer *cbp) { - device_t parent, child; - device_t *kids; - int cnt, err; - struct cardbus_softc *sc; struct tuple_callbacks cb[] = { {CISTPL_GENERIC, "GENERIC", cardbus_build_cis} }; - 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; - if (cnt == 0) { - free(kids, M_TEMP); - sc->sc_cis_open++; - sc->sc_cis = NULL; - return (0); - } - child = kids[0]; - free(kids, M_TEMP); - sc->sc_cis = malloc(sizeof(*sc->sc_cis), M_TEMP, M_ZERO | M_WAITOK); - err = cardbus_parse_cis(parent, child, cb, sc->sc_cis); - if (err) { - free(sc->sc_cis, M_TEMP); - sc->sc_cis = NULL; - return (err); - } - sc->sc_cis_open++; + 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; + int unit; + + cardbus_device_buffer_cis(parent, child, &devi->sc_cis); + minor = (device_get_unit(sc->sc_dev) << 8) + devi->pci.cfg.func; + unit = device_get_unit(sc->sc_dev); + devi->sc_cisdev = make_dev(&cardbus_cdevsw, minor, 0, 0, 0666, + "cardbus%d.%d.cis", unit, devi->pci.cfg.func); + if (devi->pci.cfg.func == 0) + make_dev_alias(devi->sc_cisdev, "cardbus%d.cis", unit); + 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) +{ + return (0); } static int cardbus_close(struct cdev *dev, int fflags, int devtype, struct thread *td) { - struct cardbus_softc *sc; - sc = dev->si_drv1; - free(sc->sc_cis, M_TEMP); - sc->sc_cis = NULL; - sc->sc_cis_open = 0; return (0); } @@ -169,12 +155,12 @@ cardbus_ioctl(struct cdev *dev, u_long c 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 (sc->sc_cis == NULL || 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)); } Modified: stable/7/sys/dev/cardbus/cardbusvar.h ============================================================================== --- stable/7/sys/dev/cardbus/cardbusvar.h Wed Jun 10 19:03:23 2009 (r193944) +++ stable/7/sys/dev/cardbus/cardbusvar.h Wed Jun 10 19:21:23 2009 (r193945) @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2008, M. Warner Losh * Copyright (c) 2000,2001 Jonathan Chen. * All rights reserved. * @@ -29,12 +30,26 @@ /* * 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; uint8_t mprefetchable; /* bit mask of prefetchable BARs */ uint8_t mbelow1mb; /* bit mask of BARs which require below 1Mb */ - uint8_t ibelow1mb; /* bit mask of BARs which require below 1Mb */ uint16_t mfrid; /* manufacturer id */ uint16_t prodid; /* product id */ u_int funcid; /* function id */ @@ -44,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 { - /* XXX need mutex XXX */ device_t sc_dev; - 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 *);